<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="http://wiki.openhome.org/mediawiki/skins/common/feed.css?270"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>http://wiki.openhome.org/mediawiki/index.php?feed=atom&amp;target=Openhome&amp;title=Special%3AContributions</id>
		<title>OpenHome - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="http://wiki.openhome.org/mediawiki/index.php?feed=atom&amp;target=Openhome&amp;title=Special%3AContributions"/>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Special:Contributions/Openhome"/>
		<updated>2026-04-16T07:05:45Z</updated>
		<subtitle>From OpenHome</subtitle>
		<generator>MediaWiki 1.16.2</generator>

	<entry>
		<id>http://wiki.openhome.org/wiki/File:Jigsaw.png</id>
		<title>File:Jigsaw.png</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/File:Jigsaw.png"/>
				<updated>2013-07-04T14:12:58Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: uploaded a new version of &amp;amp;quot;File:Jigsaw.png&amp;amp;quot;: Reverted to version as of 14:10, 4 July 2013&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Jigsaw&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/File:Jigsaw.png</id>
		<title>File:Jigsaw.png</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/File:Jigsaw.png"/>
				<updated>2013-07-04T14:12:31Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: uploaded a new version of &amp;amp;quot;File:Jigsaw.png&amp;amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Jigsaw&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/File:Jigsaw.png</id>
		<title>File:Jigsaw.png</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/File:Jigsaw.png"/>
				<updated>2013-07-04T14:10:57Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: uploaded a new version of &amp;amp;quot;File:Jigsaw.png&amp;amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Jigsaw&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/File:Jigsaw.png</id>
		<title>File:Jigsaw.png</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/File:Jigsaw.png"/>
				<updated>2013-07-04T14:06:21Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: uploaded a new version of &amp;amp;quot;File:Jigsaw.png&amp;amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Jigsaw&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhRemote</id>
		<title>OhRemote</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhRemote"/>
				<updated>2012-03-06T15:54:05Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= ohRemote = &lt;br /&gt;
&lt;br /&gt;
ohRemote provides the set of server components used to access ohOs apps from outside the home.&lt;br /&gt;
&lt;br /&gt;
==== Simple for an end user to set up and use ====&lt;br /&gt;
It has been designed to be trivial for end users to setup and use.  All communications are routed through a central server, avoiding any requirement for users to learn about port forwarding, static external IP addresses, or setup firewall rules to allow incoming http connections etc.&lt;br /&gt;
&lt;br /&gt;
==== Cheap to host ====&lt;br /&gt;
Secondly, it has been designed so that the central server can be inexpensive for Node manufacturers to host.  It is intended that tens of thousands of clients (homes) can be accommodated by a single server.  When user numbers grow beyond this or the geographical spread of users makes a single server a bottleneck, minimal work will allow any number of additional servers to be deployed.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In addition to the software in ohRemote, remote access requires some additional features in [[ohOs|ohOs]].  These are also described below.&lt;br /&gt;
&lt;br /&gt;
== How do I get it? ==&lt;br /&gt;
[https://github.com/openhome/ohremote Source code] is available to selected partners.  OpenHome also maintain a demo server.  Contact info@openhome.org if you require access to either.&lt;br /&gt;
&lt;br /&gt;
== System Architecture ==&lt;br /&gt;
[[File:RemoteAccessOverview.png|800px|center]]&lt;br /&gt;
&lt;br /&gt;
The server contains the following components:&lt;br /&gt;
* [http://www.stunnel.org/ Stunnel] – a SSL tunnel which allows secure communications between user/node and the server without server components having to understand SSL.&lt;br /&gt;
* A reverse proxy server – [http://haproxy.1wt.eu/ HaProxy].  This directs web requests to the correct server component.&lt;br /&gt;
* Web server, provided by [http://nodejs.org/ Node.js]&lt;br /&gt;
* Web services, implemented using [http://nodejs.org/ Node.js]&lt;br /&gt;
* SSH server, provided by [http://matt.ucc.asn.au/dropbear/dropbear.html dropbear]&lt;br /&gt;
* Client authentication – a [http://en.wikipedia.org/wiki/Pluggable_authentication_module pluggable authentication module] used by the ssh server when deciding whether to accept a connection request from a Node.&lt;br /&gt;
* Databases, provided by [http://www.mysql.com MySQL]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The Node contains the following components:&lt;br /&gt;
* Standard node software&lt;br /&gt;
* Provider for RemoteAccess UPnP service&lt;br /&gt;
* Remote access settings registry (currently combined with provider).  This stores username, password, user-facing control url &amp;amp; node-facing web services url&lt;br /&gt;
* Proxy server.  This connects to the remote access server’s ssh server and listens for requests, forwarding them to the appropriate locations on the standard node web server.  The proxy server uses standard .NET classes – &amp;lt;tt&amp;gt;HttpListener&amp;lt;/tt&amp;gt; for the server and &amp;lt;tt&amp;gt;HttpWebRequest&amp;lt;/tt&amp;gt; to forward requests.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The remote client contains the following components:&lt;br /&gt;
* Any web browser supported by the Node UI.&lt;br /&gt;
&lt;br /&gt;
== Use cases == &lt;br /&gt;
To aid understanding of the architecture diagram, key use cases for the system are described below.&lt;br /&gt;
&lt;br /&gt;
=== Register new Node ===&lt;br /&gt;
* User brings up their Node UI inside the home&lt;br /&gt;
* User enters desired username &amp;amp; password&lt;br /&gt;
* Provider for RemoteAccess service is called for &amp;lt;tt&amp;gt;SetUserName&amp;lt;/tt&amp;gt; action&lt;br /&gt;
* Provider calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; web service&lt;br /&gt;
* Registration web service on remote access server is called (via Stunnel then HaProxy)&lt;br /&gt;
* If requested username is available, registration service adds a record to the Login Database.  Otherwise, it generates a list of similar usernames which are still available and returns this as part of an error.&lt;br /&gt;
* Assuming registration succeeded, Username is added to remote access registry.  &amp;lt;tt&amp;gt;SetUserName&amp;lt;/tt&amp;gt; action returns success.&lt;br /&gt;
* UI calls &amp;lt;tt&amp;gt;SetPassword&amp;lt;/tt&amp;gt; action.  Password is added to remote access registry and action returns success.&lt;br /&gt;
* UI calls &amp;lt;tt&amp;gt;SetEnable&amp;lt;/tt&amp;gt; action.  Enabled state is set in remote access registry.  Enabling remote access is then covered by the next use case...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Connect a registered Node ===&lt;br /&gt;
* Happens either when &amp;lt;tt&amp;gt;SetEnable&amp;lt;/tt&amp;gt; action is called or ohOs starts when remote access was previously enabled.&lt;br /&gt;
* Provider for RemoteAccess service calls &amp;lt;tt&amp;gt;getaddress&amp;lt;/tt&amp;gt; on Node Login service (via Stunnel then HaProxy)&lt;br /&gt;
* Node Login service checks that node has been previously registered (by checking for node’s udn in Login Database).  If the node is unregistered, an error is returned.&lt;br /&gt;
* Node Login service calls Port Finder service to determine which port of the ssh server the node should connect to.&lt;br /&gt;
* Port Finder service determines a free port.  Node Login service writes node udn, port and status (pending) to the Session Database.&lt;br /&gt;
* Home node now has approx 1 minute to connect to the ssh server.  The Node Login service periodically checks the Session Database and removes records that have been pending for longer than 1 minute.&lt;br /&gt;
* Node Login service checks config file to determine ssh server host name and IP address/port to bind to for remote port forwarding.  These 3 details plus the port determined above are returned to the home node.&lt;br /&gt;
* Home node starts its proxy server.  This is currently hard-coded to listen on port 55170.&lt;br /&gt;
* Home node connects to ssh server.  Server uses PAM SQL Lookup to validate ssh key used in connection request against key in Login Database.  Server then changes status of node’s record in Session Database to ‘connected’.&lt;br /&gt;
* Home node sets up remote port forwarding for the port its proxy server is listening on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== User connects remotely ===&lt;br /&gt;
* User enters the url returned by the node registration process into their web browser.&lt;br /&gt;
* This reaches the Login web service (via Stunnel and HaProxy).&lt;br /&gt;
* The url path is the user name that was selected during registration.  Login service looks this up in Login Database and redirects the request to HaProxy with the path changed to the node udn which matches the username.&lt;br /&gt;
* HaProxy uses the node udn to look up ssh server address/port in the Session Database.&lt;br /&gt;
* HaProxy forwards the request to the appropriate address/port on the ssh server.&lt;br /&gt;
* Ssh server forwards the request to the appropriate proxy server on a home node.&lt;br /&gt;
* Home node checks for the presence of a login cookie in the request.  If this is missing, the request is redirected to a login page hosted by the home node.&lt;br /&gt;
* When the first request completes, HaProxy sets a session cookie noting the Session Database row id for this user.&lt;br /&gt;
* The user’s web browser displays the login page prompting for username and password.  The results from this are sent to the home node’s proxy server which checks them against the data in its remote access registry.  If the login is valid, another session cookie is set and the user is redirected to the root of the home node’s proxy server.&lt;br /&gt;
* The user’s web browser issues a GET request for ‘/’.  HaProxy uses its cookie to find the correct ssh server address/port.  (This may come from either the session database or an in-memory cache.)  The home node’s proxy server manually forwards the request to the web server home UIs are available from, applying minor rewrites (such as compression) to the response.&lt;br /&gt;
&lt;br /&gt;
== Deployment ==&lt;br /&gt;
=== Server ===&lt;br /&gt;
All configuration options are contained in the file &amp;lt;tt&amp;gt;ohremote/scripts/config&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;br&amp;gt;Hosting the server on a box with 2 IP addresses is recommended.  This allows both the ssh server and web services to operate on port 443.  This port is used by https so is likely to be open for outbound requests on most firewalls.  (An argument could be made for port 80 – as used by http.  This is at least as likely to be open on firewalls but is more likely to be subject to packet inspection and blocked as our use here will appear different to traditional web access.)&lt;br /&gt;
&lt;br /&gt;
=== Node ===&lt;br /&gt;
The location of the remote access server must be set in the &amp;lt;tt&amp;gt;remote-access-server&amp;lt;/tt&amp;gt; tag of &amp;lt;tt&amp;gt;ohos.ohconfig.xml&amp;lt;/tt&amp;gt;.  This file is generated from &amp;lt;tt&amp;gt;ohOs/src/Host/Host.ohconfig.xml.template&amp;lt;/tt&amp;gt; during a build or the generated file can be edited and ohOs restarted to apply changes.&lt;br /&gt;
&amp;lt;br&amp;gt;The Node must be capable of generating a RSA format SSH key.  This is currently only supported on Linux; other platforms need to manually generate the keys and move them (named key.priv &amp;amp; key.pub) to the remote directory in ohWidget’s store.&lt;br /&gt;
&lt;br /&gt;
== Monitoring ==&lt;br /&gt;
=== Server ===&lt;br /&gt;
Every 3 seconds, checks status of each component, restarting server if any component does not respond correctly.  See &amp;lt;tt&amp;gt;ohremote/scripts/ohmonitor&amp;lt;/tt&amp;gt; for details.&lt;br /&gt;
&lt;br /&gt;
=== Node ===&lt;br /&gt;
Every 5 minutes, issues a &amp;lt;tt&amp;gt;HEAD&amp;lt;/tt&amp;gt; request to the user-facing uri returned by register web service (and then stored in registry).  If this fails, disconnects from ssh server, stops (local) proxy server then repeats “Connect a registered node” use case.  If connection fails, it is retried at randomised (but increasing) intervals thereafter.&lt;br /&gt;
&lt;br /&gt;
== APIs ==&lt;br /&gt;
=== Server Web Services ===&lt;br /&gt;
'''1. To register for remote access, including selecting a username'''&lt;br /&gt;
 URL:  [server_url]/register&lt;br /&gt;
 Body:&lt;br /&gt;
    &amp;lt;register&amp;gt;&lt;br /&gt;
        &amp;lt;username&amp;gt;[Proposed username]&amp;lt;/username&amp;gt;&lt;br /&gt;
        &amp;lt;uidnode&amp;gt;[Node’s UDN]&amp;lt;/uidnode&amp;gt;&lt;br /&gt;
        &amp;lt;sshkey&amp;gt;[Contents of public key]&amp;lt;/sshkey&amp;gt;&lt;br /&gt;
    &amp;lt;/register&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Returns (success):&lt;br /&gt;
    &amp;lt;result&amp;gt;&lt;br /&gt;
        &amp;lt;success&amp;gt;[Proposed username]&amp;lt;/success&amp;gt;&lt;br /&gt;
    &amp;lt;/result&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Returns (failure):&lt;br /&gt;
    &amp;lt;result&amp;gt;&lt;br /&gt;
        &amp;lt;error&amp;gt;Username exists&amp;lt;/error&amp;gt;&lt;br /&gt;
        &amp;lt;suggestionlist&amp;gt;&lt;br /&gt;
            &amp;lt;suggestion&amp;gt;First suggested free name&amp;lt;/suggestion&amp;gt;&lt;br /&gt;
            &amp;lt;suggestion&amp;gt;Second suggested free name&amp;lt;/suggestion&amp;gt;&lt;br /&gt;
            &amp;lt;suggestion&amp;gt;etc.&amp;lt;/suggestion&amp;gt;&lt;br /&gt;
        &amp;lt;/suggestionlist&amp;gt;&lt;br /&gt;
    &amp;lt;/result&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''2. To clear an account - (deregister interest in remote access, remove username)'''&lt;br /&gt;
 URL:  [server_url]/remove&lt;br /&gt;
 Body:&lt;br /&gt;
    &amp;lt;remove&amp;gt;&lt;br /&gt;
        &amp;lt;uidnode&amp;gt;[Node’s UDN]&amp;lt;/uidnode&amp;gt;&lt;br /&gt;
    &amp;lt;/remove&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Returns (success):&lt;br /&gt;
    &amp;lt;result&amp;gt;&lt;br /&gt;
        &amp;lt;success&amp;gt;[Node’s UDN]&amp;lt;/success&amp;gt;&lt;br /&gt;
    &amp;lt;/result&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Returns (failure):&lt;br /&gt;
    &amp;lt;result&amp;gt;&lt;br /&gt;
        &amp;lt;error&amp;gt;[Error Message]&amp;lt;/error&amp;gt;&lt;br /&gt;
    &amp;lt;/result&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''3. To get connection details for the ssh tunnel'''&lt;br /&gt;
 URL:  [server_url]/getaddress&lt;br /&gt;
 Body:&lt;br /&gt;
    &amp;lt;getaddress&amp;gt;&lt;br /&gt;
        &amp;lt;uidnode&amp;gt;[Node’s UDN]&amp;lt;/uidnode&amp;gt;&lt;br /&gt;
    &amp;lt;/getaddress&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Returns (success):&lt;br /&gt;
    &amp;lt;result&amp;gt;&lt;br /&gt;
        &amp;lt;success&amp;gt;&lt;br /&gt;
            &amp;lt;sshserver&amp;gt;&lt;br /&gt;
                &amp;lt;address&amp;gt;[Ssh server host (or address)]&amp;lt;/address&amp;gt;&lt;br /&gt;
                &amp;lt;port&amp;gt;[Ssh server port to connect to]&amp;lt;/port&amp;gt;&lt;br /&gt;
            &amp;lt;/sshserver&amp;gt;&lt;br /&gt;
            &amp;lt;portforward&amp;gt;&lt;br /&gt;
                &amp;lt;address&amp;gt;[Address for remote port forwarding]&amp;lt;/address&amp;gt;&lt;br /&gt;
                &amp;lt;port&amp;gt;[Port for remote port forwarding]&amp;lt;/port&amp;gt;&lt;br /&gt;
            &amp;lt;/portforward&amp;gt;&lt;br /&gt;
        &amp;lt;/success&amp;gt;&lt;br /&gt;
    &amp;lt;/result&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Returns (failure):&lt;br /&gt;
    &amp;lt;result&amp;gt;&lt;br /&gt;
        &amp;lt;error&amp;gt;[Error Message]&amp;lt;/error&amp;gt;&lt;br /&gt;
    &amp;lt;/result&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Node web service ===&lt;br /&gt;
As with other Node features, this is available as a UPnP service - openhome-org:service:RemoteAccess:1.&lt;br /&gt;
==== State variables ====&lt;br /&gt;
* &amp;lt;tt&amp;gt;Enabled&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; if remote access is currently enabled; &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; otherwise.&lt;br /&gt;
* &amp;lt;tt&amp;gt;PasswordSet&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; if a password is currently set; &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; otherwise.  (Note that the password itself cannot be queried.)&lt;br /&gt;
* &amp;lt;tt&amp;gt;PublicUri&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;The url used for remote access.  This is set once a Node has registered for remote access.  The value does not change when &amp;lt;tt&amp;gt;Enabled&amp;lt;/tt&amp;gt; changes.&lt;br /&gt;
* &amp;lt;tt&amp;gt;UserName&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;The username selected during registration; or &amp;lt;tt&amp;gt;&amp;quot;&amp;quot;&amp;lt;/tt&amp;gt; if the Node is not registered for remote access.&lt;br /&gt;
&lt;br /&gt;
==== Actions ====&lt;br /&gt;
* &amp;lt;tt&amp;gt;SetUserName(in uint Handle, in string UserName, out bool Succeeded, out string AlternativeNames)&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;Register a Node for remote access, selecting its unique username.  Arguments are:&lt;br /&gt;
** &amp;lt;tt&amp;gt;''Handle'': &amp;lt;/tt&amp;gt;Reserved for future compatability.  Must be 0.&lt;br /&gt;
** &amp;lt;tt&amp;gt;''UserName'': &amp;lt;/tt&amp;gt;Proposed username.&lt;br /&gt;
** &amp;lt;tt&amp;gt;''Succeeded'': &amp;lt;/tt&amp;gt;&amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt; if &amp;lt;tt&amp;gt;UserName&amp;lt;/tt&amp;gt; was available; &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; otherwise.&lt;br /&gt;
** &amp;lt;tt&amp;gt;''AlternativeNames'': &amp;lt;/tt&amp;gt;XML block in the same form as &amp;lt;tt&amp;gt;suggestionlist&amp;lt;/tt&amp;gt; block from &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; web service.&lt;br /&gt;
* &amp;lt;tt&amp;gt;SetPassword(int uint Handle, in string Password)&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;Set a password used to authenticate remote connection requests.  Arguments are:&lt;br /&gt;
** &amp;lt;tt&amp;gt;''Handle'': &amp;lt;/tt&amp;gt;Reserved for future compatability.  Must be 0.&lt;br /&gt;
** &amp;lt;tt&amp;gt;''Password'': &amp;lt;/tt&amp;gt;Password.  This is held locally on the Node so is guaranteed to be valid.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Enable(bool Enable)&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;Enable remote access.  This can only be called when a valid username and password are set.  i.e. When the &amp;lt;tt&amp;gt;UserName&amp;lt;/tt&amp;gt; state variable is non-empty and the &amp;lt;tt&amp;gt;PasswordSet&amp;lt;/tt&amp;gt; state variable is &amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;.  Arguments are:&lt;br /&gt;
** &amp;lt;tt&amp;gt;''Enable'': &amp;lt;/tt&amp;gt;&amp;lt;tt&amp;gt;True&amp;lt;/tt&amp;gt; if remote access should be enabled; &amp;lt;tt&amp;gt;false&amp;lt;/tt&amp;gt; if it is currently enabled and should be disabled.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Reset(uint Handle)&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;Disable remote access, remove registration with remote access server and clear local username and password.&lt;br /&gt;
* &amp;lt;tt&amp;gt;ClearAuthenticatedClients()&amp;lt;/tt&amp;gt;&amp;lt;br&amp;gt;Force any active remote access sessions to re-authenticate.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhMedia</id>
		<title>OhMedia</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhMedia"/>
				<updated>2012-03-02T10:48:44Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Developers */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= ohMedia Overview =&lt;br /&gt;
&lt;br /&gt;
ohMedia is an open standard that allows the seamless interaction of media within your home.&lt;br /&gt;
&lt;br /&gt;
ohMedia's high level design is influenced by the UPnP AV standard (UAV). UAV correctly modelled media in the home as the interaction between 3 types of devices: Control Points, Media Renderers, and Media Servers.&lt;br /&gt;
&amp;lt;&amp;lt;picture&amp;gt;&amp;gt;&lt;br /&gt;
This model correctly identified the potential presence of an arbitrary number of each of these devices. However, the Media Server specification, and in particular the Media Renderer specification is deeply flawed. The next section explains those flaws and outlines how ohMedia fixes them.&lt;br /&gt;
&lt;br /&gt;
= Flaws in the UPnP AV Standard =&lt;br /&gt;
&lt;br /&gt;
== Problem 1: No support for gap-less audio ==&lt;br /&gt;
&lt;br /&gt;
The UPnP AV media renderer specification is technically able to support gap-less audio though the AV Transport service actions, setAVTRansportURI and setNextAVTransportURI. However, the UPnP forum chose to make the setNextAVTransportURI action optional. This meant that no, or very few, media renderer manufacturers chose to support the action, which in turn, meant that no control points have added support for gap-less audio. So the real world situation is that UPnP AV has no support for gap-less audio.&lt;br /&gt;
&lt;br /&gt;
== Problem 2: No support for a user's playlist to continue playing when a control point is turned off ==&lt;br /&gt;
&lt;br /&gt;
The UPnP AV media renderer specification only allows for a media renderer to store a maximum of two URIs, but, as previously discussed, the real world maximum is in fact only a single URI. This means that in order for a media renderer to play a user created playlist the control point has to be continually monitoring the media renderer. When the media renderer indicates that it has finished playing the current URI the control point then has to set the next URI. If the control point is turned off and not monitoring the media renderer then the media renderer will not be informed of the next URI and playback will stop.&lt;br /&gt;
&lt;br /&gt;
== Problem 3:  No support for multiple control points ==&lt;br /&gt;
&lt;br /&gt;
The UPnP AV media renderer specification caters for the case where a user wants multiple control  points to show the metadata that is associated with the currently playing URI. However when it comes to controlling a media renderer from multiple control points the standard quickly shows it inadequacies.&lt;br /&gt;
&lt;br /&gt;
The main problems comes from the fact that the media renderer only holds a URI for the currently playing URI. This means that only the control point that the user used to create a playlist has knowledge about the playlist. As described earlier, because this control point holds the user's playlist it is actually controlling the flow of URIs to the media renderer. What happens if the same user adds tracks to a different control point? At this point two control points are trying to control the flow of different URIs to the media renderer. At this point the whole system fails to operate as the user expects.&lt;br /&gt;
&lt;br /&gt;
When a user creates a playlist on their control point and starts playback on a UPnP AV media renderer the renderer only holds the currently playing URI. When the renderer finishes the current URI the control point provides the renderer with next URI. If the control point is turned off at the point when the renderer finishes playing the current URI the renderer will stop playback.&lt;br /&gt;
&lt;br /&gt;
With the control point controlling the flow of URIs to the media renderer the UPnP AV media renderer specification violates the 3 box model separation where the control point should, without any intervention, enable content to flow between the media server and media renderer.&lt;br /&gt;
&lt;br /&gt;
== Problem 4: No concept of a Hi-Fi system comprising of more than one product or a home comprising of more than one Hi-Fi system ==&lt;br /&gt;
&lt;br /&gt;
A modern home can have one or more Hi-Fi systems of which each Hi-Fi system can comprise of one or more products connected together, e.g. a media player and a pre-amp.&lt;br /&gt;
&lt;br /&gt;
The UPnP AV standard assumes a single box which is made up of a single source and possibly a volume control. The standard has no way of representing a system that is made up of several different boxes connected together, e.g. a media renderer connected into a pre-amp. Taking the example of a media renderer connected to a pre-amp, without the ability to represent the different boxes and how they are connected it is impossible, using the UPnP AV standard, to select the input on the pre-amp that the media renderer is connected to when the user selects the media renderer in a control point.&lt;br /&gt;
&lt;br /&gt;
== Problem 5: Media's URI changing when media server rebuilds its database ==&lt;br /&gt;
&lt;br /&gt;
The UPnP AV media server specification does not have a requirement for media servers to present a piece of media to the network with the same URI. This has resulted in media server implementations that change media URIs when a user changes their media collection. This results in unexpected behaviour for the user. For example, a user plays some media on their renderer. The user then modifies their media collection which results in the media server rebuilding its database. The user then presses play on their renderer to only hear nothing (the URI is now no longer valid) or worse some different piece of media (the URI now represents some different media).&lt;br /&gt;
&lt;br /&gt;
= ohMedia Solutions =&lt;br /&gt;
The ohMedia standard has been designed to solve all the problems described above.&lt;br /&gt;
&lt;br /&gt;
The first three problems are solved through the [[#ohPlaylist|ohPlaylist]] service specification.&lt;br /&gt;
&lt;br /&gt;
Problem 4 is solved through the [[#ohProduct_and_ohTopology|ohProduct service specification and the ohTopology algorithm]].&lt;br /&gt;
&lt;br /&gt;
Problem 5 is solved through the [[#Server|ohMedia server]] specification.&lt;br /&gt;
&lt;br /&gt;
The ohMedia standard goes further and adds the [[#ohSongcast|ohSongcast]] standard. [[#ohSongcast|ohSongcast]] provides the ability to synchronise playback between products, commonly referred to as party mode. However in general [[#ohSongcast|ohSongcast]] provides the ability for a product to stream its audio over a standard home network and for any product that supports the [[#ohSongcast|ohSongcast]] receiver specification to receive the audio and play it back.&lt;br /&gt;
&lt;br /&gt;
= How it works =&lt;br /&gt;
&lt;br /&gt;
ohMedia models media in the home through the interaction of 3 types of device, Control Points, Media Players and Media Servers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;&amp;lt;picture of 3 devices as before, but with arrows labelled with 1. Browse, 2. Tell, 3. Retrieve&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The Control Point first browses the Media Server to locate the desired media. The Control Point then tells the Media Player to play the selected media and finally Media Player retrieves the media from the Media Server.&lt;br /&gt;
&lt;br /&gt;
== ohProduct and ohTopology ==&lt;br /&gt;
&lt;br /&gt;
ohMedia models a home as a number Hi-Fi systems, which are located in rooms.&lt;br /&gt;
&lt;br /&gt;
ohMedia models a Hi-Fi system as a hierarchical tree of products, where a product is defined as a single physical box that is located in a room, has a unique name within the room, has one output and any number of sources.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;&amp;lt;diagram of a product with multi-in, one out&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A product is modelled through the ohProduct service specification.&lt;br /&gt;
&lt;br /&gt;
When a control point wants to construct a model of a user's home they use the ohTopology algorithm. The ohTopology algorithm is as follows,&lt;br /&gt;
&lt;br /&gt;
#discover all the products in the home that have an ohProduct service&lt;br /&gt;
#group the discovered products based on the room they are in&lt;br /&gt;
#create a hierarchical tree structure by matching source names to product names&lt;br /&gt;
#discover source functionality based on source type&lt;br /&gt;
#discover additional functionality based on product attributes&lt;br /&gt;
&lt;br /&gt;
e.g. if we had two products, a pre-amp and a media player, which were connected together then both their ohProduct services would return the same room name and one of the source names returned by the pre-amp's ohProduct service would be the same as the product name returned by the media renderer's ohProduct service.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;&amp;lt;picture of example&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sources ==&lt;br /&gt;
&lt;br /&gt;
ohMedia defines four source types,&lt;br /&gt;
&lt;br /&gt;
#Playlist – product supports on device playlists&lt;br /&gt;
#Radio – product supports internet radio with presets&lt;br /&gt;
#Receiver – product supports receiving ohSongcast broadcasts&lt;br /&gt;
#UpnpAv – product also implements the UPnP AV media renderer specification&lt;br /&gt;
&lt;br /&gt;
If a source type is not one of the types above an ohMedia control point will be able to switch to the source but will treat the source as a non controllable external input e.g. Analogue, TOS or HDMI.&lt;br /&gt;
&lt;br /&gt;
== Attributes ==&lt;br /&gt;
&lt;br /&gt;
ohMedia defines three attributes,&lt;br /&gt;
&lt;br /&gt;
#Volume – product supports volume control&lt;br /&gt;
#Info – product supports providing information about the currently playing media&lt;br /&gt;
#Time – product supports providing the current time within the currently playing media&lt;br /&gt;
#Sender – product supports ohSongcast broadcasting&lt;br /&gt;
&lt;br /&gt;
== ohPlaylist ==&lt;br /&gt;
&lt;br /&gt;
The ohPlaylist specification has been designed to allow gap-less audio, playlists to proceed without the intervention of a control point and to function correctly under the manipulation of multiple control points.&lt;br /&gt;
&lt;br /&gt;
The ohPlaylist is a list of media associated with a unique ID. Media is defined by its URI and metadata. A control point is required to keep in memory the current list of playlist IDs. This list of IDs can then be used to list the media in the order of play, obtain the metadata and manipulate the list.&lt;br /&gt;
&lt;br /&gt;
The Playlist service provides the API that allow control points to manipulate, keep track of playlist changes and control playback.&lt;br /&gt;
&lt;br /&gt;
== ohSongcast ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;&amp;lt;to do&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Server ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;&amp;lt;to do&amp;gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Developers =&lt;br /&gt;
&lt;br /&gt;
If you are interested in ohMedia development, more information can be found [[Av:Developer|here]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget</id>
		<title>OhWidget</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget"/>
				<updated>2012-03-02T10:47:34Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* ohWidget */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= ohWidget = &lt;br /&gt;
&lt;br /&gt;
== What is it? ==&lt;br /&gt;
&lt;br /&gt;
ohWidget is a home control app which runs on [[ohOs|ohOs]].&lt;br /&gt;
&lt;br /&gt;
It makes it simple get a basic widget, for example a light, thermostat or even a washing machine onto the network, share its data, and make available a graphical user interface representation for its control.&lt;br /&gt;
&lt;br /&gt;
The ohWidget Graphical User Interface framework provides a rich overview of all connected devices in the home, agnostic of their chosen communications protocol. The specific user interface for various widget types is auto-generated. It also presents the user with a number of key features such as;&lt;br /&gt;
&lt;br /&gt;
* Scheduler - set a specific day or time for when a widget needs to change state.&lt;br /&gt;
&lt;br /&gt;
* Presets/Scenes - group widgets together so their collective state change can be invoked by 1 button press.&lt;br /&gt;
&lt;br /&gt;
* Triggers - The action of 1 widget invokes an action on 1 or many another widgets.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ohWidget also makes it simple for other apps (external widgets) to plug in to this framework, share their information, and present their UI.&lt;br /&gt;
&lt;br /&gt;
== How do I get it? ==&lt;br /&gt;
&lt;br /&gt;
ohWidget will be available for download soon from [https://github.com/Openhome GitHub]. &lt;br /&gt;
&lt;br /&gt;
For any immediate requirement contact info@openhome.org&lt;br /&gt;
&lt;br /&gt;
== Documentation ==&lt;br /&gt;
&lt;br /&gt;
=== Overview ===&lt;br /&gt;
&lt;br /&gt;
[[ ohWidget Technical Overview|ohWidget Technical Overview]]&lt;br /&gt;
&lt;br /&gt;
[[ohWidget Driver Development|ohWidget Driver Development]]&lt;br /&gt;
&lt;br /&gt;
[[ohWidget Service XML Definition|ohWidget Service XML Definition]]&lt;br /&gt;
&lt;br /&gt;
[[External Widget Application Development|ohWidget External Widget Application Development]] - coming soon&lt;br /&gt;
&lt;br /&gt;
== Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== ohWidget Workbench ===&lt;br /&gt;
ohWidget Workbench is a useful development tool. It allows a widget to be modelled and then appear on a network &amp;quot;virtually&amp;quot;. This means any connected control point can see the user interface and observe any change in state reflected in the widget instance running in widget workbench. This saves developers from having to wait until a new physical widget is created before developing and testing the widget driver. ohWidget Workbench can be downloaded from here.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhOs</id>
		<title>OhOs</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhOs"/>
				<updated>2012-03-02T10:35:30Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* ohOS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= ohOS =&lt;br /&gt;
&lt;br /&gt;
== What is it? ==&lt;br /&gt;
&lt;br /&gt;
ohOs is designed to be deployed onto a modern Operating System and hosts a number of applications. Each of these applications can automatically run on any host OS. Deployments are maintained for:&lt;br /&gt;
&lt;br /&gt;
* Windows x86/x64 desktop&lt;br /&gt;
* Mac x64 desktop&lt;br /&gt;
* Linux x86/x64 desktop&lt;br /&gt;
* Linux ARM&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linux ARM allows deployment on a [http://en.wikipedia.org/wiki/SheevaPlug plug computer].  The unobtrusive factor and low power requirements of these devices make them very well suited as the hosts for apps which should always be on.&lt;br /&gt;
&lt;br /&gt;
== Related projects ==&lt;br /&gt;
&lt;br /&gt;
=== [[ohWidget|ohWidget]] ===&lt;br /&gt;
&lt;br /&gt;
ohWidget offers a home control framework which runs as an app on ohOs.&lt;br /&gt;
&lt;br /&gt;
=== [[ohRemote|ohRemote]] ===&lt;br /&gt;
&lt;br /&gt;
ohRemote provides remote access framework and is installed as an app on ohOs.&lt;br /&gt;
&lt;br /&gt;
== System architecture ==&lt;br /&gt;
&lt;br /&gt;
System architecture can be summarised as:&lt;br /&gt;
&lt;br /&gt;
[[File:ohOsOverviewArchDiagram.png|400px|thumb|center|System architecture]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ohOs hosts a number of applications (apps), each of which is always running.  All code in ohOs is managed.  This has the benefit of making applications portable across all platforms at no cost to the app developer.  All code in ohOs is written in C#.  Apps can be written in C# or other managed languages.&lt;br /&gt;
&lt;br /&gt;
Each ohOs app runs in its own process.  Communication with the app’s user interface or with other apps occurs using service interface calls over the network.  Service interfaces are typically presented as standard classes which internally use [[OhNet|ohNet]] to handle the invocation of a service function or notification of a change in a member variable.&lt;br /&gt;
&lt;br /&gt;
ohOs apps contain a web-based user interface, allowing users to access the apps on any control point without installing extra software.  Each app is automatically supplied with a rudimentary web server which delivers the web UI.  Apps are not required to generate complex html inside ohOs; instead they serve up JavaScript which uses the services exposed by the app to generate its UI client-side.&lt;br /&gt;
&lt;br /&gt;
Web UIs can use HTML5 features to provide an interface as graphically rich as native apps.  While there should be no pressing need to write native control points, ohOs does allow this.  In addition to C#, proxies for an app’s services can be generated in C or C++ (suitable for Apple’s iOS) or Java (suitable for Google’s Android).&lt;br /&gt;
&lt;br /&gt;
== How do I get it? ==&lt;br /&gt;
&lt;br /&gt;
ohOs is available as a [http://www.openhome.org/releases/artifacts/ohOs/ binary release] and coming soon to the [https://github.com/Openhome OpenHome Github account]&lt;br /&gt;
&lt;br /&gt;
== Docs ==&lt;br /&gt;
&lt;br /&gt;
Coming soon.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhOs</id>
		<title>OhOs</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhOs"/>
				<updated>2012-03-02T10:34:02Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* ohOS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= ohOS =&lt;br /&gt;
&lt;br /&gt;
== Related Projects ==&lt;br /&gt;
&lt;br /&gt;
=== [[ohWidget|ohWidget]] ===&lt;br /&gt;
&lt;br /&gt;
ohWidget offers a home control framework which runs as an app on ohOs.&lt;br /&gt;
&lt;br /&gt;
=== [[ohRemote|ohRemote]] ===&lt;br /&gt;
&lt;br /&gt;
ohRemote provides remote access framework and is installed as an app on ohOs.&lt;br /&gt;
&lt;br /&gt;
== What is it? ==&lt;br /&gt;
&lt;br /&gt;
ohOs is designed to be deployed onto a modern Operating System and hosts a number of applications. Each of these applications can automatically run on any host OS. Deployments are maintained for:&lt;br /&gt;
&lt;br /&gt;
* Windows x86/x64 desktop&lt;br /&gt;
* Mac x64 desktop&lt;br /&gt;
* Linux x86/x64 desktop&lt;br /&gt;
* Linux ARM&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linux ARM allows deployment on a [http://en.wikipedia.org/wiki/SheevaPlug plug computer].  The unobtrusive factor and low power requirements of these devices make them very well suited as the hosts for apps which should always be on.&lt;br /&gt;
&lt;br /&gt;
System architecture can be summarised as:&lt;br /&gt;
&lt;br /&gt;
[[File:ohOsOverviewArchDiagram.png|400px|thumb|center|System architecture]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ohOs hosts a number of applications (apps), each of which is always running.  All code in ohOs is managed.  This has the benefit of making applications portable across all platforms at no cost to the app developer.  All code in ohOs is written in C#.  Apps can be written in C# or other managed languages.&lt;br /&gt;
&lt;br /&gt;
Each ohOs app runs in its own process.  Communication with the app’s user interface or with other apps occurs using service interface calls over the network.  Service interfaces are typically presented as standard classes which internally use [[OhNet|ohNet]] to handle the invocation of a service function or notification of a change in a member variable.&lt;br /&gt;
&lt;br /&gt;
ohOs apps contain a web-based user interface, allowing users to access the apps on any control point without installing extra software.  Each app is automatically supplied with a rudimentary web server which delivers the web UI.  Apps are not required to generate complex html inside ohOs; instead they serve up JavaScript which uses the services exposed by the app to generate its UI client-side.&lt;br /&gt;
&lt;br /&gt;
Web UIs can use HTML5 features to provide an interface as graphically rich as native apps.  While there should be no pressing need to write native control points, ohOs does allow this.  In addition to C#, proxies for an app’s services can be generated in C or C++ (suitable for Apple’s iOS) or Java (suitable for Google’s Android).&lt;br /&gt;
&lt;br /&gt;
== How do I get it? ==&lt;br /&gt;
&lt;br /&gt;
ohOs is available as a [http://www.openhome.org/releases/artifacts/ohOs/ binary release] and coming soon to the [https://github.com/Openhome OpenHome Github account]&lt;br /&gt;
&lt;br /&gt;
== Docs ==&lt;br /&gt;
&lt;br /&gt;
Coming soon.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhOs</id>
		<title>OhOs</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhOs"/>
				<updated>2012-03-02T10:33:41Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* ohOS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= ohOS =&lt;br /&gt;
&lt;br /&gt;
== Related Projects ==&lt;br /&gt;
&lt;br /&gt;
=== [[ohWidget|ohWidget]] ===&lt;br /&gt;
&lt;br /&gt;
ohWidget offers a home control framework which runs as an app on ohOs.&lt;br /&gt;
&lt;br /&gt;
=== [[ohRemote|ohRemote]] ===&lt;br /&gt;
&lt;br /&gt;
ohRemote provides remote access framework and is installed as an app on ohOs.&lt;br /&gt;
&lt;br /&gt;
== What is it? ==&lt;br /&gt;
&lt;br /&gt;
ohOs is designed to be deployed onto a modern Operating System and hosts a number of applications. Each of these applications can automatically run on any host OS. Deployments are maintained for:&lt;br /&gt;
&lt;br /&gt;
* Windows x86/x64 desktop&lt;br /&gt;
* Mac x64 desktop&lt;br /&gt;
* Linux x86/x64 desktop&lt;br /&gt;
* Linux ARM&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linux ARM allows deployment on a [http://en.wikipedia.org/wiki/SheevaPlug plug computer].  The unobtrusive factor and low power requirements of these devices make them very well suited as the hosts for apps which should always be on.&lt;br /&gt;
&lt;br /&gt;
System architecture can be summarised as:&lt;br /&gt;
&lt;br /&gt;
[[File:ohOsOverviewArchDiagram.png|400px|thumb|center|System architecture]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ohOs hosts a number of applications (apps), each of which is always running.  All code in ohOs is managed.  This has the benefit of making applications portable across all platforms at no cost to the app developer.  All code in ohOs is written in C#.  Apps can be written in C# or other managed languages.&lt;br /&gt;
&lt;br /&gt;
Each ohOs app runs in its own process.  Communication with the app’s user interface or with other apps occurs using service interface calls over the network.  Service interfaces are typically presented as standard classes which internally use [[OhNet|ohNet]] to handle the invocation of a service function or notification of a change in a member variable.&lt;br /&gt;
&lt;br /&gt;
ohOs apps contain a web-based user interface, allowing users to access the apps on any control point without installing extra software.  Each app is automatically supplied with a rudimentary web server which delivers the web UI.  Apps are not required to generate complex html inside ohOs; instead they serve up JavaScript which uses the services exposed by the app to generate its UI client-side.&lt;br /&gt;
&lt;br /&gt;
Web UIs can use HTML5 features to provide an interface as graphically rich as native apps.  While there should be no pressing need to write native control points, ohOs does allow this.  In addition to C#, proxies for an app’s services can be generated in C or C++ (suitable for Apple’s iOS) or Java (suitable for Google’s Android).&lt;br /&gt;
&lt;br /&gt;
== How do I get it? ==&lt;br /&gt;
&lt;br /&gt;
ohOs is available as a [http://www.openhome.org/releases/artifacts/ohOs/ binary release] and coming soon to the [https://github.com/Openhome OpenHome Github account]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Docs ==&lt;br /&gt;
&lt;br /&gt;
Coming soon.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhOs</id>
		<title>OhOs</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhOs"/>
				<updated>2012-03-02T10:33:17Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* ohOS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= ohOS =&lt;br /&gt;
&lt;br /&gt;
== Related Projects ==&lt;br /&gt;
&lt;br /&gt;
=== [[ohWidget|ohWidget]] ===&lt;br /&gt;
&lt;br /&gt;
ohWidget offers a home control framework which runs as an app on ohOs.&lt;br /&gt;
&lt;br /&gt;
=== [[ohRemote|ohRemote]] ===&lt;br /&gt;
&lt;br /&gt;
ohRemote provides remote access framework and is installed as an app on ohOs.&lt;br /&gt;
&lt;br /&gt;
== What is it? ==&lt;br /&gt;
&lt;br /&gt;
ohOs is designed to be deployed onto a modern Operating System and hosts a number of applications. Each of these applications can automatically run on any host OS. Deployments are maintained for:&lt;br /&gt;
&lt;br /&gt;
* Windows x86/x64 desktop&lt;br /&gt;
* Mac x64 desktop&lt;br /&gt;
* Linux x86/x64 desktop&lt;br /&gt;
* Linux ARM&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linux ARM allows deployment on a [http://en.wikipedia.org/wiki/SheevaPlug plug computer].  The unobtrusive factor and low power requirements of these devices make them very well suited as the hosts for apps which should always be on.&lt;br /&gt;
&lt;br /&gt;
System architecture can be summarised as:&lt;br /&gt;
&lt;br /&gt;
[[File:ohOsOverviewArchDiagram.png|400px|thumb|center|System architecture]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ohOs hosts a number of applications (apps), each of which is always running.  All code in ohOs is managed.  This has the benefit of making applications portable across all platforms at no cost to the app developer.  All code in ohOs is written in C#.  Apps can be written in C# or other managed languages.&lt;br /&gt;
&lt;br /&gt;
Each ohOs app runs in its own process.  Communication with the app’s user interface or with other apps occurs using service interface calls over the network.  Service interfaces are typically presented as standard classes which internally use [[OhNet|ohNet]] to handle the invocation of a service function or notification of a change in a member variable.&lt;br /&gt;
&lt;br /&gt;
ohOs apps contain a web-based user interface, allowing users to access the apps on any control point without installing extra software.  Each app is automatically supplied with a rudimentary web server which delivers the web UI.  Apps are not required to generate complex html inside ohOs; instead they serve up JavaScript which uses the services exposed by the app to generate its UI client-side.&lt;br /&gt;
&lt;br /&gt;
Web UIs can use HTML5 features to provide an interface as graphically rich as native apps.  While there should be no pressing need to write native control points, ohOs does allow this.  In addition to C#, proxies for an app’s services can be generated in C or C++ (suitable for Apple’s iOS) or Java (suitable for Google’s Android).&lt;br /&gt;
&lt;br /&gt;
== How do I get it? ==&lt;br /&gt;
&lt;br /&gt;
ohOs is available as a [http://www.openhome.org/releases/artifacts/ohOs/ binary release] and coming soon to the [https://github.com/Openhome OpenHome Github account]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Docs ==&lt;br /&gt;
&lt;br /&gt;
Coming soon.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhOs</id>
		<title>OhOs</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhOs"/>
				<updated>2012-03-02T10:33:01Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* ohOS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= ohOS =&lt;br /&gt;
&lt;br /&gt;
== Related Projects ==&lt;br /&gt;
&lt;br /&gt;
=== [[ohWidget|ohWidget]] ===&lt;br /&gt;
&lt;br /&gt;
ohWidget offers a home control framework which runs as an app on ohOs.&lt;br /&gt;
&lt;br /&gt;
=== [[ohRemote|ohRemote]] ===&lt;br /&gt;
&lt;br /&gt;
ohRemote provides remote access framework and is installed as an app on ohOs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== What is it? ==&lt;br /&gt;
&lt;br /&gt;
ohOs is designed to be deployed onto a modern Operating System and hosts a number of applications. Each of these applications can automatically run on any host OS. Deployments are maintained for:&lt;br /&gt;
&lt;br /&gt;
* Windows x86/x64 desktop&lt;br /&gt;
* Mac x64 desktop&lt;br /&gt;
* Linux x86/x64 desktop&lt;br /&gt;
* Linux ARM&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linux ARM allows deployment on a [http://en.wikipedia.org/wiki/SheevaPlug plug computer].  The unobtrusive factor and low power requirements of these devices make them very well suited as the hosts for apps which should always be on.&lt;br /&gt;
&lt;br /&gt;
System architecture can be summarised as:&lt;br /&gt;
&lt;br /&gt;
[[File:ohOsOverviewArchDiagram.png|400px|thumb|center|System architecture]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ohOs hosts a number of applications (apps), each of which is always running.  All code in ohOs is managed.  This has the benefit of making applications portable across all platforms at no cost to the app developer.  All code in ohOs is written in C#.  Apps can be written in C# or other managed languages.&lt;br /&gt;
&lt;br /&gt;
Each ohOs app runs in its own process.  Communication with the app’s user interface or with other apps occurs using service interface calls over the network.  Service interfaces are typically presented as standard classes which internally use [[OhNet|ohNet]] to handle the invocation of a service function or notification of a change in a member variable.&lt;br /&gt;
&lt;br /&gt;
ohOs apps contain a web-based user interface, allowing users to access the apps on any control point without installing extra software.  Each app is automatically supplied with a rudimentary web server which delivers the web UI.  Apps are not required to generate complex html inside ohOs; instead they serve up JavaScript which uses the services exposed by the app to generate its UI client-side.&lt;br /&gt;
&lt;br /&gt;
Web UIs can use HTML5 features to provide an interface as graphically rich as native apps.  While there should be no pressing need to write native control points, ohOs does allow this.  In addition to C#, proxies for an app’s services can be generated in C or C++ (suitable for Apple’s iOS) or Java (suitable for Google’s Android).&lt;br /&gt;
&lt;br /&gt;
== How do I get it? ==&lt;br /&gt;
&lt;br /&gt;
ohOs is available as a [http://www.openhome.org/releases/artifacts/ohOs/ binary release] and coming soon to the [https://github.com/Openhome OpenHome Github account]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Docs ==&lt;br /&gt;
&lt;br /&gt;
Coming soon.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Oh:Overview</id>
		<title>Oh:Overview</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Oh:Overview"/>
				<updated>2012-03-02T10:31:37Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* OPENHOME DEVELOPMENT */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OPENHOME DEVELOPMENT =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Jigsaw.png|300px|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt; OpenHome currently sponsors two major programmes, ohOs and ohMedia. &amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Programmes ==&lt;br /&gt;
&lt;br /&gt;
=== [[ohOs|ohOs]] ===&lt;br /&gt;
&lt;br /&gt;
The OpenHome Operating System provides an OS layer for the deployment and hosting of apps. The [[ohOs|ohOs]] sits on top of all popular base operating systems such as Windows, Linux and Mac.&lt;br /&gt;
&lt;br /&gt;
=== [[ohMedia|ohMedia]] ===&lt;br /&gt;
&lt;br /&gt;
[[ohMedia|ohMedia]] is an open standard that allows the seamless interaction of media within your home.&lt;br /&gt;
&lt;br /&gt;
== Libraries ==&lt;br /&gt;
&lt;br /&gt;
In addition to these programmes, OpenHome also makes available ohNet.&lt;br /&gt;
&lt;br /&gt;
=== [[ohNet|ohNet]] ===&lt;br /&gt;
[[ohNet|ohNet]] is a modern cross platform networking stack.&lt;br /&gt;
&lt;br /&gt;
== Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== [[ohSpy|ohSpy]] ===&lt;br /&gt;
[[ohSpy|ohSpy]] helps provide detail on all UPnP connected devices on a network.&lt;br /&gt;
&lt;br /&gt;
=== [[ohNetworkmonitor|ohNetworkmonitor]] ===&lt;br /&gt;
[[ohNetworkmonitor|ohNetworkmonitor]] can be used to run some performance diagnostics on your network. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Oh:Overview</id>
		<title>Oh:Overview</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Oh:Overview"/>
				<updated>2012-03-02T10:31:28Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* OPENHOME DEVELOPMENT */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OPENHOME DEVELOPMENT =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Jigsaw.png|200px|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt; OpenHome currently sponsors two major programmes, ohOs and ohMedia. &amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Programmes ==&lt;br /&gt;
&lt;br /&gt;
=== [[ohOs|ohOs]] ===&lt;br /&gt;
&lt;br /&gt;
The OpenHome Operating System provides an OS layer for the deployment and hosting of apps. The [[ohOs|ohOs]] sits on top of all popular base operating systems such as Windows, Linux and Mac.&lt;br /&gt;
&lt;br /&gt;
=== [[ohMedia|ohMedia]] ===&lt;br /&gt;
&lt;br /&gt;
[[ohMedia|ohMedia]] is an open standard that allows the seamless interaction of media within your home.&lt;br /&gt;
&lt;br /&gt;
== Libraries ==&lt;br /&gt;
&lt;br /&gt;
In addition to these programmes, OpenHome also makes available ohNet.&lt;br /&gt;
&lt;br /&gt;
=== [[ohNet|ohNet]] ===&lt;br /&gt;
[[ohNet|ohNet]] is a modern cross platform networking stack.&lt;br /&gt;
&lt;br /&gt;
== Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== [[ohSpy|ohSpy]] ===&lt;br /&gt;
[[ohSpy|ohSpy]] helps provide detail on all UPnP connected devices on a network.&lt;br /&gt;
&lt;br /&gt;
=== [[ohNetworkmonitor|ohNetworkmonitor]] ===&lt;br /&gt;
[[ohNetworkmonitor|ohNetworkmonitor]] can be used to run some performance diagnostics on your network. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Oh:Downloads</id>
		<title>Oh:Downloads</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Oh:Downloads"/>
				<updated>2012-03-02T10:30:41Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Downloads */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Downloads = &lt;br /&gt;
&lt;br /&gt;
[[File:Downloads.png|200px|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All code relating to the projects will be made Open Source soon.&lt;br /&gt;
&lt;br /&gt;
For any immediate requirements contact info@openhome.org&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/File:Downloads.png</id>
		<title>File:Downloads.png</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/File:Downloads.png"/>
				<updated>2012-03-02T10:29:14Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: Downloads&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Downloads&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Oh:Overview</id>
		<title>Oh:Overview</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Oh:Overview"/>
				<updated>2012-03-02T10:28:02Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* OPENHOME DEVELOPMENT */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OPENHOME DEVELOPMENT =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Jigsaw.png|400px|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt; OpenHome currently sponsors two major programmes, ohOs and ohMedia. &amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Programmes ==&lt;br /&gt;
&lt;br /&gt;
=== [[ohOs|ohOs]] ===&lt;br /&gt;
&lt;br /&gt;
The OpenHome Operating System provides an OS layer for the deployment and hosting of apps. The [[ohOs|ohOs]] sits on top of all popular base operating systems such as Windows, Linux and Mac.&lt;br /&gt;
&lt;br /&gt;
=== [[ohMedia|ohMedia]] ===&lt;br /&gt;
&lt;br /&gt;
[[ohMedia|ohMedia]] is an open standard that allows the seamless interaction of media within your home.&lt;br /&gt;
&lt;br /&gt;
== Libraries ==&lt;br /&gt;
&lt;br /&gt;
In addition to these programmes, OpenHome also makes available ohNet.&lt;br /&gt;
&lt;br /&gt;
=== [[ohNet|ohNet]] ===&lt;br /&gt;
[[ohNet|ohNet]] is a modern cross platform networking stack.&lt;br /&gt;
&lt;br /&gt;
== Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== [[ohSpy|ohSpy]] ===&lt;br /&gt;
[[ohSpy|ohSpy]] helps provide detail on all UPnP connected devices on a network.&lt;br /&gt;
&lt;br /&gt;
=== [[ohNetworkmonitor|ohNetworkmonitor]] ===&lt;br /&gt;
[[ohNetworkmonitor|ohNetworkmonitor]] can be used to run some performance diagnostics on your network. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Oh:Overview</id>
		<title>Oh:Overview</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Oh:Overview"/>
				<updated>2012-03-02T10:27:53Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* OPENHOME DEVELOPMENT */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OPENHOME DEVELOPMENT =&lt;br /&gt;
&lt;br /&gt;
[[File:Jigsaw.png|400px|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt; OpenHome currently sponsors two major programmes, ohOs and ohMedia. &amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Programmes ==&lt;br /&gt;
&lt;br /&gt;
=== [[ohOs|ohOs]] ===&lt;br /&gt;
&lt;br /&gt;
The OpenHome Operating System provides an OS layer for the deployment and hosting of apps. The [[ohOs|ohOs]] sits on top of all popular base operating systems such as Windows, Linux and Mac.&lt;br /&gt;
&lt;br /&gt;
=== [[ohMedia|ohMedia]] ===&lt;br /&gt;
&lt;br /&gt;
[[ohMedia|ohMedia]] is an open standard that allows the seamless interaction of media within your home.&lt;br /&gt;
&lt;br /&gt;
== Libraries ==&lt;br /&gt;
&lt;br /&gt;
In addition to these programmes, OpenHome also makes available ohNet.&lt;br /&gt;
&lt;br /&gt;
=== [[ohNet|ohNet]] ===&lt;br /&gt;
[[ohNet|ohNet]] is a modern cross platform networking stack.&lt;br /&gt;
&lt;br /&gt;
== Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== [[ohSpy|ohSpy]] ===&lt;br /&gt;
[[ohSpy|ohSpy]] helps provide detail on all UPnP connected devices on a network.&lt;br /&gt;
&lt;br /&gt;
=== [[ohNetworkmonitor|ohNetworkmonitor]] ===&lt;br /&gt;
[[ohNetworkmonitor|ohNetworkmonitor]] can be used to run some performance diagnostics on your network. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/Oh:Overview</id>
		<title>Oh:Overview</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/Oh:Overview"/>
				<updated>2012-03-02T10:27:14Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* OPENHOME DEVELOPMENT */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OPENHOME DEVELOPMENT =&lt;br /&gt;
[[File:Jigsaw.png|400px|center]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt; OpenHome currently sponsors two major programmes, ohOs and ohMedia. &amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Programmes ==&lt;br /&gt;
&lt;br /&gt;
=== [[ohOs|ohOs]] ===&lt;br /&gt;
&lt;br /&gt;
The OpenHome Operating System provides an OS layer for the deployment and hosting of apps. The [[ohOs|ohOs]] sits on top of all popular base operating systems such as Windows, Linux and Mac.&lt;br /&gt;
&lt;br /&gt;
=== [[ohMedia|ohMedia]] ===&lt;br /&gt;
&lt;br /&gt;
[[ohMedia|ohMedia]] is an open standard that allows the seamless interaction of media within your home.&lt;br /&gt;
&lt;br /&gt;
== Libraries ==&lt;br /&gt;
&lt;br /&gt;
In addition to these programmes, OpenHome also makes available ohNet.&lt;br /&gt;
&lt;br /&gt;
=== [[ohNet|ohNet]] ===&lt;br /&gt;
[[ohNet|ohNet]] is a modern cross platform networking stack.&lt;br /&gt;
&lt;br /&gt;
== Utilities ==&lt;br /&gt;
&lt;br /&gt;
=== [[ohSpy|ohSpy]] ===&lt;br /&gt;
[[ohSpy|ohSpy]] helps provide detail on all UPnP connected devices on a network.&lt;br /&gt;
&lt;br /&gt;
=== [[ohNetworkmonitor|ohNetworkmonitor]] ===&lt;br /&gt;
[[ohNetworkmonitor|ohNetworkmonitor]] can be used to run some performance diagnostics on your network. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/File:Jigsaw.png</id>
		<title>File:Jigsaw.png</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/File:Jigsaw.png"/>
				<updated>2012-03-02T10:22:46Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: Jigsaw&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Jigsaw&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Service_XML_Definition</id>
		<title>OhWidget Service XML Definition</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Service_XML_Definition"/>
				<updated>2012-03-01T15:34:39Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Glossary */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for Widget manufacturers using OpenHome to define Widget services and properties.&lt;br /&gt;
The services and properties are defined in XML, following the schema published by OpenHome.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Note The OpenHome SDK contains a copy of the WidgetService.xsd used for validation. OpenHome may occasionally update the XSD definition to include new Widget properties. When these become available, OpenHome will publish the new XSD documents on openhome.org. All new XSD documents will be included in new releases of the SDK.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To help you produce your Widget Service XML file, this document provides descriptions of each element you can use in your own Widget Service XML file. A sample Widget Service XML file is used throughout the document.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin defining your Widget Service XML you must in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* technical details about the properties your Widget physically provides&lt;br /&gt;
* the OpenHome SDK, specifically the WidgetService.xsd file&lt;br /&gt;
&lt;br /&gt;
== Related documents ==&lt;br /&gt;
&lt;br /&gt;
The XML you define is used in several areas of Widget development. Refer to the following documents&lt;br /&gt;
to see how the XML is used:&lt;br /&gt;
* [[ohWidget Driver Development|OpenHome Widget Driver Development]]&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
The Widget Service XML file is used to define the features that your Widget provides to users.&lt;br /&gt;
&lt;br /&gt;
Each of these features is described as a property in the Widget Service XML. This may be a simple light Widget offering an on/off — or power — property, or a more complicated Widget offering volume, bass, and treble properties.&lt;br /&gt;
&lt;br /&gt;
Your Widget Service XML file can contain as many properties as are necessary to describe the full range of the Widget's feature set. Your Widget Service XML must contain at least one property.&lt;br /&gt;
&lt;br /&gt;
== Internal structure ==&lt;br /&gt;
&lt;br /&gt;
The Widget Service XML file is validated against an XSD. The XSD is included in the OpenHome SDK.&lt;br /&gt;
&lt;br /&gt;
Snippet 1 shows an abstract hierarchy of the elements used in a Widget Service XML file.&lt;br /&gt;
&lt;br /&gt;
 widgetservice&lt;br /&gt;
   description&lt;br /&gt;
   version&lt;br /&gt;
       major&lt;br /&gt;
       minor&lt;br /&gt;
   propertylist&lt;br /&gt;
       property&lt;br /&gt;
           name&lt;br /&gt;
           description&lt;br /&gt;
           dataType&lt;br /&gt;
           access&lt;br /&gt;
           allowedValueList*&lt;br /&gt;
               allowedValue&lt;br /&gt;
           allowedValueRange*&lt;br /&gt;
               minimum*&lt;br /&gt;
               maximum*&lt;br /&gt;
               step*&lt;br /&gt;
&lt;br /&gt;
Snippet 1: An abstract view of a Widget Service XML, showing the structure of the various elements used.&lt;br /&gt;
Elements marked * are optional.&lt;br /&gt;
&lt;br /&gt;
The structure of the XML is defined by OpenHome. You cannot change it and expect your Widget to operate on an OpenHome network. However, some of the files you generate from it can be customized.&lt;br /&gt;
&lt;br /&gt;
== External document dependencies ==&lt;br /&gt;
&lt;br /&gt;
Your Widget Service XML is used in several areas of Widget development. Several files are automatically generated from this one. Driver authors and UI developers both depend heavily on the code generated from your Widget Service XML. It is therefore essential that you write a well-formed Widget Service XML, conforming to the schema defined in the WidgetService.xsd.&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the significance of the Widget Service XML in relation to the generated files used by other developers to define and publish your Widget on an OpenHome network:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarcy, showing the files you can generate from the Widget Service&lt;br /&gt;
XML.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The JavaScript proxies and the UI HTML and JavaScript files are used by Web UI developers to style and customize the UI that will run on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
The C# Provider is used by Widget driver authors to help them write the code required to operate the Widget.&lt;br /&gt;
&lt;br /&gt;
The C# Proxy is used by developers to produce a C# control point application which can be used in place of the standard Web UI.&lt;br /&gt;
&lt;br /&gt;
= XML elements = &lt;br /&gt;
&lt;br /&gt;
The following tables explain each XML element that can appear in a Widget Service XML file. Descriptions of each element are provided alongside to explain their use. An example of the elements in use is provided in the appendix.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Unless otherwise stated, each of the following elements is mandatory and must appear in your Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== widgetService ==&lt;br /&gt;
&lt;br /&gt;
The widgetService element contains the definition of a service available on the Widget.&lt;br /&gt;
&lt;br /&gt;
==== Table 3.1. widgetService element description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
| widgetService&lt;br /&gt;
| Contains the definition of a Widget's service. This element begins and ends a Widget Service XML file.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The widgetService element has several child elements. They are defined as follows:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.2. widgetService child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|description&lt;br /&gt;
|Contains a plain text description of your Widget, its service and the properties the service provides. It appears as a programmer API comment above the class definitions in both the auto-generated Proxy and Provider files.&lt;br /&gt;
|-&lt;br /&gt;
|version&lt;br /&gt;
|Contains a plain text description of your Widget, its service and the properties the service provides. It appears as a programmer API comment above the class definitions in both the auto-generated Proxy and Provider files.&lt;br /&gt;
|-&lt;br /&gt;
|propertylist &lt;br /&gt;
|Contains the list of properties you want to make available on the Widget. Each entry in this list describes a single property using the property element.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== version ==&lt;br /&gt;
&lt;br /&gt;
The version element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.3. version child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|major &lt;br /&gt;
|This element must appear once only and must contain the value 1.&lt;br /&gt;
|-&lt;br /&gt;
|minor &lt;br /&gt;
|This element must appear once only and must contain the value 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== propertylist ==&lt;br /&gt;
&lt;br /&gt;
Use the propertylist element to hold the list of properties you want to make available on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Your propertylist should ideally contain a property entry for each feature your Widget provides.&lt;br /&gt;
&lt;br /&gt;
If you choose to exclude a feature from the propertylist, it will not be accessible to the user from any OpenHome UI.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
The propertylist element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.4. propertylist child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|property &lt;br /&gt;
|Contains a definition of a property available on the Widget, including: the property's name; the data type used to store the property's value; the read and write access for each property. Your Widget Service&lt;br /&gt;
XML must contain at least one property definition.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== property ==&lt;br /&gt;
&lt;br /&gt;
Use the property element to define a single property on the Widget. A property is one part of the service the Widget provides, such as power, volume or any other single feature.&lt;br /&gt;
&lt;br /&gt;
The property element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.5. property child elements description ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|access &lt;br /&gt;
|Defines the read and write attributes of the property. The access definitions are: readOnly; read-&lt;br /&gt;
Write; writeOnly.&lt;br /&gt;
|-&lt;br /&gt;
|allowedValueList &lt;br /&gt;
|This only affects properties with the string dataType. Contains the list of acceptable string values the property can have. This element is optional.&lt;br /&gt;
|-&lt;br /&gt;
|allowedValueRange &lt;br /&gt;
|This only affects properties with the integer dataType. Contains the minimum and maximum integer values the property can have and an optional step value which defines the interval between the minimum and maximum values. For example, a minimum of 0, a maximum of 10 and a step of 2 means the property can have the following values: 0, 2, 4, 6, 8, 10. This element is optional.&lt;br /&gt;
|-&lt;br /&gt;
|dataType &lt;br /&gt;
|Contains the name of the data type used to store the value of the property. Data types currently supported are: binary; boolean; color; integer;string.&lt;br /&gt;
|-&lt;br /&gt;
|description &lt;br /&gt;
|Contains the plain-text description of the property. The description is included in the generated files as developer documentation.&lt;br /&gt;
|-&lt;br /&gt;
|hint &lt;br /&gt;
|This element allows you to add special definitions to both the boolean and the string dataType properties. Supported values for boolean are: booleanlockunlock; boolean-onoff; booleanopenclose; boolean-updown. This changes the default text strings used when the control is generated in the UI, rather than just on and off. Note that if you do not specify a hint value (either by leaving the element blank or not including it at all) the control will use the default value of booleanonoff. The supported value for string is uri-image. Any string property whose hint element is defined in this way is assumed to be a URI pointing to an image which will be displayed in the UI.&lt;br /&gt;
|-&lt;br /&gt;
|name &lt;br /&gt;
|Contains the unique name for the property. The name must be unique within the service definition. This ensures the code in the generated files has unique function names for each property.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== dataType ==&lt;br /&gt;
&lt;br /&gt;
The dataType element specifies the name of the data type used to store the value of the property. The value you specify here determines that type of information the property can process. It also determines which type of control is generated in the UI's HTML.&lt;br /&gt;
&lt;br /&gt;
Choosing the correct value for the dataType element is important as it ensures that the Widget can be properly controlled by users. To help you ensure you are choosing the correct value, each of the supported values are described in more detail in the table below:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.6. dataType values description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Value''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|binary &lt;br /&gt;
|Use this datatype when processing raw binary data, such as that used to represent a file or stream of data.&lt;br /&gt;
|-&lt;br /&gt;
|boolean &lt;br /&gt;
|For specifying data that can have only one of two states. Typically used for controls to change a Widget&lt;br /&gt;
from one of two allowed states to the other. Note that the hint element can be used to further define&lt;br /&gt;
boolean to make sure the correct labeling is used. See the hint child element under property for&lt;br /&gt;
more details.&lt;br /&gt;
|-&lt;br /&gt;
|color &lt;br /&gt;
|This generates a color picker control that can be used to select a new RGB value.&lt;br /&gt;
|-&lt;br /&gt;
|integer &lt;br /&gt;
|Used for representing whole numbers that can be used for properties that need a range of values, or need to have their value specified from a list of allowed values.&lt;br /&gt;
|-&lt;br /&gt;
|string &lt;br /&gt;
|Displays plain text, typically as a label on the UI. Note that the hint element can be used to further define string to reference an image. This allows this type of property to display an image instead of text. See the hint child element under property for more details.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== allowedValueRange ==&lt;br /&gt;
&lt;br /&gt;
Use the allowedValueRange to restrict the upper and lower values an integer property can have.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
If you do not set an allowedValueRange, the generated code will bound the values to the range of a 32-bit signed integer. Typically this range is too large to provide useful upper and lower limits for a property such as a light dimmer or a volume control.&lt;br /&gt;
&lt;br /&gt;
Setting your own limits means you get to determine what the boundaries for your Widget's properties are. This also has a direct effect on the sensitivity of the HTML controls generated for the UI.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
The allowedValueRange element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.7. allowedValueRange child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|minimum &lt;br /&gt;
|Contains the lowest integer value this property can have.&lt;br /&gt;
|-&lt;br /&gt;
|maximum &lt;br /&gt;
|Contains the highest integer value this property can have. The maximum value must be greater than or&lt;br /&gt;
equal to the minimum value.&lt;br /&gt;
|-&lt;br /&gt;
|step &lt;br /&gt;
|Contains a non-negative integer to define the increment between each change in value. The value you&lt;br /&gt;
specify here must be exactly divisible into the difference between the maximum and minimum values.&lt;br /&gt;
For example, if your minimum and maximum values are 0 and 50 respectively, your step value must&lt;br /&gt;
be one of the following: 1, 2, 5, 10, 25 or 50.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''HTML controls''' The use of allowedValueRange in an integer property affects whether a text box or slider control is generated. &lt;br /&gt;
&lt;br /&gt;
A text box is displayed in the Web UI if you do not provide an allowedValueRange.&lt;br /&gt;
&lt;br /&gt;
A text box is also displayed if you do provide an allowedValueRange, but the difference between the maximum and minimum values is too great.&lt;br /&gt;
&lt;br /&gt;
A slider control is displayed only if the difference between maximum and minimum is a small enough value. This value is set by OpenHome and is currently undefined.&lt;br /&gt;
&lt;br /&gt;
== allowedValueList ==&lt;br /&gt;
&lt;br /&gt;
Use the allowedValueList to restrict the values a string property can have.&lt;br /&gt;
&lt;br /&gt;
The allowedValueList element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.8. allowedValueList child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|allowedValue &lt;br /&gt;
|Contains a plain text string defining one of the allowed values. You must define a new allowedValue&lt;br /&gt;
for each new value you want the control to be able to accept.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''HTML controls''' The use of allowedValueList affects how the control for a string property is&lt;br /&gt;
generated.&lt;br /&gt;
&lt;br /&gt;
If you provide an allowedValueList, a drop-down list is displayed in the Web UI with your defined entries in it. Users can select the value from this list.&lt;br /&gt;
&lt;br /&gt;
If you do not provide an allowedValueList, a text box is displayed in the Web UI. Users can manually enter the desired value.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Primary property = &lt;br /&gt;
&lt;br /&gt;
A Widget's primary property is the property that users will want to access most often.&lt;br /&gt;
&lt;br /&gt;
Once defined, the primary property is automatically displayed in the Web UI's summary view, along with the name of the Widget.&lt;br /&gt;
&lt;br /&gt;
[[File:SummaryViewAbstract.png|800px|thumb|center|Figure 2. An abstract view of several Widgets' summary views, aggregated in the Node UI.]]&lt;br /&gt;
&lt;br /&gt;
For some simple Widgets the primary property is often the power property. For a more complicated Widget you will need to consider which property you want to assign as primary.&lt;br /&gt;
&lt;br /&gt;
The details of the primary property are stored in the auto-generated Provider. This means the Node has direct access to these details and can provide the summary view UI at run-time.&lt;br /&gt;
&lt;br /&gt;
== Assigning the primary property ==&lt;br /&gt;
&lt;br /&gt;
You assign the primary property by adding an attribute to the chosen property in the XML. For example,&lt;br /&gt;
if we take the On property from a Basic Light Widget we can define it as the primary property by inserting&lt;br /&gt;
primary=&amp;quot;true&amp;quot;. For example:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
         illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
     &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
     &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
     &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
 &amp;lt;/property&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You must assign at most one primary property. Defining more than one property as the primary property&lt;br /&gt;
will leave your XML unable to generate the other files used in Widget development.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* Defining a primary property is not mandatory.&lt;br /&gt;
* You do not need to indicate which properties are NOT the primary property. You use the primary attribute only once in your Widget Service XML as shown in the example above.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
For more details about the Provider, see the [[ohWidget Driver Development|OpenHome Widget Driver Development]] document.&lt;br /&gt;
&lt;br /&gt;
= Naming rules =&lt;br /&gt;
&lt;br /&gt;
The contents of some elements in the Widget Service XML directly affect the output in the generated files.&lt;br /&gt;
&lt;br /&gt;
These details are important for the developers who will use your Widget Service XML file to write drivers&lt;br /&gt;
and UIs for the Widget.&lt;br /&gt;
&lt;br /&gt;
The following sections explain how the XML you define affects the auto-generated output.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The following sections are provided for information. You are not expected to learn any of this information to be able to write a Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Summary view UI == &lt;br /&gt;
&lt;br /&gt;
The details for the summary view UI are defined by the primary property in the XML.&lt;br /&gt;
&lt;br /&gt;
Those details are stored in the Provider so that the Node can always access them and generate the summary view UI at run-time.&lt;br /&gt;
&lt;br /&gt;
== Details view UI ==&lt;br /&gt;
&lt;br /&gt;
=== HTML and UI JavaScript ===&lt;br /&gt;
&lt;br /&gt;
The generated code used in the UI JavaScript and the HTML is based on the content of each of the elements&lt;br /&gt;
you define in the XML.&lt;br /&gt;
&lt;br /&gt;
== Provider == &lt;br /&gt;
&lt;br /&gt;
The code generated in the C# provider presents the driver developers with a series of abstract functions they can implement. Those functions are generated using the values you provide in each property's name, dataType and access elements.&lt;br /&gt;
&lt;br /&gt;
For example, the following property in the XML:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
         illuminated &amp;lt;/description&amp;gt;&lt;br /&gt;
     &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
     &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
     &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
     &amp;lt;/property&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will produce the following auto-generated code in the Provider:&lt;br /&gt;
&lt;br /&gt;
 public bool SetPropertyOn(bool aValue)&lt;br /&gt;
 {&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 public bool PropertyOn()&lt;br /&gt;
 {&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
 ...&lt;br /&gt;
 protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
&lt;br /&gt;
Here we see two accessor functions and one abstract function have been created. The accessor functions allow the property's value to be read and written. The abstract function is for Widget driver writers to implement in the code they write.&lt;br /&gt;
&lt;br /&gt;
Let's examine how each of the XML elements affects them.&lt;br /&gt;
&lt;br /&gt;
=== name ===&lt;br /&gt;
&lt;br /&gt;
The XML defines the property's &amp;lt;name&amp;gt; as On:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The generated code includes the property name in the names of each of the generated functions: Set-&lt;br /&gt;
PropertyOn, PropertyOn and SetOn.&lt;br /&gt;
&lt;br /&gt;
SetOn is the abstract function used in the Widget driver. This means that Widget driver writers will&lt;br /&gt;
consistently use the same names throughout the code they write.&lt;br /&gt;
&lt;br /&gt;
=== access ===&lt;br /&gt;
&lt;br /&gt;
The XML defines the property's access as readWrite:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The generated code provides two functions that meet this access setting. The first, SetPropertyOn, provides a way to write the property's value. The second, PropertyOn, provides a way to read the property's value.&lt;br /&gt;
&lt;br /&gt;
If the access was defined as writeOnly, only the abstract SetOn function would be generated.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
If the access was defined as readOnly, a SetPropertyOn function is still generated, but is not accessible from the UI. The function remains in the auto-generated code so that the Widget can update the Node with the property's new state when it changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== dataType ===&lt;br /&gt;
&lt;br /&gt;
The XML defines the property's dataType as boolean:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SetPropertyOn function automatically takes a bool as the parameter to use to set the new value of the property.&lt;br /&gt;
&lt;br /&gt;
The PropertyOn function automatically returns a bool to report the value of the property. &lt;br /&gt;
&lt;br /&gt;
The abstract SetOn function automatically takes a bool as the parameter used to set the new value of the property.&lt;br /&gt;
&lt;br /&gt;
= Appendix A = &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
     &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
     &amp;lt;version&amp;gt;&lt;br /&gt;
         &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
         &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
     &amp;lt;/version&amp;gt;&lt;br /&gt;
     &amp;lt;propertylist&amp;gt;&lt;br /&gt;
         &amp;lt;propertyprimary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
             &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
                 illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
             &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
             &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
             &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
             &amp;lt;hint&amp;gt;boolean-onoff&amp;lt;/hint&amp;gt;&lt;br /&gt;
         &amp;lt;/property&amp;gt;&lt;br /&gt;
     &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary =&lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in Openhome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by Openhome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh A - collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs inside ohOS.&lt;br /&gt;
&lt;br /&gt;
[[ohNet|ohNet]] - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
[[ohOs|ohOs]] - The Openhome Operating System. Core software for Openhome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
PDLP - Proxy Device List Provider. The pattern used to represent the layers of UPnP in the Openhome code. All layers except the Presentation layer are represented in this pattern.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. Typical Widgets are lights, speakers, temperature controls.&lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. Widget manufacturers are responsible for choosing which protocols each Widget supports. A typical Widget supports only one Widget communication protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Service_XML_Definition</id>
		<title>OhWidget Service XML Definition</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Service_XML_Definition"/>
				<updated>2012-03-01T15:33:57Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* HTML and UI JavaScript */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for Widget manufacturers using OpenHome to define Widget services and properties.&lt;br /&gt;
The services and properties are defined in XML, following the schema published by OpenHome.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Note The OpenHome SDK contains a copy of the WidgetService.xsd used for validation. OpenHome may occasionally update the XSD definition to include new Widget properties. When these become available, OpenHome will publish the new XSD documents on openhome.org. All new XSD documents will be included in new releases of the SDK.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To help you produce your Widget Service XML file, this document provides descriptions of each element you can use in your own Widget Service XML file. A sample Widget Service XML file is used throughout the document.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin defining your Widget Service XML you must in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* technical details about the properties your Widget physically provides&lt;br /&gt;
* the OpenHome SDK, specifically the WidgetService.xsd file&lt;br /&gt;
&lt;br /&gt;
== Related documents ==&lt;br /&gt;
&lt;br /&gt;
The XML you define is used in several areas of Widget development. Refer to the following documents&lt;br /&gt;
to see how the XML is used:&lt;br /&gt;
* [[ohWidget Driver Development|OpenHome Widget Driver Development]]&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
The Widget Service XML file is used to define the features that your Widget provides to users.&lt;br /&gt;
&lt;br /&gt;
Each of these features is described as a property in the Widget Service XML. This may be a simple light Widget offering an on/off — or power — property, or a more complicated Widget offering volume, bass, and treble properties.&lt;br /&gt;
&lt;br /&gt;
Your Widget Service XML file can contain as many properties as are necessary to describe the full range of the Widget's feature set. Your Widget Service XML must contain at least one property.&lt;br /&gt;
&lt;br /&gt;
== Internal structure ==&lt;br /&gt;
&lt;br /&gt;
The Widget Service XML file is validated against an XSD. The XSD is included in the OpenHome SDK.&lt;br /&gt;
&lt;br /&gt;
Snippet 1 shows an abstract hierarchy of the elements used in a Widget Service XML file.&lt;br /&gt;
&lt;br /&gt;
 widgetservice&lt;br /&gt;
   description&lt;br /&gt;
   version&lt;br /&gt;
       major&lt;br /&gt;
       minor&lt;br /&gt;
   propertylist&lt;br /&gt;
       property&lt;br /&gt;
           name&lt;br /&gt;
           description&lt;br /&gt;
           dataType&lt;br /&gt;
           access&lt;br /&gt;
           allowedValueList*&lt;br /&gt;
               allowedValue&lt;br /&gt;
           allowedValueRange*&lt;br /&gt;
               minimum*&lt;br /&gt;
               maximum*&lt;br /&gt;
               step*&lt;br /&gt;
&lt;br /&gt;
Snippet 1: An abstract view of a Widget Service XML, showing the structure of the various elements used.&lt;br /&gt;
Elements marked * are optional.&lt;br /&gt;
&lt;br /&gt;
The structure of the XML is defined by OpenHome. You cannot change it and expect your Widget to operate on an OpenHome network. However, some of the files you generate from it can be customized.&lt;br /&gt;
&lt;br /&gt;
== External document dependencies ==&lt;br /&gt;
&lt;br /&gt;
Your Widget Service XML is used in several areas of Widget development. Several files are automatically generated from this one. Driver authors and UI developers both depend heavily on the code generated from your Widget Service XML. It is therefore essential that you write a well-formed Widget Service XML, conforming to the schema defined in the WidgetService.xsd.&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the significance of the Widget Service XML in relation to the generated files used by other developers to define and publish your Widget on an OpenHome network:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarcy, showing the files you can generate from the Widget Service&lt;br /&gt;
XML.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The JavaScript proxies and the UI HTML and JavaScript files are used by Web UI developers to style and customize the UI that will run on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
The C# Provider is used by Widget driver authors to help them write the code required to operate the Widget.&lt;br /&gt;
&lt;br /&gt;
The C# Proxy is used by developers to produce a C# control point application which can be used in place of the standard Web UI.&lt;br /&gt;
&lt;br /&gt;
= XML elements = &lt;br /&gt;
&lt;br /&gt;
The following tables explain each XML element that can appear in a Widget Service XML file. Descriptions of each element are provided alongside to explain their use. An example of the elements in use is provided in the appendix.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Unless otherwise stated, each of the following elements is mandatory and must appear in your Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== widgetService ==&lt;br /&gt;
&lt;br /&gt;
The widgetService element contains the definition of a service available on the Widget.&lt;br /&gt;
&lt;br /&gt;
==== Table 3.1. widgetService element description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
| widgetService&lt;br /&gt;
| Contains the definition of a Widget's service. This element begins and ends a Widget Service XML file.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The widgetService element has several child elements. They are defined as follows:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.2. widgetService child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|description&lt;br /&gt;
|Contains a plain text description of your Widget, its service and the properties the service provides. It appears as a programmer API comment above the class definitions in both the auto-generated Proxy and Provider files.&lt;br /&gt;
|-&lt;br /&gt;
|version&lt;br /&gt;
|Contains a plain text description of your Widget, its service and the properties the service provides. It appears as a programmer API comment above the class definitions in both the auto-generated Proxy and Provider files.&lt;br /&gt;
|-&lt;br /&gt;
|propertylist &lt;br /&gt;
|Contains the list of properties you want to make available on the Widget. Each entry in this list describes a single property using the property element.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== version ==&lt;br /&gt;
&lt;br /&gt;
The version element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.3. version child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|major &lt;br /&gt;
|This element must appear once only and must contain the value 1.&lt;br /&gt;
|-&lt;br /&gt;
|minor &lt;br /&gt;
|This element must appear once only and must contain the value 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== propertylist ==&lt;br /&gt;
&lt;br /&gt;
Use the propertylist element to hold the list of properties you want to make available on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Your propertylist should ideally contain a property entry for each feature your Widget provides.&lt;br /&gt;
&lt;br /&gt;
If you choose to exclude a feature from the propertylist, it will not be accessible to the user from any OpenHome UI.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
The propertylist element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.4. propertylist child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|property &lt;br /&gt;
|Contains a definition of a property available on the Widget, including: the property's name; the data type used to store the property's value; the read and write access for each property. Your Widget Service&lt;br /&gt;
XML must contain at least one property definition.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== property ==&lt;br /&gt;
&lt;br /&gt;
Use the property element to define a single property on the Widget. A property is one part of the service the Widget provides, such as power, volume or any other single feature.&lt;br /&gt;
&lt;br /&gt;
The property element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.5. property child elements description ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|access &lt;br /&gt;
|Defines the read and write attributes of the property. The access definitions are: readOnly; read-&lt;br /&gt;
Write; writeOnly.&lt;br /&gt;
|-&lt;br /&gt;
|allowedValueList &lt;br /&gt;
|This only affects properties with the string dataType. Contains the list of acceptable string values the property can have. This element is optional.&lt;br /&gt;
|-&lt;br /&gt;
|allowedValueRange &lt;br /&gt;
|This only affects properties with the integer dataType. Contains the minimum and maximum integer values the property can have and an optional step value which defines the interval between the minimum and maximum values. For example, a minimum of 0, a maximum of 10 and a step of 2 means the property can have the following values: 0, 2, 4, 6, 8, 10. This element is optional.&lt;br /&gt;
|-&lt;br /&gt;
|dataType &lt;br /&gt;
|Contains the name of the data type used to store the value of the property. Data types currently supported are: binary; boolean; color; integer;string.&lt;br /&gt;
|-&lt;br /&gt;
|description &lt;br /&gt;
|Contains the plain-text description of the property. The description is included in the generated files as developer documentation.&lt;br /&gt;
|-&lt;br /&gt;
|hint &lt;br /&gt;
|This element allows you to add special definitions to both the boolean and the string dataType properties. Supported values for boolean are: booleanlockunlock; boolean-onoff; booleanopenclose; boolean-updown. This changes the default text strings used when the control is generated in the UI, rather than just on and off. Note that if you do not specify a hint value (either by leaving the element blank or not including it at all) the control will use the default value of booleanonoff. The supported value for string is uri-image. Any string property whose hint element is defined in this way is assumed to be a URI pointing to an image which will be displayed in the UI.&lt;br /&gt;
|-&lt;br /&gt;
|name &lt;br /&gt;
|Contains the unique name for the property. The name must be unique within the service definition. This ensures the code in the generated files has unique function names for each property.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== dataType ==&lt;br /&gt;
&lt;br /&gt;
The dataType element specifies the name of the data type used to store the value of the property. The value you specify here determines that type of information the property can process. It also determines which type of control is generated in the UI's HTML.&lt;br /&gt;
&lt;br /&gt;
Choosing the correct value for the dataType element is important as it ensures that the Widget can be properly controlled by users. To help you ensure you are choosing the correct value, each of the supported values are described in more detail in the table below:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.6. dataType values description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Value''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|binary &lt;br /&gt;
|Use this datatype when processing raw binary data, such as that used to represent a file or stream of data.&lt;br /&gt;
|-&lt;br /&gt;
|boolean &lt;br /&gt;
|For specifying data that can have only one of two states. Typically used for controls to change a Widget&lt;br /&gt;
from one of two allowed states to the other. Note that the hint element can be used to further define&lt;br /&gt;
boolean to make sure the correct labeling is used. See the hint child element under property for&lt;br /&gt;
more details.&lt;br /&gt;
|-&lt;br /&gt;
|color &lt;br /&gt;
|This generates a color picker control that can be used to select a new RGB value.&lt;br /&gt;
|-&lt;br /&gt;
|integer &lt;br /&gt;
|Used for representing whole numbers that can be used for properties that need a range of values, or need to have their value specified from a list of allowed values.&lt;br /&gt;
|-&lt;br /&gt;
|string &lt;br /&gt;
|Displays plain text, typically as a label on the UI. Note that the hint element can be used to further define string to reference an image. This allows this type of property to display an image instead of text. See the hint child element under property for more details.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== allowedValueRange ==&lt;br /&gt;
&lt;br /&gt;
Use the allowedValueRange to restrict the upper and lower values an integer property can have.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
If you do not set an allowedValueRange, the generated code will bound the values to the range of a 32-bit signed integer. Typically this range is too large to provide useful upper and lower limits for a property such as a light dimmer or a volume control.&lt;br /&gt;
&lt;br /&gt;
Setting your own limits means you get to determine what the boundaries for your Widget's properties are. This also has a direct effect on the sensitivity of the HTML controls generated for the UI.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
The allowedValueRange element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.7. allowedValueRange child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|minimum &lt;br /&gt;
|Contains the lowest integer value this property can have.&lt;br /&gt;
|-&lt;br /&gt;
|maximum &lt;br /&gt;
|Contains the highest integer value this property can have. The maximum value must be greater than or&lt;br /&gt;
equal to the minimum value.&lt;br /&gt;
|-&lt;br /&gt;
|step &lt;br /&gt;
|Contains a non-negative integer to define the increment between each change in value. The value you&lt;br /&gt;
specify here must be exactly divisible into the difference between the maximum and minimum values.&lt;br /&gt;
For example, if your minimum and maximum values are 0 and 50 respectively, your step value must&lt;br /&gt;
be one of the following: 1, 2, 5, 10, 25 or 50.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''HTML controls''' The use of allowedValueRange in an integer property affects whether a text box or slider control is generated. &lt;br /&gt;
&lt;br /&gt;
A text box is displayed in the Web UI if you do not provide an allowedValueRange.&lt;br /&gt;
&lt;br /&gt;
A text box is also displayed if you do provide an allowedValueRange, but the difference between the maximum and minimum values is too great.&lt;br /&gt;
&lt;br /&gt;
A slider control is displayed only if the difference between maximum and minimum is a small enough value. This value is set by OpenHome and is currently undefined.&lt;br /&gt;
&lt;br /&gt;
== allowedValueList ==&lt;br /&gt;
&lt;br /&gt;
Use the allowedValueList to restrict the values a string property can have.&lt;br /&gt;
&lt;br /&gt;
The allowedValueList element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.8. allowedValueList child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|allowedValue &lt;br /&gt;
|Contains a plain text string defining one of the allowed values. You must define a new allowedValue&lt;br /&gt;
for each new value you want the control to be able to accept.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''HTML controls''' The use of allowedValueList affects how the control for a string property is&lt;br /&gt;
generated.&lt;br /&gt;
&lt;br /&gt;
If you provide an allowedValueList, a drop-down list is displayed in the Web UI with your defined entries in it. Users can select the value from this list.&lt;br /&gt;
&lt;br /&gt;
If you do not provide an allowedValueList, a text box is displayed in the Web UI. Users can manually enter the desired value.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Primary property = &lt;br /&gt;
&lt;br /&gt;
A Widget's primary property is the property that users will want to access most often.&lt;br /&gt;
&lt;br /&gt;
Once defined, the primary property is automatically displayed in the Web UI's summary view, along with the name of the Widget.&lt;br /&gt;
&lt;br /&gt;
[[File:SummaryViewAbstract.png|800px|thumb|center|Figure 2. An abstract view of several Widgets' summary views, aggregated in the Node UI.]]&lt;br /&gt;
&lt;br /&gt;
For some simple Widgets the primary property is often the power property. For a more complicated Widget you will need to consider which property you want to assign as primary.&lt;br /&gt;
&lt;br /&gt;
The details of the primary property are stored in the auto-generated Provider. This means the Node has direct access to these details and can provide the summary view UI at run-time.&lt;br /&gt;
&lt;br /&gt;
== Assigning the primary property ==&lt;br /&gt;
&lt;br /&gt;
You assign the primary property by adding an attribute to the chosen property in the XML. For example,&lt;br /&gt;
if we take the On property from a Basic Light Widget we can define it as the primary property by inserting&lt;br /&gt;
primary=&amp;quot;true&amp;quot;. For example:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
         illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
     &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
     &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
     &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
 &amp;lt;/property&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You must assign at most one primary property. Defining more than one property as the primary property&lt;br /&gt;
will leave your XML unable to generate the other files used in Widget development.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* Defining a primary property is not mandatory.&lt;br /&gt;
* You do not need to indicate which properties are NOT the primary property. You use the primary attribute only once in your Widget Service XML as shown in the example above.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
For more details about the Provider, see the [[ohWidget Driver Development|OpenHome Widget Driver Development]] document.&lt;br /&gt;
&lt;br /&gt;
= Naming rules =&lt;br /&gt;
&lt;br /&gt;
The contents of some elements in the Widget Service XML directly affect the output in the generated files.&lt;br /&gt;
&lt;br /&gt;
These details are important for the developers who will use your Widget Service XML file to write drivers&lt;br /&gt;
and UIs for the Widget.&lt;br /&gt;
&lt;br /&gt;
The following sections explain how the XML you define affects the auto-generated output.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The following sections are provided for information. You are not expected to learn any of this information to be able to write a Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Summary view UI == &lt;br /&gt;
&lt;br /&gt;
The details for the summary view UI are defined by the primary property in the XML.&lt;br /&gt;
&lt;br /&gt;
Those details are stored in the Provider so that the Node can always access them and generate the summary view UI at run-time.&lt;br /&gt;
&lt;br /&gt;
== Details view UI ==&lt;br /&gt;
&lt;br /&gt;
=== HTML and UI JavaScript ===&lt;br /&gt;
&lt;br /&gt;
The generated code used in the UI JavaScript and the HTML is based on the content of each of the elements&lt;br /&gt;
you define in the XML.&lt;br /&gt;
&lt;br /&gt;
== Provider == &lt;br /&gt;
&lt;br /&gt;
The code generated in the C# provider presents the driver developers with a series of abstract functions they can implement. Those functions are generated using the values you provide in each property's name, dataType and access elements.&lt;br /&gt;
&lt;br /&gt;
For example, the following property in the XML:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
         illuminated &amp;lt;/description&amp;gt;&lt;br /&gt;
     &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
     &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
     &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
     &amp;lt;/property&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will produce the following auto-generated code in the Provider:&lt;br /&gt;
&lt;br /&gt;
 public bool SetPropertyOn(bool aValue)&lt;br /&gt;
 {&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 public bool PropertyOn()&lt;br /&gt;
 {&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
 ...&lt;br /&gt;
 protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
&lt;br /&gt;
Here we see two accessor functions and one abstract function have been created. The accessor functions allow the property's value to be read and written. The abstract function is for Widget driver writers to implement in the code they write.&lt;br /&gt;
&lt;br /&gt;
Let's examine how each of the XML elements affects them.&lt;br /&gt;
&lt;br /&gt;
=== name ===&lt;br /&gt;
&lt;br /&gt;
The XML defines the property's &amp;lt;name&amp;gt; as On:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The generated code includes the property name in the names of each of the generated functions: Set-&lt;br /&gt;
PropertyOn, PropertyOn and SetOn.&lt;br /&gt;
&lt;br /&gt;
SetOn is the abstract function used in the Widget driver. This means that Widget driver writers will&lt;br /&gt;
consistently use the same names throughout the code they write.&lt;br /&gt;
&lt;br /&gt;
=== access ===&lt;br /&gt;
&lt;br /&gt;
The XML defines the property's access as readWrite:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The generated code provides two functions that meet this access setting. The first, SetPropertyOn, provides a way to write the property's value. The second, PropertyOn, provides a way to read the property's value.&lt;br /&gt;
&lt;br /&gt;
If the access was defined as writeOnly, only the abstract SetOn function would be generated.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
If the access was defined as readOnly, a SetPropertyOn function is still generated, but is not accessible from the UI. The function remains in the auto-generated code so that the Widget can update the Node with the property's new state when it changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== dataType ===&lt;br /&gt;
&lt;br /&gt;
The XML defines the property's dataType as boolean:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SetPropertyOn function automatically takes a bool as the parameter to use to set the new value of the property.&lt;br /&gt;
&lt;br /&gt;
The PropertyOn function automatically returns a bool to report the value of the property. &lt;br /&gt;
&lt;br /&gt;
The abstract SetOn function automatically takes a bool as the parameter used to set the new value of the property.&lt;br /&gt;
&lt;br /&gt;
= Appendix A = &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
     &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
     &amp;lt;version&amp;gt;&lt;br /&gt;
         &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
         &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
     &amp;lt;/version&amp;gt;&lt;br /&gt;
     &amp;lt;propertylist&amp;gt;&lt;br /&gt;
         &amp;lt;propertyprimary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
             &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
                 illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
             &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
             &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
             &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
             &amp;lt;hint&amp;gt;boolean-onoff&amp;lt;/hint&amp;gt;&lt;br /&gt;
         &amp;lt;/property&amp;gt;&lt;br /&gt;
     &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary =&lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in Openhome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by Openhome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh A - collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs inside ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The Openhome Operating System. Core software for Openhome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
PDLP - Proxy Device List Provider. The pattern used to represent the layers of UPnP in the Openhome code. All layers except the Presentation layer are represented in this pattern.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. Typical Widgets are lights, speakers, temperature controls.&lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. Widget manufacturers are responsible for choosing which protocols each Widget supports. A typical Widget supports only one Widget communication protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Service_XML_Definition</id>
		<title>OhWidget Service XML Definition</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Service_XML_Definition"/>
				<updated>2012-03-01T15:33:45Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Summary view UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for Widget manufacturers using OpenHome to define Widget services and properties.&lt;br /&gt;
The services and properties are defined in XML, following the schema published by OpenHome.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Note The OpenHome SDK contains a copy of the WidgetService.xsd used for validation. OpenHome may occasionally update the XSD definition to include new Widget properties. When these become available, OpenHome will publish the new XSD documents on openhome.org. All new XSD documents will be included in new releases of the SDK.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To help you produce your Widget Service XML file, this document provides descriptions of each element you can use in your own Widget Service XML file. A sample Widget Service XML file is used throughout the document.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin defining your Widget Service XML you must in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* technical details about the properties your Widget physically provides&lt;br /&gt;
* the OpenHome SDK, specifically the WidgetService.xsd file&lt;br /&gt;
&lt;br /&gt;
== Related documents ==&lt;br /&gt;
&lt;br /&gt;
The XML you define is used in several areas of Widget development. Refer to the following documents&lt;br /&gt;
to see how the XML is used:&lt;br /&gt;
* [[ohWidget Driver Development|OpenHome Widget Driver Development]]&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
The Widget Service XML file is used to define the features that your Widget provides to users.&lt;br /&gt;
&lt;br /&gt;
Each of these features is described as a property in the Widget Service XML. This may be a simple light Widget offering an on/off — or power — property, or a more complicated Widget offering volume, bass, and treble properties.&lt;br /&gt;
&lt;br /&gt;
Your Widget Service XML file can contain as many properties as are necessary to describe the full range of the Widget's feature set. Your Widget Service XML must contain at least one property.&lt;br /&gt;
&lt;br /&gt;
== Internal structure ==&lt;br /&gt;
&lt;br /&gt;
The Widget Service XML file is validated against an XSD. The XSD is included in the OpenHome SDK.&lt;br /&gt;
&lt;br /&gt;
Snippet 1 shows an abstract hierarchy of the elements used in a Widget Service XML file.&lt;br /&gt;
&lt;br /&gt;
 widgetservice&lt;br /&gt;
   description&lt;br /&gt;
   version&lt;br /&gt;
       major&lt;br /&gt;
       minor&lt;br /&gt;
   propertylist&lt;br /&gt;
       property&lt;br /&gt;
           name&lt;br /&gt;
           description&lt;br /&gt;
           dataType&lt;br /&gt;
           access&lt;br /&gt;
           allowedValueList*&lt;br /&gt;
               allowedValue&lt;br /&gt;
           allowedValueRange*&lt;br /&gt;
               minimum*&lt;br /&gt;
               maximum*&lt;br /&gt;
               step*&lt;br /&gt;
&lt;br /&gt;
Snippet 1: An abstract view of a Widget Service XML, showing the structure of the various elements used.&lt;br /&gt;
Elements marked * are optional.&lt;br /&gt;
&lt;br /&gt;
The structure of the XML is defined by OpenHome. You cannot change it and expect your Widget to operate on an OpenHome network. However, some of the files you generate from it can be customized.&lt;br /&gt;
&lt;br /&gt;
== External document dependencies ==&lt;br /&gt;
&lt;br /&gt;
Your Widget Service XML is used in several areas of Widget development. Several files are automatically generated from this one. Driver authors and UI developers both depend heavily on the code generated from your Widget Service XML. It is therefore essential that you write a well-formed Widget Service XML, conforming to the schema defined in the WidgetService.xsd.&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the significance of the Widget Service XML in relation to the generated files used by other developers to define and publish your Widget on an OpenHome network:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarcy, showing the files you can generate from the Widget Service&lt;br /&gt;
XML.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The JavaScript proxies and the UI HTML and JavaScript files are used by Web UI developers to style and customize the UI that will run on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
The C# Provider is used by Widget driver authors to help them write the code required to operate the Widget.&lt;br /&gt;
&lt;br /&gt;
The C# Proxy is used by developers to produce a C# control point application which can be used in place of the standard Web UI.&lt;br /&gt;
&lt;br /&gt;
= XML elements = &lt;br /&gt;
&lt;br /&gt;
The following tables explain each XML element that can appear in a Widget Service XML file. Descriptions of each element are provided alongside to explain their use. An example of the elements in use is provided in the appendix.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Unless otherwise stated, each of the following elements is mandatory and must appear in your Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== widgetService ==&lt;br /&gt;
&lt;br /&gt;
The widgetService element contains the definition of a service available on the Widget.&lt;br /&gt;
&lt;br /&gt;
==== Table 3.1. widgetService element description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
| widgetService&lt;br /&gt;
| Contains the definition of a Widget's service. This element begins and ends a Widget Service XML file.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The widgetService element has several child elements. They are defined as follows:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.2. widgetService child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|description&lt;br /&gt;
|Contains a plain text description of your Widget, its service and the properties the service provides. It appears as a programmer API comment above the class definitions in both the auto-generated Proxy and Provider files.&lt;br /&gt;
|-&lt;br /&gt;
|version&lt;br /&gt;
|Contains a plain text description of your Widget, its service and the properties the service provides. It appears as a programmer API comment above the class definitions in both the auto-generated Proxy and Provider files.&lt;br /&gt;
|-&lt;br /&gt;
|propertylist &lt;br /&gt;
|Contains the list of properties you want to make available on the Widget. Each entry in this list describes a single property using the property element.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== version ==&lt;br /&gt;
&lt;br /&gt;
The version element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.3. version child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|major &lt;br /&gt;
|This element must appear once only and must contain the value 1.&lt;br /&gt;
|-&lt;br /&gt;
|minor &lt;br /&gt;
|This element must appear once only and must contain the value 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== propertylist ==&lt;br /&gt;
&lt;br /&gt;
Use the propertylist element to hold the list of properties you want to make available on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Your propertylist should ideally contain a property entry for each feature your Widget provides.&lt;br /&gt;
&lt;br /&gt;
If you choose to exclude a feature from the propertylist, it will not be accessible to the user from any OpenHome UI.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
The propertylist element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.4. propertylist child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|property &lt;br /&gt;
|Contains a definition of a property available on the Widget, including: the property's name; the data type used to store the property's value; the read and write access for each property. Your Widget Service&lt;br /&gt;
XML must contain at least one property definition.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== property ==&lt;br /&gt;
&lt;br /&gt;
Use the property element to define a single property on the Widget. A property is one part of the service the Widget provides, such as power, volume or any other single feature.&lt;br /&gt;
&lt;br /&gt;
The property element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.5. property child elements description ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|access &lt;br /&gt;
|Defines the read and write attributes of the property. The access definitions are: readOnly; read-&lt;br /&gt;
Write; writeOnly.&lt;br /&gt;
|-&lt;br /&gt;
|allowedValueList &lt;br /&gt;
|This only affects properties with the string dataType. Contains the list of acceptable string values the property can have. This element is optional.&lt;br /&gt;
|-&lt;br /&gt;
|allowedValueRange &lt;br /&gt;
|This only affects properties with the integer dataType. Contains the minimum and maximum integer values the property can have and an optional step value which defines the interval between the minimum and maximum values. For example, a minimum of 0, a maximum of 10 and a step of 2 means the property can have the following values: 0, 2, 4, 6, 8, 10. This element is optional.&lt;br /&gt;
|-&lt;br /&gt;
|dataType &lt;br /&gt;
|Contains the name of the data type used to store the value of the property. Data types currently supported are: binary; boolean; color; integer;string.&lt;br /&gt;
|-&lt;br /&gt;
|description &lt;br /&gt;
|Contains the plain-text description of the property. The description is included in the generated files as developer documentation.&lt;br /&gt;
|-&lt;br /&gt;
|hint &lt;br /&gt;
|This element allows you to add special definitions to both the boolean and the string dataType properties. Supported values for boolean are: booleanlockunlock; boolean-onoff; booleanopenclose; boolean-updown. This changes the default text strings used when the control is generated in the UI, rather than just on and off. Note that if you do not specify a hint value (either by leaving the element blank or not including it at all) the control will use the default value of booleanonoff. The supported value for string is uri-image. Any string property whose hint element is defined in this way is assumed to be a URI pointing to an image which will be displayed in the UI.&lt;br /&gt;
|-&lt;br /&gt;
|name &lt;br /&gt;
|Contains the unique name for the property. The name must be unique within the service definition. This ensures the code in the generated files has unique function names for each property.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== dataType ==&lt;br /&gt;
&lt;br /&gt;
The dataType element specifies the name of the data type used to store the value of the property. The value you specify here determines that type of information the property can process. It also determines which type of control is generated in the UI's HTML.&lt;br /&gt;
&lt;br /&gt;
Choosing the correct value for the dataType element is important as it ensures that the Widget can be properly controlled by users. To help you ensure you are choosing the correct value, each of the supported values are described in more detail in the table below:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.6. dataType values description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Value''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|binary &lt;br /&gt;
|Use this datatype when processing raw binary data, such as that used to represent a file or stream of data.&lt;br /&gt;
|-&lt;br /&gt;
|boolean &lt;br /&gt;
|For specifying data that can have only one of two states. Typically used for controls to change a Widget&lt;br /&gt;
from one of two allowed states to the other. Note that the hint element can be used to further define&lt;br /&gt;
boolean to make sure the correct labeling is used. See the hint child element under property for&lt;br /&gt;
more details.&lt;br /&gt;
|-&lt;br /&gt;
|color &lt;br /&gt;
|This generates a color picker control that can be used to select a new RGB value.&lt;br /&gt;
|-&lt;br /&gt;
|integer &lt;br /&gt;
|Used for representing whole numbers that can be used for properties that need a range of values, or need to have their value specified from a list of allowed values.&lt;br /&gt;
|-&lt;br /&gt;
|string &lt;br /&gt;
|Displays plain text, typically as a label on the UI. Note that the hint element can be used to further define string to reference an image. This allows this type of property to display an image instead of text. See the hint child element under property for more details.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== allowedValueRange ==&lt;br /&gt;
&lt;br /&gt;
Use the allowedValueRange to restrict the upper and lower values an integer property can have.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
If you do not set an allowedValueRange, the generated code will bound the values to the range of a 32-bit signed integer. Typically this range is too large to provide useful upper and lower limits for a property such as a light dimmer or a volume control.&lt;br /&gt;
&lt;br /&gt;
Setting your own limits means you get to determine what the boundaries for your Widget's properties are. This also has a direct effect on the sensitivity of the HTML controls generated for the UI.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
The allowedValueRange element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.7. allowedValueRange child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|minimum &lt;br /&gt;
|Contains the lowest integer value this property can have.&lt;br /&gt;
|-&lt;br /&gt;
|maximum &lt;br /&gt;
|Contains the highest integer value this property can have. The maximum value must be greater than or&lt;br /&gt;
equal to the minimum value.&lt;br /&gt;
|-&lt;br /&gt;
|step &lt;br /&gt;
|Contains a non-negative integer to define the increment between each change in value. The value you&lt;br /&gt;
specify here must be exactly divisible into the difference between the maximum and minimum values.&lt;br /&gt;
For example, if your minimum and maximum values are 0 and 50 respectively, your step value must&lt;br /&gt;
be one of the following: 1, 2, 5, 10, 25 or 50.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''HTML controls''' The use of allowedValueRange in an integer property affects whether a text box or slider control is generated. &lt;br /&gt;
&lt;br /&gt;
A text box is displayed in the Web UI if you do not provide an allowedValueRange.&lt;br /&gt;
&lt;br /&gt;
A text box is also displayed if you do provide an allowedValueRange, but the difference between the maximum and minimum values is too great.&lt;br /&gt;
&lt;br /&gt;
A slider control is displayed only if the difference between maximum and minimum is a small enough value. This value is set by OpenHome and is currently undefined.&lt;br /&gt;
&lt;br /&gt;
== allowedValueList ==&lt;br /&gt;
&lt;br /&gt;
Use the allowedValueList to restrict the values a string property can have.&lt;br /&gt;
&lt;br /&gt;
The allowedValueList element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.8. allowedValueList child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|allowedValue &lt;br /&gt;
|Contains a plain text string defining one of the allowed values. You must define a new allowedValue&lt;br /&gt;
for each new value you want the control to be able to accept.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''HTML controls''' The use of allowedValueList affects how the control for a string property is&lt;br /&gt;
generated.&lt;br /&gt;
&lt;br /&gt;
If you provide an allowedValueList, a drop-down list is displayed in the Web UI with your defined entries in it. Users can select the value from this list.&lt;br /&gt;
&lt;br /&gt;
If you do not provide an allowedValueList, a text box is displayed in the Web UI. Users can manually enter the desired value.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Primary property = &lt;br /&gt;
&lt;br /&gt;
A Widget's primary property is the property that users will want to access most often.&lt;br /&gt;
&lt;br /&gt;
Once defined, the primary property is automatically displayed in the Web UI's summary view, along with the name of the Widget.&lt;br /&gt;
&lt;br /&gt;
[[File:SummaryViewAbstract.png|800px|thumb|center|Figure 2. An abstract view of several Widgets' summary views, aggregated in the Node UI.]]&lt;br /&gt;
&lt;br /&gt;
For some simple Widgets the primary property is often the power property. For a more complicated Widget you will need to consider which property you want to assign as primary.&lt;br /&gt;
&lt;br /&gt;
The details of the primary property are stored in the auto-generated Provider. This means the Node has direct access to these details and can provide the summary view UI at run-time.&lt;br /&gt;
&lt;br /&gt;
== Assigning the primary property ==&lt;br /&gt;
&lt;br /&gt;
You assign the primary property by adding an attribute to the chosen property in the XML. For example,&lt;br /&gt;
if we take the On property from a Basic Light Widget we can define it as the primary property by inserting&lt;br /&gt;
primary=&amp;quot;true&amp;quot;. For example:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
         illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
     &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
     &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
     &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
 &amp;lt;/property&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You must assign at most one primary property. Defining more than one property as the primary property&lt;br /&gt;
will leave your XML unable to generate the other files used in Widget development.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* Defining a primary property is not mandatory.&lt;br /&gt;
* You do not need to indicate which properties are NOT the primary property. You use the primary attribute only once in your Widget Service XML as shown in the example above.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
For more details about the Provider, see the [[ohWidget Driver Development|OpenHome Widget Driver Development]] document.&lt;br /&gt;
&lt;br /&gt;
= Naming rules =&lt;br /&gt;
&lt;br /&gt;
The contents of some elements in the Widget Service XML directly affect the output in the generated files.&lt;br /&gt;
&lt;br /&gt;
These details are important for the developers who will use your Widget Service XML file to write drivers&lt;br /&gt;
and UIs for the Widget.&lt;br /&gt;
&lt;br /&gt;
The following sections explain how the XML you define affects the auto-generated output.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The following sections are provided for information. You are not expected to learn any of this information to be able to write a Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Summary view UI == &lt;br /&gt;
&lt;br /&gt;
The details for the summary view UI are defined by the primary property in the XML.&lt;br /&gt;
&lt;br /&gt;
Those details are stored in the Provider so that the Node can always access them and generate the summary view UI at run-time.&lt;br /&gt;
&lt;br /&gt;
== Details view UI ==&lt;br /&gt;
&lt;br /&gt;
=== HTML and UI JavaScript ===&lt;br /&gt;
&lt;br /&gt;
The generated code used in the UI JavaScript and the HTML is based on the content of each of the elements&lt;br /&gt;
you define in the XML. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Provider == &lt;br /&gt;
&lt;br /&gt;
The code generated in the C# provider presents the driver developers with a series of abstract functions they can implement. Those functions are generated using the values you provide in each property's name, dataType and access elements.&lt;br /&gt;
&lt;br /&gt;
For example, the following property in the XML:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
         illuminated &amp;lt;/description&amp;gt;&lt;br /&gt;
     &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
     &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
     &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
     &amp;lt;/property&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will produce the following auto-generated code in the Provider:&lt;br /&gt;
&lt;br /&gt;
 public bool SetPropertyOn(bool aValue)&lt;br /&gt;
 {&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 public bool PropertyOn()&lt;br /&gt;
 {&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
 ...&lt;br /&gt;
 protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
&lt;br /&gt;
Here we see two accessor functions and one abstract function have been created. The accessor functions allow the property's value to be read and written. The abstract function is for Widget driver writers to implement in the code they write.&lt;br /&gt;
&lt;br /&gt;
Let's examine how each of the XML elements affects them.&lt;br /&gt;
&lt;br /&gt;
=== name ===&lt;br /&gt;
&lt;br /&gt;
The XML defines the property's &amp;lt;name&amp;gt; as On:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The generated code includes the property name in the names of each of the generated functions: Set-&lt;br /&gt;
PropertyOn, PropertyOn and SetOn.&lt;br /&gt;
&lt;br /&gt;
SetOn is the abstract function used in the Widget driver. This means that Widget driver writers will&lt;br /&gt;
consistently use the same names throughout the code they write.&lt;br /&gt;
&lt;br /&gt;
=== access ===&lt;br /&gt;
&lt;br /&gt;
The XML defines the property's access as readWrite:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The generated code provides two functions that meet this access setting. The first, SetPropertyOn, provides a way to write the property's value. The second, PropertyOn, provides a way to read the property's value.&lt;br /&gt;
&lt;br /&gt;
If the access was defined as writeOnly, only the abstract SetOn function would be generated.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
If the access was defined as readOnly, a SetPropertyOn function is still generated, but is not accessible from the UI. The function remains in the auto-generated code so that the Widget can update the Node with the property's new state when it changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== dataType ===&lt;br /&gt;
&lt;br /&gt;
The XML defines the property's dataType as boolean:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SetPropertyOn function automatically takes a bool as the parameter to use to set the new value of the property.&lt;br /&gt;
&lt;br /&gt;
The PropertyOn function automatically returns a bool to report the value of the property. &lt;br /&gt;
&lt;br /&gt;
The abstract SetOn function automatically takes a bool as the parameter used to set the new value of the property.&lt;br /&gt;
&lt;br /&gt;
= Appendix A = &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
     &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
     &amp;lt;version&amp;gt;&lt;br /&gt;
         &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
         &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
     &amp;lt;/version&amp;gt;&lt;br /&gt;
     &amp;lt;propertylist&amp;gt;&lt;br /&gt;
         &amp;lt;propertyprimary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
             &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
                 illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
             &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
             &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
             &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
             &amp;lt;hint&amp;gt;boolean-onoff&amp;lt;/hint&amp;gt;&lt;br /&gt;
         &amp;lt;/property&amp;gt;&lt;br /&gt;
     &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary =&lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in Openhome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by Openhome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh A - collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs inside ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The Openhome Operating System. Core software for Openhome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
PDLP - Proxy Device List Provider. The pattern used to represent the layers of UPnP in the Openhome code. All layers except the Presentation layer are represented in this pattern.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. Typical Widgets are lights, speakers, temperature controls.&lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. Widget manufacturers are responsible for choosing which protocols each Widget supports. A typical Widget supports only one Widget communication protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Service_XML_Definition</id>
		<title>OhWidget Service XML Definition</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Service_XML_Definition"/>
				<updated>2012-03-01T15:33:00Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* propertylist */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for Widget manufacturers using OpenHome to define Widget services and properties.&lt;br /&gt;
The services and properties are defined in XML, following the schema published by OpenHome.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Note The OpenHome SDK contains a copy of the WidgetService.xsd used for validation. OpenHome may occasionally update the XSD definition to include new Widget properties. When these become available, OpenHome will publish the new XSD documents on openhome.org. All new XSD documents will be included in new releases of the SDK.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To help you produce your Widget Service XML file, this document provides descriptions of each element you can use in your own Widget Service XML file. A sample Widget Service XML file is used throughout the document.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin defining your Widget Service XML you must in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* technical details about the properties your Widget physically provides&lt;br /&gt;
* the OpenHome SDK, specifically the WidgetService.xsd file&lt;br /&gt;
&lt;br /&gt;
== Related documents ==&lt;br /&gt;
&lt;br /&gt;
The XML you define is used in several areas of Widget development. Refer to the following documents&lt;br /&gt;
to see how the XML is used:&lt;br /&gt;
* [[ohWidget Driver Development|OpenHome Widget Driver Development]]&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
The Widget Service XML file is used to define the features that your Widget provides to users.&lt;br /&gt;
&lt;br /&gt;
Each of these features is described as a property in the Widget Service XML. This may be a simple light Widget offering an on/off — or power — property, or a more complicated Widget offering volume, bass, and treble properties.&lt;br /&gt;
&lt;br /&gt;
Your Widget Service XML file can contain as many properties as are necessary to describe the full range of the Widget's feature set. Your Widget Service XML must contain at least one property.&lt;br /&gt;
&lt;br /&gt;
== Internal structure ==&lt;br /&gt;
&lt;br /&gt;
The Widget Service XML file is validated against an XSD. The XSD is included in the OpenHome SDK.&lt;br /&gt;
&lt;br /&gt;
Snippet 1 shows an abstract hierarchy of the elements used in a Widget Service XML file.&lt;br /&gt;
&lt;br /&gt;
 widgetservice&lt;br /&gt;
   description&lt;br /&gt;
   version&lt;br /&gt;
       major&lt;br /&gt;
       minor&lt;br /&gt;
   propertylist&lt;br /&gt;
       property&lt;br /&gt;
           name&lt;br /&gt;
           description&lt;br /&gt;
           dataType&lt;br /&gt;
           access&lt;br /&gt;
           allowedValueList*&lt;br /&gt;
               allowedValue&lt;br /&gt;
           allowedValueRange*&lt;br /&gt;
               minimum*&lt;br /&gt;
               maximum*&lt;br /&gt;
               step*&lt;br /&gt;
&lt;br /&gt;
Snippet 1: An abstract view of a Widget Service XML, showing the structure of the various elements used.&lt;br /&gt;
Elements marked * are optional.&lt;br /&gt;
&lt;br /&gt;
The structure of the XML is defined by OpenHome. You cannot change it and expect your Widget to operate on an OpenHome network. However, some of the files you generate from it can be customized.&lt;br /&gt;
&lt;br /&gt;
== External document dependencies ==&lt;br /&gt;
&lt;br /&gt;
Your Widget Service XML is used in several areas of Widget development. Several files are automatically generated from this one. Driver authors and UI developers both depend heavily on the code generated from your Widget Service XML. It is therefore essential that you write a well-formed Widget Service XML, conforming to the schema defined in the WidgetService.xsd.&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the significance of the Widget Service XML in relation to the generated files used by other developers to define and publish your Widget on an OpenHome network:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarcy, showing the files you can generate from the Widget Service&lt;br /&gt;
XML.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The JavaScript proxies and the UI HTML and JavaScript files are used by Web UI developers to style and customize the UI that will run on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
The C# Provider is used by Widget driver authors to help them write the code required to operate the Widget.&lt;br /&gt;
&lt;br /&gt;
The C# Proxy is used by developers to produce a C# control point application which can be used in place of the standard Web UI.&lt;br /&gt;
&lt;br /&gt;
= XML elements = &lt;br /&gt;
&lt;br /&gt;
The following tables explain each XML element that can appear in a Widget Service XML file. Descriptions of each element are provided alongside to explain their use. An example of the elements in use is provided in the appendix.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Unless otherwise stated, each of the following elements is mandatory and must appear in your Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== widgetService ==&lt;br /&gt;
&lt;br /&gt;
The widgetService element contains the definition of a service available on the Widget.&lt;br /&gt;
&lt;br /&gt;
==== Table 3.1. widgetService element description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
| widgetService&lt;br /&gt;
| Contains the definition of a Widget's service. This element begins and ends a Widget Service XML file.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The widgetService element has several child elements. They are defined as follows:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.2. widgetService child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|description&lt;br /&gt;
|Contains a plain text description of your Widget, its service and the properties the service provides. It appears as a programmer API comment above the class definitions in both the auto-generated Proxy and Provider files.&lt;br /&gt;
|-&lt;br /&gt;
|version&lt;br /&gt;
|Contains a plain text description of your Widget, its service and the properties the service provides. It appears as a programmer API comment above the class definitions in both the auto-generated Proxy and Provider files.&lt;br /&gt;
|-&lt;br /&gt;
|propertylist &lt;br /&gt;
|Contains the list of properties you want to make available on the Widget. Each entry in this list describes a single property using the property element.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== version ==&lt;br /&gt;
&lt;br /&gt;
The version element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.3. version child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|major &lt;br /&gt;
|This element must appear once only and must contain the value 1.&lt;br /&gt;
|-&lt;br /&gt;
|minor &lt;br /&gt;
|This element must appear once only and must contain the value 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== propertylist ==&lt;br /&gt;
&lt;br /&gt;
Use the propertylist element to hold the list of properties you want to make available on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Your propertylist should ideally contain a property entry for each feature your Widget provides.&lt;br /&gt;
&lt;br /&gt;
If you choose to exclude a feature from the propertylist, it will not be accessible to the user from any OpenHome UI.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
The propertylist element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.4. propertylist child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|property &lt;br /&gt;
|Contains a definition of a property available on the Widget, including: the property's name; the data type used to store the property's value; the read and write access for each property. Your Widget Service&lt;br /&gt;
XML must contain at least one property definition.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== property ==&lt;br /&gt;
&lt;br /&gt;
Use the property element to define a single property on the Widget. A property is one part of the service the Widget provides, such as power, volume or any other single feature.&lt;br /&gt;
&lt;br /&gt;
The property element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.5. property child elements description ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|access &lt;br /&gt;
|Defines the read and write attributes of the property. The access definitions are: readOnly; read-&lt;br /&gt;
Write; writeOnly.&lt;br /&gt;
|-&lt;br /&gt;
|allowedValueList &lt;br /&gt;
|This only affects properties with the string dataType. Contains the list of acceptable string values the property can have. This element is optional.&lt;br /&gt;
|-&lt;br /&gt;
|allowedValueRange &lt;br /&gt;
|This only affects properties with the integer dataType. Contains the minimum and maximum integer values the property can have and an optional step value which defines the interval between the minimum and maximum values. For example, a minimum of 0, a maximum of 10 and a step of 2 means the property can have the following values: 0, 2, 4, 6, 8, 10. This element is optional.&lt;br /&gt;
|-&lt;br /&gt;
|dataType &lt;br /&gt;
|Contains the name of the data type used to store the value of the property. Data types currently supported are: binary; boolean; color; integer;string.&lt;br /&gt;
|-&lt;br /&gt;
|description &lt;br /&gt;
|Contains the plain-text description of the property. The description is included in the generated files as developer documentation.&lt;br /&gt;
|-&lt;br /&gt;
|hint &lt;br /&gt;
|This element allows you to add special definitions to both the boolean and the string dataType properties. Supported values for boolean are: booleanlockunlock; boolean-onoff; booleanopenclose; boolean-updown. This changes the default text strings used when the control is generated in the UI, rather than just on and off. Note that if you do not specify a hint value (either by leaving the element blank or not including it at all) the control will use the default value of booleanonoff. The supported value for string is uri-image. Any string property whose hint element is defined in this way is assumed to be a URI pointing to an image which will be displayed in the UI.&lt;br /&gt;
|-&lt;br /&gt;
|name &lt;br /&gt;
|Contains the unique name for the property. The name must be unique within the service definition. This ensures the code in the generated files has unique function names for each property.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== dataType ==&lt;br /&gt;
&lt;br /&gt;
The dataType element specifies the name of the data type used to store the value of the property. The value you specify here determines that type of information the property can process. It also determines which type of control is generated in the UI's HTML.&lt;br /&gt;
&lt;br /&gt;
Choosing the correct value for the dataType element is important as it ensures that the Widget can be properly controlled by users. To help you ensure you are choosing the correct value, each of the supported values are described in more detail in the table below:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.6. dataType values description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Value''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|binary &lt;br /&gt;
|Use this datatype when processing raw binary data, such as that used to represent a file or stream of data.&lt;br /&gt;
|-&lt;br /&gt;
|boolean &lt;br /&gt;
|For specifying data that can have only one of two states. Typically used for controls to change a Widget&lt;br /&gt;
from one of two allowed states to the other. Note that the hint element can be used to further define&lt;br /&gt;
boolean to make sure the correct labeling is used. See the hint child element under property for&lt;br /&gt;
more details.&lt;br /&gt;
|-&lt;br /&gt;
|color &lt;br /&gt;
|This generates a color picker control that can be used to select a new RGB value.&lt;br /&gt;
|-&lt;br /&gt;
|integer &lt;br /&gt;
|Used for representing whole numbers that can be used for properties that need a range of values, or need to have their value specified from a list of allowed values.&lt;br /&gt;
|-&lt;br /&gt;
|string &lt;br /&gt;
|Displays plain text, typically as a label on the UI. Note that the hint element can be used to further define string to reference an image. This allows this type of property to display an image instead of text. See the hint child element under property for more details.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== allowedValueRange ==&lt;br /&gt;
&lt;br /&gt;
Use the allowedValueRange to restrict the upper and lower values an integer property can have.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
If you do not set an allowedValueRange, the generated code will bound the values to the range of a 32-bit signed integer. Typically this range is too large to provide useful upper and lower limits for a property such as a light dimmer or a volume control.&lt;br /&gt;
&lt;br /&gt;
Setting your own limits means you get to determine what the boundaries for your Widget's properties are. This also has a direct effect on the sensitivity of the HTML controls generated for the UI.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
The allowedValueRange element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.7. allowedValueRange child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|minimum &lt;br /&gt;
|Contains the lowest integer value this property can have.&lt;br /&gt;
|-&lt;br /&gt;
|maximum &lt;br /&gt;
|Contains the highest integer value this property can have. The maximum value must be greater than or&lt;br /&gt;
equal to the minimum value.&lt;br /&gt;
|-&lt;br /&gt;
|step &lt;br /&gt;
|Contains a non-negative integer to define the increment between each change in value. The value you&lt;br /&gt;
specify here must be exactly divisible into the difference between the maximum and minimum values.&lt;br /&gt;
For example, if your minimum and maximum values are 0 and 50 respectively, your step value must&lt;br /&gt;
be one of the following: 1, 2, 5, 10, 25 or 50.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''HTML controls''' The use of allowedValueRange in an integer property affects whether a text box or slider control is generated. &lt;br /&gt;
&lt;br /&gt;
A text box is displayed in the Web UI if you do not provide an allowedValueRange.&lt;br /&gt;
&lt;br /&gt;
A text box is also displayed if you do provide an allowedValueRange, but the difference between the maximum and minimum values is too great.&lt;br /&gt;
&lt;br /&gt;
A slider control is displayed only if the difference between maximum and minimum is a small enough value. This value is set by OpenHome and is currently undefined.&lt;br /&gt;
&lt;br /&gt;
== allowedValueList ==&lt;br /&gt;
&lt;br /&gt;
Use the allowedValueList to restrict the values a string property can have.&lt;br /&gt;
&lt;br /&gt;
The allowedValueList element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.8. allowedValueList child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|allowedValue &lt;br /&gt;
|Contains a plain text string defining one of the allowed values. You must define a new allowedValue&lt;br /&gt;
for each new value you want the control to be able to accept.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''HTML controls''' The use of allowedValueList affects how the control for a string property is&lt;br /&gt;
generated.&lt;br /&gt;
&lt;br /&gt;
If you provide an allowedValueList, a drop-down list is displayed in the Web UI with your defined entries in it. Users can select the value from this list.&lt;br /&gt;
&lt;br /&gt;
If you do not provide an allowedValueList, a text box is displayed in the Web UI. Users can manually enter the desired value.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Primary property = &lt;br /&gt;
&lt;br /&gt;
A Widget's primary property is the property that users will want to access most often.&lt;br /&gt;
&lt;br /&gt;
Once defined, the primary property is automatically displayed in the Web UI's summary view, along with the name of the Widget.&lt;br /&gt;
&lt;br /&gt;
[[File:SummaryViewAbstract.png|800px|thumb|center|Figure 2. An abstract view of several Widgets' summary views, aggregated in the Node UI.]]&lt;br /&gt;
&lt;br /&gt;
For some simple Widgets the primary property is often the power property. For a more complicated Widget you will need to consider which property you want to assign as primary.&lt;br /&gt;
&lt;br /&gt;
The details of the primary property are stored in the auto-generated Provider. This means the Node has direct access to these details and can provide the summary view UI at run-time.&lt;br /&gt;
&lt;br /&gt;
== Assigning the primary property ==&lt;br /&gt;
&lt;br /&gt;
You assign the primary property by adding an attribute to the chosen property in the XML. For example,&lt;br /&gt;
if we take the On property from a Basic Light Widget we can define it as the primary property by inserting&lt;br /&gt;
primary=&amp;quot;true&amp;quot;. For example:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
         illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
     &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
     &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
     &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
 &amp;lt;/property&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You must assign at most one primary property. Defining more than one property as the primary property&lt;br /&gt;
will leave your XML unable to generate the other files used in Widget development.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* Defining a primary property is not mandatory.&lt;br /&gt;
* You do not need to indicate which properties are NOT the primary property. You use the primary attribute only once in your Widget Service XML as shown in the example above.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
For more details about the Provider, see the [[ohWidget Driver Development|OpenHome Widget Driver Development]] document.&lt;br /&gt;
&lt;br /&gt;
= Naming rules =&lt;br /&gt;
&lt;br /&gt;
The contents of some elements in the Widget Service XML directly affect the output in the generated files.&lt;br /&gt;
&lt;br /&gt;
These details are important for the developers who will use your Widget Service XML file to write drivers&lt;br /&gt;
and UIs for the Widget.&lt;br /&gt;
&lt;br /&gt;
The following sections explain how the XML you define affects the auto-generated output.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The following sections are provided for information. You are not expected to learn any of this information to be able to write a Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Summary view UI == &lt;br /&gt;
&lt;br /&gt;
The details for the summary view UI are defined by the primary property in the XML.&lt;br /&gt;
&lt;br /&gt;
Those details are stored in the Provider so that the Node can always access them and generate the summary view UI at run-time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Details view UI ==&lt;br /&gt;
&lt;br /&gt;
=== HTML and UI JavaScript ===&lt;br /&gt;
&lt;br /&gt;
The generated code used in the UI JavaScript and the HTML is based on the content of each of the elements&lt;br /&gt;
you define in the XML. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Provider == &lt;br /&gt;
&lt;br /&gt;
The code generated in the C# provider presents the driver developers with a series of abstract functions they can implement. Those functions are generated using the values you provide in each property's name, dataType and access elements.&lt;br /&gt;
&lt;br /&gt;
For example, the following property in the XML:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
         illuminated &amp;lt;/description&amp;gt;&lt;br /&gt;
     &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
     &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
     &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
     &amp;lt;/property&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will produce the following auto-generated code in the Provider:&lt;br /&gt;
&lt;br /&gt;
 public bool SetPropertyOn(bool aValue)&lt;br /&gt;
 {&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 public bool PropertyOn()&lt;br /&gt;
 {&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
 ...&lt;br /&gt;
 protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
&lt;br /&gt;
Here we see two accessor functions and one abstract function have been created. The accessor functions allow the property's value to be read and written. The abstract function is for Widget driver writers to implement in the code they write.&lt;br /&gt;
&lt;br /&gt;
Let's examine how each of the XML elements affects them.&lt;br /&gt;
&lt;br /&gt;
=== name ===&lt;br /&gt;
&lt;br /&gt;
The XML defines the property's &amp;lt;name&amp;gt; as On:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The generated code includes the property name in the names of each of the generated functions: Set-&lt;br /&gt;
PropertyOn, PropertyOn and SetOn.&lt;br /&gt;
&lt;br /&gt;
SetOn is the abstract function used in the Widget driver. This means that Widget driver writers will&lt;br /&gt;
consistently use the same names throughout the code they write.&lt;br /&gt;
&lt;br /&gt;
=== access ===&lt;br /&gt;
&lt;br /&gt;
The XML defines the property's access as readWrite:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The generated code provides two functions that meet this access setting. The first, SetPropertyOn, provides a way to write the property's value. The second, PropertyOn, provides a way to read the property's value.&lt;br /&gt;
&lt;br /&gt;
If the access was defined as writeOnly, only the abstract SetOn function would be generated.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
If the access was defined as readOnly, a SetPropertyOn function is still generated, but is not accessible from the UI. The function remains in the auto-generated code so that the Widget can update the Node with the property's new state when it changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== dataType ===&lt;br /&gt;
&lt;br /&gt;
The XML defines the property's dataType as boolean:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SetPropertyOn function automatically takes a bool as the parameter to use to set the new value of the property.&lt;br /&gt;
&lt;br /&gt;
The PropertyOn function automatically returns a bool to report the value of the property. &lt;br /&gt;
&lt;br /&gt;
The abstract SetOn function automatically takes a bool as the parameter used to set the new value of the property.&lt;br /&gt;
&lt;br /&gt;
= Appendix A = &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
     &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
     &amp;lt;version&amp;gt;&lt;br /&gt;
         &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
         &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
     &amp;lt;/version&amp;gt;&lt;br /&gt;
     &amp;lt;propertylist&amp;gt;&lt;br /&gt;
         &amp;lt;propertyprimary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
             &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
                 illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
             &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
             &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
             &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
             &amp;lt;hint&amp;gt;boolean-onoff&amp;lt;/hint&amp;gt;&lt;br /&gt;
         &amp;lt;/property&amp;gt;&lt;br /&gt;
     &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary =&lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in Openhome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by Openhome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh A - collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs inside ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The Openhome Operating System. Core software for Openhome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
PDLP - Proxy Device List Provider. The pattern used to represent the layers of UPnP in the Openhome code. All layers except the Presentation layer are represented in this pattern.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. Typical Widgets are lights, speakers, temperature controls.&lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. Widget manufacturers are responsible for choosing which protocols each Widget supports. A typical Widget supports only one Widget communication protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Service_XML_Definition</id>
		<title>OhWidget Service XML Definition</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Service_XML_Definition"/>
				<updated>2012-03-01T15:32:44Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Table 3.3. version child elements description */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for Widget manufacturers using OpenHome to define Widget services and properties.&lt;br /&gt;
The services and properties are defined in XML, following the schema published by OpenHome.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Note The OpenHome SDK contains a copy of the WidgetService.xsd used for validation. OpenHome may occasionally update the XSD definition to include new Widget properties. When these become available, OpenHome will publish the new XSD documents on openhome.org. All new XSD documents will be included in new releases of the SDK.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To help you produce your Widget Service XML file, this document provides descriptions of each element you can use in your own Widget Service XML file. A sample Widget Service XML file is used throughout the document.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin defining your Widget Service XML you must in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* technical details about the properties your Widget physically provides&lt;br /&gt;
* the OpenHome SDK, specifically the WidgetService.xsd file&lt;br /&gt;
&lt;br /&gt;
== Related documents ==&lt;br /&gt;
&lt;br /&gt;
The XML you define is used in several areas of Widget development. Refer to the following documents&lt;br /&gt;
to see how the XML is used:&lt;br /&gt;
* [[ohWidget Driver Development|OpenHome Widget Driver Development]]&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
The Widget Service XML file is used to define the features that your Widget provides to users.&lt;br /&gt;
&lt;br /&gt;
Each of these features is described as a property in the Widget Service XML. This may be a simple light Widget offering an on/off — or power — property, or a more complicated Widget offering volume, bass, and treble properties.&lt;br /&gt;
&lt;br /&gt;
Your Widget Service XML file can contain as many properties as are necessary to describe the full range of the Widget's feature set. Your Widget Service XML must contain at least one property.&lt;br /&gt;
&lt;br /&gt;
== Internal structure ==&lt;br /&gt;
&lt;br /&gt;
The Widget Service XML file is validated against an XSD. The XSD is included in the OpenHome SDK.&lt;br /&gt;
&lt;br /&gt;
Snippet 1 shows an abstract hierarchy of the elements used in a Widget Service XML file.&lt;br /&gt;
&lt;br /&gt;
 widgetservice&lt;br /&gt;
   description&lt;br /&gt;
   version&lt;br /&gt;
       major&lt;br /&gt;
       minor&lt;br /&gt;
   propertylist&lt;br /&gt;
       property&lt;br /&gt;
           name&lt;br /&gt;
           description&lt;br /&gt;
           dataType&lt;br /&gt;
           access&lt;br /&gt;
           allowedValueList*&lt;br /&gt;
               allowedValue&lt;br /&gt;
           allowedValueRange*&lt;br /&gt;
               minimum*&lt;br /&gt;
               maximum*&lt;br /&gt;
               step*&lt;br /&gt;
&lt;br /&gt;
Snippet 1: An abstract view of a Widget Service XML, showing the structure of the various elements used.&lt;br /&gt;
Elements marked * are optional.&lt;br /&gt;
&lt;br /&gt;
The structure of the XML is defined by OpenHome. You cannot change it and expect your Widget to operate on an OpenHome network. However, some of the files you generate from it can be customized.&lt;br /&gt;
&lt;br /&gt;
== External document dependencies ==&lt;br /&gt;
&lt;br /&gt;
Your Widget Service XML is used in several areas of Widget development. Several files are automatically generated from this one. Driver authors and UI developers both depend heavily on the code generated from your Widget Service XML. It is therefore essential that you write a well-formed Widget Service XML, conforming to the schema defined in the WidgetService.xsd.&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the significance of the Widget Service XML in relation to the generated files used by other developers to define and publish your Widget on an OpenHome network:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarcy, showing the files you can generate from the Widget Service&lt;br /&gt;
XML.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The JavaScript proxies and the UI HTML and JavaScript files are used by Web UI developers to style and customize the UI that will run on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
The C# Provider is used by Widget driver authors to help them write the code required to operate the Widget.&lt;br /&gt;
&lt;br /&gt;
The C# Proxy is used by developers to produce a C# control point application which can be used in place of the standard Web UI.&lt;br /&gt;
&lt;br /&gt;
= XML elements = &lt;br /&gt;
&lt;br /&gt;
The following tables explain each XML element that can appear in a Widget Service XML file. Descriptions of each element are provided alongside to explain their use. An example of the elements in use is provided in the appendix.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Unless otherwise stated, each of the following elements is mandatory and must appear in your Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== widgetService ==&lt;br /&gt;
&lt;br /&gt;
The widgetService element contains the definition of a service available on the Widget.&lt;br /&gt;
&lt;br /&gt;
==== Table 3.1. widgetService element description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
| widgetService&lt;br /&gt;
| Contains the definition of a Widget's service. This element begins and ends a Widget Service XML file.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The widgetService element has several child elements. They are defined as follows:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.2. widgetService child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|description&lt;br /&gt;
|Contains a plain text description of your Widget, its service and the properties the service provides. It appears as a programmer API comment above the class definitions in both the auto-generated Proxy and Provider files.&lt;br /&gt;
|-&lt;br /&gt;
|version&lt;br /&gt;
|Contains a plain text description of your Widget, its service and the properties the service provides. It appears as a programmer API comment above the class definitions in both the auto-generated Proxy and Provider files.&lt;br /&gt;
|-&lt;br /&gt;
|propertylist &lt;br /&gt;
|Contains the list of properties you want to make available on the Widget. Each entry in this list describes a single property using the property element.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== version ==&lt;br /&gt;
&lt;br /&gt;
The version element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.3. version child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|major &lt;br /&gt;
|This element must appear once only and must contain the value 1.&lt;br /&gt;
|-&lt;br /&gt;
|minor &lt;br /&gt;
|This element must appear once only and must contain the value 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== propertylist ==&lt;br /&gt;
&lt;br /&gt;
Use the propertylist element to hold the list of properties you want to make available on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Your propertylist should ideally contain a property entry for each feature your Widget provides.&lt;br /&gt;
&lt;br /&gt;
If you choose to exclude a feature from the propertylist, it will not be accessible to the user from any OpenHome UI.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The propertylist element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.4. propertylist child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|property &lt;br /&gt;
|Contains a definition of a property available on the Widget, including: the property's name; the data type used to store the property's value; the read and write access for each property. Your Widget Service&lt;br /&gt;
XML must contain at least one property definition.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== property ==&lt;br /&gt;
&lt;br /&gt;
Use the property element to define a single property on the Widget. A property is one part of the service the Widget provides, such as power, volume or any other single feature.&lt;br /&gt;
&lt;br /&gt;
The property element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.5. property child elements description ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|access &lt;br /&gt;
|Defines the read and write attributes of the property. The access definitions are: readOnly; read-&lt;br /&gt;
Write; writeOnly.&lt;br /&gt;
|-&lt;br /&gt;
|allowedValueList &lt;br /&gt;
|This only affects properties with the string dataType. Contains the list of acceptable string values the property can have. This element is optional.&lt;br /&gt;
|-&lt;br /&gt;
|allowedValueRange &lt;br /&gt;
|This only affects properties with the integer dataType. Contains the minimum and maximum integer values the property can have and an optional step value which defines the interval between the minimum and maximum values. For example, a minimum of 0, a maximum of 10 and a step of 2 means the property can have the following values: 0, 2, 4, 6, 8, 10. This element is optional.&lt;br /&gt;
|-&lt;br /&gt;
|dataType &lt;br /&gt;
|Contains the name of the data type used to store the value of the property. Data types currently supported are: binary; boolean; color; integer;string.&lt;br /&gt;
|-&lt;br /&gt;
|description &lt;br /&gt;
|Contains the plain-text description of the property. The description is included in the generated files as developer documentation.&lt;br /&gt;
|-&lt;br /&gt;
|hint &lt;br /&gt;
|This element allows you to add special definitions to both the boolean and the string dataType properties. Supported values for boolean are: booleanlockunlock; boolean-onoff; booleanopenclose; boolean-updown. This changes the default text strings used when the control is generated in the UI, rather than just on and off. Note that if you do not specify a hint value (either by leaving the element blank or not including it at all) the control will use the default value of booleanonoff. The supported value for string is uri-image. Any string property whose hint element is defined in this way is assumed to be a URI pointing to an image which will be displayed in the UI.&lt;br /&gt;
|-&lt;br /&gt;
|name &lt;br /&gt;
|Contains the unique name for the property. The name must be unique within the service definition. This ensures the code in the generated files has unique function names for each property.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== dataType ==&lt;br /&gt;
&lt;br /&gt;
The dataType element specifies the name of the data type used to store the value of the property. The value you specify here determines that type of information the property can process. It also determines which type of control is generated in the UI's HTML.&lt;br /&gt;
&lt;br /&gt;
Choosing the correct value for the dataType element is important as it ensures that the Widget can be properly controlled by users. To help you ensure you are choosing the correct value, each of the supported values are described in more detail in the table below:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.6. dataType values description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Value''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|binary &lt;br /&gt;
|Use this datatype when processing raw binary data, such as that used to represent a file or stream of data.&lt;br /&gt;
|-&lt;br /&gt;
|boolean &lt;br /&gt;
|For specifying data that can have only one of two states. Typically used for controls to change a Widget&lt;br /&gt;
from one of two allowed states to the other. Note that the hint element can be used to further define&lt;br /&gt;
boolean to make sure the correct labeling is used. See the hint child element under property for&lt;br /&gt;
more details.&lt;br /&gt;
|-&lt;br /&gt;
|color &lt;br /&gt;
|This generates a color picker control that can be used to select a new RGB value.&lt;br /&gt;
|-&lt;br /&gt;
|integer &lt;br /&gt;
|Used for representing whole numbers that can be used for properties that need a range of values, or need to have their value specified from a list of allowed values.&lt;br /&gt;
|-&lt;br /&gt;
|string &lt;br /&gt;
|Displays plain text, typically as a label on the UI. Note that the hint element can be used to further define string to reference an image. This allows this type of property to display an image instead of text. See the hint child element under property for more details.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== allowedValueRange ==&lt;br /&gt;
&lt;br /&gt;
Use the allowedValueRange to restrict the upper and lower values an integer property can have.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
If you do not set an allowedValueRange, the generated code will bound the values to the range of a 32-bit signed integer. Typically this range is too large to provide useful upper and lower limits for a property such as a light dimmer or a volume control.&lt;br /&gt;
&lt;br /&gt;
Setting your own limits means you get to determine what the boundaries for your Widget's properties are. This also has a direct effect on the sensitivity of the HTML controls generated for the UI.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
The allowedValueRange element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.7. allowedValueRange child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|minimum &lt;br /&gt;
|Contains the lowest integer value this property can have.&lt;br /&gt;
|-&lt;br /&gt;
|maximum &lt;br /&gt;
|Contains the highest integer value this property can have. The maximum value must be greater than or&lt;br /&gt;
equal to the minimum value.&lt;br /&gt;
|-&lt;br /&gt;
|step &lt;br /&gt;
|Contains a non-negative integer to define the increment between each change in value. The value you&lt;br /&gt;
specify here must be exactly divisible into the difference between the maximum and minimum values.&lt;br /&gt;
For example, if your minimum and maximum values are 0 and 50 respectively, your step value must&lt;br /&gt;
be one of the following: 1, 2, 5, 10, 25 or 50.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''HTML controls''' The use of allowedValueRange in an integer property affects whether a text box or slider control is generated. &lt;br /&gt;
&lt;br /&gt;
A text box is displayed in the Web UI if you do not provide an allowedValueRange.&lt;br /&gt;
&lt;br /&gt;
A text box is also displayed if you do provide an allowedValueRange, but the difference between the maximum and minimum values is too great.&lt;br /&gt;
&lt;br /&gt;
A slider control is displayed only if the difference between maximum and minimum is a small enough value. This value is set by OpenHome and is currently undefined.&lt;br /&gt;
&lt;br /&gt;
== allowedValueList ==&lt;br /&gt;
&lt;br /&gt;
Use the allowedValueList to restrict the values a string property can have.&lt;br /&gt;
&lt;br /&gt;
The allowedValueList element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.8. allowedValueList child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|allowedValue &lt;br /&gt;
|Contains a plain text string defining one of the allowed values. You must define a new allowedValue&lt;br /&gt;
for each new value you want the control to be able to accept.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''HTML controls''' The use of allowedValueList affects how the control for a string property is&lt;br /&gt;
generated.&lt;br /&gt;
&lt;br /&gt;
If you provide an allowedValueList, a drop-down list is displayed in the Web UI with your defined entries in it. Users can select the value from this list.&lt;br /&gt;
&lt;br /&gt;
If you do not provide an allowedValueList, a text box is displayed in the Web UI. Users can manually enter the desired value.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Primary property = &lt;br /&gt;
&lt;br /&gt;
A Widget's primary property is the property that users will want to access most often.&lt;br /&gt;
&lt;br /&gt;
Once defined, the primary property is automatically displayed in the Web UI's summary view, along with the name of the Widget.&lt;br /&gt;
&lt;br /&gt;
[[File:SummaryViewAbstract.png|800px|thumb|center|Figure 2. An abstract view of several Widgets' summary views, aggregated in the Node UI.]]&lt;br /&gt;
&lt;br /&gt;
For some simple Widgets the primary property is often the power property. For a more complicated Widget you will need to consider which property you want to assign as primary.&lt;br /&gt;
&lt;br /&gt;
The details of the primary property are stored in the auto-generated Provider. This means the Node has direct access to these details and can provide the summary view UI at run-time.&lt;br /&gt;
&lt;br /&gt;
== Assigning the primary property ==&lt;br /&gt;
&lt;br /&gt;
You assign the primary property by adding an attribute to the chosen property in the XML. For example,&lt;br /&gt;
if we take the On property from a Basic Light Widget we can define it as the primary property by inserting&lt;br /&gt;
primary=&amp;quot;true&amp;quot;. For example:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
         illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
     &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
     &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
     &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
 &amp;lt;/property&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You must assign at most one primary property. Defining more than one property as the primary property&lt;br /&gt;
will leave your XML unable to generate the other files used in Widget development.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* Defining a primary property is not mandatory.&lt;br /&gt;
* You do not need to indicate which properties are NOT the primary property. You use the primary attribute only once in your Widget Service XML as shown in the example above.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
For more details about the Provider, see the [[ohWidget Driver Development|OpenHome Widget Driver Development]] document.&lt;br /&gt;
&lt;br /&gt;
= Naming rules =&lt;br /&gt;
&lt;br /&gt;
The contents of some elements in the Widget Service XML directly affect the output in the generated files.&lt;br /&gt;
&lt;br /&gt;
These details are important for the developers who will use your Widget Service XML file to write drivers&lt;br /&gt;
and UIs for the Widget.&lt;br /&gt;
&lt;br /&gt;
The following sections explain how the XML you define affects the auto-generated output.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The following sections are provided for information. You are not expected to learn any of this information to be able to write a Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Summary view UI == &lt;br /&gt;
&lt;br /&gt;
The details for the summary view UI are defined by the primary property in the XML.&lt;br /&gt;
&lt;br /&gt;
Those details are stored in the Provider so that the Node can always access them and generate the summary view UI at run-time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Details view UI ==&lt;br /&gt;
&lt;br /&gt;
=== HTML and UI JavaScript ===&lt;br /&gt;
&lt;br /&gt;
The generated code used in the UI JavaScript and the HTML is based on the content of each of the elements&lt;br /&gt;
you define in the XML. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Provider == &lt;br /&gt;
&lt;br /&gt;
The code generated in the C# provider presents the driver developers with a series of abstract functions they can implement. Those functions are generated using the values you provide in each property's name, dataType and access elements.&lt;br /&gt;
&lt;br /&gt;
For example, the following property in the XML:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
         illuminated &amp;lt;/description&amp;gt;&lt;br /&gt;
     &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
     &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
     &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
     &amp;lt;/property&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will produce the following auto-generated code in the Provider:&lt;br /&gt;
&lt;br /&gt;
 public bool SetPropertyOn(bool aValue)&lt;br /&gt;
 {&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 public bool PropertyOn()&lt;br /&gt;
 {&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
 ...&lt;br /&gt;
 protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
&lt;br /&gt;
Here we see two accessor functions and one abstract function have been created. The accessor functions allow the property's value to be read and written. The abstract function is for Widget driver writers to implement in the code they write.&lt;br /&gt;
&lt;br /&gt;
Let's examine how each of the XML elements affects them.&lt;br /&gt;
&lt;br /&gt;
=== name ===&lt;br /&gt;
&lt;br /&gt;
The XML defines the property's &amp;lt;name&amp;gt; as On:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The generated code includes the property name in the names of each of the generated functions: Set-&lt;br /&gt;
PropertyOn, PropertyOn and SetOn.&lt;br /&gt;
&lt;br /&gt;
SetOn is the abstract function used in the Widget driver. This means that Widget driver writers will&lt;br /&gt;
consistently use the same names throughout the code they write.&lt;br /&gt;
&lt;br /&gt;
=== access ===&lt;br /&gt;
&lt;br /&gt;
The XML defines the property's access as readWrite:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The generated code provides two functions that meet this access setting. The first, SetPropertyOn, provides a way to write the property's value. The second, PropertyOn, provides a way to read the property's value.&lt;br /&gt;
&lt;br /&gt;
If the access was defined as writeOnly, only the abstract SetOn function would be generated.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
If the access was defined as readOnly, a SetPropertyOn function is still generated, but is not accessible from the UI. The function remains in the auto-generated code so that the Widget can update the Node with the property's new state when it changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== dataType ===&lt;br /&gt;
&lt;br /&gt;
The XML defines the property's dataType as boolean:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SetPropertyOn function automatically takes a bool as the parameter to use to set the new value of the property.&lt;br /&gt;
&lt;br /&gt;
The PropertyOn function automatically returns a bool to report the value of the property. &lt;br /&gt;
&lt;br /&gt;
The abstract SetOn function automatically takes a bool as the parameter used to set the new value of the property.&lt;br /&gt;
&lt;br /&gt;
= Appendix A = &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
     &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
     &amp;lt;version&amp;gt;&lt;br /&gt;
         &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
         &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
     &amp;lt;/version&amp;gt;&lt;br /&gt;
     &amp;lt;propertylist&amp;gt;&lt;br /&gt;
         &amp;lt;propertyprimary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
             &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
                 illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
             &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
             &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
             &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
             &amp;lt;hint&amp;gt;boolean-onoff&amp;lt;/hint&amp;gt;&lt;br /&gt;
         &amp;lt;/property&amp;gt;&lt;br /&gt;
     &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary =&lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in Openhome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by Openhome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh A - collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs inside ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The Openhome Operating System. Core software for Openhome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
PDLP - Proxy Device List Provider. The pattern used to represent the layers of UPnP in the Openhome code. All layers except the Presentation layer are represented in this pattern.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. Typical Widgets are lights, speakers, temperature controls.&lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. Widget manufacturers are responsible for choosing which protocols each Widget supports. A typical Widget supports only one Widget communication protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Service_XML_Definition</id>
		<title>OhWidget Service XML Definition</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Service_XML_Definition"/>
				<updated>2012-03-01T15:29:53Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Internal structure */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for Widget manufacturers using OpenHome to define Widget services and properties.&lt;br /&gt;
The services and properties are defined in XML, following the schema published by OpenHome.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Note The OpenHome SDK contains a copy of the WidgetService.xsd used for validation. OpenHome may occasionally update the XSD definition to include new Widget properties. When these become available, OpenHome will publish the new XSD documents on openhome.org. All new XSD documents will be included in new releases of the SDK.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To help you produce your Widget Service XML file, this document provides descriptions of each element you can use in your own Widget Service XML file. A sample Widget Service XML file is used throughout the document.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin defining your Widget Service XML you must in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* technical details about the properties your Widget physically provides&lt;br /&gt;
* the OpenHome SDK, specifically the WidgetService.xsd file&lt;br /&gt;
&lt;br /&gt;
== Related documents ==&lt;br /&gt;
&lt;br /&gt;
The XML you define is used in several areas of Widget development. Refer to the following documents&lt;br /&gt;
to see how the XML is used:&lt;br /&gt;
* [[ohWidget Driver Development|OpenHome Widget Driver Development]]&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
The Widget Service XML file is used to define the features that your Widget provides to users.&lt;br /&gt;
&lt;br /&gt;
Each of these features is described as a property in the Widget Service XML. This may be a simple light Widget offering an on/off — or power — property, or a more complicated Widget offering volume, bass, and treble properties.&lt;br /&gt;
&lt;br /&gt;
Your Widget Service XML file can contain as many properties as are necessary to describe the full range of the Widget's feature set. Your Widget Service XML must contain at least one property.&lt;br /&gt;
&lt;br /&gt;
== Internal structure ==&lt;br /&gt;
&lt;br /&gt;
The Widget Service XML file is validated against an XSD. The XSD is included in the OpenHome SDK.&lt;br /&gt;
&lt;br /&gt;
Snippet 1 shows an abstract hierarchy of the elements used in a Widget Service XML file.&lt;br /&gt;
&lt;br /&gt;
 widgetservice&lt;br /&gt;
   description&lt;br /&gt;
   version&lt;br /&gt;
       major&lt;br /&gt;
       minor&lt;br /&gt;
   propertylist&lt;br /&gt;
       property&lt;br /&gt;
           name&lt;br /&gt;
           description&lt;br /&gt;
           dataType&lt;br /&gt;
           access&lt;br /&gt;
           allowedValueList*&lt;br /&gt;
               allowedValue&lt;br /&gt;
           allowedValueRange*&lt;br /&gt;
               minimum*&lt;br /&gt;
               maximum*&lt;br /&gt;
               step*&lt;br /&gt;
&lt;br /&gt;
Snippet 1: An abstract view of a Widget Service XML, showing the structure of the various elements used.&lt;br /&gt;
Elements marked * are optional.&lt;br /&gt;
&lt;br /&gt;
The structure of the XML is defined by OpenHome. You cannot change it and expect your Widget to operate on an OpenHome network. However, some of the files you generate from it can be customized.&lt;br /&gt;
&lt;br /&gt;
== External document dependencies ==&lt;br /&gt;
&lt;br /&gt;
Your Widget Service XML is used in several areas of Widget development. Several files are automatically generated from this one. Driver authors and UI developers both depend heavily on the code generated from your Widget Service XML. It is therefore essential that you write a well-formed Widget Service XML, conforming to the schema defined in the WidgetService.xsd.&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the significance of the Widget Service XML in relation to the generated files used by other developers to define and publish your Widget on an OpenHome network:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarcy, showing the files you can generate from the Widget Service&lt;br /&gt;
XML.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The JavaScript proxies and the UI HTML and JavaScript files are used by Web UI developers to style and customize the UI that will run on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
The C# Provider is used by Widget driver authors to help them write the code required to operate the Widget.&lt;br /&gt;
&lt;br /&gt;
The C# Proxy is used by developers to produce a C# control point application which can be used in place of the standard Web UI.&lt;br /&gt;
&lt;br /&gt;
= XML elements = &lt;br /&gt;
&lt;br /&gt;
The following tables explain each XML element that can appear in a Widget Service XML file. Descriptions of each element are provided alongside to explain their use. An example of the elements in use is provided in the appendix.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Unless otherwise stated, each of the following elements is mandatory and must appear in your Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== widgetService ==&lt;br /&gt;
&lt;br /&gt;
The widgetService element contains the definition of a service available on the Widget.&lt;br /&gt;
&lt;br /&gt;
==== Table 3.1. widgetService element description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
| widgetService&lt;br /&gt;
| Contains the definition of a Widget's service. This element begins and ends a Widget Service XML file.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The widgetService element has several child elements. They are defined as follows:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.2. widgetService child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|description&lt;br /&gt;
|Contains a plain text description of your Widget, its service and the properties the service provides. It appears as a programmer API comment above the class definitions in both the auto-generated Proxy and Provider files.&lt;br /&gt;
|-&lt;br /&gt;
|version&lt;br /&gt;
|Contains a plain text description of your Widget, its service and the properties the service provides. It appears as a programmer API comment above the class definitions in both the auto-generated Proxy and Provider files.&lt;br /&gt;
|-&lt;br /&gt;
|propertylist &lt;br /&gt;
|Contains the list of properties you want to make available on the Widget. Each entry in this list describes a single property using the property element.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== version ==&lt;br /&gt;
&lt;br /&gt;
The version element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.3. version child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|major &lt;br /&gt;
|This element must appear once only and must contain the value 1.&lt;br /&gt;
|-&lt;br /&gt;
|minor &lt;br /&gt;
|This element must appear once only and must contain the value 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== propertylist ==&lt;br /&gt;
&lt;br /&gt;
Use the propertylist element to hold the list of properties you want to make available on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Your propertylist should ideally contain a property entry for each feature your Widget provides.&lt;br /&gt;
&lt;br /&gt;
If you choose to exclude a feature from the propertylist, it will not be accessible to the user from any OpenHome UI.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The propertylist element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.4. propertylist child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|property &lt;br /&gt;
|Contains a definition of a property available on the Widget, including: the property's name; the data type used to store the property's value; the read and write access for each property. Your Widget Service&lt;br /&gt;
XML must contain at least one property definition.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== property ==&lt;br /&gt;
&lt;br /&gt;
Use the property element to define a single property on the Widget. A property is one part of the service the Widget provides, such as power, volume or any other single feature.&lt;br /&gt;
&lt;br /&gt;
The property element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.5. property child elements description ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|access &lt;br /&gt;
|Defines the read and write attributes of the property. The access definitions are: readOnly; read-&lt;br /&gt;
Write; writeOnly.&lt;br /&gt;
|-&lt;br /&gt;
|allowedValueList &lt;br /&gt;
|This only affects properties with the string dataType. Contains the list of acceptable string values the property can have. This element is optional.&lt;br /&gt;
|-&lt;br /&gt;
|allowedValueRange &lt;br /&gt;
|This only affects properties with the integer dataType. Contains the minimum and maximum integer values the property can have and an optional step value which defines the interval between the minimum and maximum values. For example, a minimum of 0, a maximum of 10 and a step of 2 means the property can have the following values: 0, 2, 4, 6, 8, 10. This element is optional.&lt;br /&gt;
|-&lt;br /&gt;
|dataType &lt;br /&gt;
|Contains the name of the data type used to store the value of the property. Data types currently supported are: binary; boolean; color; integer;string.&lt;br /&gt;
|-&lt;br /&gt;
|description &lt;br /&gt;
|Contains the plain-text description of the property. The description is included in the generated files as developer documentation.&lt;br /&gt;
|-&lt;br /&gt;
|hint &lt;br /&gt;
|This element allows you to add special definitions to both the boolean and the string dataType properties. Supported values for boolean are: booleanlockunlock; boolean-onoff; booleanopenclose; boolean-updown. This changes the default text strings used when the control is generated in the UI, rather than just on and off. Note that if you do not specify a hint value (either by leaving the element blank or not including it at all) the control will use the default value of booleanonoff. The supported value for string is uri-image. Any string property whose hint element is defined in this way is assumed to be a URI pointing to an image which will be displayed in the UI.&lt;br /&gt;
|-&lt;br /&gt;
|name &lt;br /&gt;
|Contains the unique name for the property. The name must be unique within the service definition. This ensures the code in the generated files has unique function names for each property.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== dataType ==&lt;br /&gt;
&lt;br /&gt;
The dataType element specifies the name of the data type used to store the value of the property. The value you specify here determines that type of information the property can process. It also determines which type of control is generated in the UI's HTML.&lt;br /&gt;
&lt;br /&gt;
Choosing the correct value for the dataType element is important as it ensures that the Widget can be properly controlled by users. To help you ensure you are choosing the correct value, each of the supported values are described in more detail in the table below:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.6. dataType values description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Value''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|binary &lt;br /&gt;
|Use this datatype when processing raw binary data, such as that used to represent a file or stream of data.&lt;br /&gt;
|-&lt;br /&gt;
|boolean &lt;br /&gt;
|For specifying data that can have only one of two states. Typically used for controls to change a Widget&lt;br /&gt;
from one of two allowed states to the other. Note that the hint element can be used to further define&lt;br /&gt;
boolean to make sure the correct labeling is used. See the hint child element under property for&lt;br /&gt;
more details.&lt;br /&gt;
|-&lt;br /&gt;
|color &lt;br /&gt;
|This generates a color picker control that can be used to select a new RGB value.&lt;br /&gt;
|-&lt;br /&gt;
|integer &lt;br /&gt;
|Used for representing whole numbers that can be used for properties that need a range of values, or need to have their value specified from a list of allowed values.&lt;br /&gt;
|-&lt;br /&gt;
|string &lt;br /&gt;
|Displays plain text, typically as a label on the UI. Note that the hint element can be used to further define string to reference an image. This allows this type of property to display an image instead of text. See the hint child element under property for more details.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== allowedValueRange ==&lt;br /&gt;
&lt;br /&gt;
Use the allowedValueRange to restrict the upper and lower values an integer property can have.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
If you do not set an allowedValueRange, the generated code will bound the values to the range of a 32-bit signed integer. Typically this range is too large to provide useful upper and lower limits for a property such as a light dimmer or a volume control.&lt;br /&gt;
&lt;br /&gt;
Setting your own limits means you get to determine what the boundaries for your Widget's properties are. This also has a direct effect on the sensitivity of the HTML controls generated for the UI.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
The allowedValueRange element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.7. allowedValueRange child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|minimum &lt;br /&gt;
|Contains the lowest integer value this property can have.&lt;br /&gt;
|-&lt;br /&gt;
|maximum &lt;br /&gt;
|Contains the highest integer value this property can have. The maximum value must be greater than or&lt;br /&gt;
equal to the minimum value.&lt;br /&gt;
|-&lt;br /&gt;
|step &lt;br /&gt;
|Contains a non-negative integer to define the increment between each change in value. The value you&lt;br /&gt;
specify here must be exactly divisible into the difference between the maximum and minimum values.&lt;br /&gt;
For example, if your minimum and maximum values are 0 and 50 respectively, your step value must&lt;br /&gt;
be one of the following: 1, 2, 5, 10, 25 or 50.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''HTML controls''' The use of allowedValueRange in an integer property affects whether a text box or slider control is generated. &lt;br /&gt;
&lt;br /&gt;
A text box is displayed in the Web UI if you do not provide an allowedValueRange.&lt;br /&gt;
&lt;br /&gt;
A text box is also displayed if you do provide an allowedValueRange, but the difference between the maximum and minimum values is too great.&lt;br /&gt;
&lt;br /&gt;
A slider control is displayed only if the difference between maximum and minimum is a small enough value. This value is set by OpenHome and is currently undefined.&lt;br /&gt;
&lt;br /&gt;
== allowedValueList ==&lt;br /&gt;
&lt;br /&gt;
Use the allowedValueList to restrict the values a string property can have.&lt;br /&gt;
&lt;br /&gt;
The allowedValueList element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.8. allowedValueList child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|allowedValue &lt;br /&gt;
|Contains a plain text string defining one of the allowed values. You must define a new allowedValue&lt;br /&gt;
for each new value you want the control to be able to accept.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''HTML controls''' The use of allowedValueList affects how the control for a string property is&lt;br /&gt;
generated.&lt;br /&gt;
&lt;br /&gt;
If you provide an allowedValueList, a drop-down list is displayed in the Web UI with your defined entries in it. Users can select the value from this list.&lt;br /&gt;
&lt;br /&gt;
If you do not provide an allowedValueList, a text box is displayed in the Web UI. Users can manually enter the desired value.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Primary property = &lt;br /&gt;
&lt;br /&gt;
A Widget's primary property is the property that users will want to access most often.&lt;br /&gt;
&lt;br /&gt;
Once defined, the primary property is automatically displayed in the Web UI's summary view, along with the name of the Widget.&lt;br /&gt;
&lt;br /&gt;
[[File:SummaryViewAbstract.png|800px|thumb|center|Figure 2. An abstract view of several Widgets' summary views, aggregated in the Node UI.]]&lt;br /&gt;
&lt;br /&gt;
For some simple Widgets the primary property is often the power property. For a more complicated Widget you will need to consider which property you want to assign as primary.&lt;br /&gt;
&lt;br /&gt;
The details of the primary property are stored in the auto-generated Provider. This means the Node has direct access to these details and can provide the summary view UI at run-time.&lt;br /&gt;
&lt;br /&gt;
== Assigning the primary property ==&lt;br /&gt;
&lt;br /&gt;
You assign the primary property by adding an attribute to the chosen property in the XML. For example,&lt;br /&gt;
if we take the On property from a Basic Light Widget we can define it as the primary property by inserting&lt;br /&gt;
primary=&amp;quot;true&amp;quot;. For example:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
         illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
     &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
     &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
     &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
 &amp;lt;/property&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You must assign at most one primary property. Defining more than one property as the primary property&lt;br /&gt;
will leave your XML unable to generate the other files used in Widget development.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* Defining a primary property is not mandatory.&lt;br /&gt;
* You do not need to indicate which properties are NOT the primary property. You use the primary attribute only once in your Widget Service XML as shown in the example above.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
For more details about the Provider, see the [[ohWidget Driver Development|OpenHome Widget Driver Development]] document.&lt;br /&gt;
&lt;br /&gt;
= Naming rules =&lt;br /&gt;
&lt;br /&gt;
The contents of some elements in the Widget Service XML directly affect the output in the generated files.&lt;br /&gt;
&lt;br /&gt;
These details are important for the developers who will use your Widget Service XML file to write drivers&lt;br /&gt;
and UIs for the Widget.&lt;br /&gt;
&lt;br /&gt;
The following sections explain how the XML you define affects the auto-generated output.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The following sections are provided for information. You are not expected to learn any of this information to be able to write a Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Summary view UI == &lt;br /&gt;
&lt;br /&gt;
The details for the summary view UI are defined by the primary property in the XML.&lt;br /&gt;
&lt;br /&gt;
Those details are stored in the Provider so that the Node can always access them and generate the summary view UI at run-time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Details view UI ==&lt;br /&gt;
&lt;br /&gt;
=== HTML and UI JavaScript ===&lt;br /&gt;
&lt;br /&gt;
The generated code used in the UI JavaScript and the HTML is based on the content of each of the elements&lt;br /&gt;
you define in the XML. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Provider == &lt;br /&gt;
&lt;br /&gt;
The code generated in the C# provider presents the driver developers with a series of abstract functions they can implement. Those functions are generated using the values you provide in each property's name, dataType and access elements.&lt;br /&gt;
&lt;br /&gt;
For example, the following property in the XML:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
         illuminated &amp;lt;/description&amp;gt;&lt;br /&gt;
     &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
     &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
     &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
     &amp;lt;/property&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will produce the following auto-generated code in the Provider:&lt;br /&gt;
&lt;br /&gt;
 public bool SetPropertyOn(bool aValue)&lt;br /&gt;
 {&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 public bool PropertyOn()&lt;br /&gt;
 {&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
 ...&lt;br /&gt;
 protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
&lt;br /&gt;
Here we see two accessor functions and one abstract function have been created. The accessor functions allow the property's value to be read and written. The abstract function is for Widget driver writers to implement in the code they write.&lt;br /&gt;
&lt;br /&gt;
Let's examine how each of the XML elements affects them.&lt;br /&gt;
&lt;br /&gt;
=== name ===&lt;br /&gt;
&lt;br /&gt;
The XML defines the property's &amp;lt;name&amp;gt; as On:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The generated code includes the property name in the names of each of the generated functions: Set-&lt;br /&gt;
PropertyOn, PropertyOn and SetOn.&lt;br /&gt;
&lt;br /&gt;
SetOn is the abstract function used in the Widget driver. This means that Widget driver writers will&lt;br /&gt;
consistently use the same names throughout the code they write.&lt;br /&gt;
&lt;br /&gt;
=== access ===&lt;br /&gt;
&lt;br /&gt;
The XML defines the property's access as readWrite:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The generated code provides two functions that meet this access setting. The first, SetPropertyOn, provides a way to write the property's value. The second, PropertyOn, provides a way to read the property's value.&lt;br /&gt;
&lt;br /&gt;
If the access was defined as writeOnly, only the abstract SetOn function would be generated.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
If the access was defined as readOnly, a SetPropertyOn function is still generated, but is not accessible from the UI. The function remains in the auto-generated code so that the Widget can update the Node with the property's new state when it changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== dataType ===&lt;br /&gt;
&lt;br /&gt;
The XML defines the property's dataType as boolean:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SetPropertyOn function automatically takes a bool as the parameter to use to set the new value of the property.&lt;br /&gt;
&lt;br /&gt;
The PropertyOn function automatically returns a bool to report the value of the property. &lt;br /&gt;
&lt;br /&gt;
The abstract SetOn function automatically takes a bool as the parameter used to set the new value of the property.&lt;br /&gt;
&lt;br /&gt;
= Appendix A = &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
     &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
     &amp;lt;version&amp;gt;&lt;br /&gt;
         &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
         &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
     &amp;lt;/version&amp;gt;&lt;br /&gt;
     &amp;lt;propertylist&amp;gt;&lt;br /&gt;
         &amp;lt;propertyprimary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
             &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
                 illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
             &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
             &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
             &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
             &amp;lt;hint&amp;gt;boolean-onoff&amp;lt;/hint&amp;gt;&lt;br /&gt;
         &amp;lt;/property&amp;gt;&lt;br /&gt;
     &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary =&lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in Openhome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by Openhome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh A - collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs inside ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The Openhome Operating System. Core software for Openhome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
PDLP - Proxy Device List Provider. The pattern used to represent the layers of UPnP in the Openhome code. All layers except the Presentation layer are represented in this pattern.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. Typical Widgets are lights, speakers, temperature controls.&lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. Widget manufacturers are responsible for choosing which protocols each Widget supports. A typical Widget supports only one Widget communication protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Service_XML_Definition</id>
		<title>OhWidget Service XML Definition</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Service_XML_Definition"/>
				<updated>2012-03-01T15:29:27Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Introduction */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for Widget manufacturers using OpenHome to define Widget services and properties.&lt;br /&gt;
The services and properties are defined in XML, following the schema published by OpenHome.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Note The OpenHome SDK contains a copy of the WidgetService.xsd used for validation. OpenHome may occasionally update the XSD definition to include new Widget properties. When these become available, OpenHome will publish the new XSD documents on openhome.org. All new XSD documents will be included in new releases of the SDK.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To help you produce your Widget Service XML file, this document provides descriptions of each element you can use in your own Widget Service XML file. A sample Widget Service XML file is used throughout the document.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin defining your Widget Service XML you must in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* technical details about the properties your Widget physically provides&lt;br /&gt;
* the OpenHome SDK, specifically the WidgetService.xsd file&lt;br /&gt;
&lt;br /&gt;
== Related documents ==&lt;br /&gt;
&lt;br /&gt;
The XML you define is used in several areas of Widget development. Refer to the following documents&lt;br /&gt;
to see how the XML is used:&lt;br /&gt;
* [[ohWidget Driver Development|OpenHome Widget Driver Development]]&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
The Widget Service XML file is used to define the features that your Widget provides to users.&lt;br /&gt;
&lt;br /&gt;
Each of these features is described as a property in the Widget Service XML. This may be a simple light Widget offering an on/off — or power — property, or a more complicated Widget offering volume, bass, and treble properties.&lt;br /&gt;
&lt;br /&gt;
Your Widget Service XML file can contain as many properties as are necessary to describe the full range of the Widget's feature set. Your Widget Service XML must contain at least one property.&lt;br /&gt;
&lt;br /&gt;
== Internal structure ==&lt;br /&gt;
&lt;br /&gt;
The Widget Service XML file is validated against an XSD. The XSD is included in the OpenHome SDK.&lt;br /&gt;
&lt;br /&gt;
Snippet 1 shows an abstract hierarchy of the elements used in a Widget Service XML file.&lt;br /&gt;
&lt;br /&gt;
 widgetservice&lt;br /&gt;
   description&lt;br /&gt;
   version&lt;br /&gt;
       major&lt;br /&gt;
       minor&lt;br /&gt;
   propertylist&lt;br /&gt;
       property&lt;br /&gt;
           name&lt;br /&gt;
           description&lt;br /&gt;
           dataType&lt;br /&gt;
           access&lt;br /&gt;
           allowedValueList*&lt;br /&gt;
               allowedValue&lt;br /&gt;
           allowedValueRange*&lt;br /&gt;
               minimum*&lt;br /&gt;
               maximum*&lt;br /&gt;
               step*&lt;br /&gt;
&lt;br /&gt;
Snippet 1: An abstract view of a Widget Service XML, showing the structure of the various elements used.&lt;br /&gt;
Elements marked * are optional.&lt;br /&gt;
&lt;br /&gt;
The structure of the XML is defined by OpenHome. You cannot change it and expect your Widget to operate on an OpenHome network. However, some of the files you generate from it can be customized.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== External document dependencies ==&lt;br /&gt;
&lt;br /&gt;
Your Widget Service XML is used in several areas of Widget development. Several files are automatically generated from this one. Driver authors and UI developers both depend heavily on the code generated from your Widget Service XML. It is therefore essential that you write a well-formed Widget Service XML, conforming to the schema defined in the WidgetService.xsd.&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the significance of the Widget Service XML in relation to the generated files used by other developers to define and publish your Widget on an OpenHome network:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarcy, showing the files you can generate from the Widget Service&lt;br /&gt;
XML.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The JavaScript proxies and the UI HTML and JavaScript files are used by Web UI developers to style and customize the UI that will run on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
The C# Provider is used by Widget driver authors to help them write the code required to operate the Widget.&lt;br /&gt;
&lt;br /&gt;
The C# Proxy is used by developers to produce a C# control point application which can be used in place of the standard Web UI.&lt;br /&gt;
&lt;br /&gt;
= XML elements = &lt;br /&gt;
&lt;br /&gt;
The following tables explain each XML element that can appear in a Widget Service XML file. Descriptions of each element are provided alongside to explain their use. An example of the elements in use is provided in the appendix.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Unless otherwise stated, each of the following elements is mandatory and must appear in your Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== widgetService ==&lt;br /&gt;
&lt;br /&gt;
The widgetService element contains the definition of a service available on the Widget.&lt;br /&gt;
&lt;br /&gt;
==== Table 3.1. widgetService element description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
| widgetService&lt;br /&gt;
| Contains the definition of a Widget's service. This element begins and ends a Widget Service XML file.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The widgetService element has several child elements. They are defined as follows:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.2. widgetService child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|description&lt;br /&gt;
|Contains a plain text description of your Widget, its service and the properties the service provides. It appears as a programmer API comment above the class definitions in both the auto-generated Proxy and Provider files.&lt;br /&gt;
|-&lt;br /&gt;
|version&lt;br /&gt;
|Contains a plain text description of your Widget, its service and the properties the service provides. It appears as a programmer API comment above the class definitions in both the auto-generated Proxy and Provider files.&lt;br /&gt;
|-&lt;br /&gt;
|propertylist &lt;br /&gt;
|Contains the list of properties you want to make available on the Widget. Each entry in this list describes a single property using the property element.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== version ==&lt;br /&gt;
&lt;br /&gt;
The version element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.3. version child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|major &lt;br /&gt;
|This element must appear once only and must contain the value 1.&lt;br /&gt;
|-&lt;br /&gt;
|minor &lt;br /&gt;
|This element must appear once only and must contain the value 0.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== propertylist ==&lt;br /&gt;
&lt;br /&gt;
Use the propertylist element to hold the list of properties you want to make available on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Your propertylist should ideally contain a property entry for each feature your Widget provides.&lt;br /&gt;
&lt;br /&gt;
If you choose to exclude a feature from the propertylist, it will not be accessible to the user from any OpenHome UI.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The propertylist element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.4. propertylist child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|property &lt;br /&gt;
|Contains a definition of a property available on the Widget, including: the property's name; the data type used to store the property's value; the read and write access for each property. Your Widget Service&lt;br /&gt;
XML must contain at least one property definition.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== property ==&lt;br /&gt;
&lt;br /&gt;
Use the property element to define a single property on the Widget. A property is one part of the service the Widget provides, such as power, volume or any other single feature.&lt;br /&gt;
&lt;br /&gt;
The property element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.5. property child elements description ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|access &lt;br /&gt;
|Defines the read and write attributes of the property. The access definitions are: readOnly; read-&lt;br /&gt;
Write; writeOnly.&lt;br /&gt;
|-&lt;br /&gt;
|allowedValueList &lt;br /&gt;
|This only affects properties with the string dataType. Contains the list of acceptable string values the property can have. This element is optional.&lt;br /&gt;
|-&lt;br /&gt;
|allowedValueRange &lt;br /&gt;
|This only affects properties with the integer dataType. Contains the minimum and maximum integer values the property can have and an optional step value which defines the interval between the minimum and maximum values. For example, a minimum of 0, a maximum of 10 and a step of 2 means the property can have the following values: 0, 2, 4, 6, 8, 10. This element is optional.&lt;br /&gt;
|-&lt;br /&gt;
|dataType &lt;br /&gt;
|Contains the name of the data type used to store the value of the property. Data types currently supported are: binary; boolean; color; integer;string.&lt;br /&gt;
|-&lt;br /&gt;
|description &lt;br /&gt;
|Contains the plain-text description of the property. The description is included in the generated files as developer documentation.&lt;br /&gt;
|-&lt;br /&gt;
|hint &lt;br /&gt;
|This element allows you to add special definitions to both the boolean and the string dataType properties. Supported values for boolean are: booleanlockunlock; boolean-onoff; booleanopenclose; boolean-updown. This changes the default text strings used when the control is generated in the UI, rather than just on and off. Note that if you do not specify a hint value (either by leaving the element blank or not including it at all) the control will use the default value of booleanonoff. The supported value for string is uri-image. Any string property whose hint element is defined in this way is assumed to be a URI pointing to an image which will be displayed in the UI.&lt;br /&gt;
|-&lt;br /&gt;
|name &lt;br /&gt;
|Contains the unique name for the property. The name must be unique within the service definition. This ensures the code in the generated files has unique function names for each property.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== dataType ==&lt;br /&gt;
&lt;br /&gt;
The dataType element specifies the name of the data type used to store the value of the property. The value you specify here determines that type of information the property can process. It also determines which type of control is generated in the UI's HTML.&lt;br /&gt;
&lt;br /&gt;
Choosing the correct value for the dataType element is important as it ensures that the Widget can be properly controlled by users. To help you ensure you are choosing the correct value, each of the supported values are described in more detail in the table below:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.6. dataType values description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Value''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|binary &lt;br /&gt;
|Use this datatype when processing raw binary data, such as that used to represent a file or stream of data.&lt;br /&gt;
|-&lt;br /&gt;
|boolean &lt;br /&gt;
|For specifying data that can have only one of two states. Typically used for controls to change a Widget&lt;br /&gt;
from one of two allowed states to the other. Note that the hint element can be used to further define&lt;br /&gt;
boolean to make sure the correct labeling is used. See the hint child element under property for&lt;br /&gt;
more details.&lt;br /&gt;
|-&lt;br /&gt;
|color &lt;br /&gt;
|This generates a color picker control that can be used to select a new RGB value.&lt;br /&gt;
|-&lt;br /&gt;
|integer &lt;br /&gt;
|Used for representing whole numbers that can be used for properties that need a range of values, or need to have their value specified from a list of allowed values.&lt;br /&gt;
|-&lt;br /&gt;
|string &lt;br /&gt;
|Displays plain text, typically as a label on the UI. Note that the hint element can be used to further define string to reference an image. This allows this type of property to display an image instead of text. See the hint child element under property for more details.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== allowedValueRange ==&lt;br /&gt;
&lt;br /&gt;
Use the allowedValueRange to restrict the upper and lower values an integer property can have.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
If you do not set an allowedValueRange, the generated code will bound the values to the range of a 32-bit signed integer. Typically this range is too large to provide useful upper and lower limits for a property such as a light dimmer or a volume control.&lt;br /&gt;
&lt;br /&gt;
Setting your own limits means you get to determine what the boundaries for your Widget's properties are. This also has a direct effect on the sensitivity of the HTML controls generated for the UI.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
The allowedValueRange element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.7. allowedValueRange child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|minimum &lt;br /&gt;
|Contains the lowest integer value this property can have.&lt;br /&gt;
|-&lt;br /&gt;
|maximum &lt;br /&gt;
|Contains the highest integer value this property can have. The maximum value must be greater than or&lt;br /&gt;
equal to the minimum value.&lt;br /&gt;
|-&lt;br /&gt;
|step &lt;br /&gt;
|Contains a non-negative integer to define the increment between each change in value. The value you&lt;br /&gt;
specify here must be exactly divisible into the difference between the maximum and minimum values.&lt;br /&gt;
For example, if your minimum and maximum values are 0 and 50 respectively, your step value must&lt;br /&gt;
be one of the following: 1, 2, 5, 10, 25 or 50.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''HTML controls''' The use of allowedValueRange in an integer property affects whether a text box or slider control is generated. &lt;br /&gt;
&lt;br /&gt;
A text box is displayed in the Web UI if you do not provide an allowedValueRange.&lt;br /&gt;
&lt;br /&gt;
A text box is also displayed if you do provide an allowedValueRange, but the difference between the maximum and minimum values is too great.&lt;br /&gt;
&lt;br /&gt;
A slider control is displayed only if the difference between maximum and minimum is a small enough value. This value is set by OpenHome and is currently undefined.&lt;br /&gt;
&lt;br /&gt;
== allowedValueList ==&lt;br /&gt;
&lt;br /&gt;
Use the allowedValueList to restrict the values a string property can have.&lt;br /&gt;
&lt;br /&gt;
The allowedValueList element has the following child elements:&lt;br /&gt;
&lt;br /&gt;
==== Table 3.8. allowedValueList child elements description ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!|'''Element''' &lt;br /&gt;
!| '''Description'''&lt;br /&gt;
|-&lt;br /&gt;
|allowedValue &lt;br /&gt;
|Contains a plain text string defining one of the allowed values. You must define a new allowedValue&lt;br /&gt;
for each new value you want the control to be able to accept.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''HTML controls''' The use of allowedValueList affects how the control for a string property is&lt;br /&gt;
generated.&lt;br /&gt;
&lt;br /&gt;
If you provide an allowedValueList, a drop-down list is displayed in the Web UI with your defined entries in it. Users can select the value from this list.&lt;br /&gt;
&lt;br /&gt;
If you do not provide an allowedValueList, a text box is displayed in the Web UI. Users can manually enter the desired value.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Primary property = &lt;br /&gt;
&lt;br /&gt;
A Widget's primary property is the property that users will want to access most often.&lt;br /&gt;
&lt;br /&gt;
Once defined, the primary property is automatically displayed in the Web UI's summary view, along with the name of the Widget.&lt;br /&gt;
&lt;br /&gt;
[[File:SummaryViewAbstract.png|800px|thumb|center|Figure 2. An abstract view of several Widgets' summary views, aggregated in the Node UI.]]&lt;br /&gt;
&lt;br /&gt;
For some simple Widgets the primary property is often the power property. For a more complicated Widget you will need to consider which property you want to assign as primary.&lt;br /&gt;
&lt;br /&gt;
The details of the primary property are stored in the auto-generated Provider. This means the Node has direct access to these details and can provide the summary view UI at run-time.&lt;br /&gt;
&lt;br /&gt;
== Assigning the primary property ==&lt;br /&gt;
&lt;br /&gt;
You assign the primary property by adding an attribute to the chosen property in the XML. For example,&lt;br /&gt;
if we take the On property from a Basic Light Widget we can define it as the primary property by inserting&lt;br /&gt;
primary=&amp;quot;true&amp;quot;. For example:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
         illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
     &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
     &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
     &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
 &amp;lt;/property&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You must assign at most one primary property. Defining more than one property as the primary property&lt;br /&gt;
will leave your XML unable to generate the other files used in Widget development.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* Defining a primary property is not mandatory.&lt;br /&gt;
* You do not need to indicate which properties are NOT the primary property. You use the primary attribute only once in your Widget Service XML as shown in the example above.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
For more details about the Provider, see the [[ohWidget Driver Development|OpenHome Widget Driver Development]] document.&lt;br /&gt;
&lt;br /&gt;
= Naming rules =&lt;br /&gt;
&lt;br /&gt;
The contents of some elements in the Widget Service XML directly affect the output in the generated files.&lt;br /&gt;
&lt;br /&gt;
These details are important for the developers who will use your Widget Service XML file to write drivers&lt;br /&gt;
and UIs for the Widget.&lt;br /&gt;
&lt;br /&gt;
The following sections explain how the XML you define affects the auto-generated output.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The following sections are provided for information. You are not expected to learn any of this information to be able to write a Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Summary view UI == &lt;br /&gt;
&lt;br /&gt;
The details for the summary view UI are defined by the primary property in the XML.&lt;br /&gt;
&lt;br /&gt;
Those details are stored in the Provider so that the Node can always access them and generate the summary view UI at run-time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Details view UI ==&lt;br /&gt;
&lt;br /&gt;
=== HTML and UI JavaScript ===&lt;br /&gt;
&lt;br /&gt;
The generated code used in the UI JavaScript and the HTML is based on the content of each of the elements&lt;br /&gt;
you define in the XML. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Provider == &lt;br /&gt;
&lt;br /&gt;
The code generated in the C# provider presents the driver developers with a series of abstract functions they can implement. Those functions are generated using the values you provide in each property's name, dataType and access elements.&lt;br /&gt;
&lt;br /&gt;
For example, the following property in the XML:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
         illuminated &amp;lt;/description&amp;gt;&lt;br /&gt;
     &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
     &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
     &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
     &amp;lt;/property&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will produce the following auto-generated code in the Provider:&lt;br /&gt;
&lt;br /&gt;
 public bool SetPropertyOn(bool aValue)&lt;br /&gt;
 {&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 public bool PropertyOn()&lt;br /&gt;
 {&lt;br /&gt;
    ...&lt;br /&gt;
 }&lt;br /&gt;
 ...&lt;br /&gt;
 protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
&lt;br /&gt;
Here we see two accessor functions and one abstract function have been created. The accessor functions allow the property's value to be read and written. The abstract function is for Widget driver writers to implement in the code they write.&lt;br /&gt;
&lt;br /&gt;
Let's examine how each of the XML elements affects them.&lt;br /&gt;
&lt;br /&gt;
=== name ===&lt;br /&gt;
&lt;br /&gt;
The XML defines the property's &amp;lt;name&amp;gt; as On:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The generated code includes the property name in the names of each of the generated functions: Set-&lt;br /&gt;
PropertyOn, PropertyOn and SetOn.&lt;br /&gt;
&lt;br /&gt;
SetOn is the abstract function used in the Widget driver. This means that Widget driver writers will&lt;br /&gt;
consistently use the same names throughout the code they write.&lt;br /&gt;
&lt;br /&gt;
=== access ===&lt;br /&gt;
&lt;br /&gt;
The XML defines the property's access as readWrite:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The generated code provides two functions that meet this access setting. The first, SetPropertyOn, provides a way to write the property's value. The second, PropertyOn, provides a way to read the property's value.&lt;br /&gt;
&lt;br /&gt;
If the access was defined as writeOnly, only the abstract SetOn function would be generated.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
If the access was defined as readOnly, a SetPropertyOn function is still generated, but is not accessible from the UI. The function remains in the auto-generated code so that the Widget can update the Node with the property's new state when it changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== dataType ===&lt;br /&gt;
&lt;br /&gt;
The XML defines the property's dataType as boolean:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The SetPropertyOn function automatically takes a bool as the parameter to use to set the new value of the property.&lt;br /&gt;
&lt;br /&gt;
The PropertyOn function automatically returns a bool to report the value of the property. &lt;br /&gt;
&lt;br /&gt;
The abstract SetOn function automatically takes a bool as the parameter used to set the new value of the property.&lt;br /&gt;
&lt;br /&gt;
= Appendix A = &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
     &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
     &amp;lt;version&amp;gt;&lt;br /&gt;
         &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
         &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
     &amp;lt;/version&amp;gt;&lt;br /&gt;
     &amp;lt;propertylist&amp;gt;&lt;br /&gt;
         &amp;lt;propertyprimary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
             &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
                 illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
             &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
             &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
             &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
             &amp;lt;hint&amp;gt;boolean-onoff&amp;lt;/hint&amp;gt;&lt;br /&gt;
         &amp;lt;/property&amp;gt;&lt;br /&gt;
     &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary =&lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in Openhome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by Openhome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh A - collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs inside ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The Openhome Operating System. Core software for Openhome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
PDLP - Proxy Device List Provider. The pattern used to represent the layers of UPnP in the Openhome code. All layers except the Presentation layer are represented in this pattern.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. Typical Widgets are lights, speakers, temperature controls.&lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. Widget manufacturers are responsible for choosing which protocols each Widget supports. A typical Widget supports only one Widget communication protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Driver_Development</id>
		<title>OhWidget Driver Development</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Driver_Development"/>
				<updated>2012-03-01T15:28:30Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Glossary */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for developers using the OpenHome SDK to integrate a Widget into an OpenHome system. Each Widget must have its own driver to allow it to communicate with the OpenHome Nodes. &lt;br /&gt;
&lt;br /&gt;
To help you write your driver, this document provides high level descriptions of the core responsibilities of a Widget driver and gives a detailed walk-through using example code.&lt;br /&gt;
&lt;br /&gt;
Full versions of each file used in the development of the example driver are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin development of your Widget driver you must be in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* your Widget Service XML that describes the properties on your Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document does not contain advice on how to write Widget Service XML. Refer to the OpenHome Widget Service XML definition document for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK&lt;br /&gt;
* your chosen communication protocol's API&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The protocol you choose for your Widgets must be the same protocol used on your choice of Node.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document focuses on the development of the Widget driver. Details about the communications protocol used are beyond the scope of this document. This document assumes you are familiar with your chosen protocol's code libraries and are able to use them in the driver code you write.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Related Documents ==&lt;br /&gt;
&lt;br /&gt;
The following related OpenHome documentation may be of interest to you:&lt;br /&gt;
&lt;br /&gt;
* [[ohWidget Technical Overview|ohWidget Technical Overview]]&lt;br /&gt;
* [[OpenHome Widget Service XML definition|OpenHome Widget Service XML definition]]&lt;br /&gt;
* [http://www.openhome.org/releases/ohNet_DeviceStack.pdf  OpenHome ohNet Device Stack]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
None of the related documents listed above is mandatory reading for Widget driver development.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
== Widget Service XML ==&lt;br /&gt;
OpenHome Widget driver writing relies heavily on the use of code generated from a single source — the Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
The service and actions your Widget provides are represented in code in a file called a Provider. The Provider is automatically generated from the Widget Service XML and produces an abstract class for you to inherit when you write your concrete class driver.&lt;br /&gt;
&lt;br /&gt;
To aid in the explanation of how the Provider is created and put to use we will follow the development of&lt;br /&gt;
a driver for a simple light Widget; taking the defined Widget Service XML and stepping through how it is used to generate the other files. Examples of code are used throughout this document to show you how each one is created and used in an OpenHome system. &lt;br /&gt;
&lt;br /&gt;
It is essential that you start with a well-formed Widget Service XML, conforming to the schema defined&lt;br /&gt;
in the WidgetService.xsd. The following diagram shows the significance of the Widget Service XML in&lt;br /&gt;
relation to the generated files you will use when writing your driver:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarchy, highlighting the areas specifically used in driver development]]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* The grayed-out files are not relevant to Widget driver development but can also be generated from the Widget Service XML.&lt;br /&gt;
* The Provider is generated in C#, meaning your driver must be written in C# as well. The use of managed code is mandatory for driver writing in the OpenHome framework.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Code sample used in this document ==&lt;br /&gt;
&lt;br /&gt;
Our examples in this document use a Widget Service XML definition for a light Widget called&lt;br /&gt;
BasicLight.xml.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Full versions of all the example files used in this document are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We will see how the Provider is generated from this XML and how it is used to aid the driver writing process. The examples also show how your chosen communication protocol should be used in the body of the driver code.&lt;br /&gt;
&lt;br /&gt;
Implementation details of specific protocols you choose to use are beyond the scope of this document. However, the samples used in this document show the use of the SimpleUPnP protocol to aid you in your development process.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol during the early stages of the OpenHome project. It is included in the OpenHome SDK and can be used as a public resource. &lt;br /&gt;
&lt;br /&gt;
The use of SimpleUPnP in the example files and the code snippets within the following sections is highlighted by the [[File:Warning.png]] icon. The lines of code marked by [[File:Warning.png]] must be changed to code from your chosen communication protocol's library. SimpleUPnP is left in to help you understand how a protocol is used in a working example.&lt;br /&gt;
&lt;br /&gt;
The sample code provided attempts to show best-practice coding standards. There are several sections of code that have a mandatory layout or that call specifically named methods and functions. These areas of the code are highlighted where required. &lt;br /&gt;
&lt;br /&gt;
Where the examples do not explicitly state that the code shown is mandatory, you are free to implement it in a different way according to your own coding style and practices.&lt;br /&gt;
&lt;br /&gt;
= Driver responsibilities = &lt;br /&gt;
&lt;br /&gt;
== Driver responsibilities ==&lt;br /&gt;
&lt;br /&gt;
An OpenHome Widget driver has several responsibilities which must be met before it can be used on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
These responsibilities are listed R1 to R7 and are defined here, explaining what each one must do. &lt;br /&gt;
&lt;br /&gt;
=== R1 Specifying the type of Widget the driver controls ===&lt;br /&gt;
A driver must know which type of Widget it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
=== R2 Reacting to a discovered Widget on the network ===&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== R3 Setting the initial values for the Widget's properties ===&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
=== R4 Publishing discovered Widgets in the Local Widget Registry on the Node ===&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object.&lt;br /&gt;
&lt;br /&gt;
=== R5 Reacting to an event reported from the Widget ===&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
=== R6 Reacting to actions sent to the Widget ===&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== R7 Reacting to a Widget's departure ===&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no&lt;br /&gt;
longer available.&lt;br /&gt;
&lt;br /&gt;
The sections of example code that follow show you how to write a driver from beginning to end. The accompanying text explaining the example code highlights when a responsibility, or part of a responsibility, has been met.&lt;br /&gt;
&lt;br /&gt;
= Driver Architecture = &lt;br /&gt;
&lt;br /&gt;
== Driver Architecture ==&lt;br /&gt;
&lt;br /&gt;
Drivers are installed on the Node and used when the Node needs to communicate with the Widget. Drivers&lt;br /&gt;
use several objects to communicate with Widgets over the Widget's lifetime. Figure 2 shows the objects&lt;br /&gt;
used by the driver and how the responsibilities listed above relate to each one:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture.png|800px|thumb|center|Figure 2: The architecture of a driver, showing the driver's relationship to the objects used to communicate with a Widget. Lines between objects show message flow.]]&lt;br /&gt;
&lt;br /&gt;
The objects contained in the dotted boundary must appear in the code you write to define your driver. The Driver, Provider and IWidgetRegistryEntry objects are all contained in the same driver file. We begin discussing this on page 12. &lt;br /&gt;
&lt;br /&gt;
The other objects are provided by the OpenHome SDK or as installed components on the Node.&lt;br /&gt;
&lt;br /&gt;
The Discovery Module informs the driver of the presence of an available Widget.&lt;br /&gt;
&lt;br /&gt;
Each Node has a Protocol Module which contains the protocol's API. Widgets can communicate with OpenHome Nodes using any one of the set of communications protocols the Node supports. The driver uses your chosen protocol's Protocol Module to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
Both the Protocol Module and the Discovery Module are installed on the Node. When you write your&lt;br /&gt;
driver you will use your Protocol Module to allow the driver to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
IWidgetPublisher, IPublishedWidget and DvDevice are objects provided in the OpenHome&lt;br /&gt;
API. You can read about them in the APIs.&lt;br /&gt;
&lt;br /&gt;
= Generating the Provider = &lt;br /&gt;
&lt;br /&gt;
== Generating the Provider ==&lt;br /&gt;
&lt;br /&gt;
You must generate your provider before you can begin writing your Widget driver. You use your provider as a guide to implement the functions your Widget needs to set the values of its properties.&lt;br /&gt;
&lt;br /&gt;
The current provider generation process is a manual one involving the use of a text transform tool.&lt;br /&gt;
&lt;br /&gt;
Speak to your OpenHome contact who will help you generate your provider.&lt;br /&gt;
&lt;br /&gt;
Future releases of the OpenHome SDK will include a tool to help you generate the provider.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
You must be in possession of:&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK, unpacked on your computer&lt;br /&gt;
* your Widget Service XML file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Writing a SimpleUPnP driver = &lt;br /&gt;
&lt;br /&gt;
== Introduction to the SimpleUPnP protocol ==&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol used to control emulated Widgets over a custom UPnP service.&lt;br /&gt;
&lt;br /&gt;
This chapter shows how a driver is written using the SimpleUPnP communications protocol. The aim is to show the code using as generic a protocol as possible so that you can see where your own protocol specific code needs to go.&lt;br /&gt;
&lt;br /&gt;
The use of code specific to the SimpleUPnP implementation is highlighted by the use of the [[File:Warning.png]] icon. The lines of code are marked by this icon to make it easier for you to see where the protocol-specific code must go and what parts of the code are generic.&lt;br /&gt;
&lt;br /&gt;
=== Register model ===&lt;br /&gt;
&lt;br /&gt;
SimpleUPnP is modeled on 8 physical registers available on the Widget. Each register is 32-bits wide. They are indexed from 0 to 7 and the last register (register 7) is reserved for storing the Widget's class.&lt;br /&gt;
&lt;br /&gt;
This detail is used by the Protocol Module on the Node to determine which driver is needed to run the new Widget when it has been discovered.&lt;br /&gt;
&lt;br /&gt;
The remaining 7 registers (registers 0 to 6) are free for Widget engineers to assign to the Widget's functions.&lt;br /&gt;
&lt;br /&gt;
Registers 0, 1, 2 and 3 are available as read/write registers. Registers 4, 5 and 6 are readonly registers.&lt;br /&gt;
&lt;br /&gt;
Only the emulated hardware (running on the Node) can change the values held in registers 4, 5 and 6.&lt;br /&gt;
&lt;br /&gt;
=== Register use in drivers ===&lt;br /&gt;
&lt;br /&gt;
In the example that follows we have a Basic Light Widget with a very simple function: it can be turned on and turned off. The on/off value is stored in register 0, with values 0=OFF and 1=ON. Register 0 is a read/write register. This means we can change the value stored there using messages passed to the Widget from the Node, and by reacting to physical interactions at the Widget (such as someone manually switching the light on or off). &lt;br /&gt;
&lt;br /&gt;
The mapping of registers to properties on the Widget is decided by the engineers who manufacture the device. You must be provided with the mapping before you begin developing your driver.&lt;br /&gt;
&lt;br /&gt;
== Starting the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-BoxHighlight.png|800px|thumb|center|Figure 3 The driver architecture highlighting the Widget driver and its component parts.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When you have generated the abstract provider you can put it to use in the Widget driver. A Widget driver&lt;br /&gt;
has three distinct components:&lt;br /&gt;
&lt;br /&gt;
* an implementation of your abstract provider&lt;br /&gt;
* a definition of the Widget driver&lt;br /&gt;
* an implementation of the IWidgetRegistryEntry interface&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must manually write the code for your Widget driver. The differences in implementation of Widget properties and communication protocols means that the driver code cannot be autogenerated.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This section takes you through how to write a Widget driver by implementing the auto-generated provider,&lt;br /&gt;
starting from a new blank file and finishing with a working driver for the Basic Light Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
No assumptions have been made about the type of editor you use to write your code. Shortcuts&lt;br /&gt;
or macros that you use as standard will not appear in the instructions below. A full example&lt;br /&gt;
BinaryLightDriver.cs is available to review in Appendix C.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a new C# file in your IDE. Ensure the following libraries are used:&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 [[File:Warning.png]]using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 namespace OpenHome.Widget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must use the libraries listed above for this specific example.&lt;br /&gt;
&lt;br /&gt;
In general, drivers require the following libraries:&lt;br /&gt;
* System*&lt;br /&gt;
* System.Collections.Generic*&lt;br /&gt;
* OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
&lt;br /&gt;
Your driver will fail to compile if you miss any of these listed libraries. Libraries marked * are typically added by default by most modern IDEs. &lt;br /&gt;
&lt;br /&gt;
The OpenHome.Widget.Protocols.SimpleUpnp library is required only in this SimpleUPnP example. Drivers using a different protocol will use their own protocol library.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Implementing the provider ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-ProviderHighlight.png|800px|thumb|center|Figure 4 The driver architecture highlighting the Provider's place]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You use your auto-generated abstract provider by writing an implementation of it in the driver file. Responsibilities met by implementing your auto-generated provider are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R6 Reacting to actions sent to the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
Begin by creating a new class. It will subclass the abstract auto-generated provider:&lt;br /&gt;
&lt;br /&gt;
 class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
The Protocol Module will provide an API for the Provider to use to communicate with the Widget. In&lt;br /&gt;
SimpleUPnP we are provided with an interface called ISimpleUpnpWidget. The provider is supplied&lt;br /&gt;
with the required instance of the interface by the Discovery Module on the Node.&lt;br /&gt;
&lt;br /&gt;
The mechanisms for registering providers with specific Protocol Modules, and for the way the module gives each provider its required interface are covered later when writing the discovery method.&lt;br /&gt;
&lt;br /&gt;
For now, we need to give the Provider a place to store the interface that it will later use to communicate&lt;br /&gt;
with the Widget:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]] private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
&lt;br /&gt;
The interface from the Protocol Module is passed in as a parameter in the Provider's constructor and then&lt;br /&gt;
assigned to the variable we just created:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightProvider(DvDevice aDevice,&lt;br /&gt;
 [[File:Warning.png]]         ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
 {&lt;br /&gt;
       iProtocol = aProtocol;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
To satisfy R3 we would normally set the Widget's properties here, giving them an initial value.&lt;br /&gt;
However, in this specific example we cannot set the value of Basic Light's only property because&lt;br /&gt;
we will never know, in advance, what the state of the light will be (either on or off) when we&lt;br /&gt;
create the DiscoveredWidget.&lt;br /&gt;
&lt;br /&gt;
When you cannot set the properties ahead of time, and you are using an eventing protocol like SimpleUPnP, you can instead set them in the HandleRegisterEvent method in the driver class. This also satisfies the requirements for R3. You must set the Widget's properties before you enable it using SetEnabled(). &lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The abstract provider includes an abstract method called SetOn. This method is invoked by the Node when passing a message to the Widget, specifically to set the on property of the Widget to either 0 or 1. The implementation of this method will meet the requirements for R6.&lt;br /&gt;
&lt;br /&gt;
We must override this method and provide the protocol module a way of passing a message on to the Widget to perform the required action, in this case turn the light on or off:&lt;br /&gt;
&lt;br /&gt;
          protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
          {&lt;br /&gt;
     [[File:Warning.png]]        iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
In this example the Basic Light's SetOn property (the boolean property that controls whether the light is&lt;br /&gt;
on or off) is represented in the physical Widget by the register that has an index of 0.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* This method is an example of an action on a Widget. Actions are messages sent from the Node to the Widget. We will see later how to handle events that need to be passed back from the Widget&lt;br /&gt;
to the Node.&lt;br /&gt;
* Your own Widget will likely provide more than a single property. Your auto-generated provider will contain one abstract method to represent each writable property. Read-only properties are not provided an abstract method.&lt;br /&gt;
&lt;br /&gt;
You must implement each abstract method in your driver to ensure the relevant property on&lt;br /&gt;
the Widget can be set.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We have now finished implementing the provider. The next step is to implement the driver.&lt;br /&gt;
&lt;br /&gt;
== Implementing the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-DriverHighlight.png|800px|thumb|center|Figure 4: The driver architecture highlighting the implemented driver's place.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The code for your Widget driver must provide an implementation of the IWidgetRegistryInterface,&lt;br /&gt;
including the following tasks:&lt;br /&gt;
&lt;br /&gt;
* methods to expose identifying details about the Widget for the Node to access&lt;br /&gt;
* providing methods to handle events reported by the Widget&lt;br /&gt;
&lt;br /&gt;
The driver is implemented as a public class within the same file as the provider code. Each driver must use the interface for the protocol you are using. For the SimpleUPnP protocol the interface is ISimple-UpnpWidgetDriver.&lt;br /&gt;
&lt;br /&gt;
=== Writing code ===&lt;br /&gt;
&lt;br /&gt;
Create your new driver class and subclass the ISimpleUpnpWidgetDriver interface:&lt;br /&gt;
&lt;br /&gt;
 public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Implementing IWidgetRegistryEntry ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry is the interface you use to represent physical Widgets. It is implemented as a subclass of your driver class. We are going to implement this interface in a class called '''DiscoveredWidget'''.&lt;br /&gt;
&lt;br /&gt;
Let's return to our driver architecture diagram for a moment:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-IRegistryEntryHighlight.png|800px|thumb|center|Figure 5 The driver architecture highlighting the IWidgetRegistryEntry object you will now implement]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry uses several other objects to help create it and respond to messages sent to and from it. These objects will be created in our implementation of DiscoveredWidget. &lt;br /&gt;
&lt;br /&gt;
When successfully created and published, the DiscoveredWidget objects are stored in a list on the Node called the Local Widget Registry. The Local Widget Registry is used by Nodes to maintain contact with the Widgets they control.&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry is shown at the top of Figure 5, marked plainly as (Registry). The path to the Local Widget Registry goes through several layers of Node architecture which are not relevant to Widget driver writing, so are not shown in the diagrams.&lt;br /&gt;
&lt;br /&gt;
==== Writing code ====&lt;br /&gt;
&lt;br /&gt;
Start by subclassing the IWidgetRegistryEntry interface in your new class:&lt;br /&gt;
&lt;br /&gt;
      private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
      {&lt;br /&gt;
&lt;br /&gt;
A DiscoveredWidget must provide the driver with the objects required to present the Widget and its&lt;br /&gt;
properties to the Node:&lt;br /&gt;
&lt;br /&gt;
           private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
           private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
           private readonly ISimpleUpnpWidget iProtocol;&lt;br /&gt;
           private readonly BinaryLightProvider iProvider;&lt;br /&gt;
           private readonly DvDevice iDvDevice;&lt;br /&gt;
           private IPublishedWidget iPublishedWidget;&lt;br /&gt;
&lt;br /&gt;
Each of the attributes in the example above are defined as follows:&lt;br /&gt;
&lt;br /&gt;
iDeviceFactory — used by the driver to create a single instance of DvDevice to represent a single Widget&lt;br /&gt;
&lt;br /&gt;
iPublisher — used by the driver to publish the Widget to the Node&lt;br /&gt;
&lt;br /&gt;
iProtocol — the object used by the Widget to communicate with the Protocol Module on the Node&lt;br /&gt;
&lt;br /&gt;
iProvider — an instantiated provider of the type you defined earlier&lt;br /&gt;
&lt;br /&gt;
iDvDevice — a representation of a Widget to which the provider is attached, created using iDevice-Factory above&lt;br /&gt;
&lt;br /&gt;
iPublishedWidget — used to contain the returned object from a successful publishing of the Widget&lt;br /&gt;
If we look again at the driver architecture diagram, we ca highlight the objects we've just defined:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-Highlight.png|800px|thumb|center|Figure 6: The driver architecture highlighting the objects used by the IWidgetRegistryEntry implementation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The DeviceFactory, defined above in the member variable iDeviceFactory, is used to create new DvDevice objects. The DeviceFactory is only ever used to do this once. It is not shown in the driver architecture diagrams due to its minimal role in the operation of a driver, but it would normally appear between the IWidgetRegistryEntry and DvDevice objects.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
A driver requires methods to expose identifying details about the Widget. We must provide access to two of the attributes we just defined above:&lt;br /&gt;
&lt;br /&gt;
 public DvDevice DvDevice&lt;br /&gt;
 {&lt;br /&gt;
     get { return iDvDevice; }&lt;br /&gt;
 }&lt;br /&gt;
 public string WidgetClass&lt;br /&gt;
 {&lt;br /&gt;
     get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The WidgetClass string is formed using a combination of the vendor name and the Widget's name in the&lt;br /&gt;
format:&lt;br /&gt;
&lt;br /&gt;
 [vendor_domain]:[widget_name]&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry can now query both the DvDevice object representing the Widget, and the specific class of Widget this driver represents. The other member variables we defined do not need their own accessor methods.&lt;br /&gt;
&lt;br /&gt;
Now we must write a constructor for DiscoveredWidget and assign the parameters accordingly: &lt;br /&gt;
&lt;br /&gt;
 public DiscoveredWidget(IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                            string aUdn,&lt;br /&gt;
                            ISimpleUpnpWidget aProxy,&lt;br /&gt;
                            IWidgetPublisher aPublisher)&lt;br /&gt;
 {&lt;br /&gt;
      iDeviceFactory = aDeviceFactory;&lt;br /&gt;
      iProtocol = aProtocol;&lt;br /&gt;
      iPublisher = aPublisher;&lt;br /&gt;
      iDvDevice = iDeviceFactory.CreateDevice(aUdn);&lt;br /&gt;
      iProvider = new BinaryLightProvider(iDvDevice,&lt;br /&gt;
      iProtocol);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Event handling ===&lt;br /&gt;
&lt;br /&gt;
A Widget's state can change in one of three significant ways:&lt;br /&gt;
&lt;br /&gt;
* when the Widget needs to be published on the Node&lt;br /&gt;
* when the Widget disappears from the network (by losing power or similar)&lt;br /&gt;
* when a property's state changes and must be updated to a new value&lt;br /&gt;
&lt;br /&gt;
We now need methods to handle these changes.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The methods we define here will be used as callbacks, rather than invoked as method calls. We define the methods here first and then use them later on. We will use the Protocol Module to listen for changes in the Widget's state and register these methods as callbacks there. See Writing the SimpleUPnP Widget discovery method for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this section of the driver are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R4 Publishing discovered Widgets in the Local Widget Registry on the Node'''&lt;br /&gt;
&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object. &lt;br /&gt;
&lt;br /&gt;
'''R5 Reacting to an event reported from the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
'''R7 Reacting to a Widget's departure'''&lt;br /&gt;
&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no longer available.&lt;br /&gt;
&lt;br /&gt;
==== Enabling and publishing a discovered Widget ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first method initializes the Widget by enabling the device and then using the IWidgetPublisher&lt;br /&gt;
to make it available on the Node:&lt;br /&gt;
&lt;br /&gt;
 public void HandleInitialEvent()&lt;br /&gt;
 {&lt;br /&gt;
      iDvDevice.SetEnabled();&lt;br /&gt;
      iPublisher.TryPublishWidget(iDvDevice.iUdn(),&lt;br /&gt;
                              this,&lt;br /&gt;
                              out iPublishedWidget);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This method meets the requirements for R4.&lt;br /&gt;
&lt;br /&gt;
The call to TryPublishWidget returns an iPublishedWidget object. We use this object later to satisfy the requirements of R7.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The ordering of the calls to SetEnabled and TryPublishWidget is vitally important. You&lt;br /&gt;
must enable the device before you attempt to publish it. Your Widget will not be available to the&lt;br /&gt;
Nodes unless SetEnabled is called first. Nodes will not be able to access a published device&lt;br /&gt;
that has not been enabled.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
R3 requires that you set the Widget's properties before you enable and publish the device. We&lt;br /&gt;
discussed on page 14 how some properties can only be set after the Widget reports what their&lt;br /&gt;
state is. We do this in HandleRegisterEvent.&lt;br /&gt;
&lt;br /&gt;
We rely on the SimpleUPnP Protocol Module guaranteeing a call to HandleRegisterEvent first before HandleInitialEvent. This is informed by guarantees made by the Control Point stack that the calls will be made in that order.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
==== Removing a Widget ====&lt;br /&gt;
&lt;br /&gt;
Removing a Widget involves unpublishing it from the Node. The IPublishedWidget interface provides us with a method we can call to manage that for us:&lt;br /&gt;
&lt;br /&gt;
 public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
 {&lt;br /&gt;
     if (iPublishedWidget != null)&lt;br /&gt;
     { iPublishedWidget.Unpublish(); }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assuming that the Widget was successfully published earlier, it is removed from the Node's Local Widget Registry.&lt;br /&gt;
&lt;br /&gt;
We must also properly handle the resources we used to create and maintain the Widget object while it was published:&lt;br /&gt;
&lt;br /&gt;
      iProvider.Dispose();&lt;br /&gt;
      iDvDevice.Dispose();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The calls to Dispose are made regardless of the Widget's published state, ensuring that any created device and associated provider are properly disposed. This implementation satisfies R7.&lt;br /&gt;
&lt;br /&gt;
====Event handling ====&lt;br /&gt;
&lt;br /&gt;
We need a method to handle changes to the state of the Widget's properties.&lt;br /&gt;
&lt;br /&gt;
If the property changes at the Widget, it needs to pass the new state back to the Node so that it is kept up-to-date on the Widget's status. This is called an event. An example in the case of our Basic Light is someone manually switching the light from on to off. This is in contrast to actions, which are passed from the Node to the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Other examples of events involve no human interaction, such as a thermometer Widget updating its current temperature based on environmental changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Our Basic Light Widget has only one property that needs to be handled:&lt;br /&gt;
&lt;br /&gt;
 public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
 {&lt;br /&gt;
     if (aIndex == 0)&lt;br /&gt;
     {&lt;br /&gt;
         iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We use our instance of the provider to update the register on the Widget that is mapped to the On property. This in turn updates the Node with the new state of the Widget.&lt;br /&gt;
&lt;br /&gt;
This method provides implementations to satisfy two driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
* R3 is now completely satisfied, as we can now set the values of all the previously unknown properties here.&lt;br /&gt;
* R5 is also satisfied as this method allows us to update the Widget's status on the Node when a property is changed on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Not all protocols pass messages back to the Node in this manner. The way we have satisfied R3 and R5 here only applies to protocols and Widgets that support this behavior.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Widgets that do not use an eventing protocol need to have their properties set in the provider's constructor to satisfy R3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To satisfy R5, the over-ridden method SetOn in the provider must include the call to SetPropertyOn. Non-eventing protocols do not require a HandleRegisterEvent method.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Constructor ===&lt;br /&gt;
&lt;br /&gt;
The final requirement for the driver is the constructor so that new DiscoveredWidget objects can be created. &lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this area of code are:&lt;br /&gt;
&lt;br /&gt;
'''R1 Specifying the type of Widget the driver controls'''&lt;br /&gt;
&lt;br /&gt;
A driver must know which type of Widget that it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
==== Writing the code ====&lt;br /&gt;
&lt;br /&gt;
We begin by defining the variables we will use to store the objects used by the driver:&lt;br /&gt;
&lt;br /&gt;
 private readonly string iName;&lt;br /&gt;
 private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
 private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now write the constructor for the driver and assign the passed in parameters appropriately:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightDriver(string aName,&lt;br /&gt;
                IWidgetPublisher aPublisher,&lt;br /&gt;
                IDvDeviceFactory aDeviceFactory)&lt;br /&gt;
 {&lt;br /&gt;
     iWidgetPublisher = aPublisher;&lt;br /&gt;
     iName = aName;&lt;br /&gt;
     iDeviceFactory = aDeviceFactory;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally we need to provide the driver a way to publish the class of Widget it controls. This information is requested by the Discovery Module and is used to ensure the Node uses the correct driver when a new Widget appears.&lt;br /&gt;
&lt;br /&gt;
The implementation for this details will be different for each protocol. The SimpleUPnP protocol library provides a file that contains the SimpleUPnP definitions as integers. Each integer represents a particular class of identified Widget.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP implementation of that method is as follows:&lt;br /&gt;
&lt;br /&gt;
 public IEnumerable&amp;lt;uint&amp;gt; WidgetClasses&lt;br /&gt;
 {&lt;br /&gt;
 [[File:Warning.png]]        get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The body of this method is specifically written for the Widget class we are defining (in this case a binary light). This method completes the driver's requirements for R1.&lt;br /&gt;
&lt;br /&gt;
== Writing the SimpleUPnP Widget discovery method ==&lt;br /&gt;
&lt;br /&gt;
Every driver must contain a method which creates new objects to represent newly discovered Widgets.&lt;br /&gt;
The Discovery Module invokes this method to begin the process of creating the objects required to allow the Node to access the Widget. &lt;br /&gt;
&lt;br /&gt;
The name of this method is dictated by your chosen protocol's API. The SimpleUPnP protocol requires a method called WidgetDiscovered.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The method's name will not always be the same for each protocol. Your protocol's documentation will contain the details of what this method must be called.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This method and its implementation will meet the following driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
'''R2 Reacting to a discovered Widget on the network'''&lt;br /&gt;
&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
Our implementation of the WidgetDiscovered method will create a new DiscoveredWidget object and use the Protocol Module to listen for changes to the Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
The method uses the Protocol Module and two ways to identify the Widget. We must pass these in as&lt;br /&gt;
parameters:&lt;br /&gt;
&lt;br /&gt;
 public void WidgetDiscovered(string aWidgetUdn,&lt;br /&gt;
                              uint aWidgetClass,&lt;br /&gt;
                              ISimpleUpnpWidget&lt;br /&gt;
                                  aSimpleUpnpWidget)&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
Every Widget that uses this driver must be uniquely identifiable:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]    string newUdn = aWidgetUdn;&lt;br /&gt;
&lt;br /&gt;
Each new Widget is represented by a DiscoveredWidget object. Create the new DiscoveredWidget and pass in the required parameters we created earlier:&lt;br /&gt;
&lt;br /&gt;
     DiscoveredWidget discoveredWidget =&lt;br /&gt;
                 new DiscoveredWidget(iDeviceFactory,&lt;br /&gt;
                                      newUdn,&lt;br /&gt;
  &lt;br /&gt;
 [[File:Warning.png]]                                    aSimpleUpnpWidget,&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Registering the callbacks ===&lt;br /&gt;
&lt;br /&gt;
Finally, we ask the Widget's protocol interface to listen for calls to the handler methods we defined earlier in DiscoveredWidget. We do this by registering those methods as callbacks for the Protocol Module&lt;br /&gt;
to listen for:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                        discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                        discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                        discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You have now met 100% of the driver responsibility requirements and have a working driver to use with your SimpleUPnP Widget.&lt;br /&gt;
&lt;br /&gt;
= Appendix A. Sample XML =&lt;br /&gt;
&lt;br /&gt;
== Binary Light.xml ==&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
  &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
  &amp;lt;version&amp;gt;&lt;br /&gt;
   &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
   &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/version&amp;gt;&lt;br /&gt;
  &amp;lt;propertylist&amp;gt;&lt;br /&gt;
   &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
       illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
   &amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix B. Sample Provider = &lt;br /&gt;
&lt;br /&gt;
== DvWidgetOpenhomeOrgBasicLight1.cs ==&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Runtime.InteropServices;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Core;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Utils.Binary;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
 {&lt;br /&gt;
    public interface IDvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
        IDisposable&lt;br /&gt;
    {&lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous value&lt;br /&gt;
        /// &amp;lt;/returns&amp;gt;&lt;br /&gt;
        bool SetPropertyOn(bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;Property's value will be copied&lt;br /&gt;
        /// here&amp;lt;/param&amp;gt;&lt;br /&gt;
        bool PropertyOn();&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt; summary&amp;gt;&lt;br /&gt;
    /// Provider for the openhome.org:BinaryLight:1 UPnP service&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public abstract class DvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
               DvProvider,&lt;br /&gt;
               IDisposable,&lt;br /&gt;
               IDvProviderOpenhomeOrgBinaryLight1&lt;br /&gt;
    {&lt;br /&gt;
        private GCHandle iGch;&lt;br /&gt;
        private PropertyBool iPropertyOn;&lt;br /&gt;
        private PropertyUint iPropertyPrimarySeq;&lt;br /&gt;
        private PropertyUint iPropertySecondarySeq;&lt;br /&gt;
        private ActionDelegate iDelegateSetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetPrimaryProperty;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Constructor&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aDevice&amp;quot;&amp;gt;Device which owns this&lt;br /&gt;
        /// provider&amp;lt;/param&amp;gt;&lt;br /&gt;
        protected DvProviderOpenhomeOrgBinaryLight1(DvDevice aDevice)&lt;br /&gt;
            : base(aDevice, &amp;quot;openhome.org&amp;quot;, &amp;quot;GenericWidget&amp;quot;, 1)&lt;br /&gt;
        {&lt;br /&gt;
            iGch = GCHandle.Alloc(this);&lt;br /&gt;
            List&amp;lt;String&amp;gt; allowedValues = new List&amp;lt;String&amp;gt;();&lt;br /&gt;
            iPropertyOn = new PropertyBool(new ParameterBool(&amp;quot;On&amp;quot;));&lt;br /&gt;
            iPropertyPrimarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;PrimarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertyPrimarySeq);&lt;br /&gt;
            iPropertySecondarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;SecondarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertySecondarySeq);&lt;br /&gt;
            SetPropertyUint(iPropertyPrimarySeq, 0);&lt;br /&gt;
            SetPropertyUint(iPropertySecondarySeq, 0);&lt;br /&gt;
  &lt;br /&gt;
            Zapp.Core.Action action = new Zapp.Core.Action&lt;br /&gt;
                (&amp;quot;SetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;FireAndForget&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddInputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateSetProperty = new ActionDelegate(DoSetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateSetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateGetProperty = new ActionDelegate(DoGetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetPrimaryProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                 (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;integer&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;boolean&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;string&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;binary&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Type&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;readWrite&amp;quot;);allowedValues.Add&lt;br /&gt;
                (&amp;quot;readOnly&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;writeOnly&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString(&amp;quot;Access&amp;quot;,&lt;br /&gt;
                allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            iDelegateGetPrimaryProperty = new&lt;br /&gt;
            ActionDelegate(DoGetPrimaryProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetPrimaryProperty,&lt;br /&gt;
            GCHandle.ToIntPtr(iGch));&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous&lt;br /&gt;
        /// value&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool SetPropertyOn(bool aValue)&lt;br /&gt;
        {&lt;br /&gt;
            if (iPropertyOn.SetValue(aValue))&lt;br /&gt;
            {&lt;br /&gt;
                lock (iPropertyPrimarySeq)&lt;br /&gt;
                {&lt;br /&gt;
                    SetPropertyUint(iPropertyPrimarySeq,&lt;br /&gt;
                        iPropertyPrimarySeq.Value() + 1);&lt;br /&gt;
                } return true;&lt;br /&gt;
            } return false;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;The value of the property&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool PropertyOn()&lt;br /&gt;
        {&lt;br /&gt;
            return iPropertyOn.Value();&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the On property.&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aVersion&amp;quot;&amp;gt;Version of the service being&lt;br /&gt;
        /// requested (will be &amp;lt;= the version advertised)&amp;lt;/param&amp;gt; &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the On property.&lt;br /&gt;
        /// &amp;lt;/param&amp;gt;&lt;br /&gt;
        protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        private static int DoSetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                byte[] valBin = invocation.ReadBinary(&amp;quot;Value&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                switch (name)&lt;br /&gt;
                {&lt;br /&gt;
                    case &amp;quot;On&amp;quot;:&lt;br /&gt;
                        self.SetOn(aVersion, Converter.&lt;br /&gt;
                            BinaryToBoolean(valBin));&lt;br /&gt;
                        break;&lt;br /&gt;
                    default:&lt;br /&gt;
                        throw new ActionError();&lt;br /&gt;
                }&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
                invocation.WriteEnd();&lt;br /&gt;
            }&lt;br /&gt;
            catch (ActionError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
            catch (PropertyUpdateError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
        return 0;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        private static int DoGetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
            switch (name)&lt;br /&gt;
            {&lt;br /&gt;
                case &amp;quot;On&amp;quot;:&lt;br /&gt;
                invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                    Converter.BooleanToBinary(self.iPropertyOn.&lt;br /&gt;
                        Value()));&lt;br /&gt;
                break;&lt;br /&gt;
                default:&lt;br /&gt;
                throw new ActionError();&lt;br /&gt;
            }&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    private static int DoGetPrimaryProperty(IntPtr aPtr,&lt;br /&gt;
                    IntPtr aInvocation,&lt;br /&gt;
                    uint aVersion)&lt;br /&gt;
    {&lt;br /&gt;
        GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
        DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
            (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
        DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
  &lt;br /&gt;
        try&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReadStart();&lt;br /&gt;
            invocation.ReadEnd();&lt;br /&gt;
            invocation.WriteStart();&lt;br /&gt;
            invocation.WriteString(&amp;quot;Name&amp;quot;, &amp;quot;On&amp;quot;);&lt;br /&gt;
            invocation.WriteString(&amp;quot;Type&amp;quot;, &amp;quot;boolean&amp;quot;);&lt;br /&gt;
            invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                Converter.BooleanToBinary(self.iPropertyOn.Value()));&lt;br /&gt;
            invocation.WriteString(&amp;quot;Access&amp;quot;, &amp;quot;readWrite&amp;quot;);&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt;summary&amp;gt;&lt;br /&gt;
    /// Must be called for each class instance. Must be called before&lt;br /&gt;
    /// Core.Library.Close().&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public void Dispose()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
        GC.SuppressFinalize(this);&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
    ~DvProviderOpenhomeOrgBinaryLight1()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
        private void DoDispose()&lt;br /&gt;
        {&lt;br /&gt;
            lock (this)&lt;br /&gt;
            {&lt;br /&gt;
                if (iHandle == IntPtr.Zero)&lt;br /&gt;
            {&lt;br /&gt;
                    return;&lt;br /&gt;
            }&lt;br /&gt;
            DisposeProvider();&lt;br /&gt;
            iPropertyOn.Dispose();&lt;br /&gt;
            iHandle = IntPtr.Zero;&lt;br /&gt;
            }&lt;br /&gt;
            iGch.Free();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix C. Sample Driver = &lt;br /&gt;
&lt;br /&gt;
== BasicLightDriver.cs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.hWidget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
     class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
     {&lt;br /&gt;
         private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
         public BinaryLightProvider(DvDevice aDevice, &lt;br /&gt;
             ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol = aProtocol;&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
     {&lt;br /&gt;
         private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
         {&lt;br /&gt;
             private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
             private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
             private readonly ISimpleUpnpWidget iProtocol; &lt;br /&gt;
 &lt;br /&gt;
             private readonly BinaryLightProvider iProvider;&lt;br /&gt;
             private readonly DvDevice iDvDevice;&lt;br /&gt;
             private IPublishedWidget iPublishedWidget; &lt;br /&gt;
 &lt;br /&gt;
             public DvDevice DvDevice&lt;br /&gt;
             {&lt;br /&gt;
                 get { return iDvDevice; }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             public string WidgetClass&lt;br /&gt;
             {&lt;br /&gt;
                 get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public DiscoveredWidget(&lt;br /&gt;
                 IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                 string aUdn,&lt;br /&gt;
                 ISimpleUpnpWidget aProxy,&lt;br /&gt;
                 IWidgetPublisher aPublisher)&lt;br /&gt;
             {&lt;br /&gt;
                 iDeviceFactory = aDeviceFactory;&lt;br /&gt;
                 iProtocol = aProtocol;&lt;br /&gt;
 &lt;br /&gt;
                 iPublisher = aPublisher;&lt;br /&gt;
                 iDvDevice = iDeviceFactory.CreateDevice(aUdn);  &lt;br /&gt;
                 iProvider = new BinaryLightProvider(iDvDevice, &lt;br /&gt;
                                                     iProtocol);&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             public void HandleInitialEvent()&lt;br /&gt;
             {&lt;br /&gt;
                 iDvDevice.SetEnabled();&lt;br /&gt;
                 iPublisher.TryPublishWidget(iDvDevice.iUdn(), this,&lt;br /&gt;
                     out iPublishedWidget);&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
             {&lt;br /&gt;
                 if (iPublishedWidget != null)&lt;br /&gt;
                 {&lt;br /&gt;
                     iPublishedWidget.Unpublish();&lt;br /&gt;
                 } &lt;br /&gt;
                 iProvider.Dispose();&lt;br /&gt;
                 iDvDevice.Dispose();&lt;br /&gt;
             }  &lt;br /&gt;
 &lt;br /&gt;
             public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
             {&lt;br /&gt;
                 if (aIndex == 0)&lt;br /&gt;
                 {&lt;br /&gt;
                     iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         private readonly string iName;&lt;br /&gt;
         private readonly IDvDeviceFactory aDeviceFactory;&lt;br /&gt;
         private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
         &lt;br /&gt;
         public BinaryLightDriver(&lt;br /&gt;
             string aName,&lt;br /&gt;
             IWidgetPublisher aPublisher,&lt;br /&gt;
             iDeviceFactory aDeviceFactory)&lt;br /&gt;
         {&lt;br /&gt;
             iWidgetPublisher = aPublisher;&lt;br /&gt;
             iName = aName;&lt;br /&gt;
             iDeviceFactory = aDeviceFactory;&lt;br /&gt;
         } &lt;br /&gt;
 &lt;br /&gt;
         public IEnumerable&amp;amp;lt;uint&amp;amp;gt; WidgetClasses&lt;br /&gt;
         {&lt;br /&gt;
             get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         public void WidgetDiscovered(&lt;br /&gt;
             string aWidgetUdn,&lt;br /&gt;
             uint aWidgetClass,&lt;br /&gt;
             ISimpleUpnpWidget aSimpleUpnpWidget)&lt;br /&gt;
         {&lt;br /&gt;
             string newUdn = aWidgetUdn;&lt;br /&gt;
             DiscoveredWidget discoveredWidget = new DiscoveredWidget&lt;br /&gt;
                 (iDeviceFactory,&lt;br /&gt;
                  newUdn,&lt;br /&gt;
                  aSimpleUpnpWidget,&lt;br /&gt;
                  iWidgetPublisher);&lt;br /&gt;
 &lt;br /&gt;
             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                 discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                 discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                 discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary = &lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in OpenHome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by OpenHome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh - A collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs on ohOS.&lt;br /&gt;
&lt;br /&gt;
[[ohNet|ohNet]] - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
[[ohOs|ohOs]] - The OpenHome Operating System. Core software for OpenHome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. &lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. A typical Widget supports only one protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Driver_Development</id>
		<title>OhWidget Driver Development</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Driver_Development"/>
				<updated>2012-03-01T15:28:15Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Glossary */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for developers using the OpenHome SDK to integrate a Widget into an OpenHome system. Each Widget must have its own driver to allow it to communicate with the OpenHome Nodes. &lt;br /&gt;
&lt;br /&gt;
To help you write your driver, this document provides high level descriptions of the core responsibilities of a Widget driver and gives a detailed walk-through using example code.&lt;br /&gt;
&lt;br /&gt;
Full versions of each file used in the development of the example driver are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin development of your Widget driver you must be in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* your Widget Service XML that describes the properties on your Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document does not contain advice on how to write Widget Service XML. Refer to the OpenHome Widget Service XML definition document for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK&lt;br /&gt;
* your chosen communication protocol's API&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The protocol you choose for your Widgets must be the same protocol used on your choice of Node.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document focuses on the development of the Widget driver. Details about the communications protocol used are beyond the scope of this document. This document assumes you are familiar with your chosen protocol's code libraries and are able to use them in the driver code you write.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Related Documents ==&lt;br /&gt;
&lt;br /&gt;
The following related OpenHome documentation may be of interest to you:&lt;br /&gt;
&lt;br /&gt;
* [[ohWidget Technical Overview|ohWidget Technical Overview]]&lt;br /&gt;
* [[OpenHome Widget Service XML definition|OpenHome Widget Service XML definition]]&lt;br /&gt;
* [http://www.openhome.org/releases/ohNet_DeviceStack.pdf  OpenHome ohNet Device Stack]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
None of the related documents listed above is mandatory reading for Widget driver development.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
== Widget Service XML ==&lt;br /&gt;
OpenHome Widget driver writing relies heavily on the use of code generated from a single source — the Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
The service and actions your Widget provides are represented in code in a file called a Provider. The Provider is automatically generated from the Widget Service XML and produces an abstract class for you to inherit when you write your concrete class driver.&lt;br /&gt;
&lt;br /&gt;
To aid in the explanation of how the Provider is created and put to use we will follow the development of&lt;br /&gt;
a driver for a simple light Widget; taking the defined Widget Service XML and stepping through how it is used to generate the other files. Examples of code are used throughout this document to show you how each one is created and used in an OpenHome system. &lt;br /&gt;
&lt;br /&gt;
It is essential that you start with a well-formed Widget Service XML, conforming to the schema defined&lt;br /&gt;
in the WidgetService.xsd. The following diagram shows the significance of the Widget Service XML in&lt;br /&gt;
relation to the generated files you will use when writing your driver:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarchy, highlighting the areas specifically used in driver development]]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* The grayed-out files are not relevant to Widget driver development but can also be generated from the Widget Service XML.&lt;br /&gt;
* The Provider is generated in C#, meaning your driver must be written in C# as well. The use of managed code is mandatory for driver writing in the OpenHome framework.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Code sample used in this document ==&lt;br /&gt;
&lt;br /&gt;
Our examples in this document use a Widget Service XML definition for a light Widget called&lt;br /&gt;
BasicLight.xml.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Full versions of all the example files used in this document are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We will see how the Provider is generated from this XML and how it is used to aid the driver writing process. The examples also show how your chosen communication protocol should be used in the body of the driver code.&lt;br /&gt;
&lt;br /&gt;
Implementation details of specific protocols you choose to use are beyond the scope of this document. However, the samples used in this document show the use of the SimpleUPnP protocol to aid you in your development process.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol during the early stages of the OpenHome project. It is included in the OpenHome SDK and can be used as a public resource. &lt;br /&gt;
&lt;br /&gt;
The use of SimpleUPnP in the example files and the code snippets within the following sections is highlighted by the [[File:Warning.png]] icon. The lines of code marked by [[File:Warning.png]] must be changed to code from your chosen communication protocol's library. SimpleUPnP is left in to help you understand how a protocol is used in a working example.&lt;br /&gt;
&lt;br /&gt;
The sample code provided attempts to show best-practice coding standards. There are several sections of code that have a mandatory layout or that call specifically named methods and functions. These areas of the code are highlighted where required. &lt;br /&gt;
&lt;br /&gt;
Where the examples do not explicitly state that the code shown is mandatory, you are free to implement it in a different way according to your own coding style and practices.&lt;br /&gt;
&lt;br /&gt;
= Driver responsibilities = &lt;br /&gt;
&lt;br /&gt;
== Driver responsibilities ==&lt;br /&gt;
&lt;br /&gt;
An OpenHome Widget driver has several responsibilities which must be met before it can be used on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
These responsibilities are listed R1 to R7 and are defined here, explaining what each one must do. &lt;br /&gt;
&lt;br /&gt;
=== R1 Specifying the type of Widget the driver controls ===&lt;br /&gt;
A driver must know which type of Widget it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
=== R2 Reacting to a discovered Widget on the network ===&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== R3 Setting the initial values for the Widget's properties ===&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
=== R4 Publishing discovered Widgets in the Local Widget Registry on the Node ===&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object.&lt;br /&gt;
&lt;br /&gt;
=== R5 Reacting to an event reported from the Widget ===&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
=== R6 Reacting to actions sent to the Widget ===&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== R7 Reacting to a Widget's departure ===&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no&lt;br /&gt;
longer available.&lt;br /&gt;
&lt;br /&gt;
The sections of example code that follow show you how to write a driver from beginning to end. The accompanying text explaining the example code highlights when a responsibility, or part of a responsibility, has been met.&lt;br /&gt;
&lt;br /&gt;
= Driver Architecture = &lt;br /&gt;
&lt;br /&gt;
== Driver Architecture ==&lt;br /&gt;
&lt;br /&gt;
Drivers are installed on the Node and used when the Node needs to communicate with the Widget. Drivers&lt;br /&gt;
use several objects to communicate with Widgets over the Widget's lifetime. Figure 2 shows the objects&lt;br /&gt;
used by the driver and how the responsibilities listed above relate to each one:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture.png|800px|thumb|center|Figure 2: The architecture of a driver, showing the driver's relationship to the objects used to communicate with a Widget. Lines between objects show message flow.]]&lt;br /&gt;
&lt;br /&gt;
The objects contained in the dotted boundary must appear in the code you write to define your driver. The Driver, Provider and IWidgetRegistryEntry objects are all contained in the same driver file. We begin discussing this on page 12. &lt;br /&gt;
&lt;br /&gt;
The other objects are provided by the OpenHome SDK or as installed components on the Node.&lt;br /&gt;
&lt;br /&gt;
The Discovery Module informs the driver of the presence of an available Widget.&lt;br /&gt;
&lt;br /&gt;
Each Node has a Protocol Module which contains the protocol's API. Widgets can communicate with OpenHome Nodes using any one of the set of communications protocols the Node supports. The driver uses your chosen protocol's Protocol Module to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
Both the Protocol Module and the Discovery Module are installed on the Node. When you write your&lt;br /&gt;
driver you will use your Protocol Module to allow the driver to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
IWidgetPublisher, IPublishedWidget and DvDevice are objects provided in the OpenHome&lt;br /&gt;
API. You can read about them in the APIs.&lt;br /&gt;
&lt;br /&gt;
= Generating the Provider = &lt;br /&gt;
&lt;br /&gt;
== Generating the Provider ==&lt;br /&gt;
&lt;br /&gt;
You must generate your provider before you can begin writing your Widget driver. You use your provider as a guide to implement the functions your Widget needs to set the values of its properties.&lt;br /&gt;
&lt;br /&gt;
The current provider generation process is a manual one involving the use of a text transform tool.&lt;br /&gt;
&lt;br /&gt;
Speak to your OpenHome contact who will help you generate your provider.&lt;br /&gt;
&lt;br /&gt;
Future releases of the OpenHome SDK will include a tool to help you generate the provider.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
You must be in possession of:&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK, unpacked on your computer&lt;br /&gt;
* your Widget Service XML file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Writing a SimpleUPnP driver = &lt;br /&gt;
&lt;br /&gt;
== Introduction to the SimpleUPnP protocol ==&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol used to control emulated Widgets over a custom UPnP service.&lt;br /&gt;
&lt;br /&gt;
This chapter shows how a driver is written using the SimpleUPnP communications protocol. The aim is to show the code using as generic a protocol as possible so that you can see where your own protocol specific code needs to go.&lt;br /&gt;
&lt;br /&gt;
The use of code specific to the SimpleUPnP implementation is highlighted by the use of the [[File:Warning.png]] icon. The lines of code are marked by this icon to make it easier for you to see where the protocol-specific code must go and what parts of the code are generic.&lt;br /&gt;
&lt;br /&gt;
=== Register model ===&lt;br /&gt;
&lt;br /&gt;
SimpleUPnP is modeled on 8 physical registers available on the Widget. Each register is 32-bits wide. They are indexed from 0 to 7 and the last register (register 7) is reserved for storing the Widget's class.&lt;br /&gt;
&lt;br /&gt;
This detail is used by the Protocol Module on the Node to determine which driver is needed to run the new Widget when it has been discovered.&lt;br /&gt;
&lt;br /&gt;
The remaining 7 registers (registers 0 to 6) are free for Widget engineers to assign to the Widget's functions.&lt;br /&gt;
&lt;br /&gt;
Registers 0, 1, 2 and 3 are available as read/write registers. Registers 4, 5 and 6 are readonly registers.&lt;br /&gt;
&lt;br /&gt;
Only the emulated hardware (running on the Node) can change the values held in registers 4, 5 and 6.&lt;br /&gt;
&lt;br /&gt;
=== Register use in drivers ===&lt;br /&gt;
&lt;br /&gt;
In the example that follows we have a Basic Light Widget with a very simple function: it can be turned on and turned off. The on/off value is stored in register 0, with values 0=OFF and 1=ON. Register 0 is a read/write register. This means we can change the value stored there using messages passed to the Widget from the Node, and by reacting to physical interactions at the Widget (such as someone manually switching the light on or off). &lt;br /&gt;
&lt;br /&gt;
The mapping of registers to properties on the Widget is decided by the engineers who manufacture the device. You must be provided with the mapping before you begin developing your driver.&lt;br /&gt;
&lt;br /&gt;
== Starting the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-BoxHighlight.png|800px|thumb|center|Figure 3 The driver architecture highlighting the Widget driver and its component parts.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When you have generated the abstract provider you can put it to use in the Widget driver. A Widget driver&lt;br /&gt;
has three distinct components:&lt;br /&gt;
&lt;br /&gt;
* an implementation of your abstract provider&lt;br /&gt;
* a definition of the Widget driver&lt;br /&gt;
* an implementation of the IWidgetRegistryEntry interface&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must manually write the code for your Widget driver. The differences in implementation of Widget properties and communication protocols means that the driver code cannot be autogenerated.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This section takes you through how to write a Widget driver by implementing the auto-generated provider,&lt;br /&gt;
starting from a new blank file and finishing with a working driver for the Basic Light Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
No assumptions have been made about the type of editor you use to write your code. Shortcuts&lt;br /&gt;
or macros that you use as standard will not appear in the instructions below. A full example&lt;br /&gt;
BinaryLightDriver.cs is available to review in Appendix C.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a new C# file in your IDE. Ensure the following libraries are used:&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 [[File:Warning.png]]using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 namespace OpenHome.Widget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must use the libraries listed above for this specific example.&lt;br /&gt;
&lt;br /&gt;
In general, drivers require the following libraries:&lt;br /&gt;
* System*&lt;br /&gt;
* System.Collections.Generic*&lt;br /&gt;
* OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
&lt;br /&gt;
Your driver will fail to compile if you miss any of these listed libraries. Libraries marked * are typically added by default by most modern IDEs. &lt;br /&gt;
&lt;br /&gt;
The OpenHome.Widget.Protocols.SimpleUpnp library is required only in this SimpleUPnP example. Drivers using a different protocol will use their own protocol library.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Implementing the provider ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-ProviderHighlight.png|800px|thumb|center|Figure 4 The driver architecture highlighting the Provider's place]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You use your auto-generated abstract provider by writing an implementation of it in the driver file. Responsibilities met by implementing your auto-generated provider are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R6 Reacting to actions sent to the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
Begin by creating a new class. It will subclass the abstract auto-generated provider:&lt;br /&gt;
&lt;br /&gt;
 class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
The Protocol Module will provide an API for the Provider to use to communicate with the Widget. In&lt;br /&gt;
SimpleUPnP we are provided with an interface called ISimpleUpnpWidget. The provider is supplied&lt;br /&gt;
with the required instance of the interface by the Discovery Module on the Node.&lt;br /&gt;
&lt;br /&gt;
The mechanisms for registering providers with specific Protocol Modules, and for the way the module gives each provider its required interface are covered later when writing the discovery method.&lt;br /&gt;
&lt;br /&gt;
For now, we need to give the Provider a place to store the interface that it will later use to communicate&lt;br /&gt;
with the Widget:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]] private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
&lt;br /&gt;
The interface from the Protocol Module is passed in as a parameter in the Provider's constructor and then&lt;br /&gt;
assigned to the variable we just created:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightProvider(DvDevice aDevice,&lt;br /&gt;
 [[File:Warning.png]]         ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
 {&lt;br /&gt;
       iProtocol = aProtocol;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
To satisfy R3 we would normally set the Widget's properties here, giving them an initial value.&lt;br /&gt;
However, in this specific example we cannot set the value of Basic Light's only property because&lt;br /&gt;
we will never know, in advance, what the state of the light will be (either on or off) when we&lt;br /&gt;
create the DiscoveredWidget.&lt;br /&gt;
&lt;br /&gt;
When you cannot set the properties ahead of time, and you are using an eventing protocol like SimpleUPnP, you can instead set them in the HandleRegisterEvent method in the driver class. This also satisfies the requirements for R3. You must set the Widget's properties before you enable it using SetEnabled(). &lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The abstract provider includes an abstract method called SetOn. This method is invoked by the Node when passing a message to the Widget, specifically to set the on property of the Widget to either 0 or 1. The implementation of this method will meet the requirements for R6.&lt;br /&gt;
&lt;br /&gt;
We must override this method and provide the protocol module a way of passing a message on to the Widget to perform the required action, in this case turn the light on or off:&lt;br /&gt;
&lt;br /&gt;
          protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
          {&lt;br /&gt;
     [[File:Warning.png]]        iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
In this example the Basic Light's SetOn property (the boolean property that controls whether the light is&lt;br /&gt;
on or off) is represented in the physical Widget by the register that has an index of 0.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* This method is an example of an action on a Widget. Actions are messages sent from the Node to the Widget. We will see later how to handle events that need to be passed back from the Widget&lt;br /&gt;
to the Node.&lt;br /&gt;
* Your own Widget will likely provide more than a single property. Your auto-generated provider will contain one abstract method to represent each writable property. Read-only properties are not provided an abstract method.&lt;br /&gt;
&lt;br /&gt;
You must implement each abstract method in your driver to ensure the relevant property on&lt;br /&gt;
the Widget can be set.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We have now finished implementing the provider. The next step is to implement the driver.&lt;br /&gt;
&lt;br /&gt;
== Implementing the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-DriverHighlight.png|800px|thumb|center|Figure 4: The driver architecture highlighting the implemented driver's place.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The code for your Widget driver must provide an implementation of the IWidgetRegistryInterface,&lt;br /&gt;
including the following tasks:&lt;br /&gt;
&lt;br /&gt;
* methods to expose identifying details about the Widget for the Node to access&lt;br /&gt;
* providing methods to handle events reported by the Widget&lt;br /&gt;
&lt;br /&gt;
The driver is implemented as a public class within the same file as the provider code. Each driver must use the interface for the protocol you are using. For the SimpleUPnP protocol the interface is ISimple-UpnpWidgetDriver.&lt;br /&gt;
&lt;br /&gt;
=== Writing code ===&lt;br /&gt;
&lt;br /&gt;
Create your new driver class and subclass the ISimpleUpnpWidgetDriver interface:&lt;br /&gt;
&lt;br /&gt;
 public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Implementing IWidgetRegistryEntry ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry is the interface you use to represent physical Widgets. It is implemented as a subclass of your driver class. We are going to implement this interface in a class called '''DiscoveredWidget'''.&lt;br /&gt;
&lt;br /&gt;
Let's return to our driver architecture diagram for a moment:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-IRegistryEntryHighlight.png|800px|thumb|center|Figure 5 The driver architecture highlighting the IWidgetRegistryEntry object you will now implement]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry uses several other objects to help create it and respond to messages sent to and from it. These objects will be created in our implementation of DiscoveredWidget. &lt;br /&gt;
&lt;br /&gt;
When successfully created and published, the DiscoveredWidget objects are stored in a list on the Node called the Local Widget Registry. The Local Widget Registry is used by Nodes to maintain contact with the Widgets they control.&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry is shown at the top of Figure 5, marked plainly as (Registry). The path to the Local Widget Registry goes through several layers of Node architecture which are not relevant to Widget driver writing, so are not shown in the diagrams.&lt;br /&gt;
&lt;br /&gt;
==== Writing code ====&lt;br /&gt;
&lt;br /&gt;
Start by subclassing the IWidgetRegistryEntry interface in your new class:&lt;br /&gt;
&lt;br /&gt;
      private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
      {&lt;br /&gt;
&lt;br /&gt;
A DiscoveredWidget must provide the driver with the objects required to present the Widget and its&lt;br /&gt;
properties to the Node:&lt;br /&gt;
&lt;br /&gt;
           private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
           private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
           private readonly ISimpleUpnpWidget iProtocol;&lt;br /&gt;
           private readonly BinaryLightProvider iProvider;&lt;br /&gt;
           private readonly DvDevice iDvDevice;&lt;br /&gt;
           private IPublishedWidget iPublishedWidget;&lt;br /&gt;
&lt;br /&gt;
Each of the attributes in the example above are defined as follows:&lt;br /&gt;
&lt;br /&gt;
iDeviceFactory — used by the driver to create a single instance of DvDevice to represent a single Widget&lt;br /&gt;
&lt;br /&gt;
iPublisher — used by the driver to publish the Widget to the Node&lt;br /&gt;
&lt;br /&gt;
iProtocol — the object used by the Widget to communicate with the Protocol Module on the Node&lt;br /&gt;
&lt;br /&gt;
iProvider — an instantiated provider of the type you defined earlier&lt;br /&gt;
&lt;br /&gt;
iDvDevice — a representation of a Widget to which the provider is attached, created using iDevice-Factory above&lt;br /&gt;
&lt;br /&gt;
iPublishedWidget — used to contain the returned object from a successful publishing of the Widget&lt;br /&gt;
If we look again at the driver architecture diagram, we ca highlight the objects we've just defined:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-Highlight.png|800px|thumb|center|Figure 6: The driver architecture highlighting the objects used by the IWidgetRegistryEntry implementation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The DeviceFactory, defined above in the member variable iDeviceFactory, is used to create new DvDevice objects. The DeviceFactory is only ever used to do this once. It is not shown in the driver architecture diagrams due to its minimal role in the operation of a driver, but it would normally appear between the IWidgetRegistryEntry and DvDevice objects.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
A driver requires methods to expose identifying details about the Widget. We must provide access to two of the attributes we just defined above:&lt;br /&gt;
&lt;br /&gt;
 public DvDevice DvDevice&lt;br /&gt;
 {&lt;br /&gt;
     get { return iDvDevice; }&lt;br /&gt;
 }&lt;br /&gt;
 public string WidgetClass&lt;br /&gt;
 {&lt;br /&gt;
     get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The WidgetClass string is formed using a combination of the vendor name and the Widget's name in the&lt;br /&gt;
format:&lt;br /&gt;
&lt;br /&gt;
 [vendor_domain]:[widget_name]&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry can now query both the DvDevice object representing the Widget, and the specific class of Widget this driver represents. The other member variables we defined do not need their own accessor methods.&lt;br /&gt;
&lt;br /&gt;
Now we must write a constructor for DiscoveredWidget and assign the parameters accordingly: &lt;br /&gt;
&lt;br /&gt;
 public DiscoveredWidget(IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                            string aUdn,&lt;br /&gt;
                            ISimpleUpnpWidget aProxy,&lt;br /&gt;
                            IWidgetPublisher aPublisher)&lt;br /&gt;
 {&lt;br /&gt;
      iDeviceFactory = aDeviceFactory;&lt;br /&gt;
      iProtocol = aProtocol;&lt;br /&gt;
      iPublisher = aPublisher;&lt;br /&gt;
      iDvDevice = iDeviceFactory.CreateDevice(aUdn);&lt;br /&gt;
      iProvider = new BinaryLightProvider(iDvDevice,&lt;br /&gt;
      iProtocol);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Event handling ===&lt;br /&gt;
&lt;br /&gt;
A Widget's state can change in one of three significant ways:&lt;br /&gt;
&lt;br /&gt;
* when the Widget needs to be published on the Node&lt;br /&gt;
* when the Widget disappears from the network (by losing power or similar)&lt;br /&gt;
* when a property's state changes and must be updated to a new value&lt;br /&gt;
&lt;br /&gt;
We now need methods to handle these changes.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The methods we define here will be used as callbacks, rather than invoked as method calls. We define the methods here first and then use them later on. We will use the Protocol Module to listen for changes in the Widget's state and register these methods as callbacks there. See Writing the SimpleUPnP Widget discovery method for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this section of the driver are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R4 Publishing discovered Widgets in the Local Widget Registry on the Node'''&lt;br /&gt;
&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object. &lt;br /&gt;
&lt;br /&gt;
'''R5 Reacting to an event reported from the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
'''R7 Reacting to a Widget's departure'''&lt;br /&gt;
&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no longer available.&lt;br /&gt;
&lt;br /&gt;
==== Enabling and publishing a discovered Widget ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first method initializes the Widget by enabling the device and then using the IWidgetPublisher&lt;br /&gt;
to make it available on the Node:&lt;br /&gt;
&lt;br /&gt;
 public void HandleInitialEvent()&lt;br /&gt;
 {&lt;br /&gt;
      iDvDevice.SetEnabled();&lt;br /&gt;
      iPublisher.TryPublishWidget(iDvDevice.iUdn(),&lt;br /&gt;
                              this,&lt;br /&gt;
                              out iPublishedWidget);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This method meets the requirements for R4.&lt;br /&gt;
&lt;br /&gt;
The call to TryPublishWidget returns an iPublishedWidget object. We use this object later to satisfy the requirements of R7.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The ordering of the calls to SetEnabled and TryPublishWidget is vitally important. You&lt;br /&gt;
must enable the device before you attempt to publish it. Your Widget will not be available to the&lt;br /&gt;
Nodes unless SetEnabled is called first. Nodes will not be able to access a published device&lt;br /&gt;
that has not been enabled.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
R3 requires that you set the Widget's properties before you enable and publish the device. We&lt;br /&gt;
discussed on page 14 how some properties can only be set after the Widget reports what their&lt;br /&gt;
state is. We do this in HandleRegisterEvent.&lt;br /&gt;
&lt;br /&gt;
We rely on the SimpleUPnP Protocol Module guaranteeing a call to HandleRegisterEvent first before HandleInitialEvent. This is informed by guarantees made by the Control Point stack that the calls will be made in that order.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
==== Removing a Widget ====&lt;br /&gt;
&lt;br /&gt;
Removing a Widget involves unpublishing it from the Node. The IPublishedWidget interface provides us with a method we can call to manage that for us:&lt;br /&gt;
&lt;br /&gt;
 public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
 {&lt;br /&gt;
     if (iPublishedWidget != null)&lt;br /&gt;
     { iPublishedWidget.Unpublish(); }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assuming that the Widget was successfully published earlier, it is removed from the Node's Local Widget Registry.&lt;br /&gt;
&lt;br /&gt;
We must also properly handle the resources we used to create and maintain the Widget object while it was published:&lt;br /&gt;
&lt;br /&gt;
      iProvider.Dispose();&lt;br /&gt;
      iDvDevice.Dispose();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The calls to Dispose are made regardless of the Widget's published state, ensuring that any created device and associated provider are properly disposed. This implementation satisfies R7.&lt;br /&gt;
&lt;br /&gt;
====Event handling ====&lt;br /&gt;
&lt;br /&gt;
We need a method to handle changes to the state of the Widget's properties.&lt;br /&gt;
&lt;br /&gt;
If the property changes at the Widget, it needs to pass the new state back to the Node so that it is kept up-to-date on the Widget's status. This is called an event. An example in the case of our Basic Light is someone manually switching the light from on to off. This is in contrast to actions, which are passed from the Node to the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Other examples of events involve no human interaction, such as a thermometer Widget updating its current temperature based on environmental changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Our Basic Light Widget has only one property that needs to be handled:&lt;br /&gt;
&lt;br /&gt;
 public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
 {&lt;br /&gt;
     if (aIndex == 0)&lt;br /&gt;
     {&lt;br /&gt;
         iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We use our instance of the provider to update the register on the Widget that is mapped to the On property. This in turn updates the Node with the new state of the Widget.&lt;br /&gt;
&lt;br /&gt;
This method provides implementations to satisfy two driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
* R3 is now completely satisfied, as we can now set the values of all the previously unknown properties here.&lt;br /&gt;
* R5 is also satisfied as this method allows us to update the Widget's status on the Node when a property is changed on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Not all protocols pass messages back to the Node in this manner. The way we have satisfied R3 and R5 here only applies to protocols and Widgets that support this behavior.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Widgets that do not use an eventing protocol need to have their properties set in the provider's constructor to satisfy R3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To satisfy R5, the over-ridden method SetOn in the provider must include the call to SetPropertyOn. Non-eventing protocols do not require a HandleRegisterEvent method.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Constructor ===&lt;br /&gt;
&lt;br /&gt;
The final requirement for the driver is the constructor so that new DiscoveredWidget objects can be created. &lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this area of code are:&lt;br /&gt;
&lt;br /&gt;
'''R1 Specifying the type of Widget the driver controls'''&lt;br /&gt;
&lt;br /&gt;
A driver must know which type of Widget that it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
==== Writing the code ====&lt;br /&gt;
&lt;br /&gt;
We begin by defining the variables we will use to store the objects used by the driver:&lt;br /&gt;
&lt;br /&gt;
 private readonly string iName;&lt;br /&gt;
 private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
 private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now write the constructor for the driver and assign the passed in parameters appropriately:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightDriver(string aName,&lt;br /&gt;
                IWidgetPublisher aPublisher,&lt;br /&gt;
                IDvDeviceFactory aDeviceFactory)&lt;br /&gt;
 {&lt;br /&gt;
     iWidgetPublisher = aPublisher;&lt;br /&gt;
     iName = aName;&lt;br /&gt;
     iDeviceFactory = aDeviceFactory;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally we need to provide the driver a way to publish the class of Widget it controls. This information is requested by the Discovery Module and is used to ensure the Node uses the correct driver when a new Widget appears.&lt;br /&gt;
&lt;br /&gt;
The implementation for this details will be different for each protocol. The SimpleUPnP protocol library provides a file that contains the SimpleUPnP definitions as integers. Each integer represents a particular class of identified Widget.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP implementation of that method is as follows:&lt;br /&gt;
&lt;br /&gt;
 public IEnumerable&amp;lt;uint&amp;gt; WidgetClasses&lt;br /&gt;
 {&lt;br /&gt;
 [[File:Warning.png]]        get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The body of this method is specifically written for the Widget class we are defining (in this case a binary light). This method completes the driver's requirements for R1.&lt;br /&gt;
&lt;br /&gt;
== Writing the SimpleUPnP Widget discovery method ==&lt;br /&gt;
&lt;br /&gt;
Every driver must contain a method which creates new objects to represent newly discovered Widgets.&lt;br /&gt;
The Discovery Module invokes this method to begin the process of creating the objects required to allow the Node to access the Widget. &lt;br /&gt;
&lt;br /&gt;
The name of this method is dictated by your chosen protocol's API. The SimpleUPnP protocol requires a method called WidgetDiscovered.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The method's name will not always be the same for each protocol. Your protocol's documentation will contain the details of what this method must be called.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This method and its implementation will meet the following driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
'''R2 Reacting to a discovered Widget on the network'''&lt;br /&gt;
&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
Our implementation of the WidgetDiscovered method will create a new DiscoveredWidget object and use the Protocol Module to listen for changes to the Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
The method uses the Protocol Module and two ways to identify the Widget. We must pass these in as&lt;br /&gt;
parameters:&lt;br /&gt;
&lt;br /&gt;
 public void WidgetDiscovered(string aWidgetUdn,&lt;br /&gt;
                              uint aWidgetClass,&lt;br /&gt;
                              ISimpleUpnpWidget&lt;br /&gt;
                                  aSimpleUpnpWidget)&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
Every Widget that uses this driver must be uniquely identifiable:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]    string newUdn = aWidgetUdn;&lt;br /&gt;
&lt;br /&gt;
Each new Widget is represented by a DiscoveredWidget object. Create the new DiscoveredWidget and pass in the required parameters we created earlier:&lt;br /&gt;
&lt;br /&gt;
     DiscoveredWidget discoveredWidget =&lt;br /&gt;
                 new DiscoveredWidget(iDeviceFactory,&lt;br /&gt;
                                      newUdn,&lt;br /&gt;
  &lt;br /&gt;
 [[File:Warning.png]]                                    aSimpleUpnpWidget,&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Registering the callbacks ===&lt;br /&gt;
&lt;br /&gt;
Finally, we ask the Widget's protocol interface to listen for calls to the handler methods we defined earlier in DiscoveredWidget. We do this by registering those methods as callbacks for the Protocol Module&lt;br /&gt;
to listen for:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                        discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                        discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                        discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You have now met 100% of the driver responsibility requirements and have a working driver to use with your SimpleUPnP Widget.&lt;br /&gt;
&lt;br /&gt;
= Appendix A. Sample XML =&lt;br /&gt;
&lt;br /&gt;
== Binary Light.xml ==&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
  &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
  &amp;lt;version&amp;gt;&lt;br /&gt;
   &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
   &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/version&amp;gt;&lt;br /&gt;
  &amp;lt;propertylist&amp;gt;&lt;br /&gt;
   &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
       illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
   &amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix B. Sample Provider = &lt;br /&gt;
&lt;br /&gt;
== DvWidgetOpenhomeOrgBasicLight1.cs ==&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Runtime.InteropServices;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Core;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Utils.Binary;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
 {&lt;br /&gt;
    public interface IDvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
        IDisposable&lt;br /&gt;
    {&lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous value&lt;br /&gt;
        /// &amp;lt;/returns&amp;gt;&lt;br /&gt;
        bool SetPropertyOn(bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;Property's value will be copied&lt;br /&gt;
        /// here&amp;lt;/param&amp;gt;&lt;br /&gt;
        bool PropertyOn();&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt; summary&amp;gt;&lt;br /&gt;
    /// Provider for the openhome.org:BinaryLight:1 UPnP service&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public abstract class DvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
               DvProvider,&lt;br /&gt;
               IDisposable,&lt;br /&gt;
               IDvProviderOpenhomeOrgBinaryLight1&lt;br /&gt;
    {&lt;br /&gt;
        private GCHandle iGch;&lt;br /&gt;
        private PropertyBool iPropertyOn;&lt;br /&gt;
        private PropertyUint iPropertyPrimarySeq;&lt;br /&gt;
        private PropertyUint iPropertySecondarySeq;&lt;br /&gt;
        private ActionDelegate iDelegateSetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetPrimaryProperty;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Constructor&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aDevice&amp;quot;&amp;gt;Device which owns this&lt;br /&gt;
        /// provider&amp;lt;/param&amp;gt;&lt;br /&gt;
        protected DvProviderOpenhomeOrgBinaryLight1(DvDevice aDevice)&lt;br /&gt;
            : base(aDevice, &amp;quot;openhome.org&amp;quot;, &amp;quot;GenericWidget&amp;quot;, 1)&lt;br /&gt;
        {&lt;br /&gt;
            iGch = GCHandle.Alloc(this);&lt;br /&gt;
            List&amp;lt;String&amp;gt; allowedValues = new List&amp;lt;String&amp;gt;();&lt;br /&gt;
            iPropertyOn = new PropertyBool(new ParameterBool(&amp;quot;On&amp;quot;));&lt;br /&gt;
            iPropertyPrimarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;PrimarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertyPrimarySeq);&lt;br /&gt;
            iPropertySecondarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;SecondarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertySecondarySeq);&lt;br /&gt;
            SetPropertyUint(iPropertyPrimarySeq, 0);&lt;br /&gt;
            SetPropertyUint(iPropertySecondarySeq, 0);&lt;br /&gt;
  &lt;br /&gt;
            Zapp.Core.Action action = new Zapp.Core.Action&lt;br /&gt;
                (&amp;quot;SetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;FireAndForget&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddInputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateSetProperty = new ActionDelegate(DoSetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateSetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateGetProperty = new ActionDelegate(DoGetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetPrimaryProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                 (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;integer&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;boolean&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;string&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;binary&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Type&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;readWrite&amp;quot;);allowedValues.Add&lt;br /&gt;
                (&amp;quot;readOnly&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;writeOnly&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString(&amp;quot;Access&amp;quot;,&lt;br /&gt;
                allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            iDelegateGetPrimaryProperty = new&lt;br /&gt;
            ActionDelegate(DoGetPrimaryProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetPrimaryProperty,&lt;br /&gt;
            GCHandle.ToIntPtr(iGch));&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous&lt;br /&gt;
        /// value&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool SetPropertyOn(bool aValue)&lt;br /&gt;
        {&lt;br /&gt;
            if (iPropertyOn.SetValue(aValue))&lt;br /&gt;
            {&lt;br /&gt;
                lock (iPropertyPrimarySeq)&lt;br /&gt;
                {&lt;br /&gt;
                    SetPropertyUint(iPropertyPrimarySeq,&lt;br /&gt;
                        iPropertyPrimarySeq.Value() + 1);&lt;br /&gt;
                } return true;&lt;br /&gt;
            } return false;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;The value of the property&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool PropertyOn()&lt;br /&gt;
        {&lt;br /&gt;
            return iPropertyOn.Value();&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the On property.&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aVersion&amp;quot;&amp;gt;Version of the service being&lt;br /&gt;
        /// requested (will be &amp;lt;= the version advertised)&amp;lt;/param&amp;gt; &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the On property.&lt;br /&gt;
        /// &amp;lt;/param&amp;gt;&lt;br /&gt;
        protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        private static int DoSetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                byte[] valBin = invocation.ReadBinary(&amp;quot;Value&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                switch (name)&lt;br /&gt;
                {&lt;br /&gt;
                    case &amp;quot;On&amp;quot;:&lt;br /&gt;
                        self.SetOn(aVersion, Converter.&lt;br /&gt;
                            BinaryToBoolean(valBin));&lt;br /&gt;
                        break;&lt;br /&gt;
                    default:&lt;br /&gt;
                        throw new ActionError();&lt;br /&gt;
                }&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
                invocation.WriteEnd();&lt;br /&gt;
            }&lt;br /&gt;
            catch (ActionError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
            catch (PropertyUpdateError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
        return 0;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        private static int DoGetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
            switch (name)&lt;br /&gt;
            {&lt;br /&gt;
                case &amp;quot;On&amp;quot;:&lt;br /&gt;
                invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                    Converter.BooleanToBinary(self.iPropertyOn.&lt;br /&gt;
                        Value()));&lt;br /&gt;
                break;&lt;br /&gt;
                default:&lt;br /&gt;
                throw new ActionError();&lt;br /&gt;
            }&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    private static int DoGetPrimaryProperty(IntPtr aPtr,&lt;br /&gt;
                    IntPtr aInvocation,&lt;br /&gt;
                    uint aVersion)&lt;br /&gt;
    {&lt;br /&gt;
        GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
        DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
            (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
        DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
  &lt;br /&gt;
        try&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReadStart();&lt;br /&gt;
            invocation.ReadEnd();&lt;br /&gt;
            invocation.WriteStart();&lt;br /&gt;
            invocation.WriteString(&amp;quot;Name&amp;quot;, &amp;quot;On&amp;quot;);&lt;br /&gt;
            invocation.WriteString(&amp;quot;Type&amp;quot;, &amp;quot;boolean&amp;quot;);&lt;br /&gt;
            invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                Converter.BooleanToBinary(self.iPropertyOn.Value()));&lt;br /&gt;
            invocation.WriteString(&amp;quot;Access&amp;quot;, &amp;quot;readWrite&amp;quot;);&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt;summary&amp;gt;&lt;br /&gt;
    /// Must be called for each class instance. Must be called before&lt;br /&gt;
    /// Core.Library.Close().&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public void Dispose()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
        GC.SuppressFinalize(this);&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
    ~DvProviderOpenhomeOrgBinaryLight1()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
        private void DoDispose()&lt;br /&gt;
        {&lt;br /&gt;
            lock (this)&lt;br /&gt;
            {&lt;br /&gt;
                if (iHandle == IntPtr.Zero)&lt;br /&gt;
            {&lt;br /&gt;
                    return;&lt;br /&gt;
            }&lt;br /&gt;
            DisposeProvider();&lt;br /&gt;
            iPropertyOn.Dispose();&lt;br /&gt;
            iHandle = IntPtr.Zero;&lt;br /&gt;
            }&lt;br /&gt;
            iGch.Free();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix C. Sample Driver = &lt;br /&gt;
&lt;br /&gt;
== BasicLightDriver.cs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.hWidget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
     class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
     {&lt;br /&gt;
         private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
         public BinaryLightProvider(DvDevice aDevice, &lt;br /&gt;
             ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol = aProtocol;&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
     {&lt;br /&gt;
         private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
         {&lt;br /&gt;
             private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
             private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
             private readonly ISimpleUpnpWidget iProtocol; &lt;br /&gt;
 &lt;br /&gt;
             private readonly BinaryLightProvider iProvider;&lt;br /&gt;
             private readonly DvDevice iDvDevice;&lt;br /&gt;
             private IPublishedWidget iPublishedWidget; &lt;br /&gt;
 &lt;br /&gt;
             public DvDevice DvDevice&lt;br /&gt;
             {&lt;br /&gt;
                 get { return iDvDevice; }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             public string WidgetClass&lt;br /&gt;
             {&lt;br /&gt;
                 get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public DiscoveredWidget(&lt;br /&gt;
                 IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                 string aUdn,&lt;br /&gt;
                 ISimpleUpnpWidget aProxy,&lt;br /&gt;
                 IWidgetPublisher aPublisher)&lt;br /&gt;
             {&lt;br /&gt;
                 iDeviceFactory = aDeviceFactory;&lt;br /&gt;
                 iProtocol = aProtocol;&lt;br /&gt;
 &lt;br /&gt;
                 iPublisher = aPublisher;&lt;br /&gt;
                 iDvDevice = iDeviceFactory.CreateDevice(aUdn);  &lt;br /&gt;
                 iProvider = new BinaryLightProvider(iDvDevice, &lt;br /&gt;
                                                     iProtocol);&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             public void HandleInitialEvent()&lt;br /&gt;
             {&lt;br /&gt;
                 iDvDevice.SetEnabled();&lt;br /&gt;
                 iPublisher.TryPublishWidget(iDvDevice.iUdn(), this,&lt;br /&gt;
                     out iPublishedWidget);&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
             {&lt;br /&gt;
                 if (iPublishedWidget != null)&lt;br /&gt;
                 {&lt;br /&gt;
                     iPublishedWidget.Unpublish();&lt;br /&gt;
                 } &lt;br /&gt;
                 iProvider.Dispose();&lt;br /&gt;
                 iDvDevice.Dispose();&lt;br /&gt;
             }  &lt;br /&gt;
 &lt;br /&gt;
             public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
             {&lt;br /&gt;
                 if (aIndex == 0)&lt;br /&gt;
                 {&lt;br /&gt;
                     iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         private readonly string iName;&lt;br /&gt;
         private readonly IDvDeviceFactory aDeviceFactory;&lt;br /&gt;
         private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
         &lt;br /&gt;
         public BinaryLightDriver(&lt;br /&gt;
             string aName,&lt;br /&gt;
             IWidgetPublisher aPublisher,&lt;br /&gt;
             iDeviceFactory aDeviceFactory)&lt;br /&gt;
         {&lt;br /&gt;
             iWidgetPublisher = aPublisher;&lt;br /&gt;
             iName = aName;&lt;br /&gt;
             iDeviceFactory = aDeviceFactory;&lt;br /&gt;
         } &lt;br /&gt;
 &lt;br /&gt;
         public IEnumerable&amp;amp;lt;uint&amp;amp;gt; WidgetClasses&lt;br /&gt;
         {&lt;br /&gt;
             get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         public void WidgetDiscovered(&lt;br /&gt;
             string aWidgetUdn,&lt;br /&gt;
             uint aWidgetClass,&lt;br /&gt;
             ISimpleUpnpWidget aSimpleUpnpWidget)&lt;br /&gt;
         {&lt;br /&gt;
             string newUdn = aWidgetUdn;&lt;br /&gt;
             DiscoveredWidget discoveredWidget = new DiscoveredWidget&lt;br /&gt;
                 (iDeviceFactory,&lt;br /&gt;
                  newUdn,&lt;br /&gt;
                  aSimpleUpnpWidget,&lt;br /&gt;
                  iWidgetPublisher);&lt;br /&gt;
 &lt;br /&gt;
             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                 discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                 discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                 discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary = &lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in OpenHome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by OpenHome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh - A collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs on ohOS.&lt;br /&gt;
&lt;br /&gt;
[[ohNet|ohNet] - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
[[ohOs|ohOs]] - The OpenHome Operating System. Core software for OpenHome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. &lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. A typical Widget supports only one protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Driver_Development</id>
		<title>OhWidget Driver Development</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Driver_Development"/>
				<updated>2012-03-01T15:27:21Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Registering the callbacks */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for developers using the OpenHome SDK to integrate a Widget into an OpenHome system. Each Widget must have its own driver to allow it to communicate with the OpenHome Nodes. &lt;br /&gt;
&lt;br /&gt;
To help you write your driver, this document provides high level descriptions of the core responsibilities of a Widget driver and gives a detailed walk-through using example code.&lt;br /&gt;
&lt;br /&gt;
Full versions of each file used in the development of the example driver are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin development of your Widget driver you must be in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* your Widget Service XML that describes the properties on your Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document does not contain advice on how to write Widget Service XML. Refer to the OpenHome Widget Service XML definition document for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK&lt;br /&gt;
* your chosen communication protocol's API&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The protocol you choose for your Widgets must be the same protocol used on your choice of Node.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document focuses on the development of the Widget driver. Details about the communications protocol used are beyond the scope of this document. This document assumes you are familiar with your chosen protocol's code libraries and are able to use them in the driver code you write.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Related Documents ==&lt;br /&gt;
&lt;br /&gt;
The following related OpenHome documentation may be of interest to you:&lt;br /&gt;
&lt;br /&gt;
* [[ohWidget Technical Overview|ohWidget Technical Overview]]&lt;br /&gt;
* [[OpenHome Widget Service XML definition|OpenHome Widget Service XML definition]]&lt;br /&gt;
* [http://www.openhome.org/releases/ohNet_DeviceStack.pdf  OpenHome ohNet Device Stack]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
None of the related documents listed above is mandatory reading for Widget driver development.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
== Widget Service XML ==&lt;br /&gt;
OpenHome Widget driver writing relies heavily on the use of code generated from a single source — the Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
The service and actions your Widget provides are represented in code in a file called a Provider. The Provider is automatically generated from the Widget Service XML and produces an abstract class for you to inherit when you write your concrete class driver.&lt;br /&gt;
&lt;br /&gt;
To aid in the explanation of how the Provider is created and put to use we will follow the development of&lt;br /&gt;
a driver for a simple light Widget; taking the defined Widget Service XML and stepping through how it is used to generate the other files. Examples of code are used throughout this document to show you how each one is created and used in an OpenHome system. &lt;br /&gt;
&lt;br /&gt;
It is essential that you start with a well-formed Widget Service XML, conforming to the schema defined&lt;br /&gt;
in the WidgetService.xsd. The following diagram shows the significance of the Widget Service XML in&lt;br /&gt;
relation to the generated files you will use when writing your driver:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarchy, highlighting the areas specifically used in driver development]]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* The grayed-out files are not relevant to Widget driver development but can also be generated from the Widget Service XML.&lt;br /&gt;
* The Provider is generated in C#, meaning your driver must be written in C# as well. The use of managed code is mandatory for driver writing in the OpenHome framework.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Code sample used in this document ==&lt;br /&gt;
&lt;br /&gt;
Our examples in this document use a Widget Service XML definition for a light Widget called&lt;br /&gt;
BasicLight.xml.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Full versions of all the example files used in this document are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We will see how the Provider is generated from this XML and how it is used to aid the driver writing process. The examples also show how your chosen communication protocol should be used in the body of the driver code.&lt;br /&gt;
&lt;br /&gt;
Implementation details of specific protocols you choose to use are beyond the scope of this document. However, the samples used in this document show the use of the SimpleUPnP protocol to aid you in your development process.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol during the early stages of the OpenHome project. It is included in the OpenHome SDK and can be used as a public resource. &lt;br /&gt;
&lt;br /&gt;
The use of SimpleUPnP in the example files and the code snippets within the following sections is highlighted by the [[File:Warning.png]] icon. The lines of code marked by [[File:Warning.png]] must be changed to code from your chosen communication protocol's library. SimpleUPnP is left in to help you understand how a protocol is used in a working example.&lt;br /&gt;
&lt;br /&gt;
The sample code provided attempts to show best-practice coding standards. There are several sections of code that have a mandatory layout or that call specifically named methods and functions. These areas of the code are highlighted where required. &lt;br /&gt;
&lt;br /&gt;
Where the examples do not explicitly state that the code shown is mandatory, you are free to implement it in a different way according to your own coding style and practices.&lt;br /&gt;
&lt;br /&gt;
= Driver responsibilities = &lt;br /&gt;
&lt;br /&gt;
== Driver responsibilities ==&lt;br /&gt;
&lt;br /&gt;
An OpenHome Widget driver has several responsibilities which must be met before it can be used on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
These responsibilities are listed R1 to R7 and are defined here, explaining what each one must do. &lt;br /&gt;
&lt;br /&gt;
=== R1 Specifying the type of Widget the driver controls ===&lt;br /&gt;
A driver must know which type of Widget it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
=== R2 Reacting to a discovered Widget on the network ===&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== R3 Setting the initial values for the Widget's properties ===&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
=== R4 Publishing discovered Widgets in the Local Widget Registry on the Node ===&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object.&lt;br /&gt;
&lt;br /&gt;
=== R5 Reacting to an event reported from the Widget ===&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
=== R6 Reacting to actions sent to the Widget ===&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== R7 Reacting to a Widget's departure ===&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no&lt;br /&gt;
longer available.&lt;br /&gt;
&lt;br /&gt;
The sections of example code that follow show you how to write a driver from beginning to end. The accompanying text explaining the example code highlights when a responsibility, or part of a responsibility, has been met.&lt;br /&gt;
&lt;br /&gt;
= Driver Architecture = &lt;br /&gt;
&lt;br /&gt;
== Driver Architecture ==&lt;br /&gt;
&lt;br /&gt;
Drivers are installed on the Node and used when the Node needs to communicate with the Widget. Drivers&lt;br /&gt;
use several objects to communicate with Widgets over the Widget's lifetime. Figure 2 shows the objects&lt;br /&gt;
used by the driver and how the responsibilities listed above relate to each one:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture.png|800px|thumb|center|Figure 2: The architecture of a driver, showing the driver's relationship to the objects used to communicate with a Widget. Lines between objects show message flow.]]&lt;br /&gt;
&lt;br /&gt;
The objects contained in the dotted boundary must appear in the code you write to define your driver. The Driver, Provider and IWidgetRegistryEntry objects are all contained in the same driver file. We begin discussing this on page 12. &lt;br /&gt;
&lt;br /&gt;
The other objects are provided by the OpenHome SDK or as installed components on the Node.&lt;br /&gt;
&lt;br /&gt;
The Discovery Module informs the driver of the presence of an available Widget.&lt;br /&gt;
&lt;br /&gt;
Each Node has a Protocol Module which contains the protocol's API. Widgets can communicate with OpenHome Nodes using any one of the set of communications protocols the Node supports. The driver uses your chosen protocol's Protocol Module to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
Both the Protocol Module and the Discovery Module are installed on the Node. When you write your&lt;br /&gt;
driver you will use your Protocol Module to allow the driver to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
IWidgetPublisher, IPublishedWidget and DvDevice are objects provided in the OpenHome&lt;br /&gt;
API. You can read about them in the APIs.&lt;br /&gt;
&lt;br /&gt;
= Generating the Provider = &lt;br /&gt;
&lt;br /&gt;
== Generating the Provider ==&lt;br /&gt;
&lt;br /&gt;
You must generate your provider before you can begin writing your Widget driver. You use your provider as a guide to implement the functions your Widget needs to set the values of its properties.&lt;br /&gt;
&lt;br /&gt;
The current provider generation process is a manual one involving the use of a text transform tool.&lt;br /&gt;
&lt;br /&gt;
Speak to your OpenHome contact who will help you generate your provider.&lt;br /&gt;
&lt;br /&gt;
Future releases of the OpenHome SDK will include a tool to help you generate the provider.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
You must be in possession of:&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK, unpacked on your computer&lt;br /&gt;
* your Widget Service XML file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Writing a SimpleUPnP driver = &lt;br /&gt;
&lt;br /&gt;
== Introduction to the SimpleUPnP protocol ==&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol used to control emulated Widgets over a custom UPnP service.&lt;br /&gt;
&lt;br /&gt;
This chapter shows how a driver is written using the SimpleUPnP communications protocol. The aim is to show the code using as generic a protocol as possible so that you can see where your own protocol specific code needs to go.&lt;br /&gt;
&lt;br /&gt;
The use of code specific to the SimpleUPnP implementation is highlighted by the use of the [[File:Warning.png]] icon. The lines of code are marked by this icon to make it easier for you to see where the protocol-specific code must go and what parts of the code are generic.&lt;br /&gt;
&lt;br /&gt;
=== Register model ===&lt;br /&gt;
&lt;br /&gt;
SimpleUPnP is modeled on 8 physical registers available on the Widget. Each register is 32-bits wide. They are indexed from 0 to 7 and the last register (register 7) is reserved for storing the Widget's class.&lt;br /&gt;
&lt;br /&gt;
This detail is used by the Protocol Module on the Node to determine which driver is needed to run the new Widget when it has been discovered.&lt;br /&gt;
&lt;br /&gt;
The remaining 7 registers (registers 0 to 6) are free for Widget engineers to assign to the Widget's functions.&lt;br /&gt;
&lt;br /&gt;
Registers 0, 1, 2 and 3 are available as read/write registers. Registers 4, 5 and 6 are readonly registers.&lt;br /&gt;
&lt;br /&gt;
Only the emulated hardware (running on the Node) can change the values held in registers 4, 5 and 6.&lt;br /&gt;
&lt;br /&gt;
=== Register use in drivers ===&lt;br /&gt;
&lt;br /&gt;
In the example that follows we have a Basic Light Widget with a very simple function: it can be turned on and turned off. The on/off value is stored in register 0, with values 0=OFF and 1=ON. Register 0 is a read/write register. This means we can change the value stored there using messages passed to the Widget from the Node, and by reacting to physical interactions at the Widget (such as someone manually switching the light on or off). &lt;br /&gt;
&lt;br /&gt;
The mapping of registers to properties on the Widget is decided by the engineers who manufacture the device. You must be provided with the mapping before you begin developing your driver.&lt;br /&gt;
&lt;br /&gt;
== Starting the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-BoxHighlight.png|800px|thumb|center|Figure 3 The driver architecture highlighting the Widget driver and its component parts.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When you have generated the abstract provider you can put it to use in the Widget driver. A Widget driver&lt;br /&gt;
has three distinct components:&lt;br /&gt;
&lt;br /&gt;
* an implementation of your abstract provider&lt;br /&gt;
* a definition of the Widget driver&lt;br /&gt;
* an implementation of the IWidgetRegistryEntry interface&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must manually write the code for your Widget driver. The differences in implementation of Widget properties and communication protocols means that the driver code cannot be autogenerated.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This section takes you through how to write a Widget driver by implementing the auto-generated provider,&lt;br /&gt;
starting from a new blank file and finishing with a working driver for the Basic Light Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
No assumptions have been made about the type of editor you use to write your code. Shortcuts&lt;br /&gt;
or macros that you use as standard will not appear in the instructions below. A full example&lt;br /&gt;
BinaryLightDriver.cs is available to review in Appendix C.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a new C# file in your IDE. Ensure the following libraries are used:&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 [[File:Warning.png]]using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 namespace OpenHome.Widget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must use the libraries listed above for this specific example.&lt;br /&gt;
&lt;br /&gt;
In general, drivers require the following libraries:&lt;br /&gt;
* System*&lt;br /&gt;
* System.Collections.Generic*&lt;br /&gt;
* OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
&lt;br /&gt;
Your driver will fail to compile if you miss any of these listed libraries. Libraries marked * are typically added by default by most modern IDEs. &lt;br /&gt;
&lt;br /&gt;
The OpenHome.Widget.Protocols.SimpleUpnp library is required only in this SimpleUPnP example. Drivers using a different protocol will use their own protocol library.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Implementing the provider ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-ProviderHighlight.png|800px|thumb|center|Figure 4 The driver architecture highlighting the Provider's place]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You use your auto-generated abstract provider by writing an implementation of it in the driver file. Responsibilities met by implementing your auto-generated provider are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R6 Reacting to actions sent to the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
Begin by creating a new class. It will subclass the abstract auto-generated provider:&lt;br /&gt;
&lt;br /&gt;
 class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
The Protocol Module will provide an API for the Provider to use to communicate with the Widget. In&lt;br /&gt;
SimpleUPnP we are provided with an interface called ISimpleUpnpWidget. The provider is supplied&lt;br /&gt;
with the required instance of the interface by the Discovery Module on the Node.&lt;br /&gt;
&lt;br /&gt;
The mechanisms for registering providers with specific Protocol Modules, and for the way the module gives each provider its required interface are covered later when writing the discovery method.&lt;br /&gt;
&lt;br /&gt;
For now, we need to give the Provider a place to store the interface that it will later use to communicate&lt;br /&gt;
with the Widget:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]] private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
&lt;br /&gt;
The interface from the Protocol Module is passed in as a parameter in the Provider's constructor and then&lt;br /&gt;
assigned to the variable we just created:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightProvider(DvDevice aDevice,&lt;br /&gt;
 [[File:Warning.png]]         ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
 {&lt;br /&gt;
       iProtocol = aProtocol;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
To satisfy R3 we would normally set the Widget's properties here, giving them an initial value.&lt;br /&gt;
However, in this specific example we cannot set the value of Basic Light's only property because&lt;br /&gt;
we will never know, in advance, what the state of the light will be (either on or off) when we&lt;br /&gt;
create the DiscoveredWidget.&lt;br /&gt;
&lt;br /&gt;
When you cannot set the properties ahead of time, and you are using an eventing protocol like SimpleUPnP, you can instead set them in the HandleRegisterEvent method in the driver class. This also satisfies the requirements for R3. You must set the Widget's properties before you enable it using SetEnabled(). &lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The abstract provider includes an abstract method called SetOn. This method is invoked by the Node when passing a message to the Widget, specifically to set the on property of the Widget to either 0 or 1. The implementation of this method will meet the requirements for R6.&lt;br /&gt;
&lt;br /&gt;
We must override this method and provide the protocol module a way of passing a message on to the Widget to perform the required action, in this case turn the light on or off:&lt;br /&gt;
&lt;br /&gt;
          protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
          {&lt;br /&gt;
     [[File:Warning.png]]        iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
In this example the Basic Light's SetOn property (the boolean property that controls whether the light is&lt;br /&gt;
on or off) is represented in the physical Widget by the register that has an index of 0.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* This method is an example of an action on a Widget. Actions are messages sent from the Node to the Widget. We will see later how to handle events that need to be passed back from the Widget&lt;br /&gt;
to the Node.&lt;br /&gt;
* Your own Widget will likely provide more than a single property. Your auto-generated provider will contain one abstract method to represent each writable property. Read-only properties are not provided an abstract method.&lt;br /&gt;
&lt;br /&gt;
You must implement each abstract method in your driver to ensure the relevant property on&lt;br /&gt;
the Widget can be set.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We have now finished implementing the provider. The next step is to implement the driver.&lt;br /&gt;
&lt;br /&gt;
== Implementing the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-DriverHighlight.png|800px|thumb|center|Figure 4: The driver architecture highlighting the implemented driver's place.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The code for your Widget driver must provide an implementation of the IWidgetRegistryInterface,&lt;br /&gt;
including the following tasks:&lt;br /&gt;
&lt;br /&gt;
* methods to expose identifying details about the Widget for the Node to access&lt;br /&gt;
* providing methods to handle events reported by the Widget&lt;br /&gt;
&lt;br /&gt;
The driver is implemented as a public class within the same file as the provider code. Each driver must use the interface for the protocol you are using. For the SimpleUPnP protocol the interface is ISimple-UpnpWidgetDriver.&lt;br /&gt;
&lt;br /&gt;
=== Writing code ===&lt;br /&gt;
&lt;br /&gt;
Create your new driver class and subclass the ISimpleUpnpWidgetDriver interface:&lt;br /&gt;
&lt;br /&gt;
 public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Implementing IWidgetRegistryEntry ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry is the interface you use to represent physical Widgets. It is implemented as a subclass of your driver class. We are going to implement this interface in a class called '''DiscoveredWidget'''.&lt;br /&gt;
&lt;br /&gt;
Let's return to our driver architecture diagram for a moment:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-IRegistryEntryHighlight.png|800px|thumb|center|Figure 5 The driver architecture highlighting the IWidgetRegistryEntry object you will now implement]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry uses several other objects to help create it and respond to messages sent to and from it. These objects will be created in our implementation of DiscoveredWidget. &lt;br /&gt;
&lt;br /&gt;
When successfully created and published, the DiscoveredWidget objects are stored in a list on the Node called the Local Widget Registry. The Local Widget Registry is used by Nodes to maintain contact with the Widgets they control.&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry is shown at the top of Figure 5, marked plainly as (Registry). The path to the Local Widget Registry goes through several layers of Node architecture which are not relevant to Widget driver writing, so are not shown in the diagrams.&lt;br /&gt;
&lt;br /&gt;
==== Writing code ====&lt;br /&gt;
&lt;br /&gt;
Start by subclassing the IWidgetRegistryEntry interface in your new class:&lt;br /&gt;
&lt;br /&gt;
      private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
      {&lt;br /&gt;
&lt;br /&gt;
A DiscoveredWidget must provide the driver with the objects required to present the Widget and its&lt;br /&gt;
properties to the Node:&lt;br /&gt;
&lt;br /&gt;
           private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
           private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
           private readonly ISimpleUpnpWidget iProtocol;&lt;br /&gt;
           private readonly BinaryLightProvider iProvider;&lt;br /&gt;
           private readonly DvDevice iDvDevice;&lt;br /&gt;
           private IPublishedWidget iPublishedWidget;&lt;br /&gt;
&lt;br /&gt;
Each of the attributes in the example above are defined as follows:&lt;br /&gt;
&lt;br /&gt;
iDeviceFactory — used by the driver to create a single instance of DvDevice to represent a single Widget&lt;br /&gt;
&lt;br /&gt;
iPublisher — used by the driver to publish the Widget to the Node&lt;br /&gt;
&lt;br /&gt;
iProtocol — the object used by the Widget to communicate with the Protocol Module on the Node&lt;br /&gt;
&lt;br /&gt;
iProvider — an instantiated provider of the type you defined earlier&lt;br /&gt;
&lt;br /&gt;
iDvDevice — a representation of a Widget to which the provider is attached, created using iDevice-Factory above&lt;br /&gt;
&lt;br /&gt;
iPublishedWidget — used to contain the returned object from a successful publishing of the Widget&lt;br /&gt;
If we look again at the driver architecture diagram, we ca highlight the objects we've just defined:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-Highlight.png|800px|thumb|center|Figure 6: The driver architecture highlighting the objects used by the IWidgetRegistryEntry implementation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The DeviceFactory, defined above in the member variable iDeviceFactory, is used to create new DvDevice objects. The DeviceFactory is only ever used to do this once. It is not shown in the driver architecture diagrams due to its minimal role in the operation of a driver, but it would normally appear between the IWidgetRegistryEntry and DvDevice objects.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
A driver requires methods to expose identifying details about the Widget. We must provide access to two of the attributes we just defined above:&lt;br /&gt;
&lt;br /&gt;
 public DvDevice DvDevice&lt;br /&gt;
 {&lt;br /&gt;
     get { return iDvDevice; }&lt;br /&gt;
 }&lt;br /&gt;
 public string WidgetClass&lt;br /&gt;
 {&lt;br /&gt;
     get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The WidgetClass string is formed using a combination of the vendor name and the Widget's name in the&lt;br /&gt;
format:&lt;br /&gt;
&lt;br /&gt;
 [vendor_domain]:[widget_name]&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry can now query both the DvDevice object representing the Widget, and the specific class of Widget this driver represents. The other member variables we defined do not need their own accessor methods.&lt;br /&gt;
&lt;br /&gt;
Now we must write a constructor for DiscoveredWidget and assign the parameters accordingly: &lt;br /&gt;
&lt;br /&gt;
 public DiscoveredWidget(IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                            string aUdn,&lt;br /&gt;
                            ISimpleUpnpWidget aProxy,&lt;br /&gt;
                            IWidgetPublisher aPublisher)&lt;br /&gt;
 {&lt;br /&gt;
      iDeviceFactory = aDeviceFactory;&lt;br /&gt;
      iProtocol = aProtocol;&lt;br /&gt;
      iPublisher = aPublisher;&lt;br /&gt;
      iDvDevice = iDeviceFactory.CreateDevice(aUdn);&lt;br /&gt;
      iProvider = new BinaryLightProvider(iDvDevice,&lt;br /&gt;
      iProtocol);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Event handling ===&lt;br /&gt;
&lt;br /&gt;
A Widget's state can change in one of three significant ways:&lt;br /&gt;
&lt;br /&gt;
* when the Widget needs to be published on the Node&lt;br /&gt;
* when the Widget disappears from the network (by losing power or similar)&lt;br /&gt;
* when a property's state changes and must be updated to a new value&lt;br /&gt;
&lt;br /&gt;
We now need methods to handle these changes.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The methods we define here will be used as callbacks, rather than invoked as method calls. We define the methods here first and then use them later on. We will use the Protocol Module to listen for changes in the Widget's state and register these methods as callbacks there. See Writing the SimpleUPnP Widget discovery method for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this section of the driver are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R4 Publishing discovered Widgets in the Local Widget Registry on the Node'''&lt;br /&gt;
&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object. &lt;br /&gt;
&lt;br /&gt;
'''R5 Reacting to an event reported from the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
'''R7 Reacting to a Widget's departure'''&lt;br /&gt;
&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no longer available.&lt;br /&gt;
&lt;br /&gt;
==== Enabling and publishing a discovered Widget ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first method initializes the Widget by enabling the device and then using the IWidgetPublisher&lt;br /&gt;
to make it available on the Node:&lt;br /&gt;
&lt;br /&gt;
 public void HandleInitialEvent()&lt;br /&gt;
 {&lt;br /&gt;
      iDvDevice.SetEnabled();&lt;br /&gt;
      iPublisher.TryPublishWidget(iDvDevice.iUdn(),&lt;br /&gt;
                              this,&lt;br /&gt;
                              out iPublishedWidget);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This method meets the requirements for R4.&lt;br /&gt;
&lt;br /&gt;
The call to TryPublishWidget returns an iPublishedWidget object. We use this object later to satisfy the requirements of R7.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The ordering of the calls to SetEnabled and TryPublishWidget is vitally important. You&lt;br /&gt;
must enable the device before you attempt to publish it. Your Widget will not be available to the&lt;br /&gt;
Nodes unless SetEnabled is called first. Nodes will not be able to access a published device&lt;br /&gt;
that has not been enabled.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
R3 requires that you set the Widget's properties before you enable and publish the device. We&lt;br /&gt;
discussed on page 14 how some properties can only be set after the Widget reports what their&lt;br /&gt;
state is. We do this in HandleRegisterEvent.&lt;br /&gt;
&lt;br /&gt;
We rely on the SimpleUPnP Protocol Module guaranteeing a call to HandleRegisterEvent first before HandleInitialEvent. This is informed by guarantees made by the Control Point stack that the calls will be made in that order.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
==== Removing a Widget ====&lt;br /&gt;
&lt;br /&gt;
Removing a Widget involves unpublishing it from the Node. The IPublishedWidget interface provides us with a method we can call to manage that for us:&lt;br /&gt;
&lt;br /&gt;
 public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
 {&lt;br /&gt;
     if (iPublishedWidget != null)&lt;br /&gt;
     { iPublishedWidget.Unpublish(); }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assuming that the Widget was successfully published earlier, it is removed from the Node's Local Widget Registry.&lt;br /&gt;
&lt;br /&gt;
We must also properly handle the resources we used to create and maintain the Widget object while it was published:&lt;br /&gt;
&lt;br /&gt;
      iProvider.Dispose();&lt;br /&gt;
      iDvDevice.Dispose();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The calls to Dispose are made regardless of the Widget's published state, ensuring that any created device and associated provider are properly disposed. This implementation satisfies R7.&lt;br /&gt;
&lt;br /&gt;
====Event handling ====&lt;br /&gt;
&lt;br /&gt;
We need a method to handle changes to the state of the Widget's properties.&lt;br /&gt;
&lt;br /&gt;
If the property changes at the Widget, it needs to pass the new state back to the Node so that it is kept up-to-date on the Widget's status. This is called an event. An example in the case of our Basic Light is someone manually switching the light from on to off. This is in contrast to actions, which are passed from the Node to the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Other examples of events involve no human interaction, such as a thermometer Widget updating its current temperature based on environmental changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Our Basic Light Widget has only one property that needs to be handled:&lt;br /&gt;
&lt;br /&gt;
 public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
 {&lt;br /&gt;
     if (aIndex == 0)&lt;br /&gt;
     {&lt;br /&gt;
         iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We use our instance of the provider to update the register on the Widget that is mapped to the On property. This in turn updates the Node with the new state of the Widget.&lt;br /&gt;
&lt;br /&gt;
This method provides implementations to satisfy two driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
* R3 is now completely satisfied, as we can now set the values of all the previously unknown properties here.&lt;br /&gt;
* R5 is also satisfied as this method allows us to update the Widget's status on the Node when a property is changed on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Not all protocols pass messages back to the Node in this manner. The way we have satisfied R3 and R5 here only applies to protocols and Widgets that support this behavior.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Widgets that do not use an eventing protocol need to have their properties set in the provider's constructor to satisfy R3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To satisfy R5, the over-ridden method SetOn in the provider must include the call to SetPropertyOn. Non-eventing protocols do not require a HandleRegisterEvent method.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Constructor ===&lt;br /&gt;
&lt;br /&gt;
The final requirement for the driver is the constructor so that new DiscoveredWidget objects can be created. &lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this area of code are:&lt;br /&gt;
&lt;br /&gt;
'''R1 Specifying the type of Widget the driver controls'''&lt;br /&gt;
&lt;br /&gt;
A driver must know which type of Widget that it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
==== Writing the code ====&lt;br /&gt;
&lt;br /&gt;
We begin by defining the variables we will use to store the objects used by the driver:&lt;br /&gt;
&lt;br /&gt;
 private readonly string iName;&lt;br /&gt;
 private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
 private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now write the constructor for the driver and assign the passed in parameters appropriately:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightDriver(string aName,&lt;br /&gt;
                IWidgetPublisher aPublisher,&lt;br /&gt;
                IDvDeviceFactory aDeviceFactory)&lt;br /&gt;
 {&lt;br /&gt;
     iWidgetPublisher = aPublisher;&lt;br /&gt;
     iName = aName;&lt;br /&gt;
     iDeviceFactory = aDeviceFactory;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally we need to provide the driver a way to publish the class of Widget it controls. This information is requested by the Discovery Module and is used to ensure the Node uses the correct driver when a new Widget appears.&lt;br /&gt;
&lt;br /&gt;
The implementation for this details will be different for each protocol. The SimpleUPnP protocol library provides a file that contains the SimpleUPnP definitions as integers. Each integer represents a particular class of identified Widget.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP implementation of that method is as follows:&lt;br /&gt;
&lt;br /&gt;
 public IEnumerable&amp;lt;uint&amp;gt; WidgetClasses&lt;br /&gt;
 {&lt;br /&gt;
 [[File:Warning.png]]        get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The body of this method is specifically written for the Widget class we are defining (in this case a binary light). This method completes the driver's requirements for R1.&lt;br /&gt;
&lt;br /&gt;
== Writing the SimpleUPnP Widget discovery method ==&lt;br /&gt;
&lt;br /&gt;
Every driver must contain a method which creates new objects to represent newly discovered Widgets.&lt;br /&gt;
The Discovery Module invokes this method to begin the process of creating the objects required to allow the Node to access the Widget. &lt;br /&gt;
&lt;br /&gt;
The name of this method is dictated by your chosen protocol's API. The SimpleUPnP protocol requires a method called WidgetDiscovered.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The method's name will not always be the same for each protocol. Your protocol's documentation will contain the details of what this method must be called.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This method and its implementation will meet the following driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
'''R2 Reacting to a discovered Widget on the network'''&lt;br /&gt;
&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
Our implementation of the WidgetDiscovered method will create a new DiscoveredWidget object and use the Protocol Module to listen for changes to the Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
The method uses the Protocol Module and two ways to identify the Widget. We must pass these in as&lt;br /&gt;
parameters:&lt;br /&gt;
&lt;br /&gt;
 public void WidgetDiscovered(string aWidgetUdn,&lt;br /&gt;
                              uint aWidgetClass,&lt;br /&gt;
                              ISimpleUpnpWidget&lt;br /&gt;
                                  aSimpleUpnpWidget)&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
Every Widget that uses this driver must be uniquely identifiable:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]    string newUdn = aWidgetUdn;&lt;br /&gt;
&lt;br /&gt;
Each new Widget is represented by a DiscoveredWidget object. Create the new DiscoveredWidget and pass in the required parameters we created earlier:&lt;br /&gt;
&lt;br /&gt;
     DiscoveredWidget discoveredWidget =&lt;br /&gt;
                 new DiscoveredWidget(iDeviceFactory,&lt;br /&gt;
                                      newUdn,&lt;br /&gt;
  &lt;br /&gt;
 [[File:Warning.png]]                                    aSimpleUpnpWidget,&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Registering the callbacks ===&lt;br /&gt;
&lt;br /&gt;
Finally, we ask the Widget's protocol interface to listen for calls to the handler methods we defined earlier in DiscoveredWidget. We do this by registering those methods as callbacks for the Protocol Module&lt;br /&gt;
to listen for:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                        discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                        discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                        discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You have now met 100% of the driver responsibility requirements and have a working driver to use with your SimpleUPnP Widget.&lt;br /&gt;
&lt;br /&gt;
= Appendix A. Sample XML =&lt;br /&gt;
&lt;br /&gt;
== Binary Light.xml ==&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
  &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
  &amp;lt;version&amp;gt;&lt;br /&gt;
   &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
   &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/version&amp;gt;&lt;br /&gt;
  &amp;lt;propertylist&amp;gt;&lt;br /&gt;
   &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
       illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
   &amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix B. Sample Provider = &lt;br /&gt;
&lt;br /&gt;
== DvWidgetOpenhomeOrgBasicLight1.cs ==&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Runtime.InteropServices;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Core;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Utils.Binary;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
 {&lt;br /&gt;
    public interface IDvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
        IDisposable&lt;br /&gt;
    {&lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous value&lt;br /&gt;
        /// &amp;lt;/returns&amp;gt;&lt;br /&gt;
        bool SetPropertyOn(bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;Property's value will be copied&lt;br /&gt;
        /// here&amp;lt;/param&amp;gt;&lt;br /&gt;
        bool PropertyOn();&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt; summary&amp;gt;&lt;br /&gt;
    /// Provider for the openhome.org:BinaryLight:1 UPnP service&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public abstract class DvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
               DvProvider,&lt;br /&gt;
               IDisposable,&lt;br /&gt;
               IDvProviderOpenhomeOrgBinaryLight1&lt;br /&gt;
    {&lt;br /&gt;
        private GCHandle iGch;&lt;br /&gt;
        private PropertyBool iPropertyOn;&lt;br /&gt;
        private PropertyUint iPropertyPrimarySeq;&lt;br /&gt;
        private PropertyUint iPropertySecondarySeq;&lt;br /&gt;
        private ActionDelegate iDelegateSetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetPrimaryProperty;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Constructor&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aDevice&amp;quot;&amp;gt;Device which owns this&lt;br /&gt;
        /// provider&amp;lt;/param&amp;gt;&lt;br /&gt;
        protected DvProviderOpenhomeOrgBinaryLight1(DvDevice aDevice)&lt;br /&gt;
            : base(aDevice, &amp;quot;openhome.org&amp;quot;, &amp;quot;GenericWidget&amp;quot;, 1)&lt;br /&gt;
        {&lt;br /&gt;
            iGch = GCHandle.Alloc(this);&lt;br /&gt;
            List&amp;lt;String&amp;gt; allowedValues = new List&amp;lt;String&amp;gt;();&lt;br /&gt;
            iPropertyOn = new PropertyBool(new ParameterBool(&amp;quot;On&amp;quot;));&lt;br /&gt;
            iPropertyPrimarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;PrimarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertyPrimarySeq);&lt;br /&gt;
            iPropertySecondarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;SecondarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertySecondarySeq);&lt;br /&gt;
            SetPropertyUint(iPropertyPrimarySeq, 0);&lt;br /&gt;
            SetPropertyUint(iPropertySecondarySeq, 0);&lt;br /&gt;
  &lt;br /&gt;
            Zapp.Core.Action action = new Zapp.Core.Action&lt;br /&gt;
                (&amp;quot;SetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;FireAndForget&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddInputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateSetProperty = new ActionDelegate(DoSetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateSetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateGetProperty = new ActionDelegate(DoGetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetPrimaryProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                 (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;integer&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;boolean&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;string&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;binary&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Type&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;readWrite&amp;quot;);allowedValues.Add&lt;br /&gt;
                (&amp;quot;readOnly&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;writeOnly&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString(&amp;quot;Access&amp;quot;,&lt;br /&gt;
                allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            iDelegateGetPrimaryProperty = new&lt;br /&gt;
            ActionDelegate(DoGetPrimaryProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetPrimaryProperty,&lt;br /&gt;
            GCHandle.ToIntPtr(iGch));&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous&lt;br /&gt;
        /// value&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool SetPropertyOn(bool aValue)&lt;br /&gt;
        {&lt;br /&gt;
            if (iPropertyOn.SetValue(aValue))&lt;br /&gt;
            {&lt;br /&gt;
                lock (iPropertyPrimarySeq)&lt;br /&gt;
                {&lt;br /&gt;
                    SetPropertyUint(iPropertyPrimarySeq,&lt;br /&gt;
                        iPropertyPrimarySeq.Value() + 1);&lt;br /&gt;
                } return true;&lt;br /&gt;
            } return false;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;The value of the property&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool PropertyOn()&lt;br /&gt;
        {&lt;br /&gt;
            return iPropertyOn.Value();&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the On property.&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aVersion&amp;quot;&amp;gt;Version of the service being&lt;br /&gt;
        /// requested (will be &amp;lt;= the version advertised)&amp;lt;/param&amp;gt; &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the On property.&lt;br /&gt;
        /// &amp;lt;/param&amp;gt;&lt;br /&gt;
        protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        private static int DoSetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                byte[] valBin = invocation.ReadBinary(&amp;quot;Value&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                switch (name)&lt;br /&gt;
                {&lt;br /&gt;
                    case &amp;quot;On&amp;quot;:&lt;br /&gt;
                        self.SetOn(aVersion, Converter.&lt;br /&gt;
                            BinaryToBoolean(valBin));&lt;br /&gt;
                        break;&lt;br /&gt;
                    default:&lt;br /&gt;
                        throw new ActionError();&lt;br /&gt;
                }&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
                invocation.WriteEnd();&lt;br /&gt;
            }&lt;br /&gt;
            catch (ActionError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
            catch (PropertyUpdateError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
        return 0;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        private static int DoGetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
            switch (name)&lt;br /&gt;
            {&lt;br /&gt;
                case &amp;quot;On&amp;quot;:&lt;br /&gt;
                invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                    Converter.BooleanToBinary(self.iPropertyOn.&lt;br /&gt;
                        Value()));&lt;br /&gt;
                break;&lt;br /&gt;
                default:&lt;br /&gt;
                throw new ActionError();&lt;br /&gt;
            }&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    private static int DoGetPrimaryProperty(IntPtr aPtr,&lt;br /&gt;
                    IntPtr aInvocation,&lt;br /&gt;
                    uint aVersion)&lt;br /&gt;
    {&lt;br /&gt;
        GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
        DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
            (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
        DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
  &lt;br /&gt;
        try&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReadStart();&lt;br /&gt;
            invocation.ReadEnd();&lt;br /&gt;
            invocation.WriteStart();&lt;br /&gt;
            invocation.WriteString(&amp;quot;Name&amp;quot;, &amp;quot;On&amp;quot;);&lt;br /&gt;
            invocation.WriteString(&amp;quot;Type&amp;quot;, &amp;quot;boolean&amp;quot;);&lt;br /&gt;
            invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                Converter.BooleanToBinary(self.iPropertyOn.Value()));&lt;br /&gt;
            invocation.WriteString(&amp;quot;Access&amp;quot;, &amp;quot;readWrite&amp;quot;);&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt;summary&amp;gt;&lt;br /&gt;
    /// Must be called for each class instance. Must be called before&lt;br /&gt;
    /// Core.Library.Close().&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public void Dispose()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
        GC.SuppressFinalize(this);&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
    ~DvProviderOpenhomeOrgBinaryLight1()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
        private void DoDispose()&lt;br /&gt;
        {&lt;br /&gt;
            lock (this)&lt;br /&gt;
            {&lt;br /&gt;
                if (iHandle == IntPtr.Zero)&lt;br /&gt;
            {&lt;br /&gt;
                    return;&lt;br /&gt;
            }&lt;br /&gt;
            DisposeProvider();&lt;br /&gt;
            iPropertyOn.Dispose();&lt;br /&gt;
            iHandle = IntPtr.Zero;&lt;br /&gt;
            }&lt;br /&gt;
            iGch.Free();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix C. Sample Driver = &lt;br /&gt;
&lt;br /&gt;
== BasicLightDriver.cs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.hWidget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
     class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
     {&lt;br /&gt;
         private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
         public BinaryLightProvider(DvDevice aDevice, &lt;br /&gt;
             ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol = aProtocol;&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
     {&lt;br /&gt;
         private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
         {&lt;br /&gt;
             private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
             private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
             private readonly ISimpleUpnpWidget iProtocol; &lt;br /&gt;
 &lt;br /&gt;
             private readonly BinaryLightProvider iProvider;&lt;br /&gt;
             private readonly DvDevice iDvDevice;&lt;br /&gt;
             private IPublishedWidget iPublishedWidget; &lt;br /&gt;
 &lt;br /&gt;
             public DvDevice DvDevice&lt;br /&gt;
             {&lt;br /&gt;
                 get { return iDvDevice; }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             public string WidgetClass&lt;br /&gt;
             {&lt;br /&gt;
                 get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public DiscoveredWidget(&lt;br /&gt;
                 IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                 string aUdn,&lt;br /&gt;
                 ISimpleUpnpWidget aProxy,&lt;br /&gt;
                 IWidgetPublisher aPublisher)&lt;br /&gt;
             {&lt;br /&gt;
                 iDeviceFactory = aDeviceFactory;&lt;br /&gt;
                 iProtocol = aProtocol;&lt;br /&gt;
 &lt;br /&gt;
                 iPublisher = aPublisher;&lt;br /&gt;
                 iDvDevice = iDeviceFactory.CreateDevice(aUdn);  &lt;br /&gt;
                 iProvider = new BinaryLightProvider(iDvDevice, &lt;br /&gt;
                                                     iProtocol);&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             public void HandleInitialEvent()&lt;br /&gt;
             {&lt;br /&gt;
                 iDvDevice.SetEnabled();&lt;br /&gt;
                 iPublisher.TryPublishWidget(iDvDevice.iUdn(), this,&lt;br /&gt;
                     out iPublishedWidget);&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
             {&lt;br /&gt;
                 if (iPublishedWidget != null)&lt;br /&gt;
                 {&lt;br /&gt;
                     iPublishedWidget.Unpublish();&lt;br /&gt;
                 } &lt;br /&gt;
                 iProvider.Dispose();&lt;br /&gt;
                 iDvDevice.Dispose();&lt;br /&gt;
             }  &lt;br /&gt;
 &lt;br /&gt;
             public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
             {&lt;br /&gt;
                 if (aIndex == 0)&lt;br /&gt;
                 {&lt;br /&gt;
                     iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         private readonly string iName;&lt;br /&gt;
         private readonly IDvDeviceFactory aDeviceFactory;&lt;br /&gt;
         private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
         &lt;br /&gt;
         public BinaryLightDriver(&lt;br /&gt;
             string aName,&lt;br /&gt;
             IWidgetPublisher aPublisher,&lt;br /&gt;
             iDeviceFactory aDeviceFactory)&lt;br /&gt;
         {&lt;br /&gt;
             iWidgetPublisher = aPublisher;&lt;br /&gt;
             iName = aName;&lt;br /&gt;
             iDeviceFactory = aDeviceFactory;&lt;br /&gt;
         } &lt;br /&gt;
 &lt;br /&gt;
         public IEnumerable&amp;amp;lt;uint&amp;amp;gt; WidgetClasses&lt;br /&gt;
         {&lt;br /&gt;
             get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         public void WidgetDiscovered(&lt;br /&gt;
             string aWidgetUdn,&lt;br /&gt;
             uint aWidgetClass,&lt;br /&gt;
             ISimpleUpnpWidget aSimpleUpnpWidget)&lt;br /&gt;
         {&lt;br /&gt;
             string newUdn = aWidgetUdn;&lt;br /&gt;
             DiscoveredWidget discoveredWidget = new DiscoveredWidget&lt;br /&gt;
                 (iDeviceFactory,&lt;br /&gt;
                  newUdn,&lt;br /&gt;
                  aSimpleUpnpWidget,&lt;br /&gt;
                  iWidgetPublisher);&lt;br /&gt;
 &lt;br /&gt;
             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                 discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                 discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                 discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary = &lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in OpenHome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by OpenHome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh - A collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs on ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The OpenHome Operating System. Core software for OpenHome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. &lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. A typical Widget supports only one protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Driver_Development</id>
		<title>OhWidget Driver Development</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Driver_Development"/>
				<updated>2012-03-01T15:26:36Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Registering the callbacks */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for developers using the OpenHome SDK to integrate a Widget into an OpenHome system. Each Widget must have its own driver to allow it to communicate with the OpenHome Nodes. &lt;br /&gt;
&lt;br /&gt;
To help you write your driver, this document provides high level descriptions of the core responsibilities of a Widget driver and gives a detailed walk-through using example code.&lt;br /&gt;
&lt;br /&gt;
Full versions of each file used in the development of the example driver are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin development of your Widget driver you must be in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* your Widget Service XML that describes the properties on your Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document does not contain advice on how to write Widget Service XML. Refer to the OpenHome Widget Service XML definition document for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK&lt;br /&gt;
* your chosen communication protocol's API&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The protocol you choose for your Widgets must be the same protocol used on your choice of Node.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document focuses on the development of the Widget driver. Details about the communications protocol used are beyond the scope of this document. This document assumes you are familiar with your chosen protocol's code libraries and are able to use them in the driver code you write.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Related Documents ==&lt;br /&gt;
&lt;br /&gt;
The following related OpenHome documentation may be of interest to you:&lt;br /&gt;
&lt;br /&gt;
* [[ohWidget Technical Overview|ohWidget Technical Overview]]&lt;br /&gt;
* [[OpenHome Widget Service XML definition|OpenHome Widget Service XML definition]]&lt;br /&gt;
* [http://www.openhome.org/releases/ohNet_DeviceStack.pdf  OpenHome ohNet Device Stack]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
None of the related documents listed above is mandatory reading for Widget driver development.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
== Widget Service XML ==&lt;br /&gt;
OpenHome Widget driver writing relies heavily on the use of code generated from a single source — the Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
The service and actions your Widget provides are represented in code in a file called a Provider. The Provider is automatically generated from the Widget Service XML and produces an abstract class for you to inherit when you write your concrete class driver.&lt;br /&gt;
&lt;br /&gt;
To aid in the explanation of how the Provider is created and put to use we will follow the development of&lt;br /&gt;
a driver for a simple light Widget; taking the defined Widget Service XML and stepping through how it is used to generate the other files. Examples of code are used throughout this document to show you how each one is created and used in an OpenHome system. &lt;br /&gt;
&lt;br /&gt;
It is essential that you start with a well-formed Widget Service XML, conforming to the schema defined&lt;br /&gt;
in the WidgetService.xsd. The following diagram shows the significance of the Widget Service XML in&lt;br /&gt;
relation to the generated files you will use when writing your driver:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarchy, highlighting the areas specifically used in driver development]]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* The grayed-out files are not relevant to Widget driver development but can also be generated from the Widget Service XML.&lt;br /&gt;
* The Provider is generated in C#, meaning your driver must be written in C# as well. The use of managed code is mandatory for driver writing in the OpenHome framework.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Code sample used in this document ==&lt;br /&gt;
&lt;br /&gt;
Our examples in this document use a Widget Service XML definition for a light Widget called&lt;br /&gt;
BasicLight.xml.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Full versions of all the example files used in this document are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We will see how the Provider is generated from this XML and how it is used to aid the driver writing process. The examples also show how your chosen communication protocol should be used in the body of the driver code.&lt;br /&gt;
&lt;br /&gt;
Implementation details of specific protocols you choose to use are beyond the scope of this document. However, the samples used in this document show the use of the SimpleUPnP protocol to aid you in your development process.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol during the early stages of the OpenHome project. It is included in the OpenHome SDK and can be used as a public resource. &lt;br /&gt;
&lt;br /&gt;
The use of SimpleUPnP in the example files and the code snippets within the following sections is highlighted by the [[File:Warning.png]] icon. The lines of code marked by [[File:Warning.png]] must be changed to code from your chosen communication protocol's library. SimpleUPnP is left in to help you understand how a protocol is used in a working example.&lt;br /&gt;
&lt;br /&gt;
The sample code provided attempts to show best-practice coding standards. There are several sections of code that have a mandatory layout or that call specifically named methods and functions. These areas of the code are highlighted where required. &lt;br /&gt;
&lt;br /&gt;
Where the examples do not explicitly state that the code shown is mandatory, you are free to implement it in a different way according to your own coding style and practices.&lt;br /&gt;
&lt;br /&gt;
= Driver responsibilities = &lt;br /&gt;
&lt;br /&gt;
== Driver responsibilities ==&lt;br /&gt;
&lt;br /&gt;
An OpenHome Widget driver has several responsibilities which must be met before it can be used on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
These responsibilities are listed R1 to R7 and are defined here, explaining what each one must do. &lt;br /&gt;
&lt;br /&gt;
=== R1 Specifying the type of Widget the driver controls ===&lt;br /&gt;
A driver must know which type of Widget it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
=== R2 Reacting to a discovered Widget on the network ===&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== R3 Setting the initial values for the Widget's properties ===&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
=== R4 Publishing discovered Widgets in the Local Widget Registry on the Node ===&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object.&lt;br /&gt;
&lt;br /&gt;
=== R5 Reacting to an event reported from the Widget ===&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
=== R6 Reacting to actions sent to the Widget ===&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== R7 Reacting to a Widget's departure ===&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no&lt;br /&gt;
longer available.&lt;br /&gt;
&lt;br /&gt;
The sections of example code that follow show you how to write a driver from beginning to end. The accompanying text explaining the example code highlights when a responsibility, or part of a responsibility, has been met.&lt;br /&gt;
&lt;br /&gt;
= Driver Architecture = &lt;br /&gt;
&lt;br /&gt;
== Driver Architecture ==&lt;br /&gt;
&lt;br /&gt;
Drivers are installed on the Node and used when the Node needs to communicate with the Widget. Drivers&lt;br /&gt;
use several objects to communicate with Widgets over the Widget's lifetime. Figure 2 shows the objects&lt;br /&gt;
used by the driver and how the responsibilities listed above relate to each one:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture.png|800px|thumb|center|Figure 2: The architecture of a driver, showing the driver's relationship to the objects used to communicate with a Widget. Lines between objects show message flow.]]&lt;br /&gt;
&lt;br /&gt;
The objects contained in the dotted boundary must appear in the code you write to define your driver. The Driver, Provider and IWidgetRegistryEntry objects are all contained in the same driver file. We begin discussing this on page 12. &lt;br /&gt;
&lt;br /&gt;
The other objects are provided by the OpenHome SDK or as installed components on the Node.&lt;br /&gt;
&lt;br /&gt;
The Discovery Module informs the driver of the presence of an available Widget.&lt;br /&gt;
&lt;br /&gt;
Each Node has a Protocol Module which contains the protocol's API. Widgets can communicate with OpenHome Nodes using any one of the set of communications protocols the Node supports. The driver uses your chosen protocol's Protocol Module to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
Both the Protocol Module and the Discovery Module are installed on the Node. When you write your&lt;br /&gt;
driver you will use your Protocol Module to allow the driver to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
IWidgetPublisher, IPublishedWidget and DvDevice are objects provided in the OpenHome&lt;br /&gt;
API. You can read about them in the APIs.&lt;br /&gt;
&lt;br /&gt;
= Generating the Provider = &lt;br /&gt;
&lt;br /&gt;
== Generating the Provider ==&lt;br /&gt;
&lt;br /&gt;
You must generate your provider before you can begin writing your Widget driver. You use your provider as a guide to implement the functions your Widget needs to set the values of its properties.&lt;br /&gt;
&lt;br /&gt;
The current provider generation process is a manual one involving the use of a text transform tool.&lt;br /&gt;
&lt;br /&gt;
Speak to your OpenHome contact who will help you generate your provider.&lt;br /&gt;
&lt;br /&gt;
Future releases of the OpenHome SDK will include a tool to help you generate the provider.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
You must be in possession of:&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK, unpacked on your computer&lt;br /&gt;
* your Widget Service XML file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Writing a SimpleUPnP driver = &lt;br /&gt;
&lt;br /&gt;
== Introduction to the SimpleUPnP protocol ==&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol used to control emulated Widgets over a custom UPnP service.&lt;br /&gt;
&lt;br /&gt;
This chapter shows how a driver is written using the SimpleUPnP communications protocol. The aim is to show the code using as generic a protocol as possible so that you can see where your own protocol specific code needs to go.&lt;br /&gt;
&lt;br /&gt;
The use of code specific to the SimpleUPnP implementation is highlighted by the use of the [[File:Warning.png]] icon. The lines of code are marked by this icon to make it easier for you to see where the protocol-specific code must go and what parts of the code are generic.&lt;br /&gt;
&lt;br /&gt;
=== Register model ===&lt;br /&gt;
&lt;br /&gt;
SimpleUPnP is modeled on 8 physical registers available on the Widget. Each register is 32-bits wide. They are indexed from 0 to 7 and the last register (register 7) is reserved for storing the Widget's class.&lt;br /&gt;
&lt;br /&gt;
This detail is used by the Protocol Module on the Node to determine which driver is needed to run the new Widget when it has been discovered.&lt;br /&gt;
&lt;br /&gt;
The remaining 7 registers (registers 0 to 6) are free for Widget engineers to assign to the Widget's functions.&lt;br /&gt;
&lt;br /&gt;
Registers 0, 1, 2 and 3 are available as read/write registers. Registers 4, 5 and 6 are readonly registers.&lt;br /&gt;
&lt;br /&gt;
Only the emulated hardware (running on the Node) can change the values held in registers 4, 5 and 6.&lt;br /&gt;
&lt;br /&gt;
=== Register use in drivers ===&lt;br /&gt;
&lt;br /&gt;
In the example that follows we have a Basic Light Widget with a very simple function: it can be turned on and turned off. The on/off value is stored in register 0, with values 0=OFF and 1=ON. Register 0 is a read/write register. This means we can change the value stored there using messages passed to the Widget from the Node, and by reacting to physical interactions at the Widget (such as someone manually switching the light on or off). &lt;br /&gt;
&lt;br /&gt;
The mapping of registers to properties on the Widget is decided by the engineers who manufacture the device. You must be provided with the mapping before you begin developing your driver.&lt;br /&gt;
&lt;br /&gt;
== Starting the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-BoxHighlight.png|800px|thumb|center|Figure 3 The driver architecture highlighting the Widget driver and its component parts.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When you have generated the abstract provider you can put it to use in the Widget driver. A Widget driver&lt;br /&gt;
has three distinct components:&lt;br /&gt;
&lt;br /&gt;
* an implementation of your abstract provider&lt;br /&gt;
* a definition of the Widget driver&lt;br /&gt;
* an implementation of the IWidgetRegistryEntry interface&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must manually write the code for your Widget driver. The differences in implementation of Widget properties and communication protocols means that the driver code cannot be autogenerated.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This section takes you through how to write a Widget driver by implementing the auto-generated provider,&lt;br /&gt;
starting from a new blank file and finishing with a working driver for the Basic Light Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
No assumptions have been made about the type of editor you use to write your code. Shortcuts&lt;br /&gt;
or macros that you use as standard will not appear in the instructions below. A full example&lt;br /&gt;
BinaryLightDriver.cs is available to review in Appendix C.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a new C# file in your IDE. Ensure the following libraries are used:&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 [[File:Warning.png]]using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 namespace OpenHome.Widget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must use the libraries listed above for this specific example.&lt;br /&gt;
&lt;br /&gt;
In general, drivers require the following libraries:&lt;br /&gt;
* System*&lt;br /&gt;
* System.Collections.Generic*&lt;br /&gt;
* OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
&lt;br /&gt;
Your driver will fail to compile if you miss any of these listed libraries. Libraries marked * are typically added by default by most modern IDEs. &lt;br /&gt;
&lt;br /&gt;
The OpenHome.Widget.Protocols.SimpleUpnp library is required only in this SimpleUPnP example. Drivers using a different protocol will use their own protocol library.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Implementing the provider ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-ProviderHighlight.png|800px|thumb|center|Figure 4 The driver architecture highlighting the Provider's place]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You use your auto-generated abstract provider by writing an implementation of it in the driver file. Responsibilities met by implementing your auto-generated provider are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R6 Reacting to actions sent to the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
Begin by creating a new class. It will subclass the abstract auto-generated provider:&lt;br /&gt;
&lt;br /&gt;
 class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
The Protocol Module will provide an API for the Provider to use to communicate with the Widget. In&lt;br /&gt;
SimpleUPnP we are provided with an interface called ISimpleUpnpWidget. The provider is supplied&lt;br /&gt;
with the required instance of the interface by the Discovery Module on the Node.&lt;br /&gt;
&lt;br /&gt;
The mechanisms for registering providers with specific Protocol Modules, and for the way the module gives each provider its required interface are covered later when writing the discovery method.&lt;br /&gt;
&lt;br /&gt;
For now, we need to give the Provider a place to store the interface that it will later use to communicate&lt;br /&gt;
with the Widget:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]] private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
&lt;br /&gt;
The interface from the Protocol Module is passed in as a parameter in the Provider's constructor and then&lt;br /&gt;
assigned to the variable we just created:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightProvider(DvDevice aDevice,&lt;br /&gt;
 [[File:Warning.png]]         ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
 {&lt;br /&gt;
       iProtocol = aProtocol;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
To satisfy R3 we would normally set the Widget's properties here, giving them an initial value.&lt;br /&gt;
However, in this specific example we cannot set the value of Basic Light's only property because&lt;br /&gt;
we will never know, in advance, what the state of the light will be (either on or off) when we&lt;br /&gt;
create the DiscoveredWidget.&lt;br /&gt;
&lt;br /&gt;
When you cannot set the properties ahead of time, and you are using an eventing protocol like SimpleUPnP, you can instead set them in the HandleRegisterEvent method in the driver class. This also satisfies the requirements for R3. You must set the Widget's properties before you enable it using SetEnabled(). &lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The abstract provider includes an abstract method called SetOn. This method is invoked by the Node when passing a message to the Widget, specifically to set the on property of the Widget to either 0 or 1. The implementation of this method will meet the requirements for R6.&lt;br /&gt;
&lt;br /&gt;
We must override this method and provide the protocol module a way of passing a message on to the Widget to perform the required action, in this case turn the light on or off:&lt;br /&gt;
&lt;br /&gt;
          protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
          {&lt;br /&gt;
     [[File:Warning.png]]        iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
In this example the Basic Light's SetOn property (the boolean property that controls whether the light is&lt;br /&gt;
on or off) is represented in the physical Widget by the register that has an index of 0.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* This method is an example of an action on a Widget. Actions are messages sent from the Node to the Widget. We will see later how to handle events that need to be passed back from the Widget&lt;br /&gt;
to the Node.&lt;br /&gt;
* Your own Widget will likely provide more than a single property. Your auto-generated provider will contain one abstract method to represent each writable property. Read-only properties are not provided an abstract method.&lt;br /&gt;
&lt;br /&gt;
You must implement each abstract method in your driver to ensure the relevant property on&lt;br /&gt;
the Widget can be set.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We have now finished implementing the provider. The next step is to implement the driver.&lt;br /&gt;
&lt;br /&gt;
== Implementing the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-DriverHighlight.png|800px|thumb|center|Figure 4: The driver architecture highlighting the implemented driver's place.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The code for your Widget driver must provide an implementation of the IWidgetRegistryInterface,&lt;br /&gt;
including the following tasks:&lt;br /&gt;
&lt;br /&gt;
* methods to expose identifying details about the Widget for the Node to access&lt;br /&gt;
* providing methods to handle events reported by the Widget&lt;br /&gt;
&lt;br /&gt;
The driver is implemented as a public class within the same file as the provider code. Each driver must use the interface for the protocol you are using. For the SimpleUPnP protocol the interface is ISimple-UpnpWidgetDriver.&lt;br /&gt;
&lt;br /&gt;
=== Writing code ===&lt;br /&gt;
&lt;br /&gt;
Create your new driver class and subclass the ISimpleUpnpWidgetDriver interface:&lt;br /&gt;
&lt;br /&gt;
 public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Implementing IWidgetRegistryEntry ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry is the interface you use to represent physical Widgets. It is implemented as a subclass of your driver class. We are going to implement this interface in a class called '''DiscoveredWidget'''.&lt;br /&gt;
&lt;br /&gt;
Let's return to our driver architecture diagram for a moment:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-IRegistryEntryHighlight.png|800px|thumb|center|Figure 5 The driver architecture highlighting the IWidgetRegistryEntry object you will now implement]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry uses several other objects to help create it and respond to messages sent to and from it. These objects will be created in our implementation of DiscoveredWidget. &lt;br /&gt;
&lt;br /&gt;
When successfully created and published, the DiscoveredWidget objects are stored in a list on the Node called the Local Widget Registry. The Local Widget Registry is used by Nodes to maintain contact with the Widgets they control.&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry is shown at the top of Figure 5, marked plainly as (Registry). The path to the Local Widget Registry goes through several layers of Node architecture which are not relevant to Widget driver writing, so are not shown in the diagrams.&lt;br /&gt;
&lt;br /&gt;
==== Writing code ====&lt;br /&gt;
&lt;br /&gt;
Start by subclassing the IWidgetRegistryEntry interface in your new class:&lt;br /&gt;
&lt;br /&gt;
      private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
      {&lt;br /&gt;
&lt;br /&gt;
A DiscoveredWidget must provide the driver with the objects required to present the Widget and its&lt;br /&gt;
properties to the Node:&lt;br /&gt;
&lt;br /&gt;
           private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
           private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
           private readonly ISimpleUpnpWidget iProtocol;&lt;br /&gt;
           private readonly BinaryLightProvider iProvider;&lt;br /&gt;
           private readonly DvDevice iDvDevice;&lt;br /&gt;
           private IPublishedWidget iPublishedWidget;&lt;br /&gt;
&lt;br /&gt;
Each of the attributes in the example above are defined as follows:&lt;br /&gt;
&lt;br /&gt;
iDeviceFactory — used by the driver to create a single instance of DvDevice to represent a single Widget&lt;br /&gt;
&lt;br /&gt;
iPublisher — used by the driver to publish the Widget to the Node&lt;br /&gt;
&lt;br /&gt;
iProtocol — the object used by the Widget to communicate with the Protocol Module on the Node&lt;br /&gt;
&lt;br /&gt;
iProvider — an instantiated provider of the type you defined earlier&lt;br /&gt;
&lt;br /&gt;
iDvDevice — a representation of a Widget to which the provider is attached, created using iDevice-Factory above&lt;br /&gt;
&lt;br /&gt;
iPublishedWidget — used to contain the returned object from a successful publishing of the Widget&lt;br /&gt;
If we look again at the driver architecture diagram, we ca highlight the objects we've just defined:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-Highlight.png|800px|thumb|center|Figure 6: The driver architecture highlighting the objects used by the IWidgetRegistryEntry implementation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The DeviceFactory, defined above in the member variable iDeviceFactory, is used to create new DvDevice objects. The DeviceFactory is only ever used to do this once. It is not shown in the driver architecture diagrams due to its minimal role in the operation of a driver, but it would normally appear between the IWidgetRegistryEntry and DvDevice objects.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
A driver requires methods to expose identifying details about the Widget. We must provide access to two of the attributes we just defined above:&lt;br /&gt;
&lt;br /&gt;
 public DvDevice DvDevice&lt;br /&gt;
 {&lt;br /&gt;
     get { return iDvDevice; }&lt;br /&gt;
 }&lt;br /&gt;
 public string WidgetClass&lt;br /&gt;
 {&lt;br /&gt;
     get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The WidgetClass string is formed using a combination of the vendor name and the Widget's name in the&lt;br /&gt;
format:&lt;br /&gt;
&lt;br /&gt;
 [vendor_domain]:[widget_name]&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry can now query both the DvDevice object representing the Widget, and the specific class of Widget this driver represents. The other member variables we defined do not need their own accessor methods.&lt;br /&gt;
&lt;br /&gt;
Now we must write a constructor for DiscoveredWidget and assign the parameters accordingly: &lt;br /&gt;
&lt;br /&gt;
 public DiscoveredWidget(IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                            string aUdn,&lt;br /&gt;
                            ISimpleUpnpWidget aProxy,&lt;br /&gt;
                            IWidgetPublisher aPublisher)&lt;br /&gt;
 {&lt;br /&gt;
      iDeviceFactory = aDeviceFactory;&lt;br /&gt;
      iProtocol = aProtocol;&lt;br /&gt;
      iPublisher = aPublisher;&lt;br /&gt;
      iDvDevice = iDeviceFactory.CreateDevice(aUdn);&lt;br /&gt;
      iProvider = new BinaryLightProvider(iDvDevice,&lt;br /&gt;
      iProtocol);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Event handling ===&lt;br /&gt;
&lt;br /&gt;
A Widget's state can change in one of three significant ways:&lt;br /&gt;
&lt;br /&gt;
* when the Widget needs to be published on the Node&lt;br /&gt;
* when the Widget disappears from the network (by losing power or similar)&lt;br /&gt;
* when a property's state changes and must be updated to a new value&lt;br /&gt;
&lt;br /&gt;
We now need methods to handle these changes.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The methods we define here will be used as callbacks, rather than invoked as method calls. We define the methods here first and then use them later on. We will use the Protocol Module to listen for changes in the Widget's state and register these methods as callbacks there. See Writing the SimpleUPnP Widget discovery method for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this section of the driver are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R4 Publishing discovered Widgets in the Local Widget Registry on the Node'''&lt;br /&gt;
&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object. &lt;br /&gt;
&lt;br /&gt;
'''R5 Reacting to an event reported from the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
'''R7 Reacting to a Widget's departure'''&lt;br /&gt;
&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no longer available.&lt;br /&gt;
&lt;br /&gt;
==== Enabling and publishing a discovered Widget ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first method initializes the Widget by enabling the device and then using the IWidgetPublisher&lt;br /&gt;
to make it available on the Node:&lt;br /&gt;
&lt;br /&gt;
 public void HandleInitialEvent()&lt;br /&gt;
 {&lt;br /&gt;
      iDvDevice.SetEnabled();&lt;br /&gt;
      iPublisher.TryPublishWidget(iDvDevice.iUdn(),&lt;br /&gt;
                              this,&lt;br /&gt;
                              out iPublishedWidget);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This method meets the requirements for R4.&lt;br /&gt;
&lt;br /&gt;
The call to TryPublishWidget returns an iPublishedWidget object. We use this object later to satisfy the requirements of R7.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The ordering of the calls to SetEnabled and TryPublishWidget is vitally important. You&lt;br /&gt;
must enable the device before you attempt to publish it. Your Widget will not be available to the&lt;br /&gt;
Nodes unless SetEnabled is called first. Nodes will not be able to access a published device&lt;br /&gt;
that has not been enabled.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
R3 requires that you set the Widget's properties before you enable and publish the device. We&lt;br /&gt;
discussed on page 14 how some properties can only be set after the Widget reports what their&lt;br /&gt;
state is. We do this in HandleRegisterEvent.&lt;br /&gt;
&lt;br /&gt;
We rely on the SimpleUPnP Protocol Module guaranteeing a call to HandleRegisterEvent first before HandleInitialEvent. This is informed by guarantees made by the Control Point stack that the calls will be made in that order.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
==== Removing a Widget ====&lt;br /&gt;
&lt;br /&gt;
Removing a Widget involves unpublishing it from the Node. The IPublishedWidget interface provides us with a method we can call to manage that for us:&lt;br /&gt;
&lt;br /&gt;
 public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
 {&lt;br /&gt;
     if (iPublishedWidget != null)&lt;br /&gt;
     { iPublishedWidget.Unpublish(); }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assuming that the Widget was successfully published earlier, it is removed from the Node's Local Widget Registry.&lt;br /&gt;
&lt;br /&gt;
We must also properly handle the resources we used to create and maintain the Widget object while it was published:&lt;br /&gt;
&lt;br /&gt;
      iProvider.Dispose();&lt;br /&gt;
      iDvDevice.Dispose();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The calls to Dispose are made regardless of the Widget's published state, ensuring that any created device and associated provider are properly disposed. This implementation satisfies R7.&lt;br /&gt;
&lt;br /&gt;
====Event handling ====&lt;br /&gt;
&lt;br /&gt;
We need a method to handle changes to the state of the Widget's properties.&lt;br /&gt;
&lt;br /&gt;
If the property changes at the Widget, it needs to pass the new state back to the Node so that it is kept up-to-date on the Widget's status. This is called an event. An example in the case of our Basic Light is someone manually switching the light from on to off. This is in contrast to actions, which are passed from the Node to the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Other examples of events involve no human interaction, such as a thermometer Widget updating its current temperature based on environmental changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Our Basic Light Widget has only one property that needs to be handled:&lt;br /&gt;
&lt;br /&gt;
 public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
 {&lt;br /&gt;
     if (aIndex == 0)&lt;br /&gt;
     {&lt;br /&gt;
         iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We use our instance of the provider to update the register on the Widget that is mapped to the On property. This in turn updates the Node with the new state of the Widget.&lt;br /&gt;
&lt;br /&gt;
This method provides implementations to satisfy two driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
* R3 is now completely satisfied, as we can now set the values of all the previously unknown properties here.&lt;br /&gt;
* R5 is also satisfied as this method allows us to update the Widget's status on the Node when a property is changed on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Not all protocols pass messages back to the Node in this manner. The way we have satisfied R3 and R5 here only applies to protocols and Widgets that support this behavior.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Widgets that do not use an eventing protocol need to have their properties set in the provider's constructor to satisfy R3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To satisfy R5, the over-ridden method SetOn in the provider must include the call to SetPropertyOn. Non-eventing protocols do not require a HandleRegisterEvent method.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Constructor ===&lt;br /&gt;
&lt;br /&gt;
The final requirement for the driver is the constructor so that new DiscoveredWidget objects can be created. &lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this area of code are:&lt;br /&gt;
&lt;br /&gt;
'''R1 Specifying the type of Widget the driver controls'''&lt;br /&gt;
&lt;br /&gt;
A driver must know which type of Widget that it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
==== Writing the code ====&lt;br /&gt;
&lt;br /&gt;
We begin by defining the variables we will use to store the objects used by the driver:&lt;br /&gt;
&lt;br /&gt;
 private readonly string iName;&lt;br /&gt;
 private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
 private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now write the constructor for the driver and assign the passed in parameters appropriately:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightDriver(string aName,&lt;br /&gt;
                IWidgetPublisher aPublisher,&lt;br /&gt;
                IDvDeviceFactory aDeviceFactory)&lt;br /&gt;
 {&lt;br /&gt;
     iWidgetPublisher = aPublisher;&lt;br /&gt;
     iName = aName;&lt;br /&gt;
     iDeviceFactory = aDeviceFactory;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally we need to provide the driver a way to publish the class of Widget it controls. This information is requested by the Discovery Module and is used to ensure the Node uses the correct driver when a new Widget appears.&lt;br /&gt;
&lt;br /&gt;
The implementation for this details will be different for each protocol. The SimpleUPnP protocol library provides a file that contains the SimpleUPnP definitions as integers. Each integer represents a particular class of identified Widget.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP implementation of that method is as follows:&lt;br /&gt;
&lt;br /&gt;
 public IEnumerable&amp;lt;uint&amp;gt; WidgetClasses&lt;br /&gt;
 {&lt;br /&gt;
 [[File:Warning.png]]        get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The body of this method is specifically written for the Widget class we are defining (in this case a binary light). This method completes the driver's requirements for R1.&lt;br /&gt;
&lt;br /&gt;
== Writing the SimpleUPnP Widget discovery method ==&lt;br /&gt;
&lt;br /&gt;
Every driver must contain a method which creates new objects to represent newly discovered Widgets.&lt;br /&gt;
The Discovery Module invokes this method to begin the process of creating the objects required to allow the Node to access the Widget. &lt;br /&gt;
&lt;br /&gt;
The name of this method is dictated by your chosen protocol's API. The SimpleUPnP protocol requires a method called WidgetDiscovered.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The method's name will not always be the same for each protocol. Your protocol's documentation will contain the details of what this method must be called.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This method and its implementation will meet the following driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
'''R2 Reacting to a discovered Widget on the network'''&lt;br /&gt;
&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
Our implementation of the WidgetDiscovered method will create a new DiscoveredWidget object and use the Protocol Module to listen for changes to the Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
The method uses the Protocol Module and two ways to identify the Widget. We must pass these in as&lt;br /&gt;
parameters:&lt;br /&gt;
&lt;br /&gt;
 public void WidgetDiscovered(string aWidgetUdn,&lt;br /&gt;
                              uint aWidgetClass,&lt;br /&gt;
                              ISimpleUpnpWidget&lt;br /&gt;
                                  aSimpleUpnpWidget)&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
Every Widget that uses this driver must be uniquely identifiable:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]    string newUdn = aWidgetUdn;&lt;br /&gt;
&lt;br /&gt;
Each new Widget is represented by a DiscoveredWidget object. Create the new DiscoveredWidget and pass in the required parameters we created earlier:&lt;br /&gt;
&lt;br /&gt;
     DiscoveredWidget discoveredWidget =&lt;br /&gt;
                 new DiscoveredWidget(iDeviceFactory,&lt;br /&gt;
                                      newUdn,&lt;br /&gt;
  &lt;br /&gt;
 [[File:Warning.png]]                                    aSimpleUpnpWidget,&lt;br /&gt;
&lt;br /&gt;
=== Registering the callbacks ===&lt;br /&gt;
&lt;br /&gt;
Finally, we ask the Widget's protocol interface to listen for calls to the handler methods we defined earlier in DiscoveredWidget. We do this by registering those methods as callbacks for the Protocol Module&lt;br /&gt;
to listen for:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                        discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                        discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                        discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You have now met 100% of the driver responsibility requirements and have a working driver to use with your SimpleUPnP Widget.&lt;br /&gt;
&lt;br /&gt;
= Appendix A. Sample XML =&lt;br /&gt;
&lt;br /&gt;
== Binary Light.xml ==&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
  &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
  &amp;lt;version&amp;gt;&lt;br /&gt;
   &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
   &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/version&amp;gt;&lt;br /&gt;
  &amp;lt;propertylist&amp;gt;&lt;br /&gt;
   &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
       illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
   &amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix B. Sample Provider = &lt;br /&gt;
&lt;br /&gt;
== DvWidgetOpenhomeOrgBasicLight1.cs ==&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Runtime.InteropServices;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Core;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Utils.Binary;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
 {&lt;br /&gt;
    public interface IDvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
        IDisposable&lt;br /&gt;
    {&lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous value&lt;br /&gt;
        /// &amp;lt;/returns&amp;gt;&lt;br /&gt;
        bool SetPropertyOn(bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;Property's value will be copied&lt;br /&gt;
        /// here&amp;lt;/param&amp;gt;&lt;br /&gt;
        bool PropertyOn();&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt; summary&amp;gt;&lt;br /&gt;
    /// Provider for the openhome.org:BinaryLight:1 UPnP service&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public abstract class DvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
               DvProvider,&lt;br /&gt;
               IDisposable,&lt;br /&gt;
               IDvProviderOpenhomeOrgBinaryLight1&lt;br /&gt;
    {&lt;br /&gt;
        private GCHandle iGch;&lt;br /&gt;
        private PropertyBool iPropertyOn;&lt;br /&gt;
        private PropertyUint iPropertyPrimarySeq;&lt;br /&gt;
        private PropertyUint iPropertySecondarySeq;&lt;br /&gt;
        private ActionDelegate iDelegateSetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetPrimaryProperty;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Constructor&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aDevice&amp;quot;&amp;gt;Device which owns this&lt;br /&gt;
        /// provider&amp;lt;/param&amp;gt;&lt;br /&gt;
        protected DvProviderOpenhomeOrgBinaryLight1(DvDevice aDevice)&lt;br /&gt;
            : base(aDevice, &amp;quot;openhome.org&amp;quot;, &amp;quot;GenericWidget&amp;quot;, 1)&lt;br /&gt;
        {&lt;br /&gt;
            iGch = GCHandle.Alloc(this);&lt;br /&gt;
            List&amp;lt;String&amp;gt; allowedValues = new List&amp;lt;String&amp;gt;();&lt;br /&gt;
            iPropertyOn = new PropertyBool(new ParameterBool(&amp;quot;On&amp;quot;));&lt;br /&gt;
            iPropertyPrimarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;PrimarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertyPrimarySeq);&lt;br /&gt;
            iPropertySecondarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;SecondarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertySecondarySeq);&lt;br /&gt;
            SetPropertyUint(iPropertyPrimarySeq, 0);&lt;br /&gt;
            SetPropertyUint(iPropertySecondarySeq, 0);&lt;br /&gt;
  &lt;br /&gt;
            Zapp.Core.Action action = new Zapp.Core.Action&lt;br /&gt;
                (&amp;quot;SetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;FireAndForget&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddInputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateSetProperty = new ActionDelegate(DoSetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateSetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateGetProperty = new ActionDelegate(DoGetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetPrimaryProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                 (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;integer&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;boolean&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;string&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;binary&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Type&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;readWrite&amp;quot;);allowedValues.Add&lt;br /&gt;
                (&amp;quot;readOnly&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;writeOnly&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString(&amp;quot;Access&amp;quot;,&lt;br /&gt;
                allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            iDelegateGetPrimaryProperty = new&lt;br /&gt;
            ActionDelegate(DoGetPrimaryProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetPrimaryProperty,&lt;br /&gt;
            GCHandle.ToIntPtr(iGch));&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous&lt;br /&gt;
        /// value&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool SetPropertyOn(bool aValue)&lt;br /&gt;
        {&lt;br /&gt;
            if (iPropertyOn.SetValue(aValue))&lt;br /&gt;
            {&lt;br /&gt;
                lock (iPropertyPrimarySeq)&lt;br /&gt;
                {&lt;br /&gt;
                    SetPropertyUint(iPropertyPrimarySeq,&lt;br /&gt;
                        iPropertyPrimarySeq.Value() + 1);&lt;br /&gt;
                } return true;&lt;br /&gt;
            } return false;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;The value of the property&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool PropertyOn()&lt;br /&gt;
        {&lt;br /&gt;
            return iPropertyOn.Value();&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the On property.&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aVersion&amp;quot;&amp;gt;Version of the service being&lt;br /&gt;
        /// requested (will be &amp;lt;= the version advertised)&amp;lt;/param&amp;gt; &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the On property.&lt;br /&gt;
        /// &amp;lt;/param&amp;gt;&lt;br /&gt;
        protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        private static int DoSetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                byte[] valBin = invocation.ReadBinary(&amp;quot;Value&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                switch (name)&lt;br /&gt;
                {&lt;br /&gt;
                    case &amp;quot;On&amp;quot;:&lt;br /&gt;
                        self.SetOn(aVersion, Converter.&lt;br /&gt;
                            BinaryToBoolean(valBin));&lt;br /&gt;
                        break;&lt;br /&gt;
                    default:&lt;br /&gt;
                        throw new ActionError();&lt;br /&gt;
                }&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
                invocation.WriteEnd();&lt;br /&gt;
            }&lt;br /&gt;
            catch (ActionError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
            catch (PropertyUpdateError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
        return 0;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        private static int DoGetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
            switch (name)&lt;br /&gt;
            {&lt;br /&gt;
                case &amp;quot;On&amp;quot;:&lt;br /&gt;
                invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                    Converter.BooleanToBinary(self.iPropertyOn.&lt;br /&gt;
                        Value()));&lt;br /&gt;
                break;&lt;br /&gt;
                default:&lt;br /&gt;
                throw new ActionError();&lt;br /&gt;
            }&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    private static int DoGetPrimaryProperty(IntPtr aPtr,&lt;br /&gt;
                    IntPtr aInvocation,&lt;br /&gt;
                    uint aVersion)&lt;br /&gt;
    {&lt;br /&gt;
        GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
        DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
            (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
        DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
  &lt;br /&gt;
        try&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReadStart();&lt;br /&gt;
            invocation.ReadEnd();&lt;br /&gt;
            invocation.WriteStart();&lt;br /&gt;
            invocation.WriteString(&amp;quot;Name&amp;quot;, &amp;quot;On&amp;quot;);&lt;br /&gt;
            invocation.WriteString(&amp;quot;Type&amp;quot;, &amp;quot;boolean&amp;quot;);&lt;br /&gt;
            invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                Converter.BooleanToBinary(self.iPropertyOn.Value()));&lt;br /&gt;
            invocation.WriteString(&amp;quot;Access&amp;quot;, &amp;quot;readWrite&amp;quot;);&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt;summary&amp;gt;&lt;br /&gt;
    /// Must be called for each class instance. Must be called before&lt;br /&gt;
    /// Core.Library.Close().&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public void Dispose()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
        GC.SuppressFinalize(this);&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
    ~DvProviderOpenhomeOrgBinaryLight1()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
        private void DoDispose()&lt;br /&gt;
        {&lt;br /&gt;
            lock (this)&lt;br /&gt;
            {&lt;br /&gt;
                if (iHandle == IntPtr.Zero)&lt;br /&gt;
            {&lt;br /&gt;
                    return;&lt;br /&gt;
            }&lt;br /&gt;
            DisposeProvider();&lt;br /&gt;
            iPropertyOn.Dispose();&lt;br /&gt;
            iHandle = IntPtr.Zero;&lt;br /&gt;
            }&lt;br /&gt;
            iGch.Free();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix C. Sample Driver = &lt;br /&gt;
&lt;br /&gt;
== BasicLightDriver.cs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.hWidget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
     class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
     {&lt;br /&gt;
         private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
         public BinaryLightProvider(DvDevice aDevice, &lt;br /&gt;
             ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol = aProtocol;&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
     {&lt;br /&gt;
         private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
         {&lt;br /&gt;
             private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
             private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
             private readonly ISimpleUpnpWidget iProtocol; &lt;br /&gt;
 &lt;br /&gt;
             private readonly BinaryLightProvider iProvider;&lt;br /&gt;
             private readonly DvDevice iDvDevice;&lt;br /&gt;
             private IPublishedWidget iPublishedWidget; &lt;br /&gt;
 &lt;br /&gt;
             public DvDevice DvDevice&lt;br /&gt;
             {&lt;br /&gt;
                 get { return iDvDevice; }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             public string WidgetClass&lt;br /&gt;
             {&lt;br /&gt;
                 get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public DiscoveredWidget(&lt;br /&gt;
                 IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                 string aUdn,&lt;br /&gt;
                 ISimpleUpnpWidget aProxy,&lt;br /&gt;
                 IWidgetPublisher aPublisher)&lt;br /&gt;
             {&lt;br /&gt;
                 iDeviceFactory = aDeviceFactory;&lt;br /&gt;
                 iProtocol = aProtocol;&lt;br /&gt;
 &lt;br /&gt;
                 iPublisher = aPublisher;&lt;br /&gt;
                 iDvDevice = iDeviceFactory.CreateDevice(aUdn);  &lt;br /&gt;
                 iProvider = new BinaryLightProvider(iDvDevice, &lt;br /&gt;
                                                     iProtocol);&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             public void HandleInitialEvent()&lt;br /&gt;
             {&lt;br /&gt;
                 iDvDevice.SetEnabled();&lt;br /&gt;
                 iPublisher.TryPublishWidget(iDvDevice.iUdn(), this,&lt;br /&gt;
                     out iPublishedWidget);&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
             {&lt;br /&gt;
                 if (iPublishedWidget != null)&lt;br /&gt;
                 {&lt;br /&gt;
                     iPublishedWidget.Unpublish();&lt;br /&gt;
                 } &lt;br /&gt;
                 iProvider.Dispose();&lt;br /&gt;
                 iDvDevice.Dispose();&lt;br /&gt;
             }  &lt;br /&gt;
 &lt;br /&gt;
             public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
             {&lt;br /&gt;
                 if (aIndex == 0)&lt;br /&gt;
                 {&lt;br /&gt;
                     iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         private readonly string iName;&lt;br /&gt;
         private readonly IDvDeviceFactory aDeviceFactory;&lt;br /&gt;
         private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
         &lt;br /&gt;
         public BinaryLightDriver(&lt;br /&gt;
             string aName,&lt;br /&gt;
             IWidgetPublisher aPublisher,&lt;br /&gt;
             iDeviceFactory aDeviceFactory)&lt;br /&gt;
         {&lt;br /&gt;
             iWidgetPublisher = aPublisher;&lt;br /&gt;
             iName = aName;&lt;br /&gt;
             iDeviceFactory = aDeviceFactory;&lt;br /&gt;
         } &lt;br /&gt;
 &lt;br /&gt;
         public IEnumerable&amp;amp;lt;uint&amp;amp;gt; WidgetClasses&lt;br /&gt;
         {&lt;br /&gt;
             get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         public void WidgetDiscovered(&lt;br /&gt;
             string aWidgetUdn,&lt;br /&gt;
             uint aWidgetClass,&lt;br /&gt;
             ISimpleUpnpWidget aSimpleUpnpWidget)&lt;br /&gt;
         {&lt;br /&gt;
             string newUdn = aWidgetUdn;&lt;br /&gt;
             DiscoveredWidget discoveredWidget = new DiscoveredWidget&lt;br /&gt;
                 (iDeviceFactory,&lt;br /&gt;
                  newUdn,&lt;br /&gt;
                  aSimpleUpnpWidget,&lt;br /&gt;
                  iWidgetPublisher);&lt;br /&gt;
 &lt;br /&gt;
             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                 discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                 discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                 discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary = &lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in OpenHome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by OpenHome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh - A collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs on ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The OpenHome Operating System. Core software for OpenHome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. &lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. A typical Widget supports only one protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Driver_Development</id>
		<title>OhWidget Driver Development</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Driver_Development"/>
				<updated>2012-03-01T15:21:40Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Implementing the driver */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for developers using the OpenHome SDK to integrate a Widget into an OpenHome system. Each Widget must have its own driver to allow it to communicate with the OpenHome Nodes. &lt;br /&gt;
&lt;br /&gt;
To help you write your driver, this document provides high level descriptions of the core responsibilities of a Widget driver and gives a detailed walk-through using example code.&lt;br /&gt;
&lt;br /&gt;
Full versions of each file used in the development of the example driver are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin development of your Widget driver you must be in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* your Widget Service XML that describes the properties on your Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document does not contain advice on how to write Widget Service XML. Refer to the OpenHome Widget Service XML definition document for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK&lt;br /&gt;
* your chosen communication protocol's API&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The protocol you choose for your Widgets must be the same protocol used on your choice of Node.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document focuses on the development of the Widget driver. Details about the communications protocol used are beyond the scope of this document. This document assumes you are familiar with your chosen protocol's code libraries and are able to use them in the driver code you write.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Related Documents ==&lt;br /&gt;
&lt;br /&gt;
The following related OpenHome documentation may be of interest to you:&lt;br /&gt;
&lt;br /&gt;
* [[ohWidget Technical Overview|ohWidget Technical Overview]]&lt;br /&gt;
* [[OpenHome Widget Service XML definition|OpenHome Widget Service XML definition]]&lt;br /&gt;
* [http://www.openhome.org/releases/ohNet_DeviceStack.pdf  OpenHome ohNet Device Stack]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
None of the related documents listed above is mandatory reading for Widget driver development.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
== Widget Service XML ==&lt;br /&gt;
OpenHome Widget driver writing relies heavily on the use of code generated from a single source — the Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
The service and actions your Widget provides are represented in code in a file called a Provider. The Provider is automatically generated from the Widget Service XML and produces an abstract class for you to inherit when you write your concrete class driver.&lt;br /&gt;
&lt;br /&gt;
To aid in the explanation of how the Provider is created and put to use we will follow the development of&lt;br /&gt;
a driver for a simple light Widget; taking the defined Widget Service XML and stepping through how it is used to generate the other files. Examples of code are used throughout this document to show you how each one is created and used in an OpenHome system. &lt;br /&gt;
&lt;br /&gt;
It is essential that you start with a well-formed Widget Service XML, conforming to the schema defined&lt;br /&gt;
in the WidgetService.xsd. The following diagram shows the significance of the Widget Service XML in&lt;br /&gt;
relation to the generated files you will use when writing your driver:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarchy, highlighting the areas specifically used in driver development]]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* The grayed-out files are not relevant to Widget driver development but can also be generated from the Widget Service XML.&lt;br /&gt;
* The Provider is generated in C#, meaning your driver must be written in C# as well. The use of managed code is mandatory for driver writing in the OpenHome framework.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Code sample used in this document ==&lt;br /&gt;
&lt;br /&gt;
Our examples in this document use a Widget Service XML definition for a light Widget called&lt;br /&gt;
BasicLight.xml.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Full versions of all the example files used in this document are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We will see how the Provider is generated from this XML and how it is used to aid the driver writing process. The examples also show how your chosen communication protocol should be used in the body of the driver code.&lt;br /&gt;
&lt;br /&gt;
Implementation details of specific protocols you choose to use are beyond the scope of this document. However, the samples used in this document show the use of the SimpleUPnP protocol to aid you in your development process.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol during the early stages of the OpenHome project. It is included in the OpenHome SDK and can be used as a public resource. &lt;br /&gt;
&lt;br /&gt;
The use of SimpleUPnP in the example files and the code snippets within the following sections is highlighted by the [[File:Warning.png]] icon. The lines of code marked by [[File:Warning.png]] must be changed to code from your chosen communication protocol's library. SimpleUPnP is left in to help you understand how a protocol is used in a working example.&lt;br /&gt;
&lt;br /&gt;
The sample code provided attempts to show best-practice coding standards. There are several sections of code that have a mandatory layout or that call specifically named methods and functions. These areas of the code are highlighted where required. &lt;br /&gt;
&lt;br /&gt;
Where the examples do not explicitly state that the code shown is mandatory, you are free to implement it in a different way according to your own coding style and practices.&lt;br /&gt;
&lt;br /&gt;
= Driver responsibilities = &lt;br /&gt;
&lt;br /&gt;
== Driver responsibilities ==&lt;br /&gt;
&lt;br /&gt;
An OpenHome Widget driver has several responsibilities which must be met before it can be used on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
These responsibilities are listed R1 to R7 and are defined here, explaining what each one must do. &lt;br /&gt;
&lt;br /&gt;
=== R1 Specifying the type of Widget the driver controls ===&lt;br /&gt;
A driver must know which type of Widget it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
=== R2 Reacting to a discovered Widget on the network ===&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== R3 Setting the initial values for the Widget's properties ===&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
=== R4 Publishing discovered Widgets in the Local Widget Registry on the Node ===&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object.&lt;br /&gt;
&lt;br /&gt;
=== R5 Reacting to an event reported from the Widget ===&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
=== R6 Reacting to actions sent to the Widget ===&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== R7 Reacting to a Widget's departure ===&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no&lt;br /&gt;
longer available.&lt;br /&gt;
&lt;br /&gt;
The sections of example code that follow show you how to write a driver from beginning to end. The accompanying text explaining the example code highlights when a responsibility, or part of a responsibility, has been met.&lt;br /&gt;
&lt;br /&gt;
= Driver Architecture = &lt;br /&gt;
&lt;br /&gt;
== Driver Architecture ==&lt;br /&gt;
&lt;br /&gt;
Drivers are installed on the Node and used when the Node needs to communicate with the Widget. Drivers&lt;br /&gt;
use several objects to communicate with Widgets over the Widget's lifetime. Figure 2 shows the objects&lt;br /&gt;
used by the driver and how the responsibilities listed above relate to each one:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture.png|800px|thumb|center|Figure 2: The architecture of a driver, showing the driver's relationship to the objects used to communicate with a Widget. Lines between objects show message flow.]]&lt;br /&gt;
&lt;br /&gt;
The objects contained in the dotted boundary must appear in the code you write to define your driver. The Driver, Provider and IWidgetRegistryEntry objects are all contained in the same driver file. We begin discussing this on page 12. &lt;br /&gt;
&lt;br /&gt;
The other objects are provided by the OpenHome SDK or as installed components on the Node.&lt;br /&gt;
&lt;br /&gt;
The Discovery Module informs the driver of the presence of an available Widget.&lt;br /&gt;
&lt;br /&gt;
Each Node has a Protocol Module which contains the protocol's API. Widgets can communicate with OpenHome Nodes using any one of the set of communications protocols the Node supports. The driver uses your chosen protocol's Protocol Module to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
Both the Protocol Module and the Discovery Module are installed on the Node. When you write your&lt;br /&gt;
driver you will use your Protocol Module to allow the driver to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
IWidgetPublisher, IPublishedWidget and DvDevice are objects provided in the OpenHome&lt;br /&gt;
API. You can read about them in the APIs.&lt;br /&gt;
&lt;br /&gt;
= Generating the Provider = &lt;br /&gt;
&lt;br /&gt;
== Generating the Provider ==&lt;br /&gt;
&lt;br /&gt;
You must generate your provider before you can begin writing your Widget driver. You use your provider as a guide to implement the functions your Widget needs to set the values of its properties.&lt;br /&gt;
&lt;br /&gt;
The current provider generation process is a manual one involving the use of a text transform tool.&lt;br /&gt;
&lt;br /&gt;
Speak to your OpenHome contact who will help you generate your provider.&lt;br /&gt;
&lt;br /&gt;
Future releases of the OpenHome SDK will include a tool to help you generate the provider.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
You must be in possession of:&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK, unpacked on your computer&lt;br /&gt;
* your Widget Service XML file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Writing a SimpleUPnP driver = &lt;br /&gt;
&lt;br /&gt;
== Introduction to the SimpleUPnP protocol ==&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol used to control emulated Widgets over a custom UPnP service.&lt;br /&gt;
&lt;br /&gt;
This chapter shows how a driver is written using the SimpleUPnP communications protocol. The aim is to show the code using as generic a protocol as possible so that you can see where your own protocol specific code needs to go.&lt;br /&gt;
&lt;br /&gt;
The use of code specific to the SimpleUPnP implementation is highlighted by the use of the [[File:Warning.png]] icon. The lines of code are marked by this icon to make it easier for you to see where the protocol-specific code must go and what parts of the code are generic.&lt;br /&gt;
&lt;br /&gt;
=== Register model ===&lt;br /&gt;
&lt;br /&gt;
SimpleUPnP is modeled on 8 physical registers available on the Widget. Each register is 32-bits wide. They are indexed from 0 to 7 and the last register (register 7) is reserved for storing the Widget's class.&lt;br /&gt;
&lt;br /&gt;
This detail is used by the Protocol Module on the Node to determine which driver is needed to run the new Widget when it has been discovered.&lt;br /&gt;
&lt;br /&gt;
The remaining 7 registers (registers 0 to 6) are free for Widget engineers to assign to the Widget's functions.&lt;br /&gt;
&lt;br /&gt;
Registers 0, 1, 2 and 3 are available as read/write registers. Registers 4, 5 and 6 are readonly registers.&lt;br /&gt;
&lt;br /&gt;
Only the emulated hardware (running on the Node) can change the values held in registers 4, 5 and 6.&lt;br /&gt;
&lt;br /&gt;
=== Register use in drivers ===&lt;br /&gt;
&lt;br /&gt;
In the example that follows we have a Basic Light Widget with a very simple function: it can be turned on and turned off. The on/off value is stored in register 0, with values 0=OFF and 1=ON. Register 0 is a read/write register. This means we can change the value stored there using messages passed to the Widget from the Node, and by reacting to physical interactions at the Widget (such as someone manually switching the light on or off). &lt;br /&gt;
&lt;br /&gt;
The mapping of registers to properties on the Widget is decided by the engineers who manufacture the device. You must be provided with the mapping before you begin developing your driver.&lt;br /&gt;
&lt;br /&gt;
== Starting the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-BoxHighlight.png|800px|thumb|center|Figure 3 The driver architecture highlighting the Widget driver and its component parts.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When you have generated the abstract provider you can put it to use in the Widget driver. A Widget driver&lt;br /&gt;
has three distinct components:&lt;br /&gt;
&lt;br /&gt;
* an implementation of your abstract provider&lt;br /&gt;
* a definition of the Widget driver&lt;br /&gt;
* an implementation of the IWidgetRegistryEntry interface&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must manually write the code for your Widget driver. The differences in implementation of Widget properties and communication protocols means that the driver code cannot be autogenerated.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This section takes you through how to write a Widget driver by implementing the auto-generated provider,&lt;br /&gt;
starting from a new blank file and finishing with a working driver for the Basic Light Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
No assumptions have been made about the type of editor you use to write your code. Shortcuts&lt;br /&gt;
or macros that you use as standard will not appear in the instructions below. A full example&lt;br /&gt;
BinaryLightDriver.cs is available to review in Appendix C.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a new C# file in your IDE. Ensure the following libraries are used:&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 [[File:Warning.png]]using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 namespace OpenHome.Widget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must use the libraries listed above for this specific example.&lt;br /&gt;
&lt;br /&gt;
In general, drivers require the following libraries:&lt;br /&gt;
* System*&lt;br /&gt;
* System.Collections.Generic*&lt;br /&gt;
* OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
&lt;br /&gt;
Your driver will fail to compile if you miss any of these listed libraries. Libraries marked * are typically added by default by most modern IDEs. &lt;br /&gt;
&lt;br /&gt;
The OpenHome.Widget.Protocols.SimpleUpnp library is required only in this SimpleUPnP example. Drivers using a different protocol will use their own protocol library.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Implementing the provider ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-ProviderHighlight.png|800px|thumb|center|Figure 4 The driver architecture highlighting the Provider's place]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You use your auto-generated abstract provider by writing an implementation of it in the driver file. Responsibilities met by implementing your auto-generated provider are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R6 Reacting to actions sent to the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
Begin by creating a new class. It will subclass the abstract auto-generated provider:&lt;br /&gt;
&lt;br /&gt;
 class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
The Protocol Module will provide an API for the Provider to use to communicate with the Widget. In&lt;br /&gt;
SimpleUPnP we are provided with an interface called ISimpleUpnpWidget. The provider is supplied&lt;br /&gt;
with the required instance of the interface by the Discovery Module on the Node.&lt;br /&gt;
&lt;br /&gt;
The mechanisms for registering providers with specific Protocol Modules, and for the way the module gives each provider its required interface are covered later when writing the discovery method.&lt;br /&gt;
&lt;br /&gt;
For now, we need to give the Provider a place to store the interface that it will later use to communicate&lt;br /&gt;
with the Widget:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]] private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
&lt;br /&gt;
The interface from the Protocol Module is passed in as a parameter in the Provider's constructor and then&lt;br /&gt;
assigned to the variable we just created:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightProvider(DvDevice aDevice,&lt;br /&gt;
 [[File:Warning.png]]         ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
 {&lt;br /&gt;
       iProtocol = aProtocol;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
To satisfy R3 we would normally set the Widget's properties here, giving them an initial value.&lt;br /&gt;
However, in this specific example we cannot set the value of Basic Light's only property because&lt;br /&gt;
we will never know, in advance, what the state of the light will be (either on or off) when we&lt;br /&gt;
create the DiscoveredWidget.&lt;br /&gt;
&lt;br /&gt;
When you cannot set the properties ahead of time, and you are using an eventing protocol like SimpleUPnP, you can instead set them in the HandleRegisterEvent method in the driver class. This also satisfies the requirements for R3. You must set the Widget's properties before you enable it using SetEnabled(). &lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The abstract provider includes an abstract method called SetOn. This method is invoked by the Node when passing a message to the Widget, specifically to set the on property of the Widget to either 0 or 1. The implementation of this method will meet the requirements for R6.&lt;br /&gt;
&lt;br /&gt;
We must override this method and provide the protocol module a way of passing a message on to the Widget to perform the required action, in this case turn the light on or off:&lt;br /&gt;
&lt;br /&gt;
          protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
          {&lt;br /&gt;
     [[File:Warning.png]]        iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
In this example the Basic Light's SetOn property (the boolean property that controls whether the light is&lt;br /&gt;
on or off) is represented in the physical Widget by the register that has an index of 0.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* This method is an example of an action on a Widget. Actions are messages sent from the Node to the Widget. We will see later how to handle events that need to be passed back from the Widget&lt;br /&gt;
to the Node.&lt;br /&gt;
* Your own Widget will likely provide more than a single property. Your auto-generated provider will contain one abstract method to represent each writable property. Read-only properties are not provided an abstract method.&lt;br /&gt;
&lt;br /&gt;
You must implement each abstract method in your driver to ensure the relevant property on&lt;br /&gt;
the Widget can be set.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We have now finished implementing the provider. The next step is to implement the driver.&lt;br /&gt;
&lt;br /&gt;
== Implementing the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-DriverHighlight.png|800px|thumb|center|Figure 4: The driver architecture highlighting the implemented driver's place.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The code for your Widget driver must provide an implementation of the IWidgetRegistryInterface,&lt;br /&gt;
including the following tasks:&lt;br /&gt;
&lt;br /&gt;
* methods to expose identifying details about the Widget for the Node to access&lt;br /&gt;
* providing methods to handle events reported by the Widget&lt;br /&gt;
&lt;br /&gt;
The driver is implemented as a public class within the same file as the provider code. Each driver must use the interface for the protocol you are using. For the SimpleUPnP protocol the interface is ISimple-UpnpWidgetDriver.&lt;br /&gt;
&lt;br /&gt;
=== Writing code ===&lt;br /&gt;
&lt;br /&gt;
Create your new driver class and subclass the ISimpleUpnpWidgetDriver interface:&lt;br /&gt;
&lt;br /&gt;
 public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Implementing IWidgetRegistryEntry ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry is the interface you use to represent physical Widgets. It is implemented as a subclass of your driver class. We are going to implement this interface in a class called '''DiscoveredWidget'''.&lt;br /&gt;
&lt;br /&gt;
Let's return to our driver architecture diagram for a moment:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-IRegistryEntryHighlight.png|800px|thumb|center|Figure 5 The driver architecture highlighting the IWidgetRegistryEntry object you will now implement]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry uses several other objects to help create it and respond to messages sent to and from it. These objects will be created in our implementation of DiscoveredWidget. &lt;br /&gt;
&lt;br /&gt;
When successfully created and published, the DiscoveredWidget objects are stored in a list on the Node called the Local Widget Registry. The Local Widget Registry is used by Nodes to maintain contact with the Widgets they control.&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry is shown at the top of Figure 5, marked plainly as (Registry). The path to the Local Widget Registry goes through several layers of Node architecture which are not relevant to Widget driver writing, so are not shown in the diagrams.&lt;br /&gt;
&lt;br /&gt;
==== Writing code ====&lt;br /&gt;
&lt;br /&gt;
Start by subclassing the IWidgetRegistryEntry interface in your new class:&lt;br /&gt;
&lt;br /&gt;
      private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
      {&lt;br /&gt;
&lt;br /&gt;
A DiscoveredWidget must provide the driver with the objects required to present the Widget and its&lt;br /&gt;
properties to the Node:&lt;br /&gt;
&lt;br /&gt;
           private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
           private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
           private readonly ISimpleUpnpWidget iProtocol;&lt;br /&gt;
           private readonly BinaryLightProvider iProvider;&lt;br /&gt;
           private readonly DvDevice iDvDevice;&lt;br /&gt;
           private IPublishedWidget iPublishedWidget;&lt;br /&gt;
&lt;br /&gt;
Each of the attributes in the example above are defined as follows:&lt;br /&gt;
&lt;br /&gt;
iDeviceFactory — used by the driver to create a single instance of DvDevice to represent a single Widget&lt;br /&gt;
&lt;br /&gt;
iPublisher — used by the driver to publish the Widget to the Node&lt;br /&gt;
&lt;br /&gt;
iProtocol — the object used by the Widget to communicate with the Protocol Module on the Node&lt;br /&gt;
&lt;br /&gt;
iProvider — an instantiated provider of the type you defined earlier&lt;br /&gt;
&lt;br /&gt;
iDvDevice — a representation of a Widget to which the provider is attached, created using iDevice-Factory above&lt;br /&gt;
&lt;br /&gt;
iPublishedWidget — used to contain the returned object from a successful publishing of the Widget&lt;br /&gt;
If we look again at the driver architecture diagram, we ca highlight the objects we've just defined:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-Highlight.png|800px|thumb|center|Figure 6: The driver architecture highlighting the objects used by the IWidgetRegistryEntry implementation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The DeviceFactory, defined above in the member variable iDeviceFactory, is used to create new DvDevice objects. The DeviceFactory is only ever used to do this once. It is not shown in the driver architecture diagrams due to its minimal role in the operation of a driver, but it would normally appear between the IWidgetRegistryEntry and DvDevice objects.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
A driver requires methods to expose identifying details about the Widget. We must provide access to two of the attributes we just defined above:&lt;br /&gt;
&lt;br /&gt;
 public DvDevice DvDevice&lt;br /&gt;
 {&lt;br /&gt;
     get { return iDvDevice; }&lt;br /&gt;
 }&lt;br /&gt;
 public string WidgetClass&lt;br /&gt;
 {&lt;br /&gt;
     get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The WidgetClass string is formed using a combination of the vendor name and the Widget's name in the&lt;br /&gt;
format:&lt;br /&gt;
&lt;br /&gt;
 [vendor_domain]:[widget_name]&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry can now query both the DvDevice object representing the Widget, and the specific class of Widget this driver represents. The other member variables we defined do not need their own accessor methods.&lt;br /&gt;
&lt;br /&gt;
Now we must write a constructor for DiscoveredWidget and assign the parameters accordingly: &lt;br /&gt;
&lt;br /&gt;
 public DiscoveredWidget(IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                            string aUdn,&lt;br /&gt;
                            ISimpleUpnpWidget aProxy,&lt;br /&gt;
                            IWidgetPublisher aPublisher)&lt;br /&gt;
 {&lt;br /&gt;
      iDeviceFactory = aDeviceFactory;&lt;br /&gt;
      iProtocol = aProtocol;&lt;br /&gt;
      iPublisher = aPublisher;&lt;br /&gt;
      iDvDevice = iDeviceFactory.CreateDevice(aUdn);&lt;br /&gt;
      iProvider = new BinaryLightProvider(iDvDevice,&lt;br /&gt;
      iProtocol);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Event handling ===&lt;br /&gt;
&lt;br /&gt;
A Widget's state can change in one of three significant ways:&lt;br /&gt;
&lt;br /&gt;
* when the Widget needs to be published on the Node&lt;br /&gt;
* when the Widget disappears from the network (by losing power or similar)&lt;br /&gt;
* when a property's state changes and must be updated to a new value&lt;br /&gt;
&lt;br /&gt;
We now need methods to handle these changes.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The methods we define here will be used as callbacks, rather than invoked as method calls. We define the methods here first and then use them later on. We will use the Protocol Module to listen for changes in the Widget's state and register these methods as callbacks there. See Writing the SimpleUPnP Widget discovery method for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this section of the driver are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R4 Publishing discovered Widgets in the Local Widget Registry on the Node'''&lt;br /&gt;
&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object. &lt;br /&gt;
&lt;br /&gt;
'''R5 Reacting to an event reported from the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
'''R7 Reacting to a Widget's departure'''&lt;br /&gt;
&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no longer available.&lt;br /&gt;
&lt;br /&gt;
==== Enabling and publishing a discovered Widget ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first method initializes the Widget by enabling the device and then using the IWidgetPublisher&lt;br /&gt;
to make it available on the Node:&lt;br /&gt;
&lt;br /&gt;
 public void HandleInitialEvent()&lt;br /&gt;
 {&lt;br /&gt;
      iDvDevice.SetEnabled();&lt;br /&gt;
      iPublisher.TryPublishWidget(iDvDevice.iUdn(),&lt;br /&gt;
                              this,&lt;br /&gt;
                              out iPublishedWidget);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This method meets the requirements for R4.&lt;br /&gt;
&lt;br /&gt;
The call to TryPublishWidget returns an iPublishedWidget object. We use this object later to satisfy the requirements of R7.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The ordering of the calls to SetEnabled and TryPublishWidget is vitally important. You&lt;br /&gt;
must enable the device before you attempt to publish it. Your Widget will not be available to the&lt;br /&gt;
Nodes unless SetEnabled is called first. Nodes will not be able to access a published device&lt;br /&gt;
that has not been enabled.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
R3 requires that you set the Widget's properties before you enable and publish the device. We&lt;br /&gt;
discussed on page 14 how some properties can only be set after the Widget reports what their&lt;br /&gt;
state is. We do this in HandleRegisterEvent.&lt;br /&gt;
&lt;br /&gt;
We rely on the SimpleUPnP Protocol Module guaranteeing a call to HandleRegisterEvent first before HandleInitialEvent. This is informed by guarantees made by the Control Point stack that the calls will be made in that order.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
==== Removing a Widget ====&lt;br /&gt;
&lt;br /&gt;
Removing a Widget involves unpublishing it from the Node. The IPublishedWidget interface provides us with a method we can call to manage that for us:&lt;br /&gt;
&lt;br /&gt;
 public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
 {&lt;br /&gt;
     if (iPublishedWidget != null)&lt;br /&gt;
     { iPublishedWidget.Unpublish(); }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assuming that the Widget was successfully published earlier, it is removed from the Node's Local Widget Registry.&lt;br /&gt;
&lt;br /&gt;
We must also properly handle the resources we used to create and maintain the Widget object while it was published:&lt;br /&gt;
&lt;br /&gt;
      iProvider.Dispose();&lt;br /&gt;
      iDvDevice.Dispose();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The calls to Dispose are made regardless of the Widget's published state, ensuring that any created device and associated provider are properly disposed. This implementation satisfies R7.&lt;br /&gt;
&lt;br /&gt;
====Event handling ====&lt;br /&gt;
&lt;br /&gt;
We need a method to handle changes to the state of the Widget's properties.&lt;br /&gt;
&lt;br /&gt;
If the property changes at the Widget, it needs to pass the new state back to the Node so that it is kept up-to-date on the Widget's status. This is called an event. An example in the case of our Basic Light is someone manually switching the light from on to off. This is in contrast to actions, which are passed from the Node to the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Other examples of events involve no human interaction, such as a thermometer Widget updating its current temperature based on environmental changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Our Basic Light Widget has only one property that needs to be handled:&lt;br /&gt;
&lt;br /&gt;
 public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
 {&lt;br /&gt;
     if (aIndex == 0)&lt;br /&gt;
     {&lt;br /&gt;
         iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We use our instance of the provider to update the register on the Widget that is mapped to the On property. This in turn updates the Node with the new state of the Widget.&lt;br /&gt;
&lt;br /&gt;
This method provides implementations to satisfy two driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
* R3 is now completely satisfied, as we can now set the values of all the previously unknown properties here.&lt;br /&gt;
* R5 is also satisfied as this method allows us to update the Widget's status on the Node when a property is changed on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Not all protocols pass messages back to the Node in this manner. The way we have satisfied R3 and R5 here only applies to protocols and Widgets that support this behavior.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Widgets that do not use an eventing protocol need to have their properties set in the provider's constructor to satisfy R3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To satisfy R5, the over-ridden method SetOn in the provider must include the call to SetPropertyOn. Non-eventing protocols do not require a HandleRegisterEvent method.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Constructor ===&lt;br /&gt;
&lt;br /&gt;
The final requirement for the driver is the constructor so that new DiscoveredWidget objects can be created. &lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this area of code are:&lt;br /&gt;
&lt;br /&gt;
'''R1 Specifying the type of Widget the driver controls'''&lt;br /&gt;
&lt;br /&gt;
A driver must know which type of Widget that it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
==== Writing the code ====&lt;br /&gt;
&lt;br /&gt;
We begin by defining the variables we will use to store the objects used by the driver:&lt;br /&gt;
&lt;br /&gt;
 private readonly string iName;&lt;br /&gt;
 private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
 private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now write the constructor for the driver and assign the passed in parameters appropriately:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightDriver(string aName,&lt;br /&gt;
                IWidgetPublisher aPublisher,&lt;br /&gt;
                IDvDeviceFactory aDeviceFactory)&lt;br /&gt;
 {&lt;br /&gt;
     iWidgetPublisher = aPublisher;&lt;br /&gt;
     iName = aName;&lt;br /&gt;
     iDeviceFactory = aDeviceFactory;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally we need to provide the driver a way to publish the class of Widget it controls. This information is requested by the Discovery Module and is used to ensure the Node uses the correct driver when a new Widget appears.&lt;br /&gt;
&lt;br /&gt;
The implementation for this details will be different for each protocol. The SimpleUPnP protocol library provides a file that contains the SimpleUPnP definitions as integers. Each integer represents a particular class of identified Widget.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP implementation of that method is as follows:&lt;br /&gt;
&lt;br /&gt;
 public IEnumerable&amp;lt;uint&amp;gt; WidgetClasses&lt;br /&gt;
 {&lt;br /&gt;
 [[File:Warning.png]]        get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The body of this method is specifically written for the Widget class we are defining (in this case a binary light). This method completes the driver's requirements for R1.&lt;br /&gt;
&lt;br /&gt;
== Writing the SimpleUPnP Widget discovery method ==&lt;br /&gt;
&lt;br /&gt;
Every driver must contain a method which creates new objects to represent newly discovered Widgets.&lt;br /&gt;
The Discovery Module invokes this method to begin the process of creating the objects required to allow the Node to access the Widget. &lt;br /&gt;
&lt;br /&gt;
The name of this method is dictated by your chosen protocol's API. The SimpleUPnP protocol requires a method called WidgetDiscovered.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The method's name will not always be the same for each protocol. Your protocol's documentation will contain the details of what this method must be called.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This method and its implementation will meet the following driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
'''R2 Reacting to a discovered Widget on the network'''&lt;br /&gt;
&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
Our implementation of the WidgetDiscovered method will create a new DiscoveredWidget object and use the Protocol Module to listen for changes to the Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
The method uses the Protocol Module and two ways to identify the Widget. We must pass these in as&lt;br /&gt;
parameters:&lt;br /&gt;
&lt;br /&gt;
 public void WidgetDiscovered(string aWidgetUdn,&lt;br /&gt;
                              uint aWidgetClass,&lt;br /&gt;
                              ISimpleUpnpWidget&lt;br /&gt;
                                  aSimpleUpnpWidget)&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
Every Widget that uses this driver must be uniquely identifiable:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]    string newUdn = aWidgetUdn;&lt;br /&gt;
&lt;br /&gt;
Each new Widget is represented by a DiscoveredWidget object. Create the new DiscoveredWidget and pass in the required parameters we created earlier:&lt;br /&gt;
&lt;br /&gt;
     DiscoveredWidget discoveredWidget =&lt;br /&gt;
                 new DiscoveredWidget(iDeviceFactory,&lt;br /&gt;
                                      newUdn,&lt;br /&gt;
  &lt;br /&gt;
 [[File:Warning.png]]                                    aSimpleUpnpWidget,&lt;br /&gt;
&lt;br /&gt;
=== Registering the callbacks ===&lt;br /&gt;
&lt;br /&gt;
Finally, we ask the Widget's protocol interface to listen for calls to the handler methods we defined earlier in DiscoveredWidget. We do this by registering those methods as callbacks for the Protocol Module&lt;br /&gt;
to listen for:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                        discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                        discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                        discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You have now met 100% of the driver responsibility requirements and have a working driver to use with your SimpleUPnP Widget.&lt;br /&gt;
&lt;br /&gt;
= Appendix A. Sample XML =&lt;br /&gt;
&lt;br /&gt;
== Binary Light.xml ==&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
  &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
  &amp;lt;version&amp;gt;&lt;br /&gt;
   &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
   &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/version&amp;gt;&lt;br /&gt;
  &amp;lt;propertylist&amp;gt;&lt;br /&gt;
   &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
       illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
   &amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix B. Sample Provider = &lt;br /&gt;
&lt;br /&gt;
== DvWidgetOpenhomeOrgBasicLight1.cs ==&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Runtime.InteropServices;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Core;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Utils.Binary;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
 {&lt;br /&gt;
    public interface IDvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
        IDisposable&lt;br /&gt;
    {&lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous value&lt;br /&gt;
        /// &amp;lt;/returns&amp;gt;&lt;br /&gt;
        bool SetPropertyOn(bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;Property's value will be copied&lt;br /&gt;
        /// here&amp;lt;/param&amp;gt;&lt;br /&gt;
        bool PropertyOn();&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt; summary&amp;gt;&lt;br /&gt;
    /// Provider for the openhome.org:BinaryLight:1 UPnP service&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public abstract class DvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
               DvProvider,&lt;br /&gt;
               IDisposable,&lt;br /&gt;
               IDvProviderOpenhomeOrgBinaryLight1&lt;br /&gt;
    {&lt;br /&gt;
        private GCHandle iGch;&lt;br /&gt;
        private PropertyBool iPropertyOn;&lt;br /&gt;
        private PropertyUint iPropertyPrimarySeq;&lt;br /&gt;
        private PropertyUint iPropertySecondarySeq;&lt;br /&gt;
        private ActionDelegate iDelegateSetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetPrimaryProperty;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Constructor&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aDevice&amp;quot;&amp;gt;Device which owns this&lt;br /&gt;
        /// provider&amp;lt;/param&amp;gt;&lt;br /&gt;
        protected DvProviderOpenhomeOrgBinaryLight1(DvDevice aDevice)&lt;br /&gt;
            : base(aDevice, &amp;quot;openhome.org&amp;quot;, &amp;quot;GenericWidget&amp;quot;, 1)&lt;br /&gt;
        {&lt;br /&gt;
            iGch = GCHandle.Alloc(this);&lt;br /&gt;
            List&amp;lt;String&amp;gt; allowedValues = new List&amp;lt;String&amp;gt;();&lt;br /&gt;
            iPropertyOn = new PropertyBool(new ParameterBool(&amp;quot;On&amp;quot;));&lt;br /&gt;
            iPropertyPrimarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;PrimarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertyPrimarySeq);&lt;br /&gt;
            iPropertySecondarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;SecondarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertySecondarySeq);&lt;br /&gt;
            SetPropertyUint(iPropertyPrimarySeq, 0);&lt;br /&gt;
            SetPropertyUint(iPropertySecondarySeq, 0);&lt;br /&gt;
  &lt;br /&gt;
            Zapp.Core.Action action = new Zapp.Core.Action&lt;br /&gt;
                (&amp;quot;SetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;FireAndForget&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddInputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateSetProperty = new ActionDelegate(DoSetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateSetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateGetProperty = new ActionDelegate(DoGetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetPrimaryProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                 (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;integer&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;boolean&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;string&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;binary&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Type&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;readWrite&amp;quot;);allowedValues.Add&lt;br /&gt;
                (&amp;quot;readOnly&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;writeOnly&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString(&amp;quot;Access&amp;quot;,&lt;br /&gt;
                allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            iDelegateGetPrimaryProperty = new&lt;br /&gt;
            ActionDelegate(DoGetPrimaryProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetPrimaryProperty,&lt;br /&gt;
            GCHandle.ToIntPtr(iGch));&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous&lt;br /&gt;
        /// value&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool SetPropertyOn(bool aValue)&lt;br /&gt;
        {&lt;br /&gt;
            if (iPropertyOn.SetValue(aValue))&lt;br /&gt;
            {&lt;br /&gt;
                lock (iPropertyPrimarySeq)&lt;br /&gt;
                {&lt;br /&gt;
                    SetPropertyUint(iPropertyPrimarySeq,&lt;br /&gt;
                        iPropertyPrimarySeq.Value() + 1);&lt;br /&gt;
                } return true;&lt;br /&gt;
            } return false;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;The value of the property&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool PropertyOn()&lt;br /&gt;
        {&lt;br /&gt;
            return iPropertyOn.Value();&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the On property.&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aVersion&amp;quot;&amp;gt;Version of the service being&lt;br /&gt;
        /// requested (will be &amp;lt;= the version advertised)&amp;lt;/param&amp;gt; &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the On property.&lt;br /&gt;
        /// &amp;lt;/param&amp;gt;&lt;br /&gt;
        protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        private static int DoSetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                byte[] valBin = invocation.ReadBinary(&amp;quot;Value&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                switch (name)&lt;br /&gt;
                {&lt;br /&gt;
                    case &amp;quot;On&amp;quot;:&lt;br /&gt;
                        self.SetOn(aVersion, Converter.&lt;br /&gt;
                            BinaryToBoolean(valBin));&lt;br /&gt;
                        break;&lt;br /&gt;
                    default:&lt;br /&gt;
                        throw new ActionError();&lt;br /&gt;
                }&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
                invocation.WriteEnd();&lt;br /&gt;
            }&lt;br /&gt;
            catch (ActionError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
            catch (PropertyUpdateError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
        return 0;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        private static int DoGetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
            switch (name)&lt;br /&gt;
            {&lt;br /&gt;
                case &amp;quot;On&amp;quot;:&lt;br /&gt;
                invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                    Converter.BooleanToBinary(self.iPropertyOn.&lt;br /&gt;
                        Value()));&lt;br /&gt;
                break;&lt;br /&gt;
                default:&lt;br /&gt;
                throw new ActionError();&lt;br /&gt;
            }&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    private static int DoGetPrimaryProperty(IntPtr aPtr,&lt;br /&gt;
                    IntPtr aInvocation,&lt;br /&gt;
                    uint aVersion)&lt;br /&gt;
    {&lt;br /&gt;
        GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
        DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
            (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
        DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
  &lt;br /&gt;
        try&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReadStart();&lt;br /&gt;
            invocation.ReadEnd();&lt;br /&gt;
            invocation.WriteStart();&lt;br /&gt;
            invocation.WriteString(&amp;quot;Name&amp;quot;, &amp;quot;On&amp;quot;);&lt;br /&gt;
            invocation.WriteString(&amp;quot;Type&amp;quot;, &amp;quot;boolean&amp;quot;);&lt;br /&gt;
            invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                Converter.BooleanToBinary(self.iPropertyOn.Value()));&lt;br /&gt;
            invocation.WriteString(&amp;quot;Access&amp;quot;, &amp;quot;readWrite&amp;quot;);&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt;summary&amp;gt;&lt;br /&gt;
    /// Must be called for each class instance. Must be called before&lt;br /&gt;
    /// Core.Library.Close().&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public void Dispose()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
        GC.SuppressFinalize(this);&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
    ~DvProviderOpenhomeOrgBinaryLight1()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
        private void DoDispose()&lt;br /&gt;
        {&lt;br /&gt;
            lock (this)&lt;br /&gt;
            {&lt;br /&gt;
                if (iHandle == IntPtr.Zero)&lt;br /&gt;
            {&lt;br /&gt;
                    return;&lt;br /&gt;
            }&lt;br /&gt;
            DisposeProvider();&lt;br /&gt;
            iPropertyOn.Dispose();&lt;br /&gt;
            iHandle = IntPtr.Zero;&lt;br /&gt;
            }&lt;br /&gt;
            iGch.Free();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix C. Sample Driver = &lt;br /&gt;
&lt;br /&gt;
== BasicLightDriver.cs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.hWidget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
     class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
     {&lt;br /&gt;
         private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
         public BinaryLightProvider(DvDevice aDevice, &lt;br /&gt;
             ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol = aProtocol;&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
     {&lt;br /&gt;
         private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
         {&lt;br /&gt;
             private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
             private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
             private readonly ISimpleUpnpWidget iProtocol; &lt;br /&gt;
 &lt;br /&gt;
             private readonly BinaryLightProvider iProvider;&lt;br /&gt;
             private readonly DvDevice iDvDevice;&lt;br /&gt;
             private IPublishedWidget iPublishedWidget; &lt;br /&gt;
 &lt;br /&gt;
             public DvDevice DvDevice&lt;br /&gt;
             {&lt;br /&gt;
                 get { return iDvDevice; }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             public string WidgetClass&lt;br /&gt;
             {&lt;br /&gt;
                 get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public DiscoveredWidget(&lt;br /&gt;
                 IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                 string aUdn,&lt;br /&gt;
                 ISimpleUpnpWidget aProxy,&lt;br /&gt;
                 IWidgetPublisher aPublisher)&lt;br /&gt;
             {&lt;br /&gt;
                 iDeviceFactory = aDeviceFactory;&lt;br /&gt;
                 iProtocol = aProtocol;&lt;br /&gt;
 &lt;br /&gt;
                 iPublisher = aPublisher;&lt;br /&gt;
                 iDvDevice = iDeviceFactory.CreateDevice(aUdn);  &lt;br /&gt;
                 iProvider = new BinaryLightProvider(iDvDevice, &lt;br /&gt;
                                                     iProtocol);&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             public void HandleInitialEvent()&lt;br /&gt;
             {&lt;br /&gt;
                 iDvDevice.SetEnabled();&lt;br /&gt;
                 iPublisher.TryPublishWidget(iDvDevice.iUdn(), this,&lt;br /&gt;
                     out iPublishedWidget);&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
             {&lt;br /&gt;
                 if (iPublishedWidget != null)&lt;br /&gt;
                 {&lt;br /&gt;
                     iPublishedWidget.Unpublish();&lt;br /&gt;
                 } &lt;br /&gt;
                 iProvider.Dispose();&lt;br /&gt;
                 iDvDevice.Dispose();&lt;br /&gt;
             }  &lt;br /&gt;
 &lt;br /&gt;
             public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
             {&lt;br /&gt;
                 if (aIndex == 0)&lt;br /&gt;
                 {&lt;br /&gt;
                     iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         private readonly string iName;&lt;br /&gt;
         private readonly IDvDeviceFactory aDeviceFactory;&lt;br /&gt;
         private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
         &lt;br /&gt;
         public BinaryLightDriver(&lt;br /&gt;
             string aName,&lt;br /&gt;
             IWidgetPublisher aPublisher,&lt;br /&gt;
             iDeviceFactory aDeviceFactory)&lt;br /&gt;
         {&lt;br /&gt;
             iWidgetPublisher = aPublisher;&lt;br /&gt;
             iName = aName;&lt;br /&gt;
             iDeviceFactory = aDeviceFactory;&lt;br /&gt;
         } &lt;br /&gt;
 &lt;br /&gt;
         public IEnumerable&amp;amp;lt;uint&amp;amp;gt; WidgetClasses&lt;br /&gt;
         {&lt;br /&gt;
             get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         public void WidgetDiscovered(&lt;br /&gt;
             string aWidgetUdn,&lt;br /&gt;
             uint aWidgetClass,&lt;br /&gt;
             ISimpleUpnpWidget aSimpleUpnpWidget)&lt;br /&gt;
         {&lt;br /&gt;
             string newUdn = aWidgetUdn;&lt;br /&gt;
             DiscoveredWidget discoveredWidget = new DiscoveredWidget&lt;br /&gt;
                 (iDeviceFactory,&lt;br /&gt;
                  newUdn,&lt;br /&gt;
                  aSimpleUpnpWidget,&lt;br /&gt;
                  iWidgetPublisher);&lt;br /&gt;
 &lt;br /&gt;
             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                 discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                 discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                 discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary = &lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in OpenHome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by OpenHome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh - A collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs on ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The OpenHome Operating System. Core software for OpenHome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. &lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. A typical Widget supports only one protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Driver_Development</id>
		<title>OhWidget Driver Development</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Driver_Development"/>
				<updated>2012-03-01T15:21:18Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Implementing the provider */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for developers using the OpenHome SDK to integrate a Widget into an OpenHome system. Each Widget must have its own driver to allow it to communicate with the OpenHome Nodes. &lt;br /&gt;
&lt;br /&gt;
To help you write your driver, this document provides high level descriptions of the core responsibilities of a Widget driver and gives a detailed walk-through using example code.&lt;br /&gt;
&lt;br /&gt;
Full versions of each file used in the development of the example driver are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin development of your Widget driver you must be in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* your Widget Service XML that describes the properties on your Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document does not contain advice on how to write Widget Service XML. Refer to the OpenHome Widget Service XML definition document for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK&lt;br /&gt;
* your chosen communication protocol's API&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The protocol you choose for your Widgets must be the same protocol used on your choice of Node.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document focuses on the development of the Widget driver. Details about the communications protocol used are beyond the scope of this document. This document assumes you are familiar with your chosen protocol's code libraries and are able to use them in the driver code you write.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Related Documents ==&lt;br /&gt;
&lt;br /&gt;
The following related OpenHome documentation may be of interest to you:&lt;br /&gt;
&lt;br /&gt;
* [[ohWidget Technical Overview|ohWidget Technical Overview]]&lt;br /&gt;
* [[OpenHome Widget Service XML definition|OpenHome Widget Service XML definition]]&lt;br /&gt;
* [http://www.openhome.org/releases/ohNet_DeviceStack.pdf  OpenHome ohNet Device Stack]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
None of the related documents listed above is mandatory reading for Widget driver development.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
== Widget Service XML ==&lt;br /&gt;
OpenHome Widget driver writing relies heavily on the use of code generated from a single source — the Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
The service and actions your Widget provides are represented in code in a file called a Provider. The Provider is automatically generated from the Widget Service XML and produces an abstract class for you to inherit when you write your concrete class driver.&lt;br /&gt;
&lt;br /&gt;
To aid in the explanation of how the Provider is created and put to use we will follow the development of&lt;br /&gt;
a driver for a simple light Widget; taking the defined Widget Service XML and stepping through how it is used to generate the other files. Examples of code are used throughout this document to show you how each one is created and used in an OpenHome system. &lt;br /&gt;
&lt;br /&gt;
It is essential that you start with a well-formed Widget Service XML, conforming to the schema defined&lt;br /&gt;
in the WidgetService.xsd. The following diagram shows the significance of the Widget Service XML in&lt;br /&gt;
relation to the generated files you will use when writing your driver:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarchy, highlighting the areas specifically used in driver development]]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* The grayed-out files are not relevant to Widget driver development but can also be generated from the Widget Service XML.&lt;br /&gt;
* The Provider is generated in C#, meaning your driver must be written in C# as well. The use of managed code is mandatory for driver writing in the OpenHome framework.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Code sample used in this document ==&lt;br /&gt;
&lt;br /&gt;
Our examples in this document use a Widget Service XML definition for a light Widget called&lt;br /&gt;
BasicLight.xml.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Full versions of all the example files used in this document are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We will see how the Provider is generated from this XML and how it is used to aid the driver writing process. The examples also show how your chosen communication protocol should be used in the body of the driver code.&lt;br /&gt;
&lt;br /&gt;
Implementation details of specific protocols you choose to use are beyond the scope of this document. However, the samples used in this document show the use of the SimpleUPnP protocol to aid you in your development process.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol during the early stages of the OpenHome project. It is included in the OpenHome SDK and can be used as a public resource. &lt;br /&gt;
&lt;br /&gt;
The use of SimpleUPnP in the example files and the code snippets within the following sections is highlighted by the [[File:Warning.png]] icon. The lines of code marked by [[File:Warning.png]] must be changed to code from your chosen communication protocol's library. SimpleUPnP is left in to help you understand how a protocol is used in a working example.&lt;br /&gt;
&lt;br /&gt;
The sample code provided attempts to show best-practice coding standards. There are several sections of code that have a mandatory layout or that call specifically named methods and functions. These areas of the code are highlighted where required. &lt;br /&gt;
&lt;br /&gt;
Where the examples do not explicitly state that the code shown is mandatory, you are free to implement it in a different way according to your own coding style and practices.&lt;br /&gt;
&lt;br /&gt;
= Driver responsibilities = &lt;br /&gt;
&lt;br /&gt;
== Driver responsibilities ==&lt;br /&gt;
&lt;br /&gt;
An OpenHome Widget driver has several responsibilities which must be met before it can be used on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
These responsibilities are listed R1 to R7 and are defined here, explaining what each one must do. &lt;br /&gt;
&lt;br /&gt;
=== R1 Specifying the type of Widget the driver controls ===&lt;br /&gt;
A driver must know which type of Widget it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
=== R2 Reacting to a discovered Widget on the network ===&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== R3 Setting the initial values for the Widget's properties ===&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
=== R4 Publishing discovered Widgets in the Local Widget Registry on the Node ===&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object.&lt;br /&gt;
&lt;br /&gt;
=== R5 Reacting to an event reported from the Widget ===&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
=== R6 Reacting to actions sent to the Widget ===&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== R7 Reacting to a Widget's departure ===&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no&lt;br /&gt;
longer available.&lt;br /&gt;
&lt;br /&gt;
The sections of example code that follow show you how to write a driver from beginning to end. The accompanying text explaining the example code highlights when a responsibility, or part of a responsibility, has been met.&lt;br /&gt;
&lt;br /&gt;
= Driver Architecture = &lt;br /&gt;
&lt;br /&gt;
== Driver Architecture ==&lt;br /&gt;
&lt;br /&gt;
Drivers are installed on the Node and used when the Node needs to communicate with the Widget. Drivers&lt;br /&gt;
use several objects to communicate with Widgets over the Widget's lifetime. Figure 2 shows the objects&lt;br /&gt;
used by the driver and how the responsibilities listed above relate to each one:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture.png|800px|thumb|center|Figure 2: The architecture of a driver, showing the driver's relationship to the objects used to communicate with a Widget. Lines between objects show message flow.]]&lt;br /&gt;
&lt;br /&gt;
The objects contained in the dotted boundary must appear in the code you write to define your driver. The Driver, Provider and IWidgetRegistryEntry objects are all contained in the same driver file. We begin discussing this on page 12. &lt;br /&gt;
&lt;br /&gt;
The other objects are provided by the OpenHome SDK or as installed components on the Node.&lt;br /&gt;
&lt;br /&gt;
The Discovery Module informs the driver of the presence of an available Widget.&lt;br /&gt;
&lt;br /&gt;
Each Node has a Protocol Module which contains the protocol's API. Widgets can communicate with OpenHome Nodes using any one of the set of communications protocols the Node supports. The driver uses your chosen protocol's Protocol Module to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
Both the Protocol Module and the Discovery Module are installed on the Node. When you write your&lt;br /&gt;
driver you will use your Protocol Module to allow the driver to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
IWidgetPublisher, IPublishedWidget and DvDevice are objects provided in the OpenHome&lt;br /&gt;
API. You can read about them in the APIs.&lt;br /&gt;
&lt;br /&gt;
= Generating the Provider = &lt;br /&gt;
&lt;br /&gt;
== Generating the Provider ==&lt;br /&gt;
&lt;br /&gt;
You must generate your provider before you can begin writing your Widget driver. You use your provider as a guide to implement the functions your Widget needs to set the values of its properties.&lt;br /&gt;
&lt;br /&gt;
The current provider generation process is a manual one involving the use of a text transform tool.&lt;br /&gt;
&lt;br /&gt;
Speak to your OpenHome contact who will help you generate your provider.&lt;br /&gt;
&lt;br /&gt;
Future releases of the OpenHome SDK will include a tool to help you generate the provider.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
You must be in possession of:&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK, unpacked on your computer&lt;br /&gt;
* your Widget Service XML file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Writing a SimpleUPnP driver = &lt;br /&gt;
&lt;br /&gt;
== Introduction to the SimpleUPnP protocol ==&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol used to control emulated Widgets over a custom UPnP service.&lt;br /&gt;
&lt;br /&gt;
This chapter shows how a driver is written using the SimpleUPnP communications protocol. The aim is to show the code using as generic a protocol as possible so that you can see where your own protocol specific code needs to go.&lt;br /&gt;
&lt;br /&gt;
The use of code specific to the SimpleUPnP implementation is highlighted by the use of the [[File:Warning.png]] icon. The lines of code are marked by this icon to make it easier for you to see where the protocol-specific code must go and what parts of the code are generic.&lt;br /&gt;
&lt;br /&gt;
=== Register model ===&lt;br /&gt;
&lt;br /&gt;
SimpleUPnP is modeled on 8 physical registers available on the Widget. Each register is 32-bits wide. They are indexed from 0 to 7 and the last register (register 7) is reserved for storing the Widget's class.&lt;br /&gt;
&lt;br /&gt;
This detail is used by the Protocol Module on the Node to determine which driver is needed to run the new Widget when it has been discovered.&lt;br /&gt;
&lt;br /&gt;
The remaining 7 registers (registers 0 to 6) are free for Widget engineers to assign to the Widget's functions.&lt;br /&gt;
&lt;br /&gt;
Registers 0, 1, 2 and 3 are available as read/write registers. Registers 4, 5 and 6 are readonly registers.&lt;br /&gt;
&lt;br /&gt;
Only the emulated hardware (running on the Node) can change the values held in registers 4, 5 and 6.&lt;br /&gt;
&lt;br /&gt;
=== Register use in drivers ===&lt;br /&gt;
&lt;br /&gt;
In the example that follows we have a Basic Light Widget with a very simple function: it can be turned on and turned off. The on/off value is stored in register 0, with values 0=OFF and 1=ON. Register 0 is a read/write register. This means we can change the value stored there using messages passed to the Widget from the Node, and by reacting to physical interactions at the Widget (such as someone manually switching the light on or off). &lt;br /&gt;
&lt;br /&gt;
The mapping of registers to properties on the Widget is decided by the engineers who manufacture the device. You must be provided with the mapping before you begin developing your driver.&lt;br /&gt;
&lt;br /&gt;
== Starting the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-BoxHighlight.png|800px|thumb|center|Figure 3 The driver architecture highlighting the Widget driver and its component parts.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When you have generated the abstract provider you can put it to use in the Widget driver. A Widget driver&lt;br /&gt;
has three distinct components:&lt;br /&gt;
&lt;br /&gt;
* an implementation of your abstract provider&lt;br /&gt;
* a definition of the Widget driver&lt;br /&gt;
* an implementation of the IWidgetRegistryEntry interface&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must manually write the code for your Widget driver. The differences in implementation of Widget properties and communication protocols means that the driver code cannot be autogenerated.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This section takes you through how to write a Widget driver by implementing the auto-generated provider,&lt;br /&gt;
starting from a new blank file and finishing with a working driver for the Basic Light Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
No assumptions have been made about the type of editor you use to write your code. Shortcuts&lt;br /&gt;
or macros that you use as standard will not appear in the instructions below. A full example&lt;br /&gt;
BinaryLightDriver.cs is available to review in Appendix C.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a new C# file in your IDE. Ensure the following libraries are used:&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 [[File:Warning.png]]using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 namespace OpenHome.Widget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must use the libraries listed above for this specific example.&lt;br /&gt;
&lt;br /&gt;
In general, drivers require the following libraries:&lt;br /&gt;
* System*&lt;br /&gt;
* System.Collections.Generic*&lt;br /&gt;
* OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
&lt;br /&gt;
Your driver will fail to compile if you miss any of these listed libraries. Libraries marked * are typically added by default by most modern IDEs. &lt;br /&gt;
&lt;br /&gt;
The OpenHome.Widget.Protocols.SimpleUpnp library is required only in this SimpleUPnP example. Drivers using a different protocol will use their own protocol library.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Implementing the provider ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-ProviderHighlight.png|800px|thumb|center|Figure 4 The driver architecture highlighting the Provider's place]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You use your auto-generated abstract provider by writing an implementation of it in the driver file. Responsibilities met by implementing your auto-generated provider are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R6 Reacting to actions sent to the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
Begin by creating a new class. It will subclass the abstract auto-generated provider:&lt;br /&gt;
&lt;br /&gt;
 class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
The Protocol Module will provide an API for the Provider to use to communicate with the Widget. In&lt;br /&gt;
SimpleUPnP we are provided with an interface called ISimpleUpnpWidget. The provider is supplied&lt;br /&gt;
with the required instance of the interface by the Discovery Module on the Node.&lt;br /&gt;
&lt;br /&gt;
The mechanisms for registering providers with specific Protocol Modules, and for the way the module gives each provider its required interface are covered later when writing the discovery method.&lt;br /&gt;
&lt;br /&gt;
For now, we need to give the Provider a place to store the interface that it will later use to communicate&lt;br /&gt;
with the Widget:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]] private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
&lt;br /&gt;
The interface from the Protocol Module is passed in as a parameter in the Provider's constructor and then&lt;br /&gt;
assigned to the variable we just created:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightProvider(DvDevice aDevice,&lt;br /&gt;
 [[File:Warning.png]]         ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
 {&lt;br /&gt;
       iProtocol = aProtocol;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
To satisfy R3 we would normally set the Widget's properties here, giving them an initial value.&lt;br /&gt;
However, in this specific example we cannot set the value of Basic Light's only property because&lt;br /&gt;
we will never know, in advance, what the state of the light will be (either on or off) when we&lt;br /&gt;
create the DiscoveredWidget.&lt;br /&gt;
&lt;br /&gt;
When you cannot set the properties ahead of time, and you are using an eventing protocol like SimpleUPnP, you can instead set them in the HandleRegisterEvent method in the driver class. This also satisfies the requirements for R3. You must set the Widget's properties before you enable it using SetEnabled(). &lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The abstract provider includes an abstract method called SetOn. This method is invoked by the Node when passing a message to the Widget, specifically to set the on property of the Widget to either 0 or 1. The implementation of this method will meet the requirements for R6.&lt;br /&gt;
&lt;br /&gt;
We must override this method and provide the protocol module a way of passing a message on to the Widget to perform the required action, in this case turn the light on or off:&lt;br /&gt;
&lt;br /&gt;
          protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
          {&lt;br /&gt;
     [[File:Warning.png]]        iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
In this example the Basic Light's SetOn property (the boolean property that controls whether the light is&lt;br /&gt;
on or off) is represented in the physical Widget by the register that has an index of 0.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* This method is an example of an action on a Widget. Actions are messages sent from the Node to the Widget. We will see later how to handle events that need to be passed back from the Widget&lt;br /&gt;
to the Node.&lt;br /&gt;
* Your own Widget will likely provide more than a single property. Your auto-generated provider will contain one abstract method to represent each writable property. Read-only properties are not provided an abstract method.&lt;br /&gt;
&lt;br /&gt;
You must implement each abstract method in your driver to ensure the relevant property on&lt;br /&gt;
the Widget can be set.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We have now finished implementing the provider. The next step is to implement the driver.&lt;br /&gt;
&lt;br /&gt;
== Implementing the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-DriverHighlight.png|800px|thumb|center|Figure 4: The driver architecture highlighting the implemented driver's place.]]&lt;br /&gt;
&lt;br /&gt;
The code for your Widget driver must provide an implementation of the IWidgetRegistryInterface,&lt;br /&gt;
including the following tasks:&lt;br /&gt;
&lt;br /&gt;
* methods to expose identifying details about the Widget for the Node to access&lt;br /&gt;
* providing methods to handle events reported by the Widget&lt;br /&gt;
&lt;br /&gt;
The driver is implemented as a public class within the same file as the provider code. Each driver must use the interface for the protocol you are using. For the SimpleUPnP protocol the interface is ISimple-UpnpWidgetDriver.&lt;br /&gt;
&lt;br /&gt;
=== Writing code ===&lt;br /&gt;
&lt;br /&gt;
Create your new driver class and subclass the ISimpleUpnpWidgetDriver interface:&lt;br /&gt;
&lt;br /&gt;
 public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Implementing IWidgetRegistryEntry ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry is the interface you use to represent physical Widgets. It is implemented as a subclass of your driver class. We are going to implement this interface in a class called '''DiscoveredWidget'''.&lt;br /&gt;
&lt;br /&gt;
Let's return to our driver architecture diagram for a moment:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-IRegistryEntryHighlight.png|800px|thumb|center|Figure 5 The driver architecture highlighting the IWidgetRegistryEntry object you will now implement]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry uses several other objects to help create it and respond to messages sent to and from it. These objects will be created in our implementation of DiscoveredWidget. &lt;br /&gt;
&lt;br /&gt;
When successfully created and published, the DiscoveredWidget objects are stored in a list on the Node called the Local Widget Registry. The Local Widget Registry is used by Nodes to maintain contact with the Widgets they control.&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry is shown at the top of Figure 5, marked plainly as (Registry). The path to the Local Widget Registry goes through several layers of Node architecture which are not relevant to Widget driver writing, so are not shown in the diagrams.&lt;br /&gt;
&lt;br /&gt;
==== Writing code ====&lt;br /&gt;
&lt;br /&gt;
Start by subclassing the IWidgetRegistryEntry interface in your new class:&lt;br /&gt;
&lt;br /&gt;
      private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
      {&lt;br /&gt;
&lt;br /&gt;
A DiscoveredWidget must provide the driver with the objects required to present the Widget and its&lt;br /&gt;
properties to the Node:&lt;br /&gt;
&lt;br /&gt;
           private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
           private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
           private readonly ISimpleUpnpWidget iProtocol;&lt;br /&gt;
           private readonly BinaryLightProvider iProvider;&lt;br /&gt;
           private readonly DvDevice iDvDevice;&lt;br /&gt;
           private IPublishedWidget iPublishedWidget;&lt;br /&gt;
&lt;br /&gt;
Each of the attributes in the example above are defined as follows:&lt;br /&gt;
&lt;br /&gt;
iDeviceFactory — used by the driver to create a single instance of DvDevice to represent a single Widget&lt;br /&gt;
&lt;br /&gt;
iPublisher — used by the driver to publish the Widget to the Node&lt;br /&gt;
&lt;br /&gt;
iProtocol — the object used by the Widget to communicate with the Protocol Module on the Node&lt;br /&gt;
&lt;br /&gt;
iProvider — an instantiated provider of the type you defined earlier&lt;br /&gt;
&lt;br /&gt;
iDvDevice — a representation of a Widget to which the provider is attached, created using iDevice-Factory above&lt;br /&gt;
&lt;br /&gt;
iPublishedWidget — used to contain the returned object from a successful publishing of the Widget&lt;br /&gt;
If we look again at the driver architecture diagram, we ca highlight the objects we've just defined:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-Highlight.png|800px|thumb|center|Figure 6: The driver architecture highlighting the objects used by the IWidgetRegistryEntry implementation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The DeviceFactory, defined above in the member variable iDeviceFactory, is used to create new DvDevice objects. The DeviceFactory is only ever used to do this once. It is not shown in the driver architecture diagrams due to its minimal role in the operation of a driver, but it would normally appear between the IWidgetRegistryEntry and DvDevice objects.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
A driver requires methods to expose identifying details about the Widget. We must provide access to two of the attributes we just defined above:&lt;br /&gt;
&lt;br /&gt;
 public DvDevice DvDevice&lt;br /&gt;
 {&lt;br /&gt;
     get { return iDvDevice; }&lt;br /&gt;
 }&lt;br /&gt;
 public string WidgetClass&lt;br /&gt;
 {&lt;br /&gt;
     get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The WidgetClass string is formed using a combination of the vendor name and the Widget's name in the&lt;br /&gt;
format:&lt;br /&gt;
&lt;br /&gt;
 [vendor_domain]:[widget_name]&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry can now query both the DvDevice object representing the Widget, and the specific class of Widget this driver represents. The other member variables we defined do not need their own accessor methods.&lt;br /&gt;
&lt;br /&gt;
Now we must write a constructor for DiscoveredWidget and assign the parameters accordingly: &lt;br /&gt;
&lt;br /&gt;
 public DiscoveredWidget(IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                            string aUdn,&lt;br /&gt;
                            ISimpleUpnpWidget aProxy,&lt;br /&gt;
                            IWidgetPublisher aPublisher)&lt;br /&gt;
 {&lt;br /&gt;
      iDeviceFactory = aDeviceFactory;&lt;br /&gt;
      iProtocol = aProtocol;&lt;br /&gt;
      iPublisher = aPublisher;&lt;br /&gt;
      iDvDevice = iDeviceFactory.CreateDevice(aUdn);&lt;br /&gt;
      iProvider = new BinaryLightProvider(iDvDevice,&lt;br /&gt;
      iProtocol);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Event handling ===&lt;br /&gt;
&lt;br /&gt;
A Widget's state can change in one of three significant ways:&lt;br /&gt;
&lt;br /&gt;
* when the Widget needs to be published on the Node&lt;br /&gt;
* when the Widget disappears from the network (by losing power or similar)&lt;br /&gt;
* when a property's state changes and must be updated to a new value&lt;br /&gt;
&lt;br /&gt;
We now need methods to handle these changes.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The methods we define here will be used as callbacks, rather than invoked as method calls. We define the methods here first and then use them later on. We will use the Protocol Module to listen for changes in the Widget's state and register these methods as callbacks there. See Writing the SimpleUPnP Widget discovery method for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this section of the driver are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R4 Publishing discovered Widgets in the Local Widget Registry on the Node'''&lt;br /&gt;
&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object. &lt;br /&gt;
&lt;br /&gt;
'''R5 Reacting to an event reported from the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
'''R7 Reacting to a Widget's departure'''&lt;br /&gt;
&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no longer available.&lt;br /&gt;
&lt;br /&gt;
==== Enabling and publishing a discovered Widget ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first method initializes the Widget by enabling the device and then using the IWidgetPublisher&lt;br /&gt;
to make it available on the Node:&lt;br /&gt;
&lt;br /&gt;
 public void HandleInitialEvent()&lt;br /&gt;
 {&lt;br /&gt;
      iDvDevice.SetEnabled();&lt;br /&gt;
      iPublisher.TryPublishWidget(iDvDevice.iUdn(),&lt;br /&gt;
                              this,&lt;br /&gt;
                              out iPublishedWidget);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This method meets the requirements for R4.&lt;br /&gt;
&lt;br /&gt;
The call to TryPublishWidget returns an iPublishedWidget object. We use this object later to satisfy the requirements of R7.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The ordering of the calls to SetEnabled and TryPublishWidget is vitally important. You&lt;br /&gt;
must enable the device before you attempt to publish it. Your Widget will not be available to the&lt;br /&gt;
Nodes unless SetEnabled is called first. Nodes will not be able to access a published device&lt;br /&gt;
that has not been enabled.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
R3 requires that you set the Widget's properties before you enable and publish the device. We&lt;br /&gt;
discussed on page 14 how some properties can only be set after the Widget reports what their&lt;br /&gt;
state is. We do this in HandleRegisterEvent.&lt;br /&gt;
&lt;br /&gt;
We rely on the SimpleUPnP Protocol Module guaranteeing a call to HandleRegisterEvent first before HandleInitialEvent. This is informed by guarantees made by the Control Point stack that the calls will be made in that order.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
==== Removing a Widget ====&lt;br /&gt;
&lt;br /&gt;
Removing a Widget involves unpublishing it from the Node. The IPublishedWidget interface provides us with a method we can call to manage that for us:&lt;br /&gt;
&lt;br /&gt;
 public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
 {&lt;br /&gt;
     if (iPublishedWidget != null)&lt;br /&gt;
     { iPublishedWidget.Unpublish(); }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assuming that the Widget was successfully published earlier, it is removed from the Node's Local Widget Registry.&lt;br /&gt;
&lt;br /&gt;
We must also properly handle the resources we used to create and maintain the Widget object while it was published:&lt;br /&gt;
&lt;br /&gt;
      iProvider.Dispose();&lt;br /&gt;
      iDvDevice.Dispose();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The calls to Dispose are made regardless of the Widget's published state, ensuring that any created device and associated provider are properly disposed. This implementation satisfies R7.&lt;br /&gt;
&lt;br /&gt;
====Event handling ====&lt;br /&gt;
&lt;br /&gt;
We need a method to handle changes to the state of the Widget's properties.&lt;br /&gt;
&lt;br /&gt;
If the property changes at the Widget, it needs to pass the new state back to the Node so that it is kept up-to-date on the Widget's status. This is called an event. An example in the case of our Basic Light is someone manually switching the light from on to off. This is in contrast to actions, which are passed from the Node to the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Other examples of events involve no human interaction, such as a thermometer Widget updating its current temperature based on environmental changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Our Basic Light Widget has only one property that needs to be handled:&lt;br /&gt;
&lt;br /&gt;
 public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
 {&lt;br /&gt;
     if (aIndex == 0)&lt;br /&gt;
     {&lt;br /&gt;
         iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We use our instance of the provider to update the register on the Widget that is mapped to the On property. This in turn updates the Node with the new state of the Widget.&lt;br /&gt;
&lt;br /&gt;
This method provides implementations to satisfy two driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
* R3 is now completely satisfied, as we can now set the values of all the previously unknown properties here.&lt;br /&gt;
* R5 is also satisfied as this method allows us to update the Widget's status on the Node when a property is changed on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Not all protocols pass messages back to the Node in this manner. The way we have satisfied R3 and R5 here only applies to protocols and Widgets that support this behavior.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Widgets that do not use an eventing protocol need to have their properties set in the provider's constructor to satisfy R3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To satisfy R5, the over-ridden method SetOn in the provider must include the call to SetPropertyOn. Non-eventing protocols do not require a HandleRegisterEvent method.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Constructor ===&lt;br /&gt;
&lt;br /&gt;
The final requirement for the driver is the constructor so that new DiscoveredWidget objects can be created. &lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this area of code are:&lt;br /&gt;
&lt;br /&gt;
'''R1 Specifying the type of Widget the driver controls'''&lt;br /&gt;
&lt;br /&gt;
A driver must know which type of Widget that it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
==== Writing the code ====&lt;br /&gt;
&lt;br /&gt;
We begin by defining the variables we will use to store the objects used by the driver:&lt;br /&gt;
&lt;br /&gt;
 private readonly string iName;&lt;br /&gt;
 private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
 private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now write the constructor for the driver and assign the passed in parameters appropriately:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightDriver(string aName,&lt;br /&gt;
                IWidgetPublisher aPublisher,&lt;br /&gt;
                IDvDeviceFactory aDeviceFactory)&lt;br /&gt;
 {&lt;br /&gt;
     iWidgetPublisher = aPublisher;&lt;br /&gt;
     iName = aName;&lt;br /&gt;
     iDeviceFactory = aDeviceFactory;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally we need to provide the driver a way to publish the class of Widget it controls. This information is requested by the Discovery Module and is used to ensure the Node uses the correct driver when a new Widget appears.&lt;br /&gt;
&lt;br /&gt;
The implementation for this details will be different for each protocol. The SimpleUPnP protocol library provides a file that contains the SimpleUPnP definitions as integers. Each integer represents a particular class of identified Widget.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP implementation of that method is as follows:&lt;br /&gt;
&lt;br /&gt;
 public IEnumerable&amp;lt;uint&amp;gt; WidgetClasses&lt;br /&gt;
 {&lt;br /&gt;
 [[File:Warning.png]]        get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The body of this method is specifically written for the Widget class we are defining (in this case a binary light). This method completes the driver's requirements for R1.&lt;br /&gt;
&lt;br /&gt;
== Writing the SimpleUPnP Widget discovery method ==&lt;br /&gt;
&lt;br /&gt;
Every driver must contain a method which creates new objects to represent newly discovered Widgets.&lt;br /&gt;
The Discovery Module invokes this method to begin the process of creating the objects required to allow the Node to access the Widget. &lt;br /&gt;
&lt;br /&gt;
The name of this method is dictated by your chosen protocol's API. The SimpleUPnP protocol requires a method called WidgetDiscovered.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The method's name will not always be the same for each protocol. Your protocol's documentation will contain the details of what this method must be called.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This method and its implementation will meet the following driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
'''R2 Reacting to a discovered Widget on the network'''&lt;br /&gt;
&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
Our implementation of the WidgetDiscovered method will create a new DiscoveredWidget object and use the Protocol Module to listen for changes to the Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
The method uses the Protocol Module and two ways to identify the Widget. We must pass these in as&lt;br /&gt;
parameters:&lt;br /&gt;
&lt;br /&gt;
 public void WidgetDiscovered(string aWidgetUdn,&lt;br /&gt;
                              uint aWidgetClass,&lt;br /&gt;
                              ISimpleUpnpWidget&lt;br /&gt;
                                  aSimpleUpnpWidget)&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
Every Widget that uses this driver must be uniquely identifiable:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]    string newUdn = aWidgetUdn;&lt;br /&gt;
&lt;br /&gt;
Each new Widget is represented by a DiscoveredWidget object. Create the new DiscoveredWidget and pass in the required parameters we created earlier:&lt;br /&gt;
&lt;br /&gt;
     DiscoveredWidget discoveredWidget =&lt;br /&gt;
                 new DiscoveredWidget(iDeviceFactory,&lt;br /&gt;
                                      newUdn,&lt;br /&gt;
  &lt;br /&gt;
 [[File:Warning.png]]                                    aSimpleUpnpWidget,&lt;br /&gt;
&lt;br /&gt;
=== Registering the callbacks ===&lt;br /&gt;
&lt;br /&gt;
Finally, we ask the Widget's protocol interface to listen for calls to the handler methods we defined earlier in DiscoveredWidget. We do this by registering those methods as callbacks for the Protocol Module&lt;br /&gt;
to listen for:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                        discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                        discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                        discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You have now met 100% of the driver responsibility requirements and have a working driver to use with your SimpleUPnP Widget.&lt;br /&gt;
&lt;br /&gt;
= Appendix A. Sample XML =&lt;br /&gt;
&lt;br /&gt;
== Binary Light.xml ==&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
  &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
  &amp;lt;version&amp;gt;&lt;br /&gt;
   &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
   &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/version&amp;gt;&lt;br /&gt;
  &amp;lt;propertylist&amp;gt;&lt;br /&gt;
   &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
       illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
   &amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix B. Sample Provider = &lt;br /&gt;
&lt;br /&gt;
== DvWidgetOpenhomeOrgBasicLight1.cs ==&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Runtime.InteropServices;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Core;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Utils.Binary;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
 {&lt;br /&gt;
    public interface IDvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
        IDisposable&lt;br /&gt;
    {&lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous value&lt;br /&gt;
        /// &amp;lt;/returns&amp;gt;&lt;br /&gt;
        bool SetPropertyOn(bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;Property's value will be copied&lt;br /&gt;
        /// here&amp;lt;/param&amp;gt;&lt;br /&gt;
        bool PropertyOn();&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt; summary&amp;gt;&lt;br /&gt;
    /// Provider for the openhome.org:BinaryLight:1 UPnP service&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public abstract class DvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
               DvProvider,&lt;br /&gt;
               IDisposable,&lt;br /&gt;
               IDvProviderOpenhomeOrgBinaryLight1&lt;br /&gt;
    {&lt;br /&gt;
        private GCHandle iGch;&lt;br /&gt;
        private PropertyBool iPropertyOn;&lt;br /&gt;
        private PropertyUint iPropertyPrimarySeq;&lt;br /&gt;
        private PropertyUint iPropertySecondarySeq;&lt;br /&gt;
        private ActionDelegate iDelegateSetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetPrimaryProperty;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Constructor&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aDevice&amp;quot;&amp;gt;Device which owns this&lt;br /&gt;
        /// provider&amp;lt;/param&amp;gt;&lt;br /&gt;
        protected DvProviderOpenhomeOrgBinaryLight1(DvDevice aDevice)&lt;br /&gt;
            : base(aDevice, &amp;quot;openhome.org&amp;quot;, &amp;quot;GenericWidget&amp;quot;, 1)&lt;br /&gt;
        {&lt;br /&gt;
            iGch = GCHandle.Alloc(this);&lt;br /&gt;
            List&amp;lt;String&amp;gt; allowedValues = new List&amp;lt;String&amp;gt;();&lt;br /&gt;
            iPropertyOn = new PropertyBool(new ParameterBool(&amp;quot;On&amp;quot;));&lt;br /&gt;
            iPropertyPrimarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;PrimarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertyPrimarySeq);&lt;br /&gt;
            iPropertySecondarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;SecondarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertySecondarySeq);&lt;br /&gt;
            SetPropertyUint(iPropertyPrimarySeq, 0);&lt;br /&gt;
            SetPropertyUint(iPropertySecondarySeq, 0);&lt;br /&gt;
  &lt;br /&gt;
            Zapp.Core.Action action = new Zapp.Core.Action&lt;br /&gt;
                (&amp;quot;SetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;FireAndForget&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddInputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateSetProperty = new ActionDelegate(DoSetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateSetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateGetProperty = new ActionDelegate(DoGetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetPrimaryProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                 (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;integer&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;boolean&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;string&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;binary&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Type&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;readWrite&amp;quot;);allowedValues.Add&lt;br /&gt;
                (&amp;quot;readOnly&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;writeOnly&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString(&amp;quot;Access&amp;quot;,&lt;br /&gt;
                allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            iDelegateGetPrimaryProperty = new&lt;br /&gt;
            ActionDelegate(DoGetPrimaryProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetPrimaryProperty,&lt;br /&gt;
            GCHandle.ToIntPtr(iGch));&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous&lt;br /&gt;
        /// value&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool SetPropertyOn(bool aValue)&lt;br /&gt;
        {&lt;br /&gt;
            if (iPropertyOn.SetValue(aValue))&lt;br /&gt;
            {&lt;br /&gt;
                lock (iPropertyPrimarySeq)&lt;br /&gt;
                {&lt;br /&gt;
                    SetPropertyUint(iPropertyPrimarySeq,&lt;br /&gt;
                        iPropertyPrimarySeq.Value() + 1);&lt;br /&gt;
                } return true;&lt;br /&gt;
            } return false;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;The value of the property&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool PropertyOn()&lt;br /&gt;
        {&lt;br /&gt;
            return iPropertyOn.Value();&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the On property.&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aVersion&amp;quot;&amp;gt;Version of the service being&lt;br /&gt;
        /// requested (will be &amp;lt;= the version advertised)&amp;lt;/param&amp;gt; &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the On property.&lt;br /&gt;
        /// &amp;lt;/param&amp;gt;&lt;br /&gt;
        protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        private static int DoSetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                byte[] valBin = invocation.ReadBinary(&amp;quot;Value&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                switch (name)&lt;br /&gt;
                {&lt;br /&gt;
                    case &amp;quot;On&amp;quot;:&lt;br /&gt;
                        self.SetOn(aVersion, Converter.&lt;br /&gt;
                            BinaryToBoolean(valBin));&lt;br /&gt;
                        break;&lt;br /&gt;
                    default:&lt;br /&gt;
                        throw new ActionError();&lt;br /&gt;
                }&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
                invocation.WriteEnd();&lt;br /&gt;
            }&lt;br /&gt;
            catch (ActionError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
            catch (PropertyUpdateError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
        return 0;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        private static int DoGetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
            switch (name)&lt;br /&gt;
            {&lt;br /&gt;
                case &amp;quot;On&amp;quot;:&lt;br /&gt;
                invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                    Converter.BooleanToBinary(self.iPropertyOn.&lt;br /&gt;
                        Value()));&lt;br /&gt;
                break;&lt;br /&gt;
                default:&lt;br /&gt;
                throw new ActionError();&lt;br /&gt;
            }&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    private static int DoGetPrimaryProperty(IntPtr aPtr,&lt;br /&gt;
                    IntPtr aInvocation,&lt;br /&gt;
                    uint aVersion)&lt;br /&gt;
    {&lt;br /&gt;
        GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
        DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
            (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
        DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
  &lt;br /&gt;
        try&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReadStart();&lt;br /&gt;
            invocation.ReadEnd();&lt;br /&gt;
            invocation.WriteStart();&lt;br /&gt;
            invocation.WriteString(&amp;quot;Name&amp;quot;, &amp;quot;On&amp;quot;);&lt;br /&gt;
            invocation.WriteString(&amp;quot;Type&amp;quot;, &amp;quot;boolean&amp;quot;);&lt;br /&gt;
            invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                Converter.BooleanToBinary(self.iPropertyOn.Value()));&lt;br /&gt;
            invocation.WriteString(&amp;quot;Access&amp;quot;, &amp;quot;readWrite&amp;quot;);&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt;summary&amp;gt;&lt;br /&gt;
    /// Must be called for each class instance. Must be called before&lt;br /&gt;
    /// Core.Library.Close().&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public void Dispose()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
        GC.SuppressFinalize(this);&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
    ~DvProviderOpenhomeOrgBinaryLight1()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
        private void DoDispose()&lt;br /&gt;
        {&lt;br /&gt;
            lock (this)&lt;br /&gt;
            {&lt;br /&gt;
                if (iHandle == IntPtr.Zero)&lt;br /&gt;
            {&lt;br /&gt;
                    return;&lt;br /&gt;
            }&lt;br /&gt;
            DisposeProvider();&lt;br /&gt;
            iPropertyOn.Dispose();&lt;br /&gt;
            iHandle = IntPtr.Zero;&lt;br /&gt;
            }&lt;br /&gt;
            iGch.Free();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix C. Sample Driver = &lt;br /&gt;
&lt;br /&gt;
== BasicLightDriver.cs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.hWidget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
     class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
     {&lt;br /&gt;
         private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
         public BinaryLightProvider(DvDevice aDevice, &lt;br /&gt;
             ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol = aProtocol;&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
     {&lt;br /&gt;
         private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
         {&lt;br /&gt;
             private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
             private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
             private readonly ISimpleUpnpWidget iProtocol; &lt;br /&gt;
 &lt;br /&gt;
             private readonly BinaryLightProvider iProvider;&lt;br /&gt;
             private readonly DvDevice iDvDevice;&lt;br /&gt;
             private IPublishedWidget iPublishedWidget; &lt;br /&gt;
 &lt;br /&gt;
             public DvDevice DvDevice&lt;br /&gt;
             {&lt;br /&gt;
                 get { return iDvDevice; }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             public string WidgetClass&lt;br /&gt;
             {&lt;br /&gt;
                 get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public DiscoveredWidget(&lt;br /&gt;
                 IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                 string aUdn,&lt;br /&gt;
                 ISimpleUpnpWidget aProxy,&lt;br /&gt;
                 IWidgetPublisher aPublisher)&lt;br /&gt;
             {&lt;br /&gt;
                 iDeviceFactory = aDeviceFactory;&lt;br /&gt;
                 iProtocol = aProtocol;&lt;br /&gt;
 &lt;br /&gt;
                 iPublisher = aPublisher;&lt;br /&gt;
                 iDvDevice = iDeviceFactory.CreateDevice(aUdn);  &lt;br /&gt;
                 iProvider = new BinaryLightProvider(iDvDevice, &lt;br /&gt;
                                                     iProtocol);&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             public void HandleInitialEvent()&lt;br /&gt;
             {&lt;br /&gt;
                 iDvDevice.SetEnabled();&lt;br /&gt;
                 iPublisher.TryPublishWidget(iDvDevice.iUdn(), this,&lt;br /&gt;
                     out iPublishedWidget);&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
             {&lt;br /&gt;
                 if (iPublishedWidget != null)&lt;br /&gt;
                 {&lt;br /&gt;
                     iPublishedWidget.Unpublish();&lt;br /&gt;
                 } &lt;br /&gt;
                 iProvider.Dispose();&lt;br /&gt;
                 iDvDevice.Dispose();&lt;br /&gt;
             }  &lt;br /&gt;
 &lt;br /&gt;
             public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
             {&lt;br /&gt;
                 if (aIndex == 0)&lt;br /&gt;
                 {&lt;br /&gt;
                     iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         private readonly string iName;&lt;br /&gt;
         private readonly IDvDeviceFactory aDeviceFactory;&lt;br /&gt;
         private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
         &lt;br /&gt;
         public BinaryLightDriver(&lt;br /&gt;
             string aName,&lt;br /&gt;
             IWidgetPublisher aPublisher,&lt;br /&gt;
             iDeviceFactory aDeviceFactory)&lt;br /&gt;
         {&lt;br /&gt;
             iWidgetPublisher = aPublisher;&lt;br /&gt;
             iName = aName;&lt;br /&gt;
             iDeviceFactory = aDeviceFactory;&lt;br /&gt;
         } &lt;br /&gt;
 &lt;br /&gt;
         public IEnumerable&amp;amp;lt;uint&amp;amp;gt; WidgetClasses&lt;br /&gt;
         {&lt;br /&gt;
             get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         public void WidgetDiscovered(&lt;br /&gt;
             string aWidgetUdn,&lt;br /&gt;
             uint aWidgetClass,&lt;br /&gt;
             ISimpleUpnpWidget aSimpleUpnpWidget)&lt;br /&gt;
         {&lt;br /&gt;
             string newUdn = aWidgetUdn;&lt;br /&gt;
             DiscoveredWidget discoveredWidget = new DiscoveredWidget&lt;br /&gt;
                 (iDeviceFactory,&lt;br /&gt;
                  newUdn,&lt;br /&gt;
                  aSimpleUpnpWidget,&lt;br /&gt;
                  iWidgetPublisher);&lt;br /&gt;
 &lt;br /&gt;
             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                 discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                 discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                 discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary = &lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in OpenHome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by OpenHome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh - A collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs on ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The OpenHome Operating System. Core software for OpenHome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. &lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. A typical Widget supports only one protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Driver_Development</id>
		<title>OhWidget Driver Development</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Driver_Development"/>
				<updated>2012-03-01T15:21:01Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Implementing the provider */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for developers using the OpenHome SDK to integrate a Widget into an OpenHome system. Each Widget must have its own driver to allow it to communicate with the OpenHome Nodes. &lt;br /&gt;
&lt;br /&gt;
To help you write your driver, this document provides high level descriptions of the core responsibilities of a Widget driver and gives a detailed walk-through using example code.&lt;br /&gt;
&lt;br /&gt;
Full versions of each file used in the development of the example driver are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin development of your Widget driver you must be in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* your Widget Service XML that describes the properties on your Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document does not contain advice on how to write Widget Service XML. Refer to the OpenHome Widget Service XML definition document for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK&lt;br /&gt;
* your chosen communication protocol's API&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The protocol you choose for your Widgets must be the same protocol used on your choice of Node.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document focuses on the development of the Widget driver. Details about the communications protocol used are beyond the scope of this document. This document assumes you are familiar with your chosen protocol's code libraries and are able to use them in the driver code you write.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Related Documents ==&lt;br /&gt;
&lt;br /&gt;
The following related OpenHome documentation may be of interest to you:&lt;br /&gt;
&lt;br /&gt;
* [[ohWidget Technical Overview|ohWidget Technical Overview]]&lt;br /&gt;
* [[OpenHome Widget Service XML definition|OpenHome Widget Service XML definition]]&lt;br /&gt;
* [http://www.openhome.org/releases/ohNet_DeviceStack.pdf  OpenHome ohNet Device Stack]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
None of the related documents listed above is mandatory reading for Widget driver development.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
== Widget Service XML ==&lt;br /&gt;
OpenHome Widget driver writing relies heavily on the use of code generated from a single source — the Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
The service and actions your Widget provides are represented in code in a file called a Provider. The Provider is automatically generated from the Widget Service XML and produces an abstract class for you to inherit when you write your concrete class driver.&lt;br /&gt;
&lt;br /&gt;
To aid in the explanation of how the Provider is created and put to use we will follow the development of&lt;br /&gt;
a driver for a simple light Widget; taking the defined Widget Service XML and stepping through how it is used to generate the other files. Examples of code are used throughout this document to show you how each one is created and used in an OpenHome system. &lt;br /&gt;
&lt;br /&gt;
It is essential that you start with a well-formed Widget Service XML, conforming to the schema defined&lt;br /&gt;
in the WidgetService.xsd. The following diagram shows the significance of the Widget Service XML in&lt;br /&gt;
relation to the generated files you will use when writing your driver:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarchy, highlighting the areas specifically used in driver development]]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* The grayed-out files are not relevant to Widget driver development but can also be generated from the Widget Service XML.&lt;br /&gt;
* The Provider is generated in C#, meaning your driver must be written in C# as well. The use of managed code is mandatory for driver writing in the OpenHome framework.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Code sample used in this document ==&lt;br /&gt;
&lt;br /&gt;
Our examples in this document use a Widget Service XML definition for a light Widget called&lt;br /&gt;
BasicLight.xml.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Full versions of all the example files used in this document are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We will see how the Provider is generated from this XML and how it is used to aid the driver writing process. The examples also show how your chosen communication protocol should be used in the body of the driver code.&lt;br /&gt;
&lt;br /&gt;
Implementation details of specific protocols you choose to use are beyond the scope of this document. However, the samples used in this document show the use of the SimpleUPnP protocol to aid you in your development process.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol during the early stages of the OpenHome project. It is included in the OpenHome SDK and can be used as a public resource. &lt;br /&gt;
&lt;br /&gt;
The use of SimpleUPnP in the example files and the code snippets within the following sections is highlighted by the [[File:Warning.png]] icon. The lines of code marked by [[File:Warning.png]] must be changed to code from your chosen communication protocol's library. SimpleUPnP is left in to help you understand how a protocol is used in a working example.&lt;br /&gt;
&lt;br /&gt;
The sample code provided attempts to show best-practice coding standards. There are several sections of code that have a mandatory layout or that call specifically named methods and functions. These areas of the code are highlighted where required. &lt;br /&gt;
&lt;br /&gt;
Where the examples do not explicitly state that the code shown is mandatory, you are free to implement it in a different way according to your own coding style and practices.&lt;br /&gt;
&lt;br /&gt;
= Driver responsibilities = &lt;br /&gt;
&lt;br /&gt;
== Driver responsibilities ==&lt;br /&gt;
&lt;br /&gt;
An OpenHome Widget driver has several responsibilities which must be met before it can be used on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
These responsibilities are listed R1 to R7 and are defined here, explaining what each one must do. &lt;br /&gt;
&lt;br /&gt;
=== R1 Specifying the type of Widget the driver controls ===&lt;br /&gt;
A driver must know which type of Widget it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
=== R2 Reacting to a discovered Widget on the network ===&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== R3 Setting the initial values for the Widget's properties ===&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
=== R4 Publishing discovered Widgets in the Local Widget Registry on the Node ===&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object.&lt;br /&gt;
&lt;br /&gt;
=== R5 Reacting to an event reported from the Widget ===&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
=== R6 Reacting to actions sent to the Widget ===&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== R7 Reacting to a Widget's departure ===&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no&lt;br /&gt;
longer available.&lt;br /&gt;
&lt;br /&gt;
The sections of example code that follow show you how to write a driver from beginning to end. The accompanying text explaining the example code highlights when a responsibility, or part of a responsibility, has been met.&lt;br /&gt;
&lt;br /&gt;
= Driver Architecture = &lt;br /&gt;
&lt;br /&gt;
== Driver Architecture ==&lt;br /&gt;
&lt;br /&gt;
Drivers are installed on the Node and used when the Node needs to communicate with the Widget. Drivers&lt;br /&gt;
use several objects to communicate with Widgets over the Widget's lifetime. Figure 2 shows the objects&lt;br /&gt;
used by the driver and how the responsibilities listed above relate to each one:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture.png|800px|thumb|center|Figure 2: The architecture of a driver, showing the driver's relationship to the objects used to communicate with a Widget. Lines between objects show message flow.]]&lt;br /&gt;
&lt;br /&gt;
The objects contained in the dotted boundary must appear in the code you write to define your driver. The Driver, Provider and IWidgetRegistryEntry objects are all contained in the same driver file. We begin discussing this on page 12. &lt;br /&gt;
&lt;br /&gt;
The other objects are provided by the OpenHome SDK or as installed components on the Node.&lt;br /&gt;
&lt;br /&gt;
The Discovery Module informs the driver of the presence of an available Widget.&lt;br /&gt;
&lt;br /&gt;
Each Node has a Protocol Module which contains the protocol's API. Widgets can communicate with OpenHome Nodes using any one of the set of communications protocols the Node supports. The driver uses your chosen protocol's Protocol Module to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
Both the Protocol Module and the Discovery Module are installed on the Node. When you write your&lt;br /&gt;
driver you will use your Protocol Module to allow the driver to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
IWidgetPublisher, IPublishedWidget and DvDevice are objects provided in the OpenHome&lt;br /&gt;
API. You can read about them in the APIs.&lt;br /&gt;
&lt;br /&gt;
= Generating the Provider = &lt;br /&gt;
&lt;br /&gt;
== Generating the Provider ==&lt;br /&gt;
&lt;br /&gt;
You must generate your provider before you can begin writing your Widget driver. You use your provider as a guide to implement the functions your Widget needs to set the values of its properties.&lt;br /&gt;
&lt;br /&gt;
The current provider generation process is a manual one involving the use of a text transform tool.&lt;br /&gt;
&lt;br /&gt;
Speak to your OpenHome contact who will help you generate your provider.&lt;br /&gt;
&lt;br /&gt;
Future releases of the OpenHome SDK will include a tool to help you generate the provider.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
You must be in possession of:&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK, unpacked on your computer&lt;br /&gt;
* your Widget Service XML file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Writing a SimpleUPnP driver = &lt;br /&gt;
&lt;br /&gt;
== Introduction to the SimpleUPnP protocol ==&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol used to control emulated Widgets over a custom UPnP service.&lt;br /&gt;
&lt;br /&gt;
This chapter shows how a driver is written using the SimpleUPnP communications protocol. The aim is to show the code using as generic a protocol as possible so that you can see where your own protocol specific code needs to go.&lt;br /&gt;
&lt;br /&gt;
The use of code specific to the SimpleUPnP implementation is highlighted by the use of the [[File:Warning.png]] icon. The lines of code are marked by this icon to make it easier for you to see where the protocol-specific code must go and what parts of the code are generic.&lt;br /&gt;
&lt;br /&gt;
=== Register model ===&lt;br /&gt;
&lt;br /&gt;
SimpleUPnP is modeled on 8 physical registers available on the Widget. Each register is 32-bits wide. They are indexed from 0 to 7 and the last register (register 7) is reserved for storing the Widget's class.&lt;br /&gt;
&lt;br /&gt;
This detail is used by the Protocol Module on the Node to determine which driver is needed to run the new Widget when it has been discovered.&lt;br /&gt;
&lt;br /&gt;
The remaining 7 registers (registers 0 to 6) are free for Widget engineers to assign to the Widget's functions.&lt;br /&gt;
&lt;br /&gt;
Registers 0, 1, 2 and 3 are available as read/write registers. Registers 4, 5 and 6 are readonly registers.&lt;br /&gt;
&lt;br /&gt;
Only the emulated hardware (running on the Node) can change the values held in registers 4, 5 and 6.&lt;br /&gt;
&lt;br /&gt;
=== Register use in drivers ===&lt;br /&gt;
&lt;br /&gt;
In the example that follows we have a Basic Light Widget with a very simple function: it can be turned on and turned off. The on/off value is stored in register 0, with values 0=OFF and 1=ON. Register 0 is a read/write register. This means we can change the value stored there using messages passed to the Widget from the Node, and by reacting to physical interactions at the Widget (such as someone manually switching the light on or off). &lt;br /&gt;
&lt;br /&gt;
The mapping of registers to properties on the Widget is decided by the engineers who manufacture the device. You must be provided with the mapping before you begin developing your driver.&lt;br /&gt;
&lt;br /&gt;
== Starting the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-BoxHighlight.png|800px|thumb|center|Figure 3 The driver architecture highlighting the Widget driver and its component parts.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When you have generated the abstract provider you can put it to use in the Widget driver. A Widget driver&lt;br /&gt;
has three distinct components:&lt;br /&gt;
&lt;br /&gt;
* an implementation of your abstract provider&lt;br /&gt;
* a definition of the Widget driver&lt;br /&gt;
* an implementation of the IWidgetRegistryEntry interface&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must manually write the code for your Widget driver. The differences in implementation of Widget properties and communication protocols means that the driver code cannot be autogenerated.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This section takes you through how to write a Widget driver by implementing the auto-generated provider,&lt;br /&gt;
starting from a new blank file and finishing with a working driver for the Basic Light Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
No assumptions have been made about the type of editor you use to write your code. Shortcuts&lt;br /&gt;
or macros that you use as standard will not appear in the instructions below. A full example&lt;br /&gt;
BinaryLightDriver.cs is available to review in Appendix C.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a new C# file in your IDE. Ensure the following libraries are used:&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 [[File:Warning.png]]using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 namespace OpenHome.Widget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must use the libraries listed above for this specific example.&lt;br /&gt;
&lt;br /&gt;
In general, drivers require the following libraries:&lt;br /&gt;
* System*&lt;br /&gt;
* System.Collections.Generic*&lt;br /&gt;
* OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
&lt;br /&gt;
Your driver will fail to compile if you miss any of these listed libraries. Libraries marked * are typically added by default by most modern IDEs. &lt;br /&gt;
&lt;br /&gt;
The OpenHome.Widget.Protocols.SimpleUpnp library is required only in this SimpleUPnP example. Drivers using a different protocol will use their own protocol library.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Implementing the provider ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-ProviderHighlight.png|800px|thumb|center|Figure 4 The driver architecture highlighting the Provider's place]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You use your auto-generated abstract provider by writing an implementation of it in the driver file. Responsibilities met by implementing your auto-generated provider are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R6 Reacting to actions sent to the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
Begin by creating a new class. It will subclass the abstract auto-generated provider:&lt;br /&gt;
&lt;br /&gt;
 class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
The Protocol Module will provide an API for the Provider to use to communicate with the Widget. In&lt;br /&gt;
SimpleUPnP we are provided with an interface called ISimpleUpnpWidget. The provider is supplied&lt;br /&gt;
with the required instance of the interface by the Discovery Module on the Node.&lt;br /&gt;
&lt;br /&gt;
The mechanisms for registering providers with specific Protocol Modules, and for the way the module gives each provider its required interface are covered later when writing the discovery method.&lt;br /&gt;
&lt;br /&gt;
For now, we need to give the Provider a place to store the interface that it will later use to communicate&lt;br /&gt;
with the Widget:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]] private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
&lt;br /&gt;
The interface from the Protocol Module is passed in as a parameter in the Provider's constructor and then&lt;br /&gt;
assigned to the variable we just created:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightProvider(DvDevice aDevice,&lt;br /&gt;
 [[File:Warning.png]]         ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
 {&lt;br /&gt;
       iProtocol = aProtocol;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
To satisfy R3 we would normally set the Widget's properties here, giving them an initial value.&lt;br /&gt;
However, in this specific example we cannot set the value of Basic Light's only property because&lt;br /&gt;
we will never know, in advance, what the state of the light will be (either on or off) when we&lt;br /&gt;
create the DiscoveredWidget.&lt;br /&gt;
&lt;br /&gt;
When you cannot set the properties ahead of time, and you are using an eventing protocol like SimpleUPnP, you can instead set them in the HandleRegisterEvent method in the driver class. This also satisfies the requirements for R3. You must set the Widget's properties before you enable it using SetEnabled(). &lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The abstract provider includes an abstract method called SetOn. This method is invoked by the Node when passing a message to the Widget, specifically to set the on property of the Widget to either 0 or 1. The implementation of this method will meet the requirements for R6.&lt;br /&gt;
&lt;br /&gt;
We must override this method and provide the protocol module a way of passing a message on to the Widget to perform the required action, in this case turn the light on or off:&lt;br /&gt;
&lt;br /&gt;
          protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
          {&lt;br /&gt;
     [[File:Warning.png]]        iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
In this example the Basic Light's SetOn property (the boolean property that controls whether the light is&lt;br /&gt;
on or off) is represented in the physical Widget by the register that has an index of 0.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* This method is an example of an action on a Widget. Actions are messages sent from the Node to the Widget. We will see later how to handle events that need to be passed back from the Widget&lt;br /&gt;
to the Node.&lt;br /&gt;
* Your own Widget will likely provide more than a single property. Your auto-generated provider will contain one abstract method to represent each writable property. Read-only properties are not provided an abstract method.&lt;br /&gt;
&lt;br /&gt;
You must implement each abstract method in your driver to ensure the relevant property on&lt;br /&gt;
the Widget can be set.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We have now finished implementing the provider. The next step is to implement the driver.&lt;br /&gt;
&lt;br /&gt;
== Implementing the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-DriverHighlight.png|800px|thumb|center|Figure 4: The driver architecture highlighting the implemented driver's place.]]&lt;br /&gt;
&lt;br /&gt;
The code for your Widget driver must provide an implementation of the IWidgetRegistryInterface,&lt;br /&gt;
including the following tasks:&lt;br /&gt;
&lt;br /&gt;
* methods to expose identifying details about the Widget for the Node to access&lt;br /&gt;
* providing methods to handle events reported by the Widget&lt;br /&gt;
&lt;br /&gt;
The driver is implemented as a public class within the same file as the provider code. Each driver must use the interface for the protocol you are using. For the SimpleUPnP protocol the interface is ISimple-UpnpWidgetDriver.&lt;br /&gt;
&lt;br /&gt;
=== Writing code ===&lt;br /&gt;
&lt;br /&gt;
Create your new driver class and subclass the ISimpleUpnpWidgetDriver interface:&lt;br /&gt;
&lt;br /&gt;
 public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Implementing IWidgetRegistryEntry ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry is the interface you use to represent physical Widgets. It is implemented as a subclass of your driver class. We are going to implement this interface in a class called '''DiscoveredWidget'''.&lt;br /&gt;
&lt;br /&gt;
Let's return to our driver architecture diagram for a moment:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-IRegistryEntryHighlight.png|800px|thumb|center|Figure 5 The driver architecture highlighting the IWidgetRegistryEntry object you will now implement]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry uses several other objects to help create it and respond to messages sent to and from it. These objects will be created in our implementation of DiscoveredWidget. &lt;br /&gt;
&lt;br /&gt;
When successfully created and published, the DiscoveredWidget objects are stored in a list on the Node called the Local Widget Registry. The Local Widget Registry is used by Nodes to maintain contact with the Widgets they control.&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry is shown at the top of Figure 5, marked plainly as (Registry). The path to the Local Widget Registry goes through several layers of Node architecture which are not relevant to Widget driver writing, so are not shown in the diagrams.&lt;br /&gt;
&lt;br /&gt;
==== Writing code ====&lt;br /&gt;
&lt;br /&gt;
Start by subclassing the IWidgetRegistryEntry interface in your new class:&lt;br /&gt;
&lt;br /&gt;
      private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
      {&lt;br /&gt;
&lt;br /&gt;
A DiscoveredWidget must provide the driver with the objects required to present the Widget and its&lt;br /&gt;
properties to the Node:&lt;br /&gt;
&lt;br /&gt;
           private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
           private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
           private readonly ISimpleUpnpWidget iProtocol;&lt;br /&gt;
           private readonly BinaryLightProvider iProvider;&lt;br /&gt;
           private readonly DvDevice iDvDevice;&lt;br /&gt;
           private IPublishedWidget iPublishedWidget;&lt;br /&gt;
&lt;br /&gt;
Each of the attributes in the example above are defined as follows:&lt;br /&gt;
&lt;br /&gt;
iDeviceFactory — used by the driver to create a single instance of DvDevice to represent a single Widget&lt;br /&gt;
&lt;br /&gt;
iPublisher — used by the driver to publish the Widget to the Node&lt;br /&gt;
&lt;br /&gt;
iProtocol — the object used by the Widget to communicate with the Protocol Module on the Node&lt;br /&gt;
&lt;br /&gt;
iProvider — an instantiated provider of the type you defined earlier&lt;br /&gt;
&lt;br /&gt;
iDvDevice — a representation of a Widget to which the provider is attached, created using iDevice-Factory above&lt;br /&gt;
&lt;br /&gt;
iPublishedWidget — used to contain the returned object from a successful publishing of the Widget&lt;br /&gt;
If we look again at the driver architecture diagram, we ca highlight the objects we've just defined:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-Highlight.png|800px|thumb|center|Figure 6: The driver architecture highlighting the objects used by the IWidgetRegistryEntry implementation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The DeviceFactory, defined above in the member variable iDeviceFactory, is used to create new DvDevice objects. The DeviceFactory is only ever used to do this once. It is not shown in the driver architecture diagrams due to its minimal role in the operation of a driver, but it would normally appear between the IWidgetRegistryEntry and DvDevice objects.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
A driver requires methods to expose identifying details about the Widget. We must provide access to two of the attributes we just defined above:&lt;br /&gt;
&lt;br /&gt;
 public DvDevice DvDevice&lt;br /&gt;
 {&lt;br /&gt;
     get { return iDvDevice; }&lt;br /&gt;
 }&lt;br /&gt;
 public string WidgetClass&lt;br /&gt;
 {&lt;br /&gt;
     get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The WidgetClass string is formed using a combination of the vendor name and the Widget's name in the&lt;br /&gt;
format:&lt;br /&gt;
&lt;br /&gt;
 [vendor_domain]:[widget_name]&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry can now query both the DvDevice object representing the Widget, and the specific class of Widget this driver represents. The other member variables we defined do not need their own accessor methods.&lt;br /&gt;
&lt;br /&gt;
Now we must write a constructor for DiscoveredWidget and assign the parameters accordingly: &lt;br /&gt;
&lt;br /&gt;
 public DiscoveredWidget(IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                            string aUdn,&lt;br /&gt;
                            ISimpleUpnpWidget aProxy,&lt;br /&gt;
                            IWidgetPublisher aPublisher)&lt;br /&gt;
 {&lt;br /&gt;
      iDeviceFactory = aDeviceFactory;&lt;br /&gt;
      iProtocol = aProtocol;&lt;br /&gt;
      iPublisher = aPublisher;&lt;br /&gt;
      iDvDevice = iDeviceFactory.CreateDevice(aUdn);&lt;br /&gt;
      iProvider = new BinaryLightProvider(iDvDevice,&lt;br /&gt;
      iProtocol);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Event handling ===&lt;br /&gt;
&lt;br /&gt;
A Widget's state can change in one of three significant ways:&lt;br /&gt;
&lt;br /&gt;
* when the Widget needs to be published on the Node&lt;br /&gt;
* when the Widget disappears from the network (by losing power or similar)&lt;br /&gt;
* when a property's state changes and must be updated to a new value&lt;br /&gt;
&lt;br /&gt;
We now need methods to handle these changes.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The methods we define here will be used as callbacks, rather than invoked as method calls. We define the methods here first and then use them later on. We will use the Protocol Module to listen for changes in the Widget's state and register these methods as callbacks there. See Writing the SimpleUPnP Widget discovery method for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this section of the driver are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R4 Publishing discovered Widgets in the Local Widget Registry on the Node'''&lt;br /&gt;
&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object. &lt;br /&gt;
&lt;br /&gt;
'''R5 Reacting to an event reported from the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
'''R7 Reacting to a Widget's departure'''&lt;br /&gt;
&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no longer available.&lt;br /&gt;
&lt;br /&gt;
==== Enabling and publishing a discovered Widget ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first method initializes the Widget by enabling the device and then using the IWidgetPublisher&lt;br /&gt;
to make it available on the Node:&lt;br /&gt;
&lt;br /&gt;
 public void HandleInitialEvent()&lt;br /&gt;
 {&lt;br /&gt;
      iDvDevice.SetEnabled();&lt;br /&gt;
      iPublisher.TryPublishWidget(iDvDevice.iUdn(),&lt;br /&gt;
                              this,&lt;br /&gt;
                              out iPublishedWidget);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This method meets the requirements for R4.&lt;br /&gt;
&lt;br /&gt;
The call to TryPublishWidget returns an iPublishedWidget object. We use this object later to satisfy the requirements of R7.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The ordering of the calls to SetEnabled and TryPublishWidget is vitally important. You&lt;br /&gt;
must enable the device before you attempt to publish it. Your Widget will not be available to the&lt;br /&gt;
Nodes unless SetEnabled is called first. Nodes will not be able to access a published device&lt;br /&gt;
that has not been enabled.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
R3 requires that you set the Widget's properties before you enable and publish the device. We&lt;br /&gt;
discussed on page 14 how some properties can only be set after the Widget reports what their&lt;br /&gt;
state is. We do this in HandleRegisterEvent.&lt;br /&gt;
&lt;br /&gt;
We rely on the SimpleUPnP Protocol Module guaranteeing a call to HandleRegisterEvent first before HandleInitialEvent. This is informed by guarantees made by the Control Point stack that the calls will be made in that order.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
==== Removing a Widget ====&lt;br /&gt;
&lt;br /&gt;
Removing a Widget involves unpublishing it from the Node. The IPublishedWidget interface provides us with a method we can call to manage that for us:&lt;br /&gt;
&lt;br /&gt;
 public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
 {&lt;br /&gt;
     if (iPublishedWidget != null)&lt;br /&gt;
     { iPublishedWidget.Unpublish(); }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assuming that the Widget was successfully published earlier, it is removed from the Node's Local Widget Registry.&lt;br /&gt;
&lt;br /&gt;
We must also properly handle the resources we used to create and maintain the Widget object while it was published:&lt;br /&gt;
&lt;br /&gt;
      iProvider.Dispose();&lt;br /&gt;
      iDvDevice.Dispose();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The calls to Dispose are made regardless of the Widget's published state, ensuring that any created device and associated provider are properly disposed. This implementation satisfies R7.&lt;br /&gt;
&lt;br /&gt;
====Event handling ====&lt;br /&gt;
&lt;br /&gt;
We need a method to handle changes to the state of the Widget's properties.&lt;br /&gt;
&lt;br /&gt;
If the property changes at the Widget, it needs to pass the new state back to the Node so that it is kept up-to-date on the Widget's status. This is called an event. An example in the case of our Basic Light is someone manually switching the light from on to off. This is in contrast to actions, which are passed from the Node to the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Other examples of events involve no human interaction, such as a thermometer Widget updating its current temperature based on environmental changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Our Basic Light Widget has only one property that needs to be handled:&lt;br /&gt;
&lt;br /&gt;
 public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
 {&lt;br /&gt;
     if (aIndex == 0)&lt;br /&gt;
     {&lt;br /&gt;
         iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We use our instance of the provider to update the register on the Widget that is mapped to the On property. This in turn updates the Node with the new state of the Widget.&lt;br /&gt;
&lt;br /&gt;
This method provides implementations to satisfy two driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
* R3 is now completely satisfied, as we can now set the values of all the previously unknown properties here.&lt;br /&gt;
* R5 is also satisfied as this method allows us to update the Widget's status on the Node when a property is changed on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Not all protocols pass messages back to the Node in this manner. The way we have satisfied R3 and R5 here only applies to protocols and Widgets that support this behavior.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Widgets that do not use an eventing protocol need to have their properties set in the provider's constructor to satisfy R3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To satisfy R5, the over-ridden method SetOn in the provider must include the call to SetPropertyOn. Non-eventing protocols do not require a HandleRegisterEvent method.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Constructor ===&lt;br /&gt;
&lt;br /&gt;
The final requirement for the driver is the constructor so that new DiscoveredWidget objects can be created. &lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this area of code are:&lt;br /&gt;
&lt;br /&gt;
'''R1 Specifying the type of Widget the driver controls'''&lt;br /&gt;
&lt;br /&gt;
A driver must know which type of Widget that it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
==== Writing the code ====&lt;br /&gt;
&lt;br /&gt;
We begin by defining the variables we will use to store the objects used by the driver:&lt;br /&gt;
&lt;br /&gt;
 private readonly string iName;&lt;br /&gt;
 private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
 private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now write the constructor for the driver and assign the passed in parameters appropriately:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightDriver(string aName,&lt;br /&gt;
                IWidgetPublisher aPublisher,&lt;br /&gt;
                IDvDeviceFactory aDeviceFactory)&lt;br /&gt;
 {&lt;br /&gt;
     iWidgetPublisher = aPublisher;&lt;br /&gt;
     iName = aName;&lt;br /&gt;
     iDeviceFactory = aDeviceFactory;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally we need to provide the driver a way to publish the class of Widget it controls. This information is requested by the Discovery Module and is used to ensure the Node uses the correct driver when a new Widget appears.&lt;br /&gt;
&lt;br /&gt;
The implementation for this details will be different for each protocol. The SimpleUPnP protocol library provides a file that contains the SimpleUPnP definitions as integers. Each integer represents a particular class of identified Widget.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP implementation of that method is as follows:&lt;br /&gt;
&lt;br /&gt;
 public IEnumerable&amp;lt;uint&amp;gt; WidgetClasses&lt;br /&gt;
 {&lt;br /&gt;
 [[File:Warning.png]]        get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The body of this method is specifically written for the Widget class we are defining (in this case a binary light). This method completes the driver's requirements for R1.&lt;br /&gt;
&lt;br /&gt;
== Writing the SimpleUPnP Widget discovery method ==&lt;br /&gt;
&lt;br /&gt;
Every driver must contain a method which creates new objects to represent newly discovered Widgets.&lt;br /&gt;
The Discovery Module invokes this method to begin the process of creating the objects required to allow the Node to access the Widget. &lt;br /&gt;
&lt;br /&gt;
The name of this method is dictated by your chosen protocol's API. The SimpleUPnP protocol requires a method called WidgetDiscovered.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The method's name will not always be the same for each protocol. Your protocol's documentation will contain the details of what this method must be called.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This method and its implementation will meet the following driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
'''R2 Reacting to a discovered Widget on the network'''&lt;br /&gt;
&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
Our implementation of the WidgetDiscovered method will create a new DiscoveredWidget object and use the Protocol Module to listen for changes to the Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
The method uses the Protocol Module and two ways to identify the Widget. We must pass these in as&lt;br /&gt;
parameters:&lt;br /&gt;
&lt;br /&gt;
 public void WidgetDiscovered(string aWidgetUdn,&lt;br /&gt;
                              uint aWidgetClass,&lt;br /&gt;
                              ISimpleUpnpWidget&lt;br /&gt;
                                  aSimpleUpnpWidget)&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
Every Widget that uses this driver must be uniquely identifiable:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]    string newUdn = aWidgetUdn;&lt;br /&gt;
&lt;br /&gt;
Each new Widget is represented by a DiscoveredWidget object. Create the new DiscoveredWidget and pass in the required parameters we created earlier:&lt;br /&gt;
&lt;br /&gt;
     DiscoveredWidget discoveredWidget =&lt;br /&gt;
                 new DiscoveredWidget(iDeviceFactory,&lt;br /&gt;
                                      newUdn,&lt;br /&gt;
  &lt;br /&gt;
 [[File:Warning.png]]                                    aSimpleUpnpWidget,&lt;br /&gt;
&lt;br /&gt;
=== Registering the callbacks ===&lt;br /&gt;
&lt;br /&gt;
Finally, we ask the Widget's protocol interface to listen for calls to the handler methods we defined earlier in DiscoveredWidget. We do this by registering those methods as callbacks for the Protocol Module&lt;br /&gt;
to listen for:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                        discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                        discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                        discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You have now met 100% of the driver responsibility requirements and have a working driver to use with your SimpleUPnP Widget.&lt;br /&gt;
&lt;br /&gt;
= Appendix A. Sample XML =&lt;br /&gt;
&lt;br /&gt;
== Binary Light.xml ==&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
  &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
  &amp;lt;version&amp;gt;&lt;br /&gt;
   &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
   &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/version&amp;gt;&lt;br /&gt;
  &amp;lt;propertylist&amp;gt;&lt;br /&gt;
   &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
       illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
   &amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix B. Sample Provider = &lt;br /&gt;
&lt;br /&gt;
== DvWidgetOpenhomeOrgBasicLight1.cs ==&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Runtime.InteropServices;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Core;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Utils.Binary;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
 {&lt;br /&gt;
    public interface IDvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
        IDisposable&lt;br /&gt;
    {&lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous value&lt;br /&gt;
        /// &amp;lt;/returns&amp;gt;&lt;br /&gt;
        bool SetPropertyOn(bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;Property's value will be copied&lt;br /&gt;
        /// here&amp;lt;/param&amp;gt;&lt;br /&gt;
        bool PropertyOn();&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt; summary&amp;gt;&lt;br /&gt;
    /// Provider for the openhome.org:BinaryLight:1 UPnP service&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public abstract class DvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
               DvProvider,&lt;br /&gt;
               IDisposable,&lt;br /&gt;
               IDvProviderOpenhomeOrgBinaryLight1&lt;br /&gt;
    {&lt;br /&gt;
        private GCHandle iGch;&lt;br /&gt;
        private PropertyBool iPropertyOn;&lt;br /&gt;
        private PropertyUint iPropertyPrimarySeq;&lt;br /&gt;
        private PropertyUint iPropertySecondarySeq;&lt;br /&gt;
        private ActionDelegate iDelegateSetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetPrimaryProperty;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Constructor&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aDevice&amp;quot;&amp;gt;Device which owns this&lt;br /&gt;
        /// provider&amp;lt;/param&amp;gt;&lt;br /&gt;
        protected DvProviderOpenhomeOrgBinaryLight1(DvDevice aDevice)&lt;br /&gt;
            : base(aDevice, &amp;quot;openhome.org&amp;quot;, &amp;quot;GenericWidget&amp;quot;, 1)&lt;br /&gt;
        {&lt;br /&gt;
            iGch = GCHandle.Alloc(this);&lt;br /&gt;
            List&amp;lt;String&amp;gt; allowedValues = new List&amp;lt;String&amp;gt;();&lt;br /&gt;
            iPropertyOn = new PropertyBool(new ParameterBool(&amp;quot;On&amp;quot;));&lt;br /&gt;
            iPropertyPrimarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;PrimarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertyPrimarySeq);&lt;br /&gt;
            iPropertySecondarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;SecondarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertySecondarySeq);&lt;br /&gt;
            SetPropertyUint(iPropertyPrimarySeq, 0);&lt;br /&gt;
            SetPropertyUint(iPropertySecondarySeq, 0);&lt;br /&gt;
  &lt;br /&gt;
            Zapp.Core.Action action = new Zapp.Core.Action&lt;br /&gt;
                (&amp;quot;SetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;FireAndForget&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddInputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateSetProperty = new ActionDelegate(DoSetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateSetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateGetProperty = new ActionDelegate(DoGetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetPrimaryProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                 (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;integer&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;boolean&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;string&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;binary&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Type&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;readWrite&amp;quot;);allowedValues.Add&lt;br /&gt;
                (&amp;quot;readOnly&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;writeOnly&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString(&amp;quot;Access&amp;quot;,&lt;br /&gt;
                allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            iDelegateGetPrimaryProperty = new&lt;br /&gt;
            ActionDelegate(DoGetPrimaryProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetPrimaryProperty,&lt;br /&gt;
            GCHandle.ToIntPtr(iGch));&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous&lt;br /&gt;
        /// value&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool SetPropertyOn(bool aValue)&lt;br /&gt;
        {&lt;br /&gt;
            if (iPropertyOn.SetValue(aValue))&lt;br /&gt;
            {&lt;br /&gt;
                lock (iPropertyPrimarySeq)&lt;br /&gt;
                {&lt;br /&gt;
                    SetPropertyUint(iPropertyPrimarySeq,&lt;br /&gt;
                        iPropertyPrimarySeq.Value() + 1);&lt;br /&gt;
                } return true;&lt;br /&gt;
            } return false;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;The value of the property&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool PropertyOn()&lt;br /&gt;
        {&lt;br /&gt;
            return iPropertyOn.Value();&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the On property.&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aVersion&amp;quot;&amp;gt;Version of the service being&lt;br /&gt;
        /// requested (will be &amp;lt;= the version advertised)&amp;lt;/param&amp;gt; &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the On property.&lt;br /&gt;
        /// &amp;lt;/param&amp;gt;&lt;br /&gt;
        protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        private static int DoSetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                byte[] valBin = invocation.ReadBinary(&amp;quot;Value&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                switch (name)&lt;br /&gt;
                {&lt;br /&gt;
                    case &amp;quot;On&amp;quot;:&lt;br /&gt;
                        self.SetOn(aVersion, Converter.&lt;br /&gt;
                            BinaryToBoolean(valBin));&lt;br /&gt;
                        break;&lt;br /&gt;
                    default:&lt;br /&gt;
                        throw new ActionError();&lt;br /&gt;
                }&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
                invocation.WriteEnd();&lt;br /&gt;
            }&lt;br /&gt;
            catch (ActionError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
            catch (PropertyUpdateError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
        return 0;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        private static int DoGetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
            switch (name)&lt;br /&gt;
            {&lt;br /&gt;
                case &amp;quot;On&amp;quot;:&lt;br /&gt;
                invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                    Converter.BooleanToBinary(self.iPropertyOn.&lt;br /&gt;
                        Value()));&lt;br /&gt;
                break;&lt;br /&gt;
                default:&lt;br /&gt;
                throw new ActionError();&lt;br /&gt;
            }&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    private static int DoGetPrimaryProperty(IntPtr aPtr,&lt;br /&gt;
                    IntPtr aInvocation,&lt;br /&gt;
                    uint aVersion)&lt;br /&gt;
    {&lt;br /&gt;
        GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
        DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
            (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
        DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
  &lt;br /&gt;
        try&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReadStart();&lt;br /&gt;
            invocation.ReadEnd();&lt;br /&gt;
            invocation.WriteStart();&lt;br /&gt;
            invocation.WriteString(&amp;quot;Name&amp;quot;, &amp;quot;On&amp;quot;);&lt;br /&gt;
            invocation.WriteString(&amp;quot;Type&amp;quot;, &amp;quot;boolean&amp;quot;);&lt;br /&gt;
            invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                Converter.BooleanToBinary(self.iPropertyOn.Value()));&lt;br /&gt;
            invocation.WriteString(&amp;quot;Access&amp;quot;, &amp;quot;readWrite&amp;quot;);&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt;summary&amp;gt;&lt;br /&gt;
    /// Must be called for each class instance. Must be called before&lt;br /&gt;
    /// Core.Library.Close().&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public void Dispose()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
        GC.SuppressFinalize(this);&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
    ~DvProviderOpenhomeOrgBinaryLight1()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
        private void DoDispose()&lt;br /&gt;
        {&lt;br /&gt;
            lock (this)&lt;br /&gt;
            {&lt;br /&gt;
                if (iHandle == IntPtr.Zero)&lt;br /&gt;
            {&lt;br /&gt;
                    return;&lt;br /&gt;
            }&lt;br /&gt;
            DisposeProvider();&lt;br /&gt;
            iPropertyOn.Dispose();&lt;br /&gt;
            iHandle = IntPtr.Zero;&lt;br /&gt;
            }&lt;br /&gt;
            iGch.Free();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix C. Sample Driver = &lt;br /&gt;
&lt;br /&gt;
== BasicLightDriver.cs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.hWidget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
     class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
     {&lt;br /&gt;
         private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
         public BinaryLightProvider(DvDevice aDevice, &lt;br /&gt;
             ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol = aProtocol;&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
     {&lt;br /&gt;
         private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
         {&lt;br /&gt;
             private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
             private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
             private readonly ISimpleUpnpWidget iProtocol; &lt;br /&gt;
 &lt;br /&gt;
             private readonly BinaryLightProvider iProvider;&lt;br /&gt;
             private readonly DvDevice iDvDevice;&lt;br /&gt;
             private IPublishedWidget iPublishedWidget; &lt;br /&gt;
 &lt;br /&gt;
             public DvDevice DvDevice&lt;br /&gt;
             {&lt;br /&gt;
                 get { return iDvDevice; }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             public string WidgetClass&lt;br /&gt;
             {&lt;br /&gt;
                 get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public DiscoveredWidget(&lt;br /&gt;
                 IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                 string aUdn,&lt;br /&gt;
                 ISimpleUpnpWidget aProxy,&lt;br /&gt;
                 IWidgetPublisher aPublisher)&lt;br /&gt;
             {&lt;br /&gt;
                 iDeviceFactory = aDeviceFactory;&lt;br /&gt;
                 iProtocol = aProtocol;&lt;br /&gt;
 &lt;br /&gt;
                 iPublisher = aPublisher;&lt;br /&gt;
                 iDvDevice = iDeviceFactory.CreateDevice(aUdn);  &lt;br /&gt;
                 iProvider = new BinaryLightProvider(iDvDevice, &lt;br /&gt;
                                                     iProtocol);&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             public void HandleInitialEvent()&lt;br /&gt;
             {&lt;br /&gt;
                 iDvDevice.SetEnabled();&lt;br /&gt;
                 iPublisher.TryPublishWidget(iDvDevice.iUdn(), this,&lt;br /&gt;
                     out iPublishedWidget);&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
             {&lt;br /&gt;
                 if (iPublishedWidget != null)&lt;br /&gt;
                 {&lt;br /&gt;
                     iPublishedWidget.Unpublish();&lt;br /&gt;
                 } &lt;br /&gt;
                 iProvider.Dispose();&lt;br /&gt;
                 iDvDevice.Dispose();&lt;br /&gt;
             }  &lt;br /&gt;
 &lt;br /&gt;
             public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
             {&lt;br /&gt;
                 if (aIndex == 0)&lt;br /&gt;
                 {&lt;br /&gt;
                     iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         private readonly string iName;&lt;br /&gt;
         private readonly IDvDeviceFactory aDeviceFactory;&lt;br /&gt;
         private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
         &lt;br /&gt;
         public BinaryLightDriver(&lt;br /&gt;
             string aName,&lt;br /&gt;
             IWidgetPublisher aPublisher,&lt;br /&gt;
             iDeviceFactory aDeviceFactory)&lt;br /&gt;
         {&lt;br /&gt;
             iWidgetPublisher = aPublisher;&lt;br /&gt;
             iName = aName;&lt;br /&gt;
             iDeviceFactory = aDeviceFactory;&lt;br /&gt;
         } &lt;br /&gt;
 &lt;br /&gt;
         public IEnumerable&amp;amp;lt;uint&amp;amp;gt; WidgetClasses&lt;br /&gt;
         {&lt;br /&gt;
             get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         public void WidgetDiscovered(&lt;br /&gt;
             string aWidgetUdn,&lt;br /&gt;
             uint aWidgetClass,&lt;br /&gt;
             ISimpleUpnpWidget aSimpleUpnpWidget)&lt;br /&gt;
         {&lt;br /&gt;
             string newUdn = aWidgetUdn;&lt;br /&gt;
             DiscoveredWidget discoveredWidget = new DiscoveredWidget&lt;br /&gt;
                 (iDeviceFactory,&lt;br /&gt;
                  newUdn,&lt;br /&gt;
                  aSimpleUpnpWidget,&lt;br /&gt;
                  iWidgetPublisher);&lt;br /&gt;
 &lt;br /&gt;
             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                 discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                 discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                 discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary = &lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in OpenHome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by OpenHome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh - A collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs on ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The OpenHome Operating System. Core software for OpenHome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. &lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. A typical Widget supports only one protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Driver_Development</id>
		<title>OhWidget Driver Development</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Driver_Development"/>
				<updated>2012-03-01T15:20:44Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Starting the driver */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for developers using the OpenHome SDK to integrate a Widget into an OpenHome system. Each Widget must have its own driver to allow it to communicate with the OpenHome Nodes. &lt;br /&gt;
&lt;br /&gt;
To help you write your driver, this document provides high level descriptions of the core responsibilities of a Widget driver and gives a detailed walk-through using example code.&lt;br /&gt;
&lt;br /&gt;
Full versions of each file used in the development of the example driver are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin development of your Widget driver you must be in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* your Widget Service XML that describes the properties on your Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document does not contain advice on how to write Widget Service XML. Refer to the OpenHome Widget Service XML definition document for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK&lt;br /&gt;
* your chosen communication protocol's API&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The protocol you choose for your Widgets must be the same protocol used on your choice of Node.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document focuses on the development of the Widget driver. Details about the communications protocol used are beyond the scope of this document. This document assumes you are familiar with your chosen protocol's code libraries and are able to use them in the driver code you write.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Related Documents ==&lt;br /&gt;
&lt;br /&gt;
The following related OpenHome documentation may be of interest to you:&lt;br /&gt;
&lt;br /&gt;
* [[ohWidget Technical Overview|ohWidget Technical Overview]]&lt;br /&gt;
* [[OpenHome Widget Service XML definition|OpenHome Widget Service XML definition]]&lt;br /&gt;
* [http://www.openhome.org/releases/ohNet_DeviceStack.pdf  OpenHome ohNet Device Stack]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
None of the related documents listed above is mandatory reading for Widget driver development.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
== Widget Service XML ==&lt;br /&gt;
OpenHome Widget driver writing relies heavily on the use of code generated from a single source — the Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
The service and actions your Widget provides are represented in code in a file called a Provider. The Provider is automatically generated from the Widget Service XML and produces an abstract class for you to inherit when you write your concrete class driver.&lt;br /&gt;
&lt;br /&gt;
To aid in the explanation of how the Provider is created and put to use we will follow the development of&lt;br /&gt;
a driver for a simple light Widget; taking the defined Widget Service XML and stepping through how it is used to generate the other files. Examples of code are used throughout this document to show you how each one is created and used in an OpenHome system. &lt;br /&gt;
&lt;br /&gt;
It is essential that you start with a well-formed Widget Service XML, conforming to the schema defined&lt;br /&gt;
in the WidgetService.xsd. The following diagram shows the significance of the Widget Service XML in&lt;br /&gt;
relation to the generated files you will use when writing your driver:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarchy, highlighting the areas specifically used in driver development]]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* The grayed-out files are not relevant to Widget driver development but can also be generated from the Widget Service XML.&lt;br /&gt;
* The Provider is generated in C#, meaning your driver must be written in C# as well. The use of managed code is mandatory for driver writing in the OpenHome framework.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Code sample used in this document ==&lt;br /&gt;
&lt;br /&gt;
Our examples in this document use a Widget Service XML definition for a light Widget called&lt;br /&gt;
BasicLight.xml.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Full versions of all the example files used in this document are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We will see how the Provider is generated from this XML and how it is used to aid the driver writing process. The examples also show how your chosen communication protocol should be used in the body of the driver code.&lt;br /&gt;
&lt;br /&gt;
Implementation details of specific protocols you choose to use are beyond the scope of this document. However, the samples used in this document show the use of the SimpleUPnP protocol to aid you in your development process.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol during the early stages of the OpenHome project. It is included in the OpenHome SDK and can be used as a public resource. &lt;br /&gt;
&lt;br /&gt;
The use of SimpleUPnP in the example files and the code snippets within the following sections is highlighted by the [[File:Warning.png]] icon. The lines of code marked by [[File:Warning.png]] must be changed to code from your chosen communication protocol's library. SimpleUPnP is left in to help you understand how a protocol is used in a working example.&lt;br /&gt;
&lt;br /&gt;
The sample code provided attempts to show best-practice coding standards. There are several sections of code that have a mandatory layout or that call specifically named methods and functions. These areas of the code are highlighted where required. &lt;br /&gt;
&lt;br /&gt;
Where the examples do not explicitly state that the code shown is mandatory, you are free to implement it in a different way according to your own coding style and practices.&lt;br /&gt;
&lt;br /&gt;
= Driver responsibilities = &lt;br /&gt;
&lt;br /&gt;
== Driver responsibilities ==&lt;br /&gt;
&lt;br /&gt;
An OpenHome Widget driver has several responsibilities which must be met before it can be used on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
These responsibilities are listed R1 to R7 and are defined here, explaining what each one must do. &lt;br /&gt;
&lt;br /&gt;
=== R1 Specifying the type of Widget the driver controls ===&lt;br /&gt;
A driver must know which type of Widget it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
=== R2 Reacting to a discovered Widget on the network ===&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== R3 Setting the initial values for the Widget's properties ===&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
=== R4 Publishing discovered Widgets in the Local Widget Registry on the Node ===&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object.&lt;br /&gt;
&lt;br /&gt;
=== R5 Reacting to an event reported from the Widget ===&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
=== R6 Reacting to actions sent to the Widget ===&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== R7 Reacting to a Widget's departure ===&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no&lt;br /&gt;
longer available.&lt;br /&gt;
&lt;br /&gt;
The sections of example code that follow show you how to write a driver from beginning to end. The accompanying text explaining the example code highlights when a responsibility, or part of a responsibility, has been met.&lt;br /&gt;
&lt;br /&gt;
= Driver Architecture = &lt;br /&gt;
&lt;br /&gt;
== Driver Architecture ==&lt;br /&gt;
&lt;br /&gt;
Drivers are installed on the Node and used when the Node needs to communicate with the Widget. Drivers&lt;br /&gt;
use several objects to communicate with Widgets over the Widget's lifetime. Figure 2 shows the objects&lt;br /&gt;
used by the driver and how the responsibilities listed above relate to each one:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture.png|800px|thumb|center|Figure 2: The architecture of a driver, showing the driver's relationship to the objects used to communicate with a Widget. Lines between objects show message flow.]]&lt;br /&gt;
&lt;br /&gt;
The objects contained in the dotted boundary must appear in the code you write to define your driver. The Driver, Provider and IWidgetRegistryEntry objects are all contained in the same driver file. We begin discussing this on page 12. &lt;br /&gt;
&lt;br /&gt;
The other objects are provided by the OpenHome SDK or as installed components on the Node.&lt;br /&gt;
&lt;br /&gt;
The Discovery Module informs the driver of the presence of an available Widget.&lt;br /&gt;
&lt;br /&gt;
Each Node has a Protocol Module which contains the protocol's API. Widgets can communicate with OpenHome Nodes using any one of the set of communications protocols the Node supports. The driver uses your chosen protocol's Protocol Module to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
Both the Protocol Module and the Discovery Module are installed on the Node. When you write your&lt;br /&gt;
driver you will use your Protocol Module to allow the driver to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
IWidgetPublisher, IPublishedWidget and DvDevice are objects provided in the OpenHome&lt;br /&gt;
API. You can read about them in the APIs.&lt;br /&gt;
&lt;br /&gt;
= Generating the Provider = &lt;br /&gt;
&lt;br /&gt;
== Generating the Provider ==&lt;br /&gt;
&lt;br /&gt;
You must generate your provider before you can begin writing your Widget driver. You use your provider as a guide to implement the functions your Widget needs to set the values of its properties.&lt;br /&gt;
&lt;br /&gt;
The current provider generation process is a manual one involving the use of a text transform tool.&lt;br /&gt;
&lt;br /&gt;
Speak to your OpenHome contact who will help you generate your provider.&lt;br /&gt;
&lt;br /&gt;
Future releases of the OpenHome SDK will include a tool to help you generate the provider.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
You must be in possession of:&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK, unpacked on your computer&lt;br /&gt;
* your Widget Service XML file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Writing a SimpleUPnP driver = &lt;br /&gt;
&lt;br /&gt;
== Introduction to the SimpleUPnP protocol ==&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol used to control emulated Widgets over a custom UPnP service.&lt;br /&gt;
&lt;br /&gt;
This chapter shows how a driver is written using the SimpleUPnP communications protocol. The aim is to show the code using as generic a protocol as possible so that you can see where your own protocol specific code needs to go.&lt;br /&gt;
&lt;br /&gt;
The use of code specific to the SimpleUPnP implementation is highlighted by the use of the [[File:Warning.png]] icon. The lines of code are marked by this icon to make it easier for you to see where the protocol-specific code must go and what parts of the code are generic.&lt;br /&gt;
&lt;br /&gt;
=== Register model ===&lt;br /&gt;
&lt;br /&gt;
SimpleUPnP is modeled on 8 physical registers available on the Widget. Each register is 32-bits wide. They are indexed from 0 to 7 and the last register (register 7) is reserved for storing the Widget's class.&lt;br /&gt;
&lt;br /&gt;
This detail is used by the Protocol Module on the Node to determine which driver is needed to run the new Widget when it has been discovered.&lt;br /&gt;
&lt;br /&gt;
The remaining 7 registers (registers 0 to 6) are free for Widget engineers to assign to the Widget's functions.&lt;br /&gt;
&lt;br /&gt;
Registers 0, 1, 2 and 3 are available as read/write registers. Registers 4, 5 and 6 are readonly registers.&lt;br /&gt;
&lt;br /&gt;
Only the emulated hardware (running on the Node) can change the values held in registers 4, 5 and 6.&lt;br /&gt;
&lt;br /&gt;
=== Register use in drivers ===&lt;br /&gt;
&lt;br /&gt;
In the example that follows we have a Basic Light Widget with a very simple function: it can be turned on and turned off. The on/off value is stored in register 0, with values 0=OFF and 1=ON. Register 0 is a read/write register. This means we can change the value stored there using messages passed to the Widget from the Node, and by reacting to physical interactions at the Widget (such as someone manually switching the light on or off). &lt;br /&gt;
&lt;br /&gt;
The mapping of registers to properties on the Widget is decided by the engineers who manufacture the device. You must be provided with the mapping before you begin developing your driver.&lt;br /&gt;
&lt;br /&gt;
== Starting the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-BoxHighlight.png|800px|thumb|center|Figure 3 The driver architecture highlighting the Widget driver and its component parts.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When you have generated the abstract provider you can put it to use in the Widget driver. A Widget driver&lt;br /&gt;
has three distinct components:&lt;br /&gt;
&lt;br /&gt;
* an implementation of your abstract provider&lt;br /&gt;
* a definition of the Widget driver&lt;br /&gt;
* an implementation of the IWidgetRegistryEntry interface&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must manually write the code for your Widget driver. The differences in implementation of Widget properties and communication protocols means that the driver code cannot be autogenerated.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This section takes you through how to write a Widget driver by implementing the auto-generated provider,&lt;br /&gt;
starting from a new blank file and finishing with a working driver for the Basic Light Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
No assumptions have been made about the type of editor you use to write your code. Shortcuts&lt;br /&gt;
or macros that you use as standard will not appear in the instructions below. A full example&lt;br /&gt;
BinaryLightDriver.cs is available to review in Appendix C.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a new C# file in your IDE. Ensure the following libraries are used:&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 [[File:Warning.png]]using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 namespace OpenHome.Widget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must use the libraries listed above for this specific example.&lt;br /&gt;
&lt;br /&gt;
In general, drivers require the following libraries:&lt;br /&gt;
* System*&lt;br /&gt;
* System.Collections.Generic*&lt;br /&gt;
* OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
&lt;br /&gt;
Your driver will fail to compile if you miss any of these listed libraries. Libraries marked * are typically added by default by most modern IDEs. &lt;br /&gt;
&lt;br /&gt;
The OpenHome.Widget.Protocols.SimpleUpnp library is required only in this SimpleUPnP example. Drivers using a different protocol will use their own protocol library.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Implementing the provider ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-ProviderHighlight.png|800px|thumb|center|Figure 4 The driver architecture highlighting the Provider's place]]&lt;br /&gt;
&lt;br /&gt;
You use your auto-generated abstract provider by writing an implementation of it in the driver file. Responsibilities met by implementing your auto-generated provider are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R6 Reacting to actions sent to the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
Begin by creating a new class. It will subclass the abstract auto-generated provider:&lt;br /&gt;
&lt;br /&gt;
 class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
The Protocol Module will provide an API for the Provider to use to communicate with the Widget. In&lt;br /&gt;
SimpleUPnP we are provided with an interface called ISimpleUpnpWidget. The provider is supplied&lt;br /&gt;
with the required instance of the interface by the Discovery Module on the Node.&lt;br /&gt;
&lt;br /&gt;
The mechanisms for registering providers with specific Protocol Modules, and for the way the module gives each provider its required interface are covered later when writing the discovery method.&lt;br /&gt;
&lt;br /&gt;
For now, we need to give the Provider a place to store the interface that it will later use to communicate&lt;br /&gt;
with the Widget:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]] private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
&lt;br /&gt;
The interface from the Protocol Module is passed in as a parameter in the Provider's constructor and then&lt;br /&gt;
assigned to the variable we just created:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightProvider(DvDevice aDevice,&lt;br /&gt;
 [[File:Warning.png]]         ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
 {&lt;br /&gt;
       iProtocol = aProtocol;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
To satisfy R3 we would normally set the Widget's properties here, giving them an initial value.&lt;br /&gt;
However, in this specific example we cannot set the value of Basic Light's only property because&lt;br /&gt;
we will never know, in advance, what the state of the light will be (either on or off) when we&lt;br /&gt;
create the DiscoveredWidget.&lt;br /&gt;
&lt;br /&gt;
When you cannot set the properties ahead of time, and you are using an eventing protocol like SimpleUPnP, you can instead set them in the HandleRegisterEvent method in the driver class. This also satisfies the requirements for R3. You must set the Widget's properties before you enable it using SetEnabled(). &lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The abstract provider includes an abstract method called SetOn. This method is invoked by the Node when passing a message to the Widget, specifically to set the on property of the Widget to either 0 or 1. The implementation of this method will meet the requirements for R6.&lt;br /&gt;
&lt;br /&gt;
We must override this method and provide the protocol module a way of passing a message on to the Widget to perform the required action, in this case turn the light on or off:&lt;br /&gt;
&lt;br /&gt;
          protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
          {&lt;br /&gt;
     [[File:Warning.png]]        iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
In this example the Basic Light's SetOn property (the boolean property that controls whether the light is&lt;br /&gt;
on or off) is represented in the physical Widget by the register that has an index of 0.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* This method is an example of an action on a Widget. Actions are messages sent from the Node to the Widget. We will see later how to handle events that need to be passed back from the Widget&lt;br /&gt;
to the Node.&lt;br /&gt;
* Your own Widget will likely provide more than a single property. Your auto-generated provider will contain one abstract method to represent each writable property. Read-only properties are not provided an abstract method.&lt;br /&gt;
&lt;br /&gt;
You must implement each abstract method in your driver to ensure the relevant property on&lt;br /&gt;
the Widget can be set.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We have now finished implementing the provider. The next step is to implement the driver.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Implementing the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-DriverHighlight.png|800px|thumb|center|Figure 4: The driver architecture highlighting the implemented driver's place.]]&lt;br /&gt;
&lt;br /&gt;
The code for your Widget driver must provide an implementation of the IWidgetRegistryInterface,&lt;br /&gt;
including the following tasks:&lt;br /&gt;
&lt;br /&gt;
* methods to expose identifying details about the Widget for the Node to access&lt;br /&gt;
* providing methods to handle events reported by the Widget&lt;br /&gt;
&lt;br /&gt;
The driver is implemented as a public class within the same file as the provider code. Each driver must use the interface for the protocol you are using. For the SimpleUPnP protocol the interface is ISimple-UpnpWidgetDriver.&lt;br /&gt;
&lt;br /&gt;
=== Writing code ===&lt;br /&gt;
&lt;br /&gt;
Create your new driver class and subclass the ISimpleUpnpWidgetDriver interface:&lt;br /&gt;
&lt;br /&gt;
 public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Implementing IWidgetRegistryEntry ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry is the interface you use to represent physical Widgets. It is implemented as a subclass of your driver class. We are going to implement this interface in a class called '''DiscoveredWidget'''.&lt;br /&gt;
&lt;br /&gt;
Let's return to our driver architecture diagram for a moment:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-IRegistryEntryHighlight.png|800px|thumb|center|Figure 5 The driver architecture highlighting the IWidgetRegistryEntry object you will now implement]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry uses several other objects to help create it and respond to messages sent to and from it. These objects will be created in our implementation of DiscoveredWidget. &lt;br /&gt;
&lt;br /&gt;
When successfully created and published, the DiscoveredWidget objects are stored in a list on the Node called the Local Widget Registry. The Local Widget Registry is used by Nodes to maintain contact with the Widgets they control.&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry is shown at the top of Figure 5, marked plainly as (Registry). The path to the Local Widget Registry goes through several layers of Node architecture which are not relevant to Widget driver writing, so are not shown in the diagrams.&lt;br /&gt;
&lt;br /&gt;
==== Writing code ====&lt;br /&gt;
&lt;br /&gt;
Start by subclassing the IWidgetRegistryEntry interface in your new class:&lt;br /&gt;
&lt;br /&gt;
      private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
      {&lt;br /&gt;
&lt;br /&gt;
A DiscoveredWidget must provide the driver with the objects required to present the Widget and its&lt;br /&gt;
properties to the Node:&lt;br /&gt;
&lt;br /&gt;
           private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
           private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
           private readonly ISimpleUpnpWidget iProtocol;&lt;br /&gt;
           private readonly BinaryLightProvider iProvider;&lt;br /&gt;
           private readonly DvDevice iDvDevice;&lt;br /&gt;
           private IPublishedWidget iPublishedWidget;&lt;br /&gt;
&lt;br /&gt;
Each of the attributes in the example above are defined as follows:&lt;br /&gt;
&lt;br /&gt;
iDeviceFactory — used by the driver to create a single instance of DvDevice to represent a single Widget&lt;br /&gt;
&lt;br /&gt;
iPublisher — used by the driver to publish the Widget to the Node&lt;br /&gt;
&lt;br /&gt;
iProtocol — the object used by the Widget to communicate with the Protocol Module on the Node&lt;br /&gt;
&lt;br /&gt;
iProvider — an instantiated provider of the type you defined earlier&lt;br /&gt;
&lt;br /&gt;
iDvDevice — a representation of a Widget to which the provider is attached, created using iDevice-Factory above&lt;br /&gt;
&lt;br /&gt;
iPublishedWidget — used to contain the returned object from a successful publishing of the Widget&lt;br /&gt;
If we look again at the driver architecture diagram, we ca highlight the objects we've just defined:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-Highlight.png|800px|thumb|center|Figure 6: The driver architecture highlighting the objects used by the IWidgetRegistryEntry implementation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The DeviceFactory, defined above in the member variable iDeviceFactory, is used to create new DvDevice objects. The DeviceFactory is only ever used to do this once. It is not shown in the driver architecture diagrams due to its minimal role in the operation of a driver, but it would normally appear between the IWidgetRegistryEntry and DvDevice objects.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
A driver requires methods to expose identifying details about the Widget. We must provide access to two of the attributes we just defined above:&lt;br /&gt;
&lt;br /&gt;
 public DvDevice DvDevice&lt;br /&gt;
 {&lt;br /&gt;
     get { return iDvDevice; }&lt;br /&gt;
 }&lt;br /&gt;
 public string WidgetClass&lt;br /&gt;
 {&lt;br /&gt;
     get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The WidgetClass string is formed using a combination of the vendor name and the Widget's name in the&lt;br /&gt;
format:&lt;br /&gt;
&lt;br /&gt;
 [vendor_domain]:[widget_name]&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry can now query both the DvDevice object representing the Widget, and the specific class of Widget this driver represents. The other member variables we defined do not need their own accessor methods.&lt;br /&gt;
&lt;br /&gt;
Now we must write a constructor for DiscoveredWidget and assign the parameters accordingly: &lt;br /&gt;
&lt;br /&gt;
 public DiscoveredWidget(IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                            string aUdn,&lt;br /&gt;
                            ISimpleUpnpWidget aProxy,&lt;br /&gt;
                            IWidgetPublisher aPublisher)&lt;br /&gt;
 {&lt;br /&gt;
      iDeviceFactory = aDeviceFactory;&lt;br /&gt;
      iProtocol = aProtocol;&lt;br /&gt;
      iPublisher = aPublisher;&lt;br /&gt;
      iDvDevice = iDeviceFactory.CreateDevice(aUdn);&lt;br /&gt;
      iProvider = new BinaryLightProvider(iDvDevice,&lt;br /&gt;
      iProtocol);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Event handling ===&lt;br /&gt;
&lt;br /&gt;
A Widget's state can change in one of three significant ways:&lt;br /&gt;
&lt;br /&gt;
* when the Widget needs to be published on the Node&lt;br /&gt;
* when the Widget disappears from the network (by losing power or similar)&lt;br /&gt;
* when a property's state changes and must be updated to a new value&lt;br /&gt;
&lt;br /&gt;
We now need methods to handle these changes.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The methods we define here will be used as callbacks, rather than invoked as method calls. We define the methods here first and then use them later on. We will use the Protocol Module to listen for changes in the Widget's state and register these methods as callbacks there. See Writing the SimpleUPnP Widget discovery method for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this section of the driver are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R4 Publishing discovered Widgets in the Local Widget Registry on the Node'''&lt;br /&gt;
&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object. &lt;br /&gt;
&lt;br /&gt;
'''R5 Reacting to an event reported from the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
'''R7 Reacting to a Widget's departure'''&lt;br /&gt;
&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no longer available.&lt;br /&gt;
&lt;br /&gt;
==== Enabling and publishing a discovered Widget ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first method initializes the Widget by enabling the device and then using the IWidgetPublisher&lt;br /&gt;
to make it available on the Node:&lt;br /&gt;
&lt;br /&gt;
 public void HandleInitialEvent()&lt;br /&gt;
 {&lt;br /&gt;
      iDvDevice.SetEnabled();&lt;br /&gt;
      iPublisher.TryPublishWidget(iDvDevice.iUdn(),&lt;br /&gt;
                              this,&lt;br /&gt;
                              out iPublishedWidget);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This method meets the requirements for R4.&lt;br /&gt;
&lt;br /&gt;
The call to TryPublishWidget returns an iPublishedWidget object. We use this object later to satisfy the requirements of R7.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The ordering of the calls to SetEnabled and TryPublishWidget is vitally important. You&lt;br /&gt;
must enable the device before you attempt to publish it. Your Widget will not be available to the&lt;br /&gt;
Nodes unless SetEnabled is called first. Nodes will not be able to access a published device&lt;br /&gt;
that has not been enabled.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
R3 requires that you set the Widget's properties before you enable and publish the device. We&lt;br /&gt;
discussed on page 14 how some properties can only be set after the Widget reports what their&lt;br /&gt;
state is. We do this in HandleRegisterEvent.&lt;br /&gt;
&lt;br /&gt;
We rely on the SimpleUPnP Protocol Module guaranteeing a call to HandleRegisterEvent first before HandleInitialEvent. This is informed by guarantees made by the Control Point stack that the calls will be made in that order.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
==== Removing a Widget ====&lt;br /&gt;
&lt;br /&gt;
Removing a Widget involves unpublishing it from the Node. The IPublishedWidget interface provides us with a method we can call to manage that for us:&lt;br /&gt;
&lt;br /&gt;
 public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
 {&lt;br /&gt;
     if (iPublishedWidget != null)&lt;br /&gt;
     { iPublishedWidget.Unpublish(); }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assuming that the Widget was successfully published earlier, it is removed from the Node's Local Widget Registry.&lt;br /&gt;
&lt;br /&gt;
We must also properly handle the resources we used to create and maintain the Widget object while it was published:&lt;br /&gt;
&lt;br /&gt;
      iProvider.Dispose();&lt;br /&gt;
      iDvDevice.Dispose();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The calls to Dispose are made regardless of the Widget's published state, ensuring that any created device and associated provider are properly disposed. This implementation satisfies R7.&lt;br /&gt;
&lt;br /&gt;
====Event handling ====&lt;br /&gt;
&lt;br /&gt;
We need a method to handle changes to the state of the Widget's properties.&lt;br /&gt;
&lt;br /&gt;
If the property changes at the Widget, it needs to pass the new state back to the Node so that it is kept up-to-date on the Widget's status. This is called an event. An example in the case of our Basic Light is someone manually switching the light from on to off. This is in contrast to actions, which are passed from the Node to the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Other examples of events involve no human interaction, such as a thermometer Widget updating its current temperature based on environmental changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Our Basic Light Widget has only one property that needs to be handled:&lt;br /&gt;
&lt;br /&gt;
 public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
 {&lt;br /&gt;
     if (aIndex == 0)&lt;br /&gt;
     {&lt;br /&gt;
         iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We use our instance of the provider to update the register on the Widget that is mapped to the On property. This in turn updates the Node with the new state of the Widget.&lt;br /&gt;
&lt;br /&gt;
This method provides implementations to satisfy two driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
* R3 is now completely satisfied, as we can now set the values of all the previously unknown properties here.&lt;br /&gt;
* R5 is also satisfied as this method allows us to update the Widget's status on the Node when a property is changed on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Not all protocols pass messages back to the Node in this manner. The way we have satisfied R3 and R5 here only applies to protocols and Widgets that support this behavior.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Widgets that do not use an eventing protocol need to have their properties set in the provider's constructor to satisfy R3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To satisfy R5, the over-ridden method SetOn in the provider must include the call to SetPropertyOn. Non-eventing protocols do not require a HandleRegisterEvent method.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Constructor ===&lt;br /&gt;
&lt;br /&gt;
The final requirement for the driver is the constructor so that new DiscoveredWidget objects can be created. &lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this area of code are:&lt;br /&gt;
&lt;br /&gt;
'''R1 Specifying the type of Widget the driver controls'''&lt;br /&gt;
&lt;br /&gt;
A driver must know which type of Widget that it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
==== Writing the code ====&lt;br /&gt;
&lt;br /&gt;
We begin by defining the variables we will use to store the objects used by the driver:&lt;br /&gt;
&lt;br /&gt;
 private readonly string iName;&lt;br /&gt;
 private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
 private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now write the constructor for the driver and assign the passed in parameters appropriately:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightDriver(string aName,&lt;br /&gt;
                IWidgetPublisher aPublisher,&lt;br /&gt;
                IDvDeviceFactory aDeviceFactory)&lt;br /&gt;
 {&lt;br /&gt;
     iWidgetPublisher = aPublisher;&lt;br /&gt;
     iName = aName;&lt;br /&gt;
     iDeviceFactory = aDeviceFactory;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally we need to provide the driver a way to publish the class of Widget it controls. This information is requested by the Discovery Module and is used to ensure the Node uses the correct driver when a new Widget appears.&lt;br /&gt;
&lt;br /&gt;
The implementation for this details will be different for each protocol. The SimpleUPnP protocol library provides a file that contains the SimpleUPnP definitions as integers. Each integer represents a particular class of identified Widget.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP implementation of that method is as follows:&lt;br /&gt;
&lt;br /&gt;
 public IEnumerable&amp;lt;uint&amp;gt; WidgetClasses&lt;br /&gt;
 {&lt;br /&gt;
 [[File:Warning.png]]        get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The body of this method is specifically written for the Widget class we are defining (in this case a binary light). This method completes the driver's requirements for R1.&lt;br /&gt;
&lt;br /&gt;
== Writing the SimpleUPnP Widget discovery method ==&lt;br /&gt;
&lt;br /&gt;
Every driver must contain a method which creates new objects to represent newly discovered Widgets.&lt;br /&gt;
The Discovery Module invokes this method to begin the process of creating the objects required to allow the Node to access the Widget. &lt;br /&gt;
&lt;br /&gt;
The name of this method is dictated by your chosen protocol's API. The SimpleUPnP protocol requires a method called WidgetDiscovered.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The method's name will not always be the same for each protocol. Your protocol's documentation will contain the details of what this method must be called.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This method and its implementation will meet the following driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
'''R2 Reacting to a discovered Widget on the network'''&lt;br /&gt;
&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
Our implementation of the WidgetDiscovered method will create a new DiscoveredWidget object and use the Protocol Module to listen for changes to the Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
The method uses the Protocol Module and two ways to identify the Widget. We must pass these in as&lt;br /&gt;
parameters:&lt;br /&gt;
&lt;br /&gt;
 public void WidgetDiscovered(string aWidgetUdn,&lt;br /&gt;
                              uint aWidgetClass,&lt;br /&gt;
                              ISimpleUpnpWidget&lt;br /&gt;
                                  aSimpleUpnpWidget)&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
Every Widget that uses this driver must be uniquely identifiable:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]    string newUdn = aWidgetUdn;&lt;br /&gt;
&lt;br /&gt;
Each new Widget is represented by a DiscoveredWidget object. Create the new DiscoveredWidget and pass in the required parameters we created earlier:&lt;br /&gt;
&lt;br /&gt;
     DiscoveredWidget discoveredWidget =&lt;br /&gt;
                 new DiscoveredWidget(iDeviceFactory,&lt;br /&gt;
                                      newUdn,&lt;br /&gt;
  &lt;br /&gt;
 [[File:Warning.png]]                                    aSimpleUpnpWidget,&lt;br /&gt;
&lt;br /&gt;
=== Registering the callbacks ===&lt;br /&gt;
&lt;br /&gt;
Finally, we ask the Widget's protocol interface to listen for calls to the handler methods we defined earlier in DiscoveredWidget. We do this by registering those methods as callbacks for the Protocol Module&lt;br /&gt;
to listen for:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                        discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                        discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                        discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You have now met 100% of the driver responsibility requirements and have a working driver to use with your SimpleUPnP Widget.&lt;br /&gt;
&lt;br /&gt;
= Appendix A. Sample XML =&lt;br /&gt;
&lt;br /&gt;
== Binary Light.xml ==&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
  &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
  &amp;lt;version&amp;gt;&lt;br /&gt;
   &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
   &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/version&amp;gt;&lt;br /&gt;
  &amp;lt;propertylist&amp;gt;&lt;br /&gt;
   &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
       illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
   &amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix B. Sample Provider = &lt;br /&gt;
&lt;br /&gt;
== DvWidgetOpenhomeOrgBasicLight1.cs ==&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Runtime.InteropServices;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Core;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Utils.Binary;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
 {&lt;br /&gt;
    public interface IDvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
        IDisposable&lt;br /&gt;
    {&lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous value&lt;br /&gt;
        /// &amp;lt;/returns&amp;gt;&lt;br /&gt;
        bool SetPropertyOn(bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;Property's value will be copied&lt;br /&gt;
        /// here&amp;lt;/param&amp;gt;&lt;br /&gt;
        bool PropertyOn();&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt; summary&amp;gt;&lt;br /&gt;
    /// Provider for the openhome.org:BinaryLight:1 UPnP service&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public abstract class DvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
               DvProvider,&lt;br /&gt;
               IDisposable,&lt;br /&gt;
               IDvProviderOpenhomeOrgBinaryLight1&lt;br /&gt;
    {&lt;br /&gt;
        private GCHandle iGch;&lt;br /&gt;
        private PropertyBool iPropertyOn;&lt;br /&gt;
        private PropertyUint iPropertyPrimarySeq;&lt;br /&gt;
        private PropertyUint iPropertySecondarySeq;&lt;br /&gt;
        private ActionDelegate iDelegateSetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetPrimaryProperty;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Constructor&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aDevice&amp;quot;&amp;gt;Device which owns this&lt;br /&gt;
        /// provider&amp;lt;/param&amp;gt;&lt;br /&gt;
        protected DvProviderOpenhomeOrgBinaryLight1(DvDevice aDevice)&lt;br /&gt;
            : base(aDevice, &amp;quot;openhome.org&amp;quot;, &amp;quot;GenericWidget&amp;quot;, 1)&lt;br /&gt;
        {&lt;br /&gt;
            iGch = GCHandle.Alloc(this);&lt;br /&gt;
            List&amp;lt;String&amp;gt; allowedValues = new List&amp;lt;String&amp;gt;();&lt;br /&gt;
            iPropertyOn = new PropertyBool(new ParameterBool(&amp;quot;On&amp;quot;));&lt;br /&gt;
            iPropertyPrimarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;PrimarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertyPrimarySeq);&lt;br /&gt;
            iPropertySecondarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;SecondarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertySecondarySeq);&lt;br /&gt;
            SetPropertyUint(iPropertyPrimarySeq, 0);&lt;br /&gt;
            SetPropertyUint(iPropertySecondarySeq, 0);&lt;br /&gt;
  &lt;br /&gt;
            Zapp.Core.Action action = new Zapp.Core.Action&lt;br /&gt;
                (&amp;quot;SetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;FireAndForget&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddInputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateSetProperty = new ActionDelegate(DoSetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateSetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateGetProperty = new ActionDelegate(DoGetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetPrimaryProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                 (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;integer&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;boolean&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;string&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;binary&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Type&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;readWrite&amp;quot;);allowedValues.Add&lt;br /&gt;
                (&amp;quot;readOnly&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;writeOnly&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString(&amp;quot;Access&amp;quot;,&lt;br /&gt;
                allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            iDelegateGetPrimaryProperty = new&lt;br /&gt;
            ActionDelegate(DoGetPrimaryProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetPrimaryProperty,&lt;br /&gt;
            GCHandle.ToIntPtr(iGch));&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous&lt;br /&gt;
        /// value&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool SetPropertyOn(bool aValue)&lt;br /&gt;
        {&lt;br /&gt;
            if (iPropertyOn.SetValue(aValue))&lt;br /&gt;
            {&lt;br /&gt;
                lock (iPropertyPrimarySeq)&lt;br /&gt;
                {&lt;br /&gt;
                    SetPropertyUint(iPropertyPrimarySeq,&lt;br /&gt;
                        iPropertyPrimarySeq.Value() + 1);&lt;br /&gt;
                } return true;&lt;br /&gt;
            } return false;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;The value of the property&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool PropertyOn()&lt;br /&gt;
        {&lt;br /&gt;
            return iPropertyOn.Value();&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the On property.&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aVersion&amp;quot;&amp;gt;Version of the service being&lt;br /&gt;
        /// requested (will be &amp;lt;= the version advertised)&amp;lt;/param&amp;gt; &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the On property.&lt;br /&gt;
        /// &amp;lt;/param&amp;gt;&lt;br /&gt;
        protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        private static int DoSetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                byte[] valBin = invocation.ReadBinary(&amp;quot;Value&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                switch (name)&lt;br /&gt;
                {&lt;br /&gt;
                    case &amp;quot;On&amp;quot;:&lt;br /&gt;
                        self.SetOn(aVersion, Converter.&lt;br /&gt;
                            BinaryToBoolean(valBin));&lt;br /&gt;
                        break;&lt;br /&gt;
                    default:&lt;br /&gt;
                        throw new ActionError();&lt;br /&gt;
                }&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
                invocation.WriteEnd();&lt;br /&gt;
            }&lt;br /&gt;
            catch (ActionError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
            catch (PropertyUpdateError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
        return 0;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        private static int DoGetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
            switch (name)&lt;br /&gt;
            {&lt;br /&gt;
                case &amp;quot;On&amp;quot;:&lt;br /&gt;
                invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                    Converter.BooleanToBinary(self.iPropertyOn.&lt;br /&gt;
                        Value()));&lt;br /&gt;
                break;&lt;br /&gt;
                default:&lt;br /&gt;
                throw new ActionError();&lt;br /&gt;
            }&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    private static int DoGetPrimaryProperty(IntPtr aPtr,&lt;br /&gt;
                    IntPtr aInvocation,&lt;br /&gt;
                    uint aVersion)&lt;br /&gt;
    {&lt;br /&gt;
        GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
        DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
            (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
        DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
  &lt;br /&gt;
        try&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReadStart();&lt;br /&gt;
            invocation.ReadEnd();&lt;br /&gt;
            invocation.WriteStart();&lt;br /&gt;
            invocation.WriteString(&amp;quot;Name&amp;quot;, &amp;quot;On&amp;quot;);&lt;br /&gt;
            invocation.WriteString(&amp;quot;Type&amp;quot;, &amp;quot;boolean&amp;quot;);&lt;br /&gt;
            invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                Converter.BooleanToBinary(self.iPropertyOn.Value()));&lt;br /&gt;
            invocation.WriteString(&amp;quot;Access&amp;quot;, &amp;quot;readWrite&amp;quot;);&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt;summary&amp;gt;&lt;br /&gt;
    /// Must be called for each class instance. Must be called before&lt;br /&gt;
    /// Core.Library.Close().&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public void Dispose()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
        GC.SuppressFinalize(this);&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
    ~DvProviderOpenhomeOrgBinaryLight1()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
        private void DoDispose()&lt;br /&gt;
        {&lt;br /&gt;
            lock (this)&lt;br /&gt;
            {&lt;br /&gt;
                if (iHandle == IntPtr.Zero)&lt;br /&gt;
            {&lt;br /&gt;
                    return;&lt;br /&gt;
            }&lt;br /&gt;
            DisposeProvider();&lt;br /&gt;
            iPropertyOn.Dispose();&lt;br /&gt;
            iHandle = IntPtr.Zero;&lt;br /&gt;
            }&lt;br /&gt;
            iGch.Free();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix C. Sample Driver = &lt;br /&gt;
&lt;br /&gt;
== BasicLightDriver.cs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.hWidget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
     class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
     {&lt;br /&gt;
         private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
         public BinaryLightProvider(DvDevice aDevice, &lt;br /&gt;
             ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol = aProtocol;&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
     {&lt;br /&gt;
         private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
         {&lt;br /&gt;
             private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
             private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
             private readonly ISimpleUpnpWidget iProtocol; &lt;br /&gt;
 &lt;br /&gt;
             private readonly BinaryLightProvider iProvider;&lt;br /&gt;
             private readonly DvDevice iDvDevice;&lt;br /&gt;
             private IPublishedWidget iPublishedWidget; &lt;br /&gt;
 &lt;br /&gt;
             public DvDevice DvDevice&lt;br /&gt;
             {&lt;br /&gt;
                 get { return iDvDevice; }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             public string WidgetClass&lt;br /&gt;
             {&lt;br /&gt;
                 get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public DiscoveredWidget(&lt;br /&gt;
                 IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                 string aUdn,&lt;br /&gt;
                 ISimpleUpnpWidget aProxy,&lt;br /&gt;
                 IWidgetPublisher aPublisher)&lt;br /&gt;
             {&lt;br /&gt;
                 iDeviceFactory = aDeviceFactory;&lt;br /&gt;
                 iProtocol = aProtocol;&lt;br /&gt;
 &lt;br /&gt;
                 iPublisher = aPublisher;&lt;br /&gt;
                 iDvDevice = iDeviceFactory.CreateDevice(aUdn);  &lt;br /&gt;
                 iProvider = new BinaryLightProvider(iDvDevice, &lt;br /&gt;
                                                     iProtocol);&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             public void HandleInitialEvent()&lt;br /&gt;
             {&lt;br /&gt;
                 iDvDevice.SetEnabled();&lt;br /&gt;
                 iPublisher.TryPublishWidget(iDvDevice.iUdn(), this,&lt;br /&gt;
                     out iPublishedWidget);&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
             {&lt;br /&gt;
                 if (iPublishedWidget != null)&lt;br /&gt;
                 {&lt;br /&gt;
                     iPublishedWidget.Unpublish();&lt;br /&gt;
                 } &lt;br /&gt;
                 iProvider.Dispose();&lt;br /&gt;
                 iDvDevice.Dispose();&lt;br /&gt;
             }  &lt;br /&gt;
 &lt;br /&gt;
             public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
             {&lt;br /&gt;
                 if (aIndex == 0)&lt;br /&gt;
                 {&lt;br /&gt;
                     iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         private readonly string iName;&lt;br /&gt;
         private readonly IDvDeviceFactory aDeviceFactory;&lt;br /&gt;
         private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
         &lt;br /&gt;
         public BinaryLightDriver(&lt;br /&gt;
             string aName,&lt;br /&gt;
             IWidgetPublisher aPublisher,&lt;br /&gt;
             iDeviceFactory aDeviceFactory)&lt;br /&gt;
         {&lt;br /&gt;
             iWidgetPublisher = aPublisher;&lt;br /&gt;
             iName = aName;&lt;br /&gt;
             iDeviceFactory = aDeviceFactory;&lt;br /&gt;
         } &lt;br /&gt;
 &lt;br /&gt;
         public IEnumerable&amp;amp;lt;uint&amp;amp;gt; WidgetClasses&lt;br /&gt;
         {&lt;br /&gt;
             get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         public void WidgetDiscovered(&lt;br /&gt;
             string aWidgetUdn,&lt;br /&gt;
             uint aWidgetClass,&lt;br /&gt;
             ISimpleUpnpWidget aSimpleUpnpWidget)&lt;br /&gt;
         {&lt;br /&gt;
             string newUdn = aWidgetUdn;&lt;br /&gt;
             DiscoveredWidget discoveredWidget = new DiscoveredWidget&lt;br /&gt;
                 (iDeviceFactory,&lt;br /&gt;
                  newUdn,&lt;br /&gt;
                  aSimpleUpnpWidget,&lt;br /&gt;
                  iWidgetPublisher);&lt;br /&gt;
 &lt;br /&gt;
             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                 discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                 discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                 discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary = &lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in OpenHome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by OpenHome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh - A collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs on ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The OpenHome Operating System. Core software for OpenHome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. &lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. A typical Widget supports only one protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Driver_Development</id>
		<title>OhWidget Driver Development</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Driver_Development"/>
				<updated>2012-03-01T15:20:21Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Writing the code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for developers using the OpenHome SDK to integrate a Widget into an OpenHome system. Each Widget must have its own driver to allow it to communicate with the OpenHome Nodes. &lt;br /&gt;
&lt;br /&gt;
To help you write your driver, this document provides high level descriptions of the core responsibilities of a Widget driver and gives a detailed walk-through using example code.&lt;br /&gt;
&lt;br /&gt;
Full versions of each file used in the development of the example driver are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin development of your Widget driver you must be in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* your Widget Service XML that describes the properties on your Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document does not contain advice on how to write Widget Service XML. Refer to the OpenHome Widget Service XML definition document for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK&lt;br /&gt;
* your chosen communication protocol's API&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The protocol you choose for your Widgets must be the same protocol used on your choice of Node.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document focuses on the development of the Widget driver. Details about the communications protocol used are beyond the scope of this document. This document assumes you are familiar with your chosen protocol's code libraries and are able to use them in the driver code you write.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Related Documents ==&lt;br /&gt;
&lt;br /&gt;
The following related OpenHome documentation may be of interest to you:&lt;br /&gt;
&lt;br /&gt;
* [[ohWidget Technical Overview|ohWidget Technical Overview]]&lt;br /&gt;
* [[OpenHome Widget Service XML definition|OpenHome Widget Service XML definition]]&lt;br /&gt;
* [http://www.openhome.org/releases/ohNet_DeviceStack.pdf  OpenHome ohNet Device Stack]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
None of the related documents listed above is mandatory reading for Widget driver development.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
== Widget Service XML ==&lt;br /&gt;
OpenHome Widget driver writing relies heavily on the use of code generated from a single source — the Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
The service and actions your Widget provides are represented in code in a file called a Provider. The Provider is automatically generated from the Widget Service XML and produces an abstract class for you to inherit when you write your concrete class driver.&lt;br /&gt;
&lt;br /&gt;
To aid in the explanation of how the Provider is created and put to use we will follow the development of&lt;br /&gt;
a driver for a simple light Widget; taking the defined Widget Service XML and stepping through how it is used to generate the other files. Examples of code are used throughout this document to show you how each one is created and used in an OpenHome system. &lt;br /&gt;
&lt;br /&gt;
It is essential that you start with a well-formed Widget Service XML, conforming to the schema defined&lt;br /&gt;
in the WidgetService.xsd. The following diagram shows the significance of the Widget Service XML in&lt;br /&gt;
relation to the generated files you will use when writing your driver:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarchy, highlighting the areas specifically used in driver development]]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* The grayed-out files are not relevant to Widget driver development but can also be generated from the Widget Service XML.&lt;br /&gt;
* The Provider is generated in C#, meaning your driver must be written in C# as well. The use of managed code is mandatory for driver writing in the OpenHome framework.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Code sample used in this document ==&lt;br /&gt;
&lt;br /&gt;
Our examples in this document use a Widget Service XML definition for a light Widget called&lt;br /&gt;
BasicLight.xml.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Full versions of all the example files used in this document are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We will see how the Provider is generated from this XML and how it is used to aid the driver writing process. The examples also show how your chosen communication protocol should be used in the body of the driver code.&lt;br /&gt;
&lt;br /&gt;
Implementation details of specific protocols you choose to use are beyond the scope of this document. However, the samples used in this document show the use of the SimpleUPnP protocol to aid you in your development process.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol during the early stages of the OpenHome project. It is included in the OpenHome SDK and can be used as a public resource. &lt;br /&gt;
&lt;br /&gt;
The use of SimpleUPnP in the example files and the code snippets within the following sections is highlighted by the [[File:Warning.png]] icon. The lines of code marked by [[File:Warning.png]] must be changed to code from your chosen communication protocol's library. SimpleUPnP is left in to help you understand how a protocol is used in a working example.&lt;br /&gt;
&lt;br /&gt;
The sample code provided attempts to show best-practice coding standards. There are several sections of code that have a mandatory layout or that call specifically named methods and functions. These areas of the code are highlighted where required. &lt;br /&gt;
&lt;br /&gt;
Where the examples do not explicitly state that the code shown is mandatory, you are free to implement it in a different way according to your own coding style and practices.&lt;br /&gt;
&lt;br /&gt;
= Driver responsibilities = &lt;br /&gt;
&lt;br /&gt;
== Driver responsibilities ==&lt;br /&gt;
&lt;br /&gt;
An OpenHome Widget driver has several responsibilities which must be met before it can be used on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
These responsibilities are listed R1 to R7 and are defined here, explaining what each one must do. &lt;br /&gt;
&lt;br /&gt;
=== R1 Specifying the type of Widget the driver controls ===&lt;br /&gt;
A driver must know which type of Widget it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
=== R2 Reacting to a discovered Widget on the network ===&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== R3 Setting the initial values for the Widget's properties ===&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
=== R4 Publishing discovered Widgets in the Local Widget Registry on the Node ===&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object.&lt;br /&gt;
&lt;br /&gt;
=== R5 Reacting to an event reported from the Widget ===&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
=== R6 Reacting to actions sent to the Widget ===&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== R7 Reacting to a Widget's departure ===&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no&lt;br /&gt;
longer available.&lt;br /&gt;
&lt;br /&gt;
The sections of example code that follow show you how to write a driver from beginning to end. The accompanying text explaining the example code highlights when a responsibility, or part of a responsibility, has been met.&lt;br /&gt;
&lt;br /&gt;
= Driver Architecture = &lt;br /&gt;
&lt;br /&gt;
== Driver Architecture ==&lt;br /&gt;
&lt;br /&gt;
Drivers are installed on the Node and used when the Node needs to communicate with the Widget. Drivers&lt;br /&gt;
use several objects to communicate with Widgets over the Widget's lifetime. Figure 2 shows the objects&lt;br /&gt;
used by the driver and how the responsibilities listed above relate to each one:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture.png|800px|thumb|center|Figure 2: The architecture of a driver, showing the driver's relationship to the objects used to communicate with a Widget. Lines between objects show message flow.]]&lt;br /&gt;
&lt;br /&gt;
The objects contained in the dotted boundary must appear in the code you write to define your driver. The Driver, Provider and IWidgetRegistryEntry objects are all contained in the same driver file. We begin discussing this on page 12. &lt;br /&gt;
&lt;br /&gt;
The other objects are provided by the OpenHome SDK or as installed components on the Node.&lt;br /&gt;
&lt;br /&gt;
The Discovery Module informs the driver of the presence of an available Widget.&lt;br /&gt;
&lt;br /&gt;
Each Node has a Protocol Module which contains the protocol's API. Widgets can communicate with OpenHome Nodes using any one of the set of communications protocols the Node supports. The driver uses your chosen protocol's Protocol Module to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
Both the Protocol Module and the Discovery Module are installed on the Node. When you write your&lt;br /&gt;
driver you will use your Protocol Module to allow the driver to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
IWidgetPublisher, IPublishedWidget and DvDevice are objects provided in the OpenHome&lt;br /&gt;
API. You can read about them in the APIs.&lt;br /&gt;
&lt;br /&gt;
= Generating the Provider = &lt;br /&gt;
&lt;br /&gt;
== Generating the Provider ==&lt;br /&gt;
&lt;br /&gt;
You must generate your provider before you can begin writing your Widget driver. You use your provider as a guide to implement the functions your Widget needs to set the values of its properties.&lt;br /&gt;
&lt;br /&gt;
The current provider generation process is a manual one involving the use of a text transform tool.&lt;br /&gt;
&lt;br /&gt;
Speak to your OpenHome contact who will help you generate your provider.&lt;br /&gt;
&lt;br /&gt;
Future releases of the OpenHome SDK will include a tool to help you generate the provider.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
You must be in possession of:&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK, unpacked on your computer&lt;br /&gt;
* your Widget Service XML file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Writing a SimpleUPnP driver = &lt;br /&gt;
&lt;br /&gt;
== Introduction to the SimpleUPnP protocol ==&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol used to control emulated Widgets over a custom UPnP service.&lt;br /&gt;
&lt;br /&gt;
This chapter shows how a driver is written using the SimpleUPnP communications protocol. The aim is to show the code using as generic a protocol as possible so that you can see where your own protocol specific code needs to go.&lt;br /&gt;
&lt;br /&gt;
The use of code specific to the SimpleUPnP implementation is highlighted by the use of the [[File:Warning.png]] icon. The lines of code are marked by this icon to make it easier for you to see where the protocol-specific code must go and what parts of the code are generic.&lt;br /&gt;
&lt;br /&gt;
=== Register model ===&lt;br /&gt;
&lt;br /&gt;
SimpleUPnP is modeled on 8 physical registers available on the Widget. Each register is 32-bits wide. They are indexed from 0 to 7 and the last register (register 7) is reserved for storing the Widget's class.&lt;br /&gt;
&lt;br /&gt;
This detail is used by the Protocol Module on the Node to determine which driver is needed to run the new Widget when it has been discovered.&lt;br /&gt;
&lt;br /&gt;
The remaining 7 registers (registers 0 to 6) are free for Widget engineers to assign to the Widget's functions.&lt;br /&gt;
&lt;br /&gt;
Registers 0, 1, 2 and 3 are available as read/write registers. Registers 4, 5 and 6 are readonly registers.&lt;br /&gt;
&lt;br /&gt;
Only the emulated hardware (running on the Node) can change the values held in registers 4, 5 and 6.&lt;br /&gt;
&lt;br /&gt;
=== Register use in drivers ===&lt;br /&gt;
&lt;br /&gt;
In the example that follows we have a Basic Light Widget with a very simple function: it can be turned on and turned off. The on/off value is stored in register 0, with values 0=OFF and 1=ON. Register 0 is a read/write register. This means we can change the value stored there using messages passed to the Widget from the Node, and by reacting to physical interactions at the Widget (such as someone manually switching the light on or off). &lt;br /&gt;
&lt;br /&gt;
The mapping of registers to properties on the Widget is decided by the engineers who manufacture the device. You must be provided with the mapping before you begin developing your driver.&lt;br /&gt;
&lt;br /&gt;
== Starting the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-BoxHighlight.png|800px|thumb|center|Figure 3 The driver architecture highlighting the Widget driver and its component parts.]]&lt;br /&gt;
&lt;br /&gt;
When you have generated the abstract provider you can put it to use in the Widget driver. A Widget driver&lt;br /&gt;
has three distinct components:&lt;br /&gt;
&lt;br /&gt;
* an implementation of your abstract provider&lt;br /&gt;
* a definition of the Widget driver&lt;br /&gt;
* an implementation of the IWidgetRegistryEntry interface&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must manually write the code for your Widget driver. The differences in implementation of Widget properties and communication protocols means that the driver code cannot be autogenerated.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This section takes you through how to write a Widget driver by implementing the auto-generated provider,&lt;br /&gt;
starting from a new blank file and finishing with a working driver for the Basic Light Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
No assumptions have been made about the type of editor you use to write your code. Shortcuts&lt;br /&gt;
or macros that you use as standard will not appear in the instructions below. A full example&lt;br /&gt;
BinaryLightDriver.cs is available to review in Appendix C.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a new C# file in your IDE. Ensure the following libraries are used:&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 [[File:Warning.png]]using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 namespace OpenHome.Widget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must use the libraries listed above for this specific example.&lt;br /&gt;
&lt;br /&gt;
In general, drivers require the following libraries:&lt;br /&gt;
* System*&lt;br /&gt;
* System.Collections.Generic*&lt;br /&gt;
* OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
&lt;br /&gt;
Your driver will fail to compile if you miss any of these listed libraries. Libraries marked * are typically added by default by most modern IDEs. &lt;br /&gt;
&lt;br /&gt;
The OpenHome.Widget.Protocols.SimpleUpnp library is required only in this SimpleUPnP example. Drivers using a different protocol will use their own protocol library.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Implementing the provider ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-ProviderHighlight.png|800px|thumb|center|Figure 4 The driver architecture highlighting the Provider's place]]&lt;br /&gt;
&lt;br /&gt;
You use your auto-generated abstract provider by writing an implementation of it in the driver file. Responsibilities met by implementing your auto-generated provider are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R6 Reacting to actions sent to the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
Begin by creating a new class. It will subclass the abstract auto-generated provider:&lt;br /&gt;
&lt;br /&gt;
 class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
The Protocol Module will provide an API for the Provider to use to communicate with the Widget. In&lt;br /&gt;
SimpleUPnP we are provided with an interface called ISimpleUpnpWidget. The provider is supplied&lt;br /&gt;
with the required instance of the interface by the Discovery Module on the Node.&lt;br /&gt;
&lt;br /&gt;
The mechanisms for registering providers with specific Protocol Modules, and for the way the module gives each provider its required interface are covered later when writing the discovery method.&lt;br /&gt;
&lt;br /&gt;
For now, we need to give the Provider a place to store the interface that it will later use to communicate&lt;br /&gt;
with the Widget:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]] private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
&lt;br /&gt;
The interface from the Protocol Module is passed in as a parameter in the Provider's constructor and then&lt;br /&gt;
assigned to the variable we just created:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightProvider(DvDevice aDevice,&lt;br /&gt;
 [[File:Warning.png]]         ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
 {&lt;br /&gt;
       iProtocol = aProtocol;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
To satisfy R3 we would normally set the Widget's properties here, giving them an initial value.&lt;br /&gt;
However, in this specific example we cannot set the value of Basic Light's only property because&lt;br /&gt;
we will never know, in advance, what the state of the light will be (either on or off) when we&lt;br /&gt;
create the DiscoveredWidget.&lt;br /&gt;
&lt;br /&gt;
When you cannot set the properties ahead of time, and you are using an eventing protocol like SimpleUPnP, you can instead set them in the HandleRegisterEvent method in the driver class. This also satisfies the requirements for R3. You must set the Widget's properties before you enable it using SetEnabled(). &lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The abstract provider includes an abstract method called SetOn. This method is invoked by the Node when passing a message to the Widget, specifically to set the on property of the Widget to either 0 or 1. The implementation of this method will meet the requirements for R6.&lt;br /&gt;
&lt;br /&gt;
We must override this method and provide the protocol module a way of passing a message on to the Widget to perform the required action, in this case turn the light on or off:&lt;br /&gt;
&lt;br /&gt;
          protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
          {&lt;br /&gt;
     [[File:Warning.png]]        iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
In this example the Basic Light's SetOn property (the boolean property that controls whether the light is&lt;br /&gt;
on or off) is represented in the physical Widget by the register that has an index of 0.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* This method is an example of an action on a Widget. Actions are messages sent from the Node to the Widget. We will see later how to handle events that need to be passed back from the Widget&lt;br /&gt;
to the Node.&lt;br /&gt;
* Your own Widget will likely provide more than a single property. Your auto-generated provider will contain one abstract method to represent each writable property. Read-only properties are not provided an abstract method.&lt;br /&gt;
&lt;br /&gt;
You must implement each abstract method in your driver to ensure the relevant property on&lt;br /&gt;
the Widget can be set.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We have now finished implementing the provider. The next step is to implement the driver.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Implementing the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-DriverHighlight.png|800px|thumb|center|Figure 4: The driver architecture highlighting the implemented driver's place.]]&lt;br /&gt;
&lt;br /&gt;
The code for your Widget driver must provide an implementation of the IWidgetRegistryInterface,&lt;br /&gt;
including the following tasks:&lt;br /&gt;
&lt;br /&gt;
* methods to expose identifying details about the Widget for the Node to access&lt;br /&gt;
* providing methods to handle events reported by the Widget&lt;br /&gt;
&lt;br /&gt;
The driver is implemented as a public class within the same file as the provider code. Each driver must use the interface for the protocol you are using. For the SimpleUPnP protocol the interface is ISimple-UpnpWidgetDriver.&lt;br /&gt;
&lt;br /&gt;
=== Writing code ===&lt;br /&gt;
&lt;br /&gt;
Create your new driver class and subclass the ISimpleUpnpWidgetDriver interface:&lt;br /&gt;
&lt;br /&gt;
 public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Implementing IWidgetRegistryEntry ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry is the interface you use to represent physical Widgets. It is implemented as a subclass of your driver class. We are going to implement this interface in a class called '''DiscoveredWidget'''.&lt;br /&gt;
&lt;br /&gt;
Let's return to our driver architecture diagram for a moment:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-IRegistryEntryHighlight.png|800px|thumb|center|Figure 5 The driver architecture highlighting the IWidgetRegistryEntry object you will now implement]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry uses several other objects to help create it and respond to messages sent to and from it. These objects will be created in our implementation of DiscoveredWidget. &lt;br /&gt;
&lt;br /&gt;
When successfully created and published, the DiscoveredWidget objects are stored in a list on the Node called the Local Widget Registry. The Local Widget Registry is used by Nodes to maintain contact with the Widgets they control.&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry is shown at the top of Figure 5, marked plainly as (Registry). The path to the Local Widget Registry goes through several layers of Node architecture which are not relevant to Widget driver writing, so are not shown in the diagrams.&lt;br /&gt;
&lt;br /&gt;
==== Writing code ====&lt;br /&gt;
&lt;br /&gt;
Start by subclassing the IWidgetRegistryEntry interface in your new class:&lt;br /&gt;
&lt;br /&gt;
      private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
      {&lt;br /&gt;
&lt;br /&gt;
A DiscoveredWidget must provide the driver with the objects required to present the Widget and its&lt;br /&gt;
properties to the Node:&lt;br /&gt;
&lt;br /&gt;
           private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
           private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
           private readonly ISimpleUpnpWidget iProtocol;&lt;br /&gt;
           private readonly BinaryLightProvider iProvider;&lt;br /&gt;
           private readonly DvDevice iDvDevice;&lt;br /&gt;
           private IPublishedWidget iPublishedWidget;&lt;br /&gt;
&lt;br /&gt;
Each of the attributes in the example above are defined as follows:&lt;br /&gt;
&lt;br /&gt;
iDeviceFactory — used by the driver to create a single instance of DvDevice to represent a single Widget&lt;br /&gt;
&lt;br /&gt;
iPublisher — used by the driver to publish the Widget to the Node&lt;br /&gt;
&lt;br /&gt;
iProtocol — the object used by the Widget to communicate with the Protocol Module on the Node&lt;br /&gt;
&lt;br /&gt;
iProvider — an instantiated provider of the type you defined earlier&lt;br /&gt;
&lt;br /&gt;
iDvDevice — a representation of a Widget to which the provider is attached, created using iDevice-Factory above&lt;br /&gt;
&lt;br /&gt;
iPublishedWidget — used to contain the returned object from a successful publishing of the Widget&lt;br /&gt;
If we look again at the driver architecture diagram, we ca highlight the objects we've just defined:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-Highlight.png|800px|thumb|center|Figure 6: The driver architecture highlighting the objects used by the IWidgetRegistryEntry implementation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The DeviceFactory, defined above in the member variable iDeviceFactory, is used to create new DvDevice objects. The DeviceFactory is only ever used to do this once. It is not shown in the driver architecture diagrams due to its minimal role in the operation of a driver, but it would normally appear between the IWidgetRegistryEntry and DvDevice objects.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
A driver requires methods to expose identifying details about the Widget. We must provide access to two of the attributes we just defined above:&lt;br /&gt;
&lt;br /&gt;
 public DvDevice DvDevice&lt;br /&gt;
 {&lt;br /&gt;
     get { return iDvDevice; }&lt;br /&gt;
 }&lt;br /&gt;
 public string WidgetClass&lt;br /&gt;
 {&lt;br /&gt;
     get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The WidgetClass string is formed using a combination of the vendor name and the Widget's name in the&lt;br /&gt;
format:&lt;br /&gt;
&lt;br /&gt;
 [vendor_domain]:[widget_name]&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry can now query both the DvDevice object representing the Widget, and the specific class of Widget this driver represents. The other member variables we defined do not need their own accessor methods.&lt;br /&gt;
&lt;br /&gt;
Now we must write a constructor for DiscoveredWidget and assign the parameters accordingly: &lt;br /&gt;
&lt;br /&gt;
 public DiscoveredWidget(IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                            string aUdn,&lt;br /&gt;
                            ISimpleUpnpWidget aProxy,&lt;br /&gt;
                            IWidgetPublisher aPublisher)&lt;br /&gt;
 {&lt;br /&gt;
      iDeviceFactory = aDeviceFactory;&lt;br /&gt;
      iProtocol = aProtocol;&lt;br /&gt;
      iPublisher = aPublisher;&lt;br /&gt;
      iDvDevice = iDeviceFactory.CreateDevice(aUdn);&lt;br /&gt;
      iProvider = new BinaryLightProvider(iDvDevice,&lt;br /&gt;
      iProtocol);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Event handling ===&lt;br /&gt;
&lt;br /&gt;
A Widget's state can change in one of three significant ways:&lt;br /&gt;
&lt;br /&gt;
* when the Widget needs to be published on the Node&lt;br /&gt;
* when the Widget disappears from the network (by losing power or similar)&lt;br /&gt;
* when a property's state changes and must be updated to a new value&lt;br /&gt;
&lt;br /&gt;
We now need methods to handle these changes.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The methods we define here will be used as callbacks, rather than invoked as method calls. We define the methods here first and then use them later on. We will use the Protocol Module to listen for changes in the Widget's state and register these methods as callbacks there. See Writing the SimpleUPnP Widget discovery method for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this section of the driver are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R4 Publishing discovered Widgets in the Local Widget Registry on the Node'''&lt;br /&gt;
&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object. &lt;br /&gt;
&lt;br /&gt;
'''R5 Reacting to an event reported from the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
'''R7 Reacting to a Widget's departure'''&lt;br /&gt;
&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no longer available.&lt;br /&gt;
&lt;br /&gt;
==== Enabling and publishing a discovered Widget ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first method initializes the Widget by enabling the device and then using the IWidgetPublisher&lt;br /&gt;
to make it available on the Node:&lt;br /&gt;
&lt;br /&gt;
 public void HandleInitialEvent()&lt;br /&gt;
 {&lt;br /&gt;
      iDvDevice.SetEnabled();&lt;br /&gt;
      iPublisher.TryPublishWidget(iDvDevice.iUdn(),&lt;br /&gt;
                              this,&lt;br /&gt;
                              out iPublishedWidget);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This method meets the requirements for R4.&lt;br /&gt;
&lt;br /&gt;
The call to TryPublishWidget returns an iPublishedWidget object. We use this object later to satisfy the requirements of R7.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The ordering of the calls to SetEnabled and TryPublishWidget is vitally important. You&lt;br /&gt;
must enable the device before you attempt to publish it. Your Widget will not be available to the&lt;br /&gt;
Nodes unless SetEnabled is called first. Nodes will not be able to access a published device&lt;br /&gt;
that has not been enabled.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
R3 requires that you set the Widget's properties before you enable and publish the device. We&lt;br /&gt;
discussed on page 14 how some properties can only be set after the Widget reports what their&lt;br /&gt;
state is. We do this in HandleRegisterEvent.&lt;br /&gt;
&lt;br /&gt;
We rely on the SimpleUPnP Protocol Module guaranteeing a call to HandleRegisterEvent first before HandleInitialEvent. This is informed by guarantees made by the Control Point stack that the calls will be made in that order.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
==== Removing a Widget ====&lt;br /&gt;
&lt;br /&gt;
Removing a Widget involves unpublishing it from the Node. The IPublishedWidget interface provides us with a method we can call to manage that for us:&lt;br /&gt;
&lt;br /&gt;
 public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
 {&lt;br /&gt;
     if (iPublishedWidget != null)&lt;br /&gt;
     { iPublishedWidget.Unpublish(); }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assuming that the Widget was successfully published earlier, it is removed from the Node's Local Widget Registry.&lt;br /&gt;
&lt;br /&gt;
We must also properly handle the resources we used to create and maintain the Widget object while it was published:&lt;br /&gt;
&lt;br /&gt;
      iProvider.Dispose();&lt;br /&gt;
      iDvDevice.Dispose();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The calls to Dispose are made regardless of the Widget's published state, ensuring that any created device and associated provider are properly disposed. This implementation satisfies R7.&lt;br /&gt;
&lt;br /&gt;
====Event handling ====&lt;br /&gt;
&lt;br /&gt;
We need a method to handle changes to the state of the Widget's properties.&lt;br /&gt;
&lt;br /&gt;
If the property changes at the Widget, it needs to pass the new state back to the Node so that it is kept up-to-date on the Widget's status. This is called an event. An example in the case of our Basic Light is someone manually switching the light from on to off. This is in contrast to actions, which are passed from the Node to the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Other examples of events involve no human interaction, such as a thermometer Widget updating its current temperature based on environmental changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Our Basic Light Widget has only one property that needs to be handled:&lt;br /&gt;
&lt;br /&gt;
 public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
 {&lt;br /&gt;
     if (aIndex == 0)&lt;br /&gt;
     {&lt;br /&gt;
         iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We use our instance of the provider to update the register on the Widget that is mapped to the On property. This in turn updates the Node with the new state of the Widget.&lt;br /&gt;
&lt;br /&gt;
This method provides implementations to satisfy two driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
* R3 is now completely satisfied, as we can now set the values of all the previously unknown properties here.&lt;br /&gt;
* R5 is also satisfied as this method allows us to update the Widget's status on the Node when a property is changed on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Not all protocols pass messages back to the Node in this manner. The way we have satisfied R3 and R5 here only applies to protocols and Widgets that support this behavior.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Widgets that do not use an eventing protocol need to have their properties set in the provider's constructor to satisfy R3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To satisfy R5, the over-ridden method SetOn in the provider must include the call to SetPropertyOn. Non-eventing protocols do not require a HandleRegisterEvent method.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Constructor ===&lt;br /&gt;
&lt;br /&gt;
The final requirement for the driver is the constructor so that new DiscoveredWidget objects can be created. &lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this area of code are:&lt;br /&gt;
&lt;br /&gt;
'''R1 Specifying the type of Widget the driver controls'''&lt;br /&gt;
&lt;br /&gt;
A driver must know which type of Widget that it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
==== Writing the code ====&lt;br /&gt;
&lt;br /&gt;
We begin by defining the variables we will use to store the objects used by the driver:&lt;br /&gt;
&lt;br /&gt;
 private readonly string iName;&lt;br /&gt;
 private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
 private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now write the constructor for the driver and assign the passed in parameters appropriately:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightDriver(string aName,&lt;br /&gt;
                IWidgetPublisher aPublisher,&lt;br /&gt;
                IDvDeviceFactory aDeviceFactory)&lt;br /&gt;
 {&lt;br /&gt;
     iWidgetPublisher = aPublisher;&lt;br /&gt;
     iName = aName;&lt;br /&gt;
     iDeviceFactory = aDeviceFactory;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally we need to provide the driver a way to publish the class of Widget it controls. This information is requested by the Discovery Module and is used to ensure the Node uses the correct driver when a new Widget appears.&lt;br /&gt;
&lt;br /&gt;
The implementation for this details will be different for each protocol. The SimpleUPnP protocol library provides a file that contains the SimpleUPnP definitions as integers. Each integer represents a particular class of identified Widget.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP implementation of that method is as follows:&lt;br /&gt;
&lt;br /&gt;
 public IEnumerable&amp;lt;uint&amp;gt; WidgetClasses&lt;br /&gt;
 {&lt;br /&gt;
 [[File:Warning.png]]        get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The body of this method is specifically written for the Widget class we are defining (in this case a binary light). This method completes the driver's requirements for R1.&lt;br /&gt;
&lt;br /&gt;
== Writing the SimpleUPnP Widget discovery method ==&lt;br /&gt;
&lt;br /&gt;
Every driver must contain a method which creates new objects to represent newly discovered Widgets.&lt;br /&gt;
The Discovery Module invokes this method to begin the process of creating the objects required to allow the Node to access the Widget. &lt;br /&gt;
&lt;br /&gt;
The name of this method is dictated by your chosen protocol's API. The SimpleUPnP protocol requires a method called WidgetDiscovered.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The method's name will not always be the same for each protocol. Your protocol's documentation will contain the details of what this method must be called.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This method and its implementation will meet the following driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
'''R2 Reacting to a discovered Widget on the network'''&lt;br /&gt;
&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
Our implementation of the WidgetDiscovered method will create a new DiscoveredWidget object and use the Protocol Module to listen for changes to the Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
The method uses the Protocol Module and two ways to identify the Widget. We must pass these in as&lt;br /&gt;
parameters:&lt;br /&gt;
&lt;br /&gt;
 public void WidgetDiscovered(string aWidgetUdn,&lt;br /&gt;
                              uint aWidgetClass,&lt;br /&gt;
                              ISimpleUpnpWidget&lt;br /&gt;
                                  aSimpleUpnpWidget)&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
Every Widget that uses this driver must be uniquely identifiable:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]    string newUdn = aWidgetUdn;&lt;br /&gt;
&lt;br /&gt;
Each new Widget is represented by a DiscoveredWidget object. Create the new DiscoveredWidget and pass in the required parameters we created earlier:&lt;br /&gt;
&lt;br /&gt;
     DiscoveredWidget discoveredWidget =&lt;br /&gt;
                 new DiscoveredWidget(iDeviceFactory,&lt;br /&gt;
                                      newUdn,&lt;br /&gt;
  &lt;br /&gt;
 [[File:Warning.png]]                                    aSimpleUpnpWidget,&lt;br /&gt;
&lt;br /&gt;
=== Registering the callbacks ===&lt;br /&gt;
&lt;br /&gt;
Finally, we ask the Widget's protocol interface to listen for calls to the handler methods we defined earlier in DiscoveredWidget. We do this by registering those methods as callbacks for the Protocol Module&lt;br /&gt;
to listen for:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                        discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                        discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                        discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You have now met 100% of the driver responsibility requirements and have a working driver to use with your SimpleUPnP Widget.&lt;br /&gt;
&lt;br /&gt;
= Appendix A. Sample XML =&lt;br /&gt;
&lt;br /&gt;
== Binary Light.xml ==&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
  &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
  &amp;lt;version&amp;gt;&lt;br /&gt;
   &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
   &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/version&amp;gt;&lt;br /&gt;
  &amp;lt;propertylist&amp;gt;&lt;br /&gt;
   &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
       illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
   &amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix B. Sample Provider = &lt;br /&gt;
&lt;br /&gt;
== DvWidgetOpenhomeOrgBasicLight1.cs ==&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Runtime.InteropServices;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Core;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Utils.Binary;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
 {&lt;br /&gt;
    public interface IDvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
        IDisposable&lt;br /&gt;
    {&lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous value&lt;br /&gt;
        /// &amp;lt;/returns&amp;gt;&lt;br /&gt;
        bool SetPropertyOn(bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;Property's value will be copied&lt;br /&gt;
        /// here&amp;lt;/param&amp;gt;&lt;br /&gt;
        bool PropertyOn();&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt; summary&amp;gt;&lt;br /&gt;
    /// Provider for the openhome.org:BinaryLight:1 UPnP service&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public abstract class DvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
               DvProvider,&lt;br /&gt;
               IDisposable,&lt;br /&gt;
               IDvProviderOpenhomeOrgBinaryLight1&lt;br /&gt;
    {&lt;br /&gt;
        private GCHandle iGch;&lt;br /&gt;
        private PropertyBool iPropertyOn;&lt;br /&gt;
        private PropertyUint iPropertyPrimarySeq;&lt;br /&gt;
        private PropertyUint iPropertySecondarySeq;&lt;br /&gt;
        private ActionDelegate iDelegateSetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetPrimaryProperty;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Constructor&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aDevice&amp;quot;&amp;gt;Device which owns this&lt;br /&gt;
        /// provider&amp;lt;/param&amp;gt;&lt;br /&gt;
        protected DvProviderOpenhomeOrgBinaryLight1(DvDevice aDevice)&lt;br /&gt;
            : base(aDevice, &amp;quot;openhome.org&amp;quot;, &amp;quot;GenericWidget&amp;quot;, 1)&lt;br /&gt;
        {&lt;br /&gt;
            iGch = GCHandle.Alloc(this);&lt;br /&gt;
            List&amp;lt;String&amp;gt; allowedValues = new List&amp;lt;String&amp;gt;();&lt;br /&gt;
            iPropertyOn = new PropertyBool(new ParameterBool(&amp;quot;On&amp;quot;));&lt;br /&gt;
            iPropertyPrimarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;PrimarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertyPrimarySeq);&lt;br /&gt;
            iPropertySecondarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;SecondarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertySecondarySeq);&lt;br /&gt;
            SetPropertyUint(iPropertyPrimarySeq, 0);&lt;br /&gt;
            SetPropertyUint(iPropertySecondarySeq, 0);&lt;br /&gt;
  &lt;br /&gt;
            Zapp.Core.Action action = new Zapp.Core.Action&lt;br /&gt;
                (&amp;quot;SetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;FireAndForget&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddInputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateSetProperty = new ActionDelegate(DoSetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateSetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateGetProperty = new ActionDelegate(DoGetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetPrimaryProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                 (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;integer&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;boolean&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;string&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;binary&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Type&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;readWrite&amp;quot;);allowedValues.Add&lt;br /&gt;
                (&amp;quot;readOnly&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;writeOnly&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString(&amp;quot;Access&amp;quot;,&lt;br /&gt;
                allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            iDelegateGetPrimaryProperty = new&lt;br /&gt;
            ActionDelegate(DoGetPrimaryProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetPrimaryProperty,&lt;br /&gt;
            GCHandle.ToIntPtr(iGch));&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous&lt;br /&gt;
        /// value&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool SetPropertyOn(bool aValue)&lt;br /&gt;
        {&lt;br /&gt;
            if (iPropertyOn.SetValue(aValue))&lt;br /&gt;
            {&lt;br /&gt;
                lock (iPropertyPrimarySeq)&lt;br /&gt;
                {&lt;br /&gt;
                    SetPropertyUint(iPropertyPrimarySeq,&lt;br /&gt;
                        iPropertyPrimarySeq.Value() + 1);&lt;br /&gt;
                } return true;&lt;br /&gt;
            } return false;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;The value of the property&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool PropertyOn()&lt;br /&gt;
        {&lt;br /&gt;
            return iPropertyOn.Value();&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the On property.&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aVersion&amp;quot;&amp;gt;Version of the service being&lt;br /&gt;
        /// requested (will be &amp;lt;= the version advertised)&amp;lt;/param&amp;gt; &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the On property.&lt;br /&gt;
        /// &amp;lt;/param&amp;gt;&lt;br /&gt;
        protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        private static int DoSetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                byte[] valBin = invocation.ReadBinary(&amp;quot;Value&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                switch (name)&lt;br /&gt;
                {&lt;br /&gt;
                    case &amp;quot;On&amp;quot;:&lt;br /&gt;
                        self.SetOn(aVersion, Converter.&lt;br /&gt;
                            BinaryToBoolean(valBin));&lt;br /&gt;
                        break;&lt;br /&gt;
                    default:&lt;br /&gt;
                        throw new ActionError();&lt;br /&gt;
                }&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
                invocation.WriteEnd();&lt;br /&gt;
            }&lt;br /&gt;
            catch (ActionError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
            catch (PropertyUpdateError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
        return 0;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        private static int DoGetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
            switch (name)&lt;br /&gt;
            {&lt;br /&gt;
                case &amp;quot;On&amp;quot;:&lt;br /&gt;
                invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                    Converter.BooleanToBinary(self.iPropertyOn.&lt;br /&gt;
                        Value()));&lt;br /&gt;
                break;&lt;br /&gt;
                default:&lt;br /&gt;
                throw new ActionError();&lt;br /&gt;
            }&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    private static int DoGetPrimaryProperty(IntPtr aPtr,&lt;br /&gt;
                    IntPtr aInvocation,&lt;br /&gt;
                    uint aVersion)&lt;br /&gt;
    {&lt;br /&gt;
        GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
        DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
            (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
        DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
  &lt;br /&gt;
        try&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReadStart();&lt;br /&gt;
            invocation.ReadEnd();&lt;br /&gt;
            invocation.WriteStart();&lt;br /&gt;
            invocation.WriteString(&amp;quot;Name&amp;quot;, &amp;quot;On&amp;quot;);&lt;br /&gt;
            invocation.WriteString(&amp;quot;Type&amp;quot;, &amp;quot;boolean&amp;quot;);&lt;br /&gt;
            invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                Converter.BooleanToBinary(self.iPropertyOn.Value()));&lt;br /&gt;
            invocation.WriteString(&amp;quot;Access&amp;quot;, &amp;quot;readWrite&amp;quot;);&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt;summary&amp;gt;&lt;br /&gt;
    /// Must be called for each class instance. Must be called before&lt;br /&gt;
    /// Core.Library.Close().&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public void Dispose()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
        GC.SuppressFinalize(this);&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
    ~DvProviderOpenhomeOrgBinaryLight1()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
        private void DoDispose()&lt;br /&gt;
        {&lt;br /&gt;
            lock (this)&lt;br /&gt;
            {&lt;br /&gt;
                if (iHandle == IntPtr.Zero)&lt;br /&gt;
            {&lt;br /&gt;
                    return;&lt;br /&gt;
            }&lt;br /&gt;
            DisposeProvider();&lt;br /&gt;
            iPropertyOn.Dispose();&lt;br /&gt;
            iHandle = IntPtr.Zero;&lt;br /&gt;
            }&lt;br /&gt;
            iGch.Free();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix C. Sample Driver = &lt;br /&gt;
&lt;br /&gt;
== BasicLightDriver.cs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.hWidget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
     class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
     {&lt;br /&gt;
         private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
         public BinaryLightProvider(DvDevice aDevice, &lt;br /&gt;
             ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol = aProtocol;&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
     {&lt;br /&gt;
         private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
         {&lt;br /&gt;
             private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
             private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
             private readonly ISimpleUpnpWidget iProtocol; &lt;br /&gt;
 &lt;br /&gt;
             private readonly BinaryLightProvider iProvider;&lt;br /&gt;
             private readonly DvDevice iDvDevice;&lt;br /&gt;
             private IPublishedWidget iPublishedWidget; &lt;br /&gt;
 &lt;br /&gt;
             public DvDevice DvDevice&lt;br /&gt;
             {&lt;br /&gt;
                 get { return iDvDevice; }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             public string WidgetClass&lt;br /&gt;
             {&lt;br /&gt;
                 get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public DiscoveredWidget(&lt;br /&gt;
                 IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                 string aUdn,&lt;br /&gt;
                 ISimpleUpnpWidget aProxy,&lt;br /&gt;
                 IWidgetPublisher aPublisher)&lt;br /&gt;
             {&lt;br /&gt;
                 iDeviceFactory = aDeviceFactory;&lt;br /&gt;
                 iProtocol = aProtocol;&lt;br /&gt;
 &lt;br /&gt;
                 iPublisher = aPublisher;&lt;br /&gt;
                 iDvDevice = iDeviceFactory.CreateDevice(aUdn);  &lt;br /&gt;
                 iProvider = new BinaryLightProvider(iDvDevice, &lt;br /&gt;
                                                     iProtocol);&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             public void HandleInitialEvent()&lt;br /&gt;
             {&lt;br /&gt;
                 iDvDevice.SetEnabled();&lt;br /&gt;
                 iPublisher.TryPublishWidget(iDvDevice.iUdn(), this,&lt;br /&gt;
                     out iPublishedWidget);&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
             {&lt;br /&gt;
                 if (iPublishedWidget != null)&lt;br /&gt;
                 {&lt;br /&gt;
                     iPublishedWidget.Unpublish();&lt;br /&gt;
                 } &lt;br /&gt;
                 iProvider.Dispose();&lt;br /&gt;
                 iDvDevice.Dispose();&lt;br /&gt;
             }  &lt;br /&gt;
 &lt;br /&gt;
             public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
             {&lt;br /&gt;
                 if (aIndex == 0)&lt;br /&gt;
                 {&lt;br /&gt;
                     iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         private readonly string iName;&lt;br /&gt;
         private readonly IDvDeviceFactory aDeviceFactory;&lt;br /&gt;
         private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
         &lt;br /&gt;
         public BinaryLightDriver(&lt;br /&gt;
             string aName,&lt;br /&gt;
             IWidgetPublisher aPublisher,&lt;br /&gt;
             iDeviceFactory aDeviceFactory)&lt;br /&gt;
         {&lt;br /&gt;
             iWidgetPublisher = aPublisher;&lt;br /&gt;
             iName = aName;&lt;br /&gt;
             iDeviceFactory = aDeviceFactory;&lt;br /&gt;
         } &lt;br /&gt;
 &lt;br /&gt;
         public IEnumerable&amp;amp;lt;uint&amp;amp;gt; WidgetClasses&lt;br /&gt;
         {&lt;br /&gt;
             get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         public void WidgetDiscovered(&lt;br /&gt;
             string aWidgetUdn,&lt;br /&gt;
             uint aWidgetClass,&lt;br /&gt;
             ISimpleUpnpWidget aSimpleUpnpWidget)&lt;br /&gt;
         {&lt;br /&gt;
             string newUdn = aWidgetUdn;&lt;br /&gt;
             DiscoveredWidget discoveredWidget = new DiscoveredWidget&lt;br /&gt;
                 (iDeviceFactory,&lt;br /&gt;
                  newUdn,&lt;br /&gt;
                  aSimpleUpnpWidget,&lt;br /&gt;
                  iWidgetPublisher);&lt;br /&gt;
 &lt;br /&gt;
             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                 discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                 discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                 discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary = &lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in OpenHome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by OpenHome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh - A collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs on ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The OpenHome Operating System. Core software for OpenHome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. &lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. A typical Widget supports only one protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Driver_Development</id>
		<title>OhWidget Driver Development</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Driver_Development"/>
				<updated>2012-03-01T15:19:59Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Writing the SimpleUPnP Widget discovery method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for developers using the OpenHome SDK to integrate a Widget into an OpenHome system. Each Widget must have its own driver to allow it to communicate with the OpenHome Nodes. &lt;br /&gt;
&lt;br /&gt;
To help you write your driver, this document provides high level descriptions of the core responsibilities of a Widget driver and gives a detailed walk-through using example code.&lt;br /&gt;
&lt;br /&gt;
Full versions of each file used in the development of the example driver are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin development of your Widget driver you must be in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* your Widget Service XML that describes the properties on your Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document does not contain advice on how to write Widget Service XML. Refer to the OpenHome Widget Service XML definition document for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK&lt;br /&gt;
* your chosen communication protocol's API&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The protocol you choose for your Widgets must be the same protocol used on your choice of Node.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document focuses on the development of the Widget driver. Details about the communications protocol used are beyond the scope of this document. This document assumes you are familiar with your chosen protocol's code libraries and are able to use them in the driver code you write.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Related Documents ==&lt;br /&gt;
&lt;br /&gt;
The following related OpenHome documentation may be of interest to you:&lt;br /&gt;
&lt;br /&gt;
* [[ohWidget Technical Overview|ohWidget Technical Overview]]&lt;br /&gt;
* [[OpenHome Widget Service XML definition|OpenHome Widget Service XML definition]]&lt;br /&gt;
* [http://www.openhome.org/releases/ohNet_DeviceStack.pdf  OpenHome ohNet Device Stack]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
None of the related documents listed above is mandatory reading for Widget driver development.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
== Widget Service XML ==&lt;br /&gt;
OpenHome Widget driver writing relies heavily on the use of code generated from a single source — the Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
The service and actions your Widget provides are represented in code in a file called a Provider. The Provider is automatically generated from the Widget Service XML and produces an abstract class for you to inherit when you write your concrete class driver.&lt;br /&gt;
&lt;br /&gt;
To aid in the explanation of how the Provider is created and put to use we will follow the development of&lt;br /&gt;
a driver for a simple light Widget; taking the defined Widget Service XML and stepping through how it is used to generate the other files. Examples of code are used throughout this document to show you how each one is created and used in an OpenHome system. &lt;br /&gt;
&lt;br /&gt;
It is essential that you start with a well-formed Widget Service XML, conforming to the schema defined&lt;br /&gt;
in the WidgetService.xsd. The following diagram shows the significance of the Widget Service XML in&lt;br /&gt;
relation to the generated files you will use when writing your driver:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarchy, highlighting the areas specifically used in driver development]]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* The grayed-out files are not relevant to Widget driver development but can also be generated from the Widget Service XML.&lt;br /&gt;
* The Provider is generated in C#, meaning your driver must be written in C# as well. The use of managed code is mandatory for driver writing in the OpenHome framework.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Code sample used in this document ==&lt;br /&gt;
&lt;br /&gt;
Our examples in this document use a Widget Service XML definition for a light Widget called&lt;br /&gt;
BasicLight.xml.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Full versions of all the example files used in this document are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We will see how the Provider is generated from this XML and how it is used to aid the driver writing process. The examples also show how your chosen communication protocol should be used in the body of the driver code.&lt;br /&gt;
&lt;br /&gt;
Implementation details of specific protocols you choose to use are beyond the scope of this document. However, the samples used in this document show the use of the SimpleUPnP protocol to aid you in your development process.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol during the early stages of the OpenHome project. It is included in the OpenHome SDK and can be used as a public resource. &lt;br /&gt;
&lt;br /&gt;
The use of SimpleUPnP in the example files and the code snippets within the following sections is highlighted by the [[File:Warning.png]] icon. The lines of code marked by [[File:Warning.png]] must be changed to code from your chosen communication protocol's library. SimpleUPnP is left in to help you understand how a protocol is used in a working example.&lt;br /&gt;
&lt;br /&gt;
The sample code provided attempts to show best-practice coding standards. There are several sections of code that have a mandatory layout or that call specifically named methods and functions. These areas of the code are highlighted where required. &lt;br /&gt;
&lt;br /&gt;
Where the examples do not explicitly state that the code shown is mandatory, you are free to implement it in a different way according to your own coding style and practices.&lt;br /&gt;
&lt;br /&gt;
= Driver responsibilities = &lt;br /&gt;
&lt;br /&gt;
== Driver responsibilities ==&lt;br /&gt;
&lt;br /&gt;
An OpenHome Widget driver has several responsibilities which must be met before it can be used on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
These responsibilities are listed R1 to R7 and are defined here, explaining what each one must do. &lt;br /&gt;
&lt;br /&gt;
=== R1 Specifying the type of Widget the driver controls ===&lt;br /&gt;
A driver must know which type of Widget it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
=== R2 Reacting to a discovered Widget on the network ===&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== R3 Setting the initial values for the Widget's properties ===&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
=== R4 Publishing discovered Widgets in the Local Widget Registry on the Node ===&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object.&lt;br /&gt;
&lt;br /&gt;
=== R5 Reacting to an event reported from the Widget ===&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
=== R6 Reacting to actions sent to the Widget ===&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== R7 Reacting to a Widget's departure ===&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no&lt;br /&gt;
longer available.&lt;br /&gt;
&lt;br /&gt;
The sections of example code that follow show you how to write a driver from beginning to end. The accompanying text explaining the example code highlights when a responsibility, or part of a responsibility, has been met.&lt;br /&gt;
&lt;br /&gt;
= Driver Architecture = &lt;br /&gt;
&lt;br /&gt;
== Driver Architecture ==&lt;br /&gt;
&lt;br /&gt;
Drivers are installed on the Node and used when the Node needs to communicate with the Widget. Drivers&lt;br /&gt;
use several objects to communicate with Widgets over the Widget's lifetime. Figure 2 shows the objects&lt;br /&gt;
used by the driver and how the responsibilities listed above relate to each one:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture.png|800px|thumb|center|Figure 2: The architecture of a driver, showing the driver's relationship to the objects used to communicate with a Widget. Lines between objects show message flow.]]&lt;br /&gt;
&lt;br /&gt;
The objects contained in the dotted boundary must appear in the code you write to define your driver. The Driver, Provider and IWidgetRegistryEntry objects are all contained in the same driver file. We begin discussing this on page 12. &lt;br /&gt;
&lt;br /&gt;
The other objects are provided by the OpenHome SDK or as installed components on the Node.&lt;br /&gt;
&lt;br /&gt;
The Discovery Module informs the driver of the presence of an available Widget.&lt;br /&gt;
&lt;br /&gt;
Each Node has a Protocol Module which contains the protocol's API. Widgets can communicate with OpenHome Nodes using any one of the set of communications protocols the Node supports. The driver uses your chosen protocol's Protocol Module to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
Both the Protocol Module and the Discovery Module are installed on the Node. When you write your&lt;br /&gt;
driver you will use your Protocol Module to allow the driver to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
IWidgetPublisher, IPublishedWidget and DvDevice are objects provided in the OpenHome&lt;br /&gt;
API. You can read about them in the APIs.&lt;br /&gt;
&lt;br /&gt;
= Generating the Provider = &lt;br /&gt;
&lt;br /&gt;
== Generating the Provider ==&lt;br /&gt;
&lt;br /&gt;
You must generate your provider before you can begin writing your Widget driver. You use your provider as a guide to implement the functions your Widget needs to set the values of its properties.&lt;br /&gt;
&lt;br /&gt;
The current provider generation process is a manual one involving the use of a text transform tool.&lt;br /&gt;
&lt;br /&gt;
Speak to your OpenHome contact who will help you generate your provider.&lt;br /&gt;
&lt;br /&gt;
Future releases of the OpenHome SDK will include a tool to help you generate the provider.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
You must be in possession of:&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK, unpacked on your computer&lt;br /&gt;
* your Widget Service XML file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Writing a SimpleUPnP driver = &lt;br /&gt;
&lt;br /&gt;
== Introduction to the SimpleUPnP protocol ==&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol used to control emulated Widgets over a custom UPnP service.&lt;br /&gt;
&lt;br /&gt;
This chapter shows how a driver is written using the SimpleUPnP communications protocol. The aim is to show the code using as generic a protocol as possible so that you can see where your own protocol specific code needs to go.&lt;br /&gt;
&lt;br /&gt;
The use of code specific to the SimpleUPnP implementation is highlighted by the use of the [[File:Warning.png]] icon. The lines of code are marked by this icon to make it easier for you to see where the protocol-specific code must go and what parts of the code are generic.&lt;br /&gt;
&lt;br /&gt;
=== Register model ===&lt;br /&gt;
&lt;br /&gt;
SimpleUPnP is modeled on 8 physical registers available on the Widget. Each register is 32-bits wide. They are indexed from 0 to 7 and the last register (register 7) is reserved for storing the Widget's class.&lt;br /&gt;
&lt;br /&gt;
This detail is used by the Protocol Module on the Node to determine which driver is needed to run the new Widget when it has been discovered.&lt;br /&gt;
&lt;br /&gt;
The remaining 7 registers (registers 0 to 6) are free for Widget engineers to assign to the Widget's functions.&lt;br /&gt;
&lt;br /&gt;
Registers 0, 1, 2 and 3 are available as read/write registers. Registers 4, 5 and 6 are readonly registers.&lt;br /&gt;
&lt;br /&gt;
Only the emulated hardware (running on the Node) can change the values held in registers 4, 5 and 6.&lt;br /&gt;
&lt;br /&gt;
=== Register use in drivers ===&lt;br /&gt;
&lt;br /&gt;
In the example that follows we have a Basic Light Widget with a very simple function: it can be turned on and turned off. The on/off value is stored in register 0, with values 0=OFF and 1=ON. Register 0 is a read/write register. This means we can change the value stored there using messages passed to the Widget from the Node, and by reacting to physical interactions at the Widget (such as someone manually switching the light on or off). &lt;br /&gt;
&lt;br /&gt;
The mapping of registers to properties on the Widget is decided by the engineers who manufacture the device. You must be provided with the mapping before you begin developing your driver.&lt;br /&gt;
&lt;br /&gt;
== Starting the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-BoxHighlight.png|800px|thumb|center|Figure 3 The driver architecture highlighting the Widget driver and its component parts.]]&lt;br /&gt;
&lt;br /&gt;
When you have generated the abstract provider you can put it to use in the Widget driver. A Widget driver&lt;br /&gt;
has three distinct components:&lt;br /&gt;
&lt;br /&gt;
* an implementation of your abstract provider&lt;br /&gt;
* a definition of the Widget driver&lt;br /&gt;
* an implementation of the IWidgetRegistryEntry interface&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must manually write the code for your Widget driver. The differences in implementation of Widget properties and communication protocols means that the driver code cannot be autogenerated.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This section takes you through how to write a Widget driver by implementing the auto-generated provider,&lt;br /&gt;
starting from a new blank file and finishing with a working driver for the Basic Light Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
No assumptions have been made about the type of editor you use to write your code. Shortcuts&lt;br /&gt;
or macros that you use as standard will not appear in the instructions below. A full example&lt;br /&gt;
BinaryLightDriver.cs is available to review in Appendix C.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a new C# file in your IDE. Ensure the following libraries are used:&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 [[File:Warning.png]]using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 namespace OpenHome.Widget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must use the libraries listed above for this specific example.&lt;br /&gt;
&lt;br /&gt;
In general, drivers require the following libraries:&lt;br /&gt;
* System*&lt;br /&gt;
* System.Collections.Generic*&lt;br /&gt;
* OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
&lt;br /&gt;
Your driver will fail to compile if you miss any of these listed libraries. Libraries marked * are typically added by default by most modern IDEs. &lt;br /&gt;
&lt;br /&gt;
The OpenHome.Widget.Protocols.SimpleUpnp library is required only in this SimpleUPnP example. Drivers using a different protocol will use their own protocol library.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Implementing the provider ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-ProviderHighlight.png|800px|thumb|center|Figure 4 The driver architecture highlighting the Provider's place]]&lt;br /&gt;
&lt;br /&gt;
You use your auto-generated abstract provider by writing an implementation of it in the driver file. Responsibilities met by implementing your auto-generated provider are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R6 Reacting to actions sent to the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
Begin by creating a new class. It will subclass the abstract auto-generated provider:&lt;br /&gt;
&lt;br /&gt;
 class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
The Protocol Module will provide an API for the Provider to use to communicate with the Widget. In&lt;br /&gt;
SimpleUPnP we are provided with an interface called ISimpleUpnpWidget. The provider is supplied&lt;br /&gt;
with the required instance of the interface by the Discovery Module on the Node.&lt;br /&gt;
&lt;br /&gt;
The mechanisms for registering providers with specific Protocol Modules, and for the way the module gives each provider its required interface are covered later when writing the discovery method.&lt;br /&gt;
&lt;br /&gt;
For now, we need to give the Provider a place to store the interface that it will later use to communicate&lt;br /&gt;
with the Widget:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]] private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
&lt;br /&gt;
The interface from the Protocol Module is passed in as a parameter in the Provider's constructor and then&lt;br /&gt;
assigned to the variable we just created:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightProvider(DvDevice aDevice,&lt;br /&gt;
 [[File:Warning.png]]         ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
 {&lt;br /&gt;
       iProtocol = aProtocol;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
To satisfy R3 we would normally set the Widget's properties here, giving them an initial value.&lt;br /&gt;
However, in this specific example we cannot set the value of Basic Light's only property because&lt;br /&gt;
we will never know, in advance, what the state of the light will be (either on or off) when we&lt;br /&gt;
create the DiscoveredWidget.&lt;br /&gt;
&lt;br /&gt;
When you cannot set the properties ahead of time, and you are using an eventing protocol like SimpleUPnP, you can instead set them in the HandleRegisterEvent method in the driver class. This also satisfies the requirements for R3. You must set the Widget's properties before you enable it using SetEnabled(). &lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The abstract provider includes an abstract method called SetOn. This method is invoked by the Node when passing a message to the Widget, specifically to set the on property of the Widget to either 0 or 1. The implementation of this method will meet the requirements for R6.&lt;br /&gt;
&lt;br /&gt;
We must override this method and provide the protocol module a way of passing a message on to the Widget to perform the required action, in this case turn the light on or off:&lt;br /&gt;
&lt;br /&gt;
          protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
          {&lt;br /&gt;
     [[File:Warning.png]]        iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
In this example the Basic Light's SetOn property (the boolean property that controls whether the light is&lt;br /&gt;
on or off) is represented in the physical Widget by the register that has an index of 0.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* This method is an example of an action on a Widget. Actions are messages sent from the Node to the Widget. We will see later how to handle events that need to be passed back from the Widget&lt;br /&gt;
to the Node.&lt;br /&gt;
* Your own Widget will likely provide more than a single property. Your auto-generated provider will contain one abstract method to represent each writable property. Read-only properties are not provided an abstract method.&lt;br /&gt;
&lt;br /&gt;
You must implement each abstract method in your driver to ensure the relevant property on&lt;br /&gt;
the Widget can be set.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We have now finished implementing the provider. The next step is to implement the driver.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Implementing the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-DriverHighlight.png|800px|thumb|center|Figure 4: The driver architecture highlighting the implemented driver's place.]]&lt;br /&gt;
&lt;br /&gt;
The code for your Widget driver must provide an implementation of the IWidgetRegistryInterface,&lt;br /&gt;
including the following tasks:&lt;br /&gt;
&lt;br /&gt;
* methods to expose identifying details about the Widget for the Node to access&lt;br /&gt;
* providing methods to handle events reported by the Widget&lt;br /&gt;
&lt;br /&gt;
The driver is implemented as a public class within the same file as the provider code. Each driver must use the interface for the protocol you are using. For the SimpleUPnP protocol the interface is ISimple-UpnpWidgetDriver.&lt;br /&gt;
&lt;br /&gt;
=== Writing code ===&lt;br /&gt;
&lt;br /&gt;
Create your new driver class and subclass the ISimpleUpnpWidgetDriver interface:&lt;br /&gt;
&lt;br /&gt;
 public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Implementing IWidgetRegistryEntry ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry is the interface you use to represent physical Widgets. It is implemented as a subclass of your driver class. We are going to implement this interface in a class called '''DiscoveredWidget'''.&lt;br /&gt;
&lt;br /&gt;
Let's return to our driver architecture diagram for a moment:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-IRegistryEntryHighlight.png|800px|thumb|center|Figure 5 The driver architecture highlighting the IWidgetRegistryEntry object you will now implement]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry uses several other objects to help create it and respond to messages sent to and from it. These objects will be created in our implementation of DiscoveredWidget. &lt;br /&gt;
&lt;br /&gt;
When successfully created and published, the DiscoveredWidget objects are stored in a list on the Node called the Local Widget Registry. The Local Widget Registry is used by Nodes to maintain contact with the Widgets they control.&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry is shown at the top of Figure 5, marked plainly as (Registry). The path to the Local Widget Registry goes through several layers of Node architecture which are not relevant to Widget driver writing, so are not shown in the diagrams.&lt;br /&gt;
&lt;br /&gt;
==== Writing code ====&lt;br /&gt;
&lt;br /&gt;
Start by subclassing the IWidgetRegistryEntry interface in your new class:&lt;br /&gt;
&lt;br /&gt;
      private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
      {&lt;br /&gt;
&lt;br /&gt;
A DiscoveredWidget must provide the driver with the objects required to present the Widget and its&lt;br /&gt;
properties to the Node:&lt;br /&gt;
&lt;br /&gt;
           private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
           private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
           private readonly ISimpleUpnpWidget iProtocol;&lt;br /&gt;
           private readonly BinaryLightProvider iProvider;&lt;br /&gt;
           private readonly DvDevice iDvDevice;&lt;br /&gt;
           private IPublishedWidget iPublishedWidget;&lt;br /&gt;
&lt;br /&gt;
Each of the attributes in the example above are defined as follows:&lt;br /&gt;
&lt;br /&gt;
iDeviceFactory — used by the driver to create a single instance of DvDevice to represent a single Widget&lt;br /&gt;
&lt;br /&gt;
iPublisher — used by the driver to publish the Widget to the Node&lt;br /&gt;
&lt;br /&gt;
iProtocol — the object used by the Widget to communicate with the Protocol Module on the Node&lt;br /&gt;
&lt;br /&gt;
iProvider — an instantiated provider of the type you defined earlier&lt;br /&gt;
&lt;br /&gt;
iDvDevice — a representation of a Widget to which the provider is attached, created using iDevice-Factory above&lt;br /&gt;
&lt;br /&gt;
iPublishedWidget — used to contain the returned object from a successful publishing of the Widget&lt;br /&gt;
If we look again at the driver architecture diagram, we ca highlight the objects we've just defined:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-Highlight.png|800px|thumb|center|Figure 6: The driver architecture highlighting the objects used by the IWidgetRegistryEntry implementation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The DeviceFactory, defined above in the member variable iDeviceFactory, is used to create new DvDevice objects. The DeviceFactory is only ever used to do this once. It is not shown in the driver architecture diagrams due to its minimal role in the operation of a driver, but it would normally appear between the IWidgetRegistryEntry and DvDevice objects.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
A driver requires methods to expose identifying details about the Widget. We must provide access to two of the attributes we just defined above:&lt;br /&gt;
&lt;br /&gt;
 public DvDevice DvDevice&lt;br /&gt;
 {&lt;br /&gt;
     get { return iDvDevice; }&lt;br /&gt;
 }&lt;br /&gt;
 public string WidgetClass&lt;br /&gt;
 {&lt;br /&gt;
     get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The WidgetClass string is formed using a combination of the vendor name and the Widget's name in the&lt;br /&gt;
format:&lt;br /&gt;
&lt;br /&gt;
 [vendor_domain]:[widget_name]&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry can now query both the DvDevice object representing the Widget, and the specific class of Widget this driver represents. The other member variables we defined do not need their own accessor methods.&lt;br /&gt;
&lt;br /&gt;
Now we must write a constructor for DiscoveredWidget and assign the parameters accordingly: &lt;br /&gt;
&lt;br /&gt;
 public DiscoveredWidget(IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                            string aUdn,&lt;br /&gt;
                            ISimpleUpnpWidget aProxy,&lt;br /&gt;
                            IWidgetPublisher aPublisher)&lt;br /&gt;
 {&lt;br /&gt;
      iDeviceFactory = aDeviceFactory;&lt;br /&gt;
      iProtocol = aProtocol;&lt;br /&gt;
      iPublisher = aPublisher;&lt;br /&gt;
      iDvDevice = iDeviceFactory.CreateDevice(aUdn);&lt;br /&gt;
      iProvider = new BinaryLightProvider(iDvDevice,&lt;br /&gt;
      iProtocol);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Event handling ===&lt;br /&gt;
&lt;br /&gt;
A Widget's state can change in one of three significant ways:&lt;br /&gt;
&lt;br /&gt;
* when the Widget needs to be published on the Node&lt;br /&gt;
* when the Widget disappears from the network (by losing power or similar)&lt;br /&gt;
* when a property's state changes and must be updated to a new value&lt;br /&gt;
&lt;br /&gt;
We now need methods to handle these changes.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The methods we define here will be used as callbacks, rather than invoked as method calls. We define the methods here first and then use them later on. We will use the Protocol Module to listen for changes in the Widget's state and register these methods as callbacks there. See Writing the SimpleUPnP Widget discovery method for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this section of the driver are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R4 Publishing discovered Widgets in the Local Widget Registry on the Node'''&lt;br /&gt;
&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object. &lt;br /&gt;
&lt;br /&gt;
'''R5 Reacting to an event reported from the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
'''R7 Reacting to a Widget's departure'''&lt;br /&gt;
&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no longer available.&lt;br /&gt;
&lt;br /&gt;
==== Enabling and publishing a discovered Widget ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first method initializes the Widget by enabling the device and then using the IWidgetPublisher&lt;br /&gt;
to make it available on the Node:&lt;br /&gt;
&lt;br /&gt;
 public void HandleInitialEvent()&lt;br /&gt;
 {&lt;br /&gt;
      iDvDevice.SetEnabled();&lt;br /&gt;
      iPublisher.TryPublishWidget(iDvDevice.iUdn(),&lt;br /&gt;
                              this,&lt;br /&gt;
                              out iPublishedWidget);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This method meets the requirements for R4.&lt;br /&gt;
&lt;br /&gt;
The call to TryPublishWidget returns an iPublishedWidget object. We use this object later to satisfy the requirements of R7.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The ordering of the calls to SetEnabled and TryPublishWidget is vitally important. You&lt;br /&gt;
must enable the device before you attempt to publish it. Your Widget will not be available to the&lt;br /&gt;
Nodes unless SetEnabled is called first. Nodes will not be able to access a published device&lt;br /&gt;
that has not been enabled.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
R3 requires that you set the Widget's properties before you enable and publish the device. We&lt;br /&gt;
discussed on page 14 how some properties can only be set after the Widget reports what their&lt;br /&gt;
state is. We do this in HandleRegisterEvent.&lt;br /&gt;
&lt;br /&gt;
We rely on the SimpleUPnP Protocol Module guaranteeing a call to HandleRegisterEvent first before HandleInitialEvent. This is informed by guarantees made by the Control Point stack that the calls will be made in that order.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
==== Removing a Widget ====&lt;br /&gt;
&lt;br /&gt;
Removing a Widget involves unpublishing it from the Node. The IPublishedWidget interface provides us with a method we can call to manage that for us:&lt;br /&gt;
&lt;br /&gt;
 public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
 {&lt;br /&gt;
     if (iPublishedWidget != null)&lt;br /&gt;
     { iPublishedWidget.Unpublish(); }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assuming that the Widget was successfully published earlier, it is removed from the Node's Local Widget Registry.&lt;br /&gt;
&lt;br /&gt;
We must also properly handle the resources we used to create and maintain the Widget object while it was published:&lt;br /&gt;
&lt;br /&gt;
      iProvider.Dispose();&lt;br /&gt;
      iDvDevice.Dispose();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The calls to Dispose are made regardless of the Widget's published state, ensuring that any created device and associated provider are properly disposed. This implementation satisfies R7.&lt;br /&gt;
&lt;br /&gt;
====Event handling ====&lt;br /&gt;
&lt;br /&gt;
We need a method to handle changes to the state of the Widget's properties.&lt;br /&gt;
&lt;br /&gt;
If the property changes at the Widget, it needs to pass the new state back to the Node so that it is kept up-to-date on the Widget's status. This is called an event. An example in the case of our Basic Light is someone manually switching the light from on to off. This is in contrast to actions, which are passed from the Node to the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Other examples of events involve no human interaction, such as a thermometer Widget updating its current temperature based on environmental changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Our Basic Light Widget has only one property that needs to be handled:&lt;br /&gt;
&lt;br /&gt;
 public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
 {&lt;br /&gt;
     if (aIndex == 0)&lt;br /&gt;
     {&lt;br /&gt;
         iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We use our instance of the provider to update the register on the Widget that is mapped to the On property. This in turn updates the Node with the new state of the Widget.&lt;br /&gt;
&lt;br /&gt;
This method provides implementations to satisfy two driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
* R3 is now completely satisfied, as we can now set the values of all the previously unknown properties here.&lt;br /&gt;
* R5 is also satisfied as this method allows us to update the Widget's status on the Node when a property is changed on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Not all protocols pass messages back to the Node in this manner. The way we have satisfied R3 and R5 here only applies to protocols and Widgets that support this behavior.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Widgets that do not use an eventing protocol need to have their properties set in the provider's constructor to satisfy R3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To satisfy R5, the over-ridden method SetOn in the provider must include the call to SetPropertyOn. Non-eventing protocols do not require a HandleRegisterEvent method.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Constructor ===&lt;br /&gt;
&lt;br /&gt;
The final requirement for the driver is the constructor so that new DiscoveredWidget objects can be created. &lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this area of code are:&lt;br /&gt;
&lt;br /&gt;
'''R1 Specifying the type of Widget the driver controls'''&lt;br /&gt;
&lt;br /&gt;
A driver must know which type of Widget that it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
==== Writing the code ====&lt;br /&gt;
&lt;br /&gt;
We begin by defining the variables we will use to store the objects used by the driver:&lt;br /&gt;
&lt;br /&gt;
 private readonly string iName;&lt;br /&gt;
 private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
 private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now write the constructor for the driver and assign the passed in parameters appropriately:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightDriver(string aName,&lt;br /&gt;
                IWidgetPublisher aPublisher,&lt;br /&gt;
                IDvDeviceFactory aDeviceFactory)&lt;br /&gt;
 {&lt;br /&gt;
     iWidgetPublisher = aPublisher;&lt;br /&gt;
     iName = aName;&lt;br /&gt;
     iDeviceFactory = aDeviceFactory;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally we need to provide the driver a way to publish the class of Widget it controls. This information is requested by the Discovery Module and is used to ensure the Node uses the correct driver when a new Widget appears.&lt;br /&gt;
&lt;br /&gt;
The implementation for this details will be different for each protocol. The SimpleUPnP protocol library provides a file that contains the SimpleUPnP definitions as integers. Each integer represents a particular class of identified Widget.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP implementation of that method is as follows:&lt;br /&gt;
&lt;br /&gt;
 public IEnumerable&amp;lt;uint&amp;gt; WidgetClasses&lt;br /&gt;
 {&lt;br /&gt;
 [[File:Warning.png]]        get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The body of this method is specifically written for the Widget class we are defining (in this case a binary light). This method completes the driver's requirements for R1.&lt;br /&gt;
&lt;br /&gt;
== Writing the SimpleUPnP Widget discovery method ==&lt;br /&gt;
&lt;br /&gt;
Every driver must contain a method which creates new objects to represent newly discovered Widgets.&lt;br /&gt;
The Discovery Module invokes this method to begin the process of creating the objects required to allow the Node to access the Widget. &lt;br /&gt;
&lt;br /&gt;
The name of this method is dictated by your chosen protocol's API. The SimpleUPnP protocol requires a method called WidgetDiscovered.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The method's name will not always be the same for each protocol. Your protocol's documentation will contain the details of what this method must be called.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This method and its implementation will meet the following driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
'''R2 Reacting to a discovered Widget on the network'''&lt;br /&gt;
&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
Our implementation of the WidgetDiscovered method will create a new DiscoveredWidget object and use the Protocol Module to listen for changes to the Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
The method uses the Protocol Module and two ways to identify the Widget. We must pass these in as&lt;br /&gt;
parameters:&lt;br /&gt;
&lt;br /&gt;
 public void WidgetDiscovered(string aWidgetUdn,&lt;br /&gt;
                              uint aWidgetClass,&lt;br /&gt;
                              ISimpleUpnpWidget&lt;br /&gt;
                                  aSimpleUpnpWidget)&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
Every Widget that uses this driver must be uniquely identifiable:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]    string newUdn = aWidgetUdn;&lt;br /&gt;
&lt;br /&gt;
Each new Widget is represented by a DiscoveredWidget object. Create the new DiscoveredWidget and pass in the required parameters we created earlier:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
     DiscoveredWidget discoveredWidget =&lt;br /&gt;
                 new DiscoveredWidget(iDeviceFactory,&lt;br /&gt;
                                      newUdn,&lt;br /&gt;
  &lt;br /&gt;
 [[File:Warning.png]]                                    aSimpleUpnpWidget,&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Registering the callbacks ===&lt;br /&gt;
&lt;br /&gt;
Finally, we ask the Widget's protocol interface to listen for calls to the handler methods we defined earlier in DiscoveredWidget. We do this by registering those methods as callbacks for the Protocol Module&lt;br /&gt;
to listen for:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                        discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                        discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                        discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You have now met 100% of the driver responsibility requirements and have a working driver to use with your SimpleUPnP Widget.&lt;br /&gt;
&lt;br /&gt;
= Appendix A. Sample XML =&lt;br /&gt;
&lt;br /&gt;
== Binary Light.xml ==&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
  &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
  &amp;lt;version&amp;gt;&lt;br /&gt;
   &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
   &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/version&amp;gt;&lt;br /&gt;
  &amp;lt;propertylist&amp;gt;&lt;br /&gt;
   &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
       illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
   &amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix B. Sample Provider = &lt;br /&gt;
&lt;br /&gt;
== DvWidgetOpenhomeOrgBasicLight1.cs ==&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Runtime.InteropServices;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Core;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Utils.Binary;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
 {&lt;br /&gt;
    public interface IDvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
        IDisposable&lt;br /&gt;
    {&lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous value&lt;br /&gt;
        /// &amp;lt;/returns&amp;gt;&lt;br /&gt;
        bool SetPropertyOn(bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;Property's value will be copied&lt;br /&gt;
        /// here&amp;lt;/param&amp;gt;&lt;br /&gt;
        bool PropertyOn();&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt; summary&amp;gt;&lt;br /&gt;
    /// Provider for the openhome.org:BinaryLight:1 UPnP service&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public abstract class DvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
               DvProvider,&lt;br /&gt;
               IDisposable,&lt;br /&gt;
               IDvProviderOpenhomeOrgBinaryLight1&lt;br /&gt;
    {&lt;br /&gt;
        private GCHandle iGch;&lt;br /&gt;
        private PropertyBool iPropertyOn;&lt;br /&gt;
        private PropertyUint iPropertyPrimarySeq;&lt;br /&gt;
        private PropertyUint iPropertySecondarySeq;&lt;br /&gt;
        private ActionDelegate iDelegateSetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetPrimaryProperty;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Constructor&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aDevice&amp;quot;&amp;gt;Device which owns this&lt;br /&gt;
        /// provider&amp;lt;/param&amp;gt;&lt;br /&gt;
        protected DvProviderOpenhomeOrgBinaryLight1(DvDevice aDevice)&lt;br /&gt;
            : base(aDevice, &amp;quot;openhome.org&amp;quot;, &amp;quot;GenericWidget&amp;quot;, 1)&lt;br /&gt;
        {&lt;br /&gt;
            iGch = GCHandle.Alloc(this);&lt;br /&gt;
            List&amp;lt;String&amp;gt; allowedValues = new List&amp;lt;String&amp;gt;();&lt;br /&gt;
            iPropertyOn = new PropertyBool(new ParameterBool(&amp;quot;On&amp;quot;));&lt;br /&gt;
            iPropertyPrimarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;PrimarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertyPrimarySeq);&lt;br /&gt;
            iPropertySecondarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;SecondarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertySecondarySeq);&lt;br /&gt;
            SetPropertyUint(iPropertyPrimarySeq, 0);&lt;br /&gt;
            SetPropertyUint(iPropertySecondarySeq, 0);&lt;br /&gt;
  &lt;br /&gt;
            Zapp.Core.Action action = new Zapp.Core.Action&lt;br /&gt;
                (&amp;quot;SetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;FireAndForget&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddInputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateSetProperty = new ActionDelegate(DoSetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateSetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateGetProperty = new ActionDelegate(DoGetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetPrimaryProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                 (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;integer&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;boolean&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;string&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;binary&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Type&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;readWrite&amp;quot;);allowedValues.Add&lt;br /&gt;
                (&amp;quot;readOnly&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;writeOnly&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString(&amp;quot;Access&amp;quot;,&lt;br /&gt;
                allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            iDelegateGetPrimaryProperty = new&lt;br /&gt;
            ActionDelegate(DoGetPrimaryProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetPrimaryProperty,&lt;br /&gt;
            GCHandle.ToIntPtr(iGch));&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous&lt;br /&gt;
        /// value&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool SetPropertyOn(bool aValue)&lt;br /&gt;
        {&lt;br /&gt;
            if (iPropertyOn.SetValue(aValue))&lt;br /&gt;
            {&lt;br /&gt;
                lock (iPropertyPrimarySeq)&lt;br /&gt;
                {&lt;br /&gt;
                    SetPropertyUint(iPropertyPrimarySeq,&lt;br /&gt;
                        iPropertyPrimarySeq.Value() + 1);&lt;br /&gt;
                } return true;&lt;br /&gt;
            } return false;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;The value of the property&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool PropertyOn()&lt;br /&gt;
        {&lt;br /&gt;
            return iPropertyOn.Value();&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the On property.&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aVersion&amp;quot;&amp;gt;Version of the service being&lt;br /&gt;
        /// requested (will be &amp;lt;= the version advertised)&amp;lt;/param&amp;gt; &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the On property.&lt;br /&gt;
        /// &amp;lt;/param&amp;gt;&lt;br /&gt;
        protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        private static int DoSetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                byte[] valBin = invocation.ReadBinary(&amp;quot;Value&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                switch (name)&lt;br /&gt;
                {&lt;br /&gt;
                    case &amp;quot;On&amp;quot;:&lt;br /&gt;
                        self.SetOn(aVersion, Converter.&lt;br /&gt;
                            BinaryToBoolean(valBin));&lt;br /&gt;
                        break;&lt;br /&gt;
                    default:&lt;br /&gt;
                        throw new ActionError();&lt;br /&gt;
                }&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
                invocation.WriteEnd();&lt;br /&gt;
            }&lt;br /&gt;
            catch (ActionError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
            catch (PropertyUpdateError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
        return 0;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        private static int DoGetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
            switch (name)&lt;br /&gt;
            {&lt;br /&gt;
                case &amp;quot;On&amp;quot;:&lt;br /&gt;
                invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                    Converter.BooleanToBinary(self.iPropertyOn.&lt;br /&gt;
                        Value()));&lt;br /&gt;
                break;&lt;br /&gt;
                default:&lt;br /&gt;
                throw new ActionError();&lt;br /&gt;
            }&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    private static int DoGetPrimaryProperty(IntPtr aPtr,&lt;br /&gt;
                    IntPtr aInvocation,&lt;br /&gt;
                    uint aVersion)&lt;br /&gt;
    {&lt;br /&gt;
        GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
        DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
            (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
        DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
  &lt;br /&gt;
        try&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReadStart();&lt;br /&gt;
            invocation.ReadEnd();&lt;br /&gt;
            invocation.WriteStart();&lt;br /&gt;
            invocation.WriteString(&amp;quot;Name&amp;quot;, &amp;quot;On&amp;quot;);&lt;br /&gt;
            invocation.WriteString(&amp;quot;Type&amp;quot;, &amp;quot;boolean&amp;quot;);&lt;br /&gt;
            invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                Converter.BooleanToBinary(self.iPropertyOn.Value()));&lt;br /&gt;
            invocation.WriteString(&amp;quot;Access&amp;quot;, &amp;quot;readWrite&amp;quot;);&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt;summary&amp;gt;&lt;br /&gt;
    /// Must be called for each class instance. Must be called before&lt;br /&gt;
    /// Core.Library.Close().&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public void Dispose()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
        GC.SuppressFinalize(this);&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
    ~DvProviderOpenhomeOrgBinaryLight1()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
        private void DoDispose()&lt;br /&gt;
        {&lt;br /&gt;
            lock (this)&lt;br /&gt;
            {&lt;br /&gt;
                if (iHandle == IntPtr.Zero)&lt;br /&gt;
            {&lt;br /&gt;
                    return;&lt;br /&gt;
            }&lt;br /&gt;
            DisposeProvider();&lt;br /&gt;
            iPropertyOn.Dispose();&lt;br /&gt;
            iHandle = IntPtr.Zero;&lt;br /&gt;
            }&lt;br /&gt;
            iGch.Free();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix C. Sample Driver = &lt;br /&gt;
&lt;br /&gt;
== BasicLightDriver.cs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.hWidget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
     class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
     {&lt;br /&gt;
         private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
         public BinaryLightProvider(DvDevice aDevice, &lt;br /&gt;
             ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol = aProtocol;&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
     {&lt;br /&gt;
         private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
         {&lt;br /&gt;
             private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
             private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
             private readonly ISimpleUpnpWidget iProtocol; &lt;br /&gt;
 &lt;br /&gt;
             private readonly BinaryLightProvider iProvider;&lt;br /&gt;
             private readonly DvDevice iDvDevice;&lt;br /&gt;
             private IPublishedWidget iPublishedWidget; &lt;br /&gt;
 &lt;br /&gt;
             public DvDevice DvDevice&lt;br /&gt;
             {&lt;br /&gt;
                 get { return iDvDevice; }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             public string WidgetClass&lt;br /&gt;
             {&lt;br /&gt;
                 get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public DiscoveredWidget(&lt;br /&gt;
                 IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                 string aUdn,&lt;br /&gt;
                 ISimpleUpnpWidget aProxy,&lt;br /&gt;
                 IWidgetPublisher aPublisher)&lt;br /&gt;
             {&lt;br /&gt;
                 iDeviceFactory = aDeviceFactory;&lt;br /&gt;
                 iProtocol = aProtocol;&lt;br /&gt;
 &lt;br /&gt;
                 iPublisher = aPublisher;&lt;br /&gt;
                 iDvDevice = iDeviceFactory.CreateDevice(aUdn);  &lt;br /&gt;
                 iProvider = new BinaryLightProvider(iDvDevice, &lt;br /&gt;
                                                     iProtocol);&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             public void HandleInitialEvent()&lt;br /&gt;
             {&lt;br /&gt;
                 iDvDevice.SetEnabled();&lt;br /&gt;
                 iPublisher.TryPublishWidget(iDvDevice.iUdn(), this,&lt;br /&gt;
                     out iPublishedWidget);&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
             {&lt;br /&gt;
                 if (iPublishedWidget != null)&lt;br /&gt;
                 {&lt;br /&gt;
                     iPublishedWidget.Unpublish();&lt;br /&gt;
                 } &lt;br /&gt;
                 iProvider.Dispose();&lt;br /&gt;
                 iDvDevice.Dispose();&lt;br /&gt;
             }  &lt;br /&gt;
 &lt;br /&gt;
             public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
             {&lt;br /&gt;
                 if (aIndex == 0)&lt;br /&gt;
                 {&lt;br /&gt;
                     iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         private readonly string iName;&lt;br /&gt;
         private readonly IDvDeviceFactory aDeviceFactory;&lt;br /&gt;
         private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
         &lt;br /&gt;
         public BinaryLightDriver(&lt;br /&gt;
             string aName,&lt;br /&gt;
             IWidgetPublisher aPublisher,&lt;br /&gt;
             iDeviceFactory aDeviceFactory)&lt;br /&gt;
         {&lt;br /&gt;
             iWidgetPublisher = aPublisher;&lt;br /&gt;
             iName = aName;&lt;br /&gt;
             iDeviceFactory = aDeviceFactory;&lt;br /&gt;
         } &lt;br /&gt;
 &lt;br /&gt;
         public IEnumerable&amp;amp;lt;uint&amp;amp;gt; WidgetClasses&lt;br /&gt;
         {&lt;br /&gt;
             get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         public void WidgetDiscovered(&lt;br /&gt;
             string aWidgetUdn,&lt;br /&gt;
             uint aWidgetClass,&lt;br /&gt;
             ISimpleUpnpWidget aSimpleUpnpWidget)&lt;br /&gt;
         {&lt;br /&gt;
             string newUdn = aWidgetUdn;&lt;br /&gt;
             DiscoveredWidget discoveredWidget = new DiscoveredWidget&lt;br /&gt;
                 (iDeviceFactory,&lt;br /&gt;
                  newUdn,&lt;br /&gt;
                  aSimpleUpnpWidget,&lt;br /&gt;
                  iWidgetPublisher);&lt;br /&gt;
 &lt;br /&gt;
             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                 discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                 discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                 discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary = &lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in OpenHome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by OpenHome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh - A collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs on ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The OpenHome Operating System. Core software for OpenHome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. &lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. A typical Widget supports only one protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Driver_Development</id>
		<title>OhWidget Driver Development</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Driver_Development"/>
				<updated>2012-03-01T15:19:42Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Writing the SimpleUPnP Widget discovery method */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for developers using the OpenHome SDK to integrate a Widget into an OpenHome system. Each Widget must have its own driver to allow it to communicate with the OpenHome Nodes. &lt;br /&gt;
&lt;br /&gt;
To help you write your driver, this document provides high level descriptions of the core responsibilities of a Widget driver and gives a detailed walk-through using example code.&lt;br /&gt;
&lt;br /&gt;
Full versions of each file used in the development of the example driver are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin development of your Widget driver you must be in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* your Widget Service XML that describes the properties on your Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document does not contain advice on how to write Widget Service XML. Refer to the OpenHome Widget Service XML definition document for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK&lt;br /&gt;
* your chosen communication protocol's API&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The protocol you choose for your Widgets must be the same protocol used on your choice of Node.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document focuses on the development of the Widget driver. Details about the communications protocol used are beyond the scope of this document. This document assumes you are familiar with your chosen protocol's code libraries and are able to use them in the driver code you write.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Related Documents ==&lt;br /&gt;
&lt;br /&gt;
The following related OpenHome documentation may be of interest to you:&lt;br /&gt;
&lt;br /&gt;
* [[ohWidget Technical Overview|ohWidget Technical Overview]]&lt;br /&gt;
* [[OpenHome Widget Service XML definition|OpenHome Widget Service XML definition]]&lt;br /&gt;
* [http://www.openhome.org/releases/ohNet_DeviceStack.pdf  OpenHome ohNet Device Stack]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
None of the related documents listed above is mandatory reading for Widget driver development.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
== Widget Service XML ==&lt;br /&gt;
OpenHome Widget driver writing relies heavily on the use of code generated from a single source — the Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
The service and actions your Widget provides are represented in code in a file called a Provider. The Provider is automatically generated from the Widget Service XML and produces an abstract class for you to inherit when you write your concrete class driver.&lt;br /&gt;
&lt;br /&gt;
To aid in the explanation of how the Provider is created and put to use we will follow the development of&lt;br /&gt;
a driver for a simple light Widget; taking the defined Widget Service XML and stepping through how it is used to generate the other files. Examples of code are used throughout this document to show you how each one is created and used in an OpenHome system. &lt;br /&gt;
&lt;br /&gt;
It is essential that you start with a well-formed Widget Service XML, conforming to the schema defined&lt;br /&gt;
in the WidgetService.xsd. The following diagram shows the significance of the Widget Service XML in&lt;br /&gt;
relation to the generated files you will use when writing your driver:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarchy, highlighting the areas specifically used in driver development]]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* The grayed-out files are not relevant to Widget driver development but can also be generated from the Widget Service XML.&lt;br /&gt;
* The Provider is generated in C#, meaning your driver must be written in C# as well. The use of managed code is mandatory for driver writing in the OpenHome framework.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Code sample used in this document ==&lt;br /&gt;
&lt;br /&gt;
Our examples in this document use a Widget Service XML definition for a light Widget called&lt;br /&gt;
BasicLight.xml.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Full versions of all the example files used in this document are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We will see how the Provider is generated from this XML and how it is used to aid the driver writing process. The examples also show how your chosen communication protocol should be used in the body of the driver code.&lt;br /&gt;
&lt;br /&gt;
Implementation details of specific protocols you choose to use are beyond the scope of this document. However, the samples used in this document show the use of the SimpleUPnP protocol to aid you in your development process.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol during the early stages of the OpenHome project. It is included in the OpenHome SDK and can be used as a public resource. &lt;br /&gt;
&lt;br /&gt;
The use of SimpleUPnP in the example files and the code snippets within the following sections is highlighted by the [[File:Warning.png]] icon. The lines of code marked by [[File:Warning.png]] must be changed to code from your chosen communication protocol's library. SimpleUPnP is left in to help you understand how a protocol is used in a working example.&lt;br /&gt;
&lt;br /&gt;
The sample code provided attempts to show best-practice coding standards. There are several sections of code that have a mandatory layout or that call specifically named methods and functions. These areas of the code are highlighted where required. &lt;br /&gt;
&lt;br /&gt;
Where the examples do not explicitly state that the code shown is mandatory, you are free to implement it in a different way according to your own coding style and practices.&lt;br /&gt;
&lt;br /&gt;
= Driver responsibilities = &lt;br /&gt;
&lt;br /&gt;
== Driver responsibilities ==&lt;br /&gt;
&lt;br /&gt;
An OpenHome Widget driver has several responsibilities which must be met before it can be used on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
These responsibilities are listed R1 to R7 and are defined here, explaining what each one must do. &lt;br /&gt;
&lt;br /&gt;
=== R1 Specifying the type of Widget the driver controls ===&lt;br /&gt;
A driver must know which type of Widget it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
=== R2 Reacting to a discovered Widget on the network ===&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== R3 Setting the initial values for the Widget's properties ===&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
=== R4 Publishing discovered Widgets in the Local Widget Registry on the Node ===&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object.&lt;br /&gt;
&lt;br /&gt;
=== R5 Reacting to an event reported from the Widget ===&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
=== R6 Reacting to actions sent to the Widget ===&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== R7 Reacting to a Widget's departure ===&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no&lt;br /&gt;
longer available.&lt;br /&gt;
&lt;br /&gt;
The sections of example code that follow show you how to write a driver from beginning to end. The accompanying text explaining the example code highlights when a responsibility, or part of a responsibility, has been met.&lt;br /&gt;
&lt;br /&gt;
= Driver Architecture = &lt;br /&gt;
&lt;br /&gt;
== Driver Architecture ==&lt;br /&gt;
&lt;br /&gt;
Drivers are installed on the Node and used when the Node needs to communicate with the Widget. Drivers&lt;br /&gt;
use several objects to communicate with Widgets over the Widget's lifetime. Figure 2 shows the objects&lt;br /&gt;
used by the driver and how the responsibilities listed above relate to each one:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture.png|800px|thumb|center|Figure 2: The architecture of a driver, showing the driver's relationship to the objects used to communicate with a Widget. Lines between objects show message flow.]]&lt;br /&gt;
&lt;br /&gt;
The objects contained in the dotted boundary must appear in the code you write to define your driver. The Driver, Provider and IWidgetRegistryEntry objects are all contained in the same driver file. We begin discussing this on page 12. &lt;br /&gt;
&lt;br /&gt;
The other objects are provided by the OpenHome SDK or as installed components on the Node.&lt;br /&gt;
&lt;br /&gt;
The Discovery Module informs the driver of the presence of an available Widget.&lt;br /&gt;
&lt;br /&gt;
Each Node has a Protocol Module which contains the protocol's API. Widgets can communicate with OpenHome Nodes using any one of the set of communications protocols the Node supports. The driver uses your chosen protocol's Protocol Module to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
Both the Protocol Module and the Discovery Module are installed on the Node. When you write your&lt;br /&gt;
driver you will use your Protocol Module to allow the driver to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
IWidgetPublisher, IPublishedWidget and DvDevice are objects provided in the OpenHome&lt;br /&gt;
API. You can read about them in the APIs.&lt;br /&gt;
&lt;br /&gt;
= Generating the Provider = &lt;br /&gt;
&lt;br /&gt;
== Generating the Provider ==&lt;br /&gt;
&lt;br /&gt;
You must generate your provider before you can begin writing your Widget driver. You use your provider as a guide to implement the functions your Widget needs to set the values of its properties.&lt;br /&gt;
&lt;br /&gt;
The current provider generation process is a manual one involving the use of a text transform tool.&lt;br /&gt;
&lt;br /&gt;
Speak to your OpenHome contact who will help you generate your provider.&lt;br /&gt;
&lt;br /&gt;
Future releases of the OpenHome SDK will include a tool to help you generate the provider.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
You must be in possession of:&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK, unpacked on your computer&lt;br /&gt;
* your Widget Service XML file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Writing a SimpleUPnP driver = &lt;br /&gt;
&lt;br /&gt;
== Introduction to the SimpleUPnP protocol ==&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol used to control emulated Widgets over a custom UPnP service.&lt;br /&gt;
&lt;br /&gt;
This chapter shows how a driver is written using the SimpleUPnP communications protocol. The aim is to show the code using as generic a protocol as possible so that you can see where your own protocol specific code needs to go.&lt;br /&gt;
&lt;br /&gt;
The use of code specific to the SimpleUPnP implementation is highlighted by the use of the [[File:Warning.png]] icon. The lines of code are marked by this icon to make it easier for you to see where the protocol-specific code must go and what parts of the code are generic.&lt;br /&gt;
&lt;br /&gt;
=== Register model ===&lt;br /&gt;
&lt;br /&gt;
SimpleUPnP is modeled on 8 physical registers available on the Widget. Each register is 32-bits wide. They are indexed from 0 to 7 and the last register (register 7) is reserved for storing the Widget's class.&lt;br /&gt;
&lt;br /&gt;
This detail is used by the Protocol Module on the Node to determine which driver is needed to run the new Widget when it has been discovered.&lt;br /&gt;
&lt;br /&gt;
The remaining 7 registers (registers 0 to 6) are free for Widget engineers to assign to the Widget's functions.&lt;br /&gt;
&lt;br /&gt;
Registers 0, 1, 2 and 3 are available as read/write registers. Registers 4, 5 and 6 are readonly registers.&lt;br /&gt;
&lt;br /&gt;
Only the emulated hardware (running on the Node) can change the values held in registers 4, 5 and 6.&lt;br /&gt;
&lt;br /&gt;
=== Register use in drivers ===&lt;br /&gt;
&lt;br /&gt;
In the example that follows we have a Basic Light Widget with a very simple function: it can be turned on and turned off. The on/off value is stored in register 0, with values 0=OFF and 1=ON. Register 0 is a read/write register. This means we can change the value stored there using messages passed to the Widget from the Node, and by reacting to physical interactions at the Widget (such as someone manually switching the light on or off). &lt;br /&gt;
&lt;br /&gt;
The mapping of registers to properties on the Widget is decided by the engineers who manufacture the device. You must be provided with the mapping before you begin developing your driver.&lt;br /&gt;
&lt;br /&gt;
== Starting the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-BoxHighlight.png|800px|thumb|center|Figure 3 The driver architecture highlighting the Widget driver and its component parts.]]&lt;br /&gt;
&lt;br /&gt;
When you have generated the abstract provider you can put it to use in the Widget driver. A Widget driver&lt;br /&gt;
has three distinct components:&lt;br /&gt;
&lt;br /&gt;
* an implementation of your abstract provider&lt;br /&gt;
* a definition of the Widget driver&lt;br /&gt;
* an implementation of the IWidgetRegistryEntry interface&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must manually write the code for your Widget driver. The differences in implementation of Widget properties and communication protocols means that the driver code cannot be autogenerated.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This section takes you through how to write a Widget driver by implementing the auto-generated provider,&lt;br /&gt;
starting from a new blank file and finishing with a working driver for the Basic Light Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
No assumptions have been made about the type of editor you use to write your code. Shortcuts&lt;br /&gt;
or macros that you use as standard will not appear in the instructions below. A full example&lt;br /&gt;
BinaryLightDriver.cs is available to review in Appendix C.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a new C# file in your IDE. Ensure the following libraries are used:&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 [[File:Warning.png]]using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 namespace OpenHome.Widget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must use the libraries listed above for this specific example.&lt;br /&gt;
&lt;br /&gt;
In general, drivers require the following libraries:&lt;br /&gt;
* System*&lt;br /&gt;
* System.Collections.Generic*&lt;br /&gt;
* OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
&lt;br /&gt;
Your driver will fail to compile if you miss any of these listed libraries. Libraries marked * are typically added by default by most modern IDEs. &lt;br /&gt;
&lt;br /&gt;
The OpenHome.Widget.Protocols.SimpleUpnp library is required only in this SimpleUPnP example. Drivers using a different protocol will use their own protocol library.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Implementing the provider ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-ProviderHighlight.png|800px|thumb|center|Figure 4 The driver architecture highlighting the Provider's place]]&lt;br /&gt;
&lt;br /&gt;
You use your auto-generated abstract provider by writing an implementation of it in the driver file. Responsibilities met by implementing your auto-generated provider are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R6 Reacting to actions sent to the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
Begin by creating a new class. It will subclass the abstract auto-generated provider:&lt;br /&gt;
&lt;br /&gt;
 class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
The Protocol Module will provide an API for the Provider to use to communicate with the Widget. In&lt;br /&gt;
SimpleUPnP we are provided with an interface called ISimpleUpnpWidget. The provider is supplied&lt;br /&gt;
with the required instance of the interface by the Discovery Module on the Node.&lt;br /&gt;
&lt;br /&gt;
The mechanisms for registering providers with specific Protocol Modules, and for the way the module gives each provider its required interface are covered later when writing the discovery method.&lt;br /&gt;
&lt;br /&gt;
For now, we need to give the Provider a place to store the interface that it will later use to communicate&lt;br /&gt;
with the Widget:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]] private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
&lt;br /&gt;
The interface from the Protocol Module is passed in as a parameter in the Provider's constructor and then&lt;br /&gt;
assigned to the variable we just created:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightProvider(DvDevice aDevice,&lt;br /&gt;
 [[File:Warning.png]]         ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
 {&lt;br /&gt;
       iProtocol = aProtocol;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
To satisfy R3 we would normally set the Widget's properties here, giving them an initial value.&lt;br /&gt;
However, in this specific example we cannot set the value of Basic Light's only property because&lt;br /&gt;
we will never know, in advance, what the state of the light will be (either on or off) when we&lt;br /&gt;
create the DiscoveredWidget.&lt;br /&gt;
&lt;br /&gt;
When you cannot set the properties ahead of time, and you are using an eventing protocol like SimpleUPnP, you can instead set them in the HandleRegisterEvent method in the driver class. This also satisfies the requirements for R3. You must set the Widget's properties before you enable it using SetEnabled(). &lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The abstract provider includes an abstract method called SetOn. This method is invoked by the Node when passing a message to the Widget, specifically to set the on property of the Widget to either 0 or 1. The implementation of this method will meet the requirements for R6.&lt;br /&gt;
&lt;br /&gt;
We must override this method and provide the protocol module a way of passing a message on to the Widget to perform the required action, in this case turn the light on or off:&lt;br /&gt;
&lt;br /&gt;
          protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
          {&lt;br /&gt;
     [[File:Warning.png]]        iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
In this example the Basic Light's SetOn property (the boolean property that controls whether the light is&lt;br /&gt;
on or off) is represented in the physical Widget by the register that has an index of 0.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* This method is an example of an action on a Widget. Actions are messages sent from the Node to the Widget. We will see later how to handle events that need to be passed back from the Widget&lt;br /&gt;
to the Node.&lt;br /&gt;
* Your own Widget will likely provide more than a single property. Your auto-generated provider will contain one abstract method to represent each writable property. Read-only properties are not provided an abstract method.&lt;br /&gt;
&lt;br /&gt;
You must implement each abstract method in your driver to ensure the relevant property on&lt;br /&gt;
the Widget can be set.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We have now finished implementing the provider. The next step is to implement the driver.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Implementing the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-DriverHighlight.png|800px|thumb|center|Figure 4: The driver architecture highlighting the implemented driver's place.]]&lt;br /&gt;
&lt;br /&gt;
The code for your Widget driver must provide an implementation of the IWidgetRegistryInterface,&lt;br /&gt;
including the following tasks:&lt;br /&gt;
&lt;br /&gt;
* methods to expose identifying details about the Widget for the Node to access&lt;br /&gt;
* providing methods to handle events reported by the Widget&lt;br /&gt;
&lt;br /&gt;
The driver is implemented as a public class within the same file as the provider code. Each driver must use the interface for the protocol you are using. For the SimpleUPnP protocol the interface is ISimple-UpnpWidgetDriver.&lt;br /&gt;
&lt;br /&gt;
=== Writing code ===&lt;br /&gt;
&lt;br /&gt;
Create your new driver class and subclass the ISimpleUpnpWidgetDriver interface:&lt;br /&gt;
&lt;br /&gt;
 public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Implementing IWidgetRegistryEntry ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry is the interface you use to represent physical Widgets. It is implemented as a subclass of your driver class. We are going to implement this interface in a class called '''DiscoveredWidget'''.&lt;br /&gt;
&lt;br /&gt;
Let's return to our driver architecture diagram for a moment:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-IRegistryEntryHighlight.png|800px|thumb|center|Figure 5 The driver architecture highlighting the IWidgetRegistryEntry object you will now implement]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry uses several other objects to help create it and respond to messages sent to and from it. These objects will be created in our implementation of DiscoveredWidget. &lt;br /&gt;
&lt;br /&gt;
When successfully created and published, the DiscoveredWidget objects are stored in a list on the Node called the Local Widget Registry. The Local Widget Registry is used by Nodes to maintain contact with the Widgets they control.&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry is shown at the top of Figure 5, marked plainly as (Registry). The path to the Local Widget Registry goes through several layers of Node architecture which are not relevant to Widget driver writing, so are not shown in the diagrams.&lt;br /&gt;
&lt;br /&gt;
==== Writing code ====&lt;br /&gt;
&lt;br /&gt;
Start by subclassing the IWidgetRegistryEntry interface in your new class:&lt;br /&gt;
&lt;br /&gt;
      private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
      {&lt;br /&gt;
&lt;br /&gt;
A DiscoveredWidget must provide the driver with the objects required to present the Widget and its&lt;br /&gt;
properties to the Node:&lt;br /&gt;
&lt;br /&gt;
           private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
           private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
           private readonly ISimpleUpnpWidget iProtocol;&lt;br /&gt;
           private readonly BinaryLightProvider iProvider;&lt;br /&gt;
           private readonly DvDevice iDvDevice;&lt;br /&gt;
           private IPublishedWidget iPublishedWidget;&lt;br /&gt;
&lt;br /&gt;
Each of the attributes in the example above are defined as follows:&lt;br /&gt;
&lt;br /&gt;
iDeviceFactory — used by the driver to create a single instance of DvDevice to represent a single Widget&lt;br /&gt;
&lt;br /&gt;
iPublisher — used by the driver to publish the Widget to the Node&lt;br /&gt;
&lt;br /&gt;
iProtocol — the object used by the Widget to communicate with the Protocol Module on the Node&lt;br /&gt;
&lt;br /&gt;
iProvider — an instantiated provider of the type you defined earlier&lt;br /&gt;
&lt;br /&gt;
iDvDevice — a representation of a Widget to which the provider is attached, created using iDevice-Factory above&lt;br /&gt;
&lt;br /&gt;
iPublishedWidget — used to contain the returned object from a successful publishing of the Widget&lt;br /&gt;
If we look again at the driver architecture diagram, we ca highlight the objects we've just defined:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-Highlight.png|800px|thumb|center|Figure 6: The driver architecture highlighting the objects used by the IWidgetRegistryEntry implementation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The DeviceFactory, defined above in the member variable iDeviceFactory, is used to create new DvDevice objects. The DeviceFactory is only ever used to do this once. It is not shown in the driver architecture diagrams due to its minimal role in the operation of a driver, but it would normally appear between the IWidgetRegistryEntry and DvDevice objects.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
A driver requires methods to expose identifying details about the Widget. We must provide access to two of the attributes we just defined above:&lt;br /&gt;
&lt;br /&gt;
 public DvDevice DvDevice&lt;br /&gt;
 {&lt;br /&gt;
     get { return iDvDevice; }&lt;br /&gt;
 }&lt;br /&gt;
 public string WidgetClass&lt;br /&gt;
 {&lt;br /&gt;
     get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The WidgetClass string is formed using a combination of the vendor name and the Widget's name in the&lt;br /&gt;
format:&lt;br /&gt;
&lt;br /&gt;
 [vendor_domain]:[widget_name]&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry can now query both the DvDevice object representing the Widget, and the specific class of Widget this driver represents. The other member variables we defined do not need their own accessor methods.&lt;br /&gt;
&lt;br /&gt;
Now we must write a constructor for DiscoveredWidget and assign the parameters accordingly: &lt;br /&gt;
&lt;br /&gt;
 public DiscoveredWidget(IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                            string aUdn,&lt;br /&gt;
                            ISimpleUpnpWidget aProxy,&lt;br /&gt;
                            IWidgetPublisher aPublisher)&lt;br /&gt;
 {&lt;br /&gt;
      iDeviceFactory = aDeviceFactory;&lt;br /&gt;
      iProtocol = aProtocol;&lt;br /&gt;
      iPublisher = aPublisher;&lt;br /&gt;
      iDvDevice = iDeviceFactory.CreateDevice(aUdn);&lt;br /&gt;
      iProvider = new BinaryLightProvider(iDvDevice,&lt;br /&gt;
      iProtocol);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Event handling ===&lt;br /&gt;
&lt;br /&gt;
A Widget's state can change in one of three significant ways:&lt;br /&gt;
&lt;br /&gt;
* when the Widget needs to be published on the Node&lt;br /&gt;
* when the Widget disappears from the network (by losing power or similar)&lt;br /&gt;
* when a property's state changes and must be updated to a new value&lt;br /&gt;
&lt;br /&gt;
We now need methods to handle these changes.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The methods we define here will be used as callbacks, rather than invoked as method calls. We define the methods here first and then use them later on. We will use the Protocol Module to listen for changes in the Widget's state and register these methods as callbacks there. See Writing the SimpleUPnP Widget discovery method for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this section of the driver are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R4 Publishing discovered Widgets in the Local Widget Registry on the Node'''&lt;br /&gt;
&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object. &lt;br /&gt;
&lt;br /&gt;
'''R5 Reacting to an event reported from the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
'''R7 Reacting to a Widget's departure'''&lt;br /&gt;
&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no longer available.&lt;br /&gt;
&lt;br /&gt;
==== Enabling and publishing a discovered Widget ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first method initializes the Widget by enabling the device and then using the IWidgetPublisher&lt;br /&gt;
to make it available on the Node:&lt;br /&gt;
&lt;br /&gt;
 public void HandleInitialEvent()&lt;br /&gt;
 {&lt;br /&gt;
      iDvDevice.SetEnabled();&lt;br /&gt;
      iPublisher.TryPublishWidget(iDvDevice.iUdn(),&lt;br /&gt;
                              this,&lt;br /&gt;
                              out iPublishedWidget);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This method meets the requirements for R4.&lt;br /&gt;
&lt;br /&gt;
The call to TryPublishWidget returns an iPublishedWidget object. We use this object later to satisfy the requirements of R7.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The ordering of the calls to SetEnabled and TryPublishWidget is vitally important. You&lt;br /&gt;
must enable the device before you attempt to publish it. Your Widget will not be available to the&lt;br /&gt;
Nodes unless SetEnabled is called first. Nodes will not be able to access a published device&lt;br /&gt;
that has not been enabled.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
R3 requires that you set the Widget's properties before you enable and publish the device. We&lt;br /&gt;
discussed on page 14 how some properties can only be set after the Widget reports what their&lt;br /&gt;
state is. We do this in HandleRegisterEvent.&lt;br /&gt;
&lt;br /&gt;
We rely on the SimpleUPnP Protocol Module guaranteeing a call to HandleRegisterEvent first before HandleInitialEvent. This is informed by guarantees made by the Control Point stack that the calls will be made in that order.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
==== Removing a Widget ====&lt;br /&gt;
&lt;br /&gt;
Removing a Widget involves unpublishing it from the Node. The IPublishedWidget interface provides us with a method we can call to manage that for us:&lt;br /&gt;
&lt;br /&gt;
 public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
 {&lt;br /&gt;
     if (iPublishedWidget != null)&lt;br /&gt;
     { iPublishedWidget.Unpublish(); }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assuming that the Widget was successfully published earlier, it is removed from the Node's Local Widget Registry.&lt;br /&gt;
&lt;br /&gt;
We must also properly handle the resources we used to create and maintain the Widget object while it was published:&lt;br /&gt;
&lt;br /&gt;
      iProvider.Dispose();&lt;br /&gt;
      iDvDevice.Dispose();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The calls to Dispose are made regardless of the Widget's published state, ensuring that any created device and associated provider are properly disposed. This implementation satisfies R7.&lt;br /&gt;
&lt;br /&gt;
====Event handling ====&lt;br /&gt;
&lt;br /&gt;
We need a method to handle changes to the state of the Widget's properties.&lt;br /&gt;
&lt;br /&gt;
If the property changes at the Widget, it needs to pass the new state back to the Node so that it is kept up-to-date on the Widget's status. This is called an event. An example in the case of our Basic Light is someone manually switching the light from on to off. This is in contrast to actions, which are passed from the Node to the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Other examples of events involve no human interaction, such as a thermometer Widget updating its current temperature based on environmental changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Our Basic Light Widget has only one property that needs to be handled:&lt;br /&gt;
&lt;br /&gt;
 public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
 {&lt;br /&gt;
     if (aIndex == 0)&lt;br /&gt;
     {&lt;br /&gt;
         iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We use our instance of the provider to update the register on the Widget that is mapped to the On property. This in turn updates the Node with the new state of the Widget.&lt;br /&gt;
&lt;br /&gt;
This method provides implementations to satisfy two driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
* R3 is now completely satisfied, as we can now set the values of all the previously unknown properties here.&lt;br /&gt;
* R5 is also satisfied as this method allows us to update the Widget's status on the Node when a property is changed on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Not all protocols pass messages back to the Node in this manner. The way we have satisfied R3 and R5 here only applies to protocols and Widgets that support this behavior.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Widgets that do not use an eventing protocol need to have their properties set in the provider's constructor to satisfy R3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To satisfy R5, the over-ridden method SetOn in the provider must include the call to SetPropertyOn. Non-eventing protocols do not require a HandleRegisterEvent method.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Constructor ===&lt;br /&gt;
&lt;br /&gt;
The final requirement for the driver is the constructor so that new DiscoveredWidget objects can be created. &lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this area of code are:&lt;br /&gt;
&lt;br /&gt;
'''R1 Specifying the type of Widget the driver controls'''&lt;br /&gt;
&lt;br /&gt;
A driver must know which type of Widget that it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
==== Writing the code ====&lt;br /&gt;
&lt;br /&gt;
We begin by defining the variables we will use to store the objects used by the driver:&lt;br /&gt;
&lt;br /&gt;
 private readonly string iName;&lt;br /&gt;
 private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
 private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now write the constructor for the driver and assign the passed in parameters appropriately:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightDriver(string aName,&lt;br /&gt;
                IWidgetPublisher aPublisher,&lt;br /&gt;
                IDvDeviceFactory aDeviceFactory)&lt;br /&gt;
 {&lt;br /&gt;
     iWidgetPublisher = aPublisher;&lt;br /&gt;
     iName = aName;&lt;br /&gt;
     iDeviceFactory = aDeviceFactory;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally we need to provide the driver a way to publish the class of Widget it controls. This information is requested by the Discovery Module and is used to ensure the Node uses the correct driver when a new Widget appears.&lt;br /&gt;
&lt;br /&gt;
The implementation for this details will be different for each protocol. The SimpleUPnP protocol library provides a file that contains the SimpleUPnP definitions as integers. Each integer represents a particular class of identified Widget.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP implementation of that method is as follows:&lt;br /&gt;
&lt;br /&gt;
 public IEnumerable&amp;lt;uint&amp;gt; WidgetClasses&lt;br /&gt;
 {&lt;br /&gt;
 [[File:Warning.png]]        get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The body of this method is specifically written for the Widget class we are defining (in this case a binary light). This method completes the driver's requirements for R1.&lt;br /&gt;
&lt;br /&gt;
== Writing the SimpleUPnP Widget discovery method ==&lt;br /&gt;
&lt;br /&gt;
Every driver must contain a method which creates new objects to represent newly discovered Widgets.&lt;br /&gt;
The Discovery Module invokes this method to begin the process of creating the objects required to allow the Node to access the Widget. &lt;br /&gt;
&lt;br /&gt;
The name of this method is dictated by your chosen protocol's API. The SimpleUPnP protocol requires a method called WidgetDiscovered.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The method's name will not always be the same for each protocol. Your protocol's documentation will contain the details of what this method must be called.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This method and its implementation will meet the following driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
'''R2 Reacting to a discovered Widget on the network'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
Our implementation of the WidgetDiscovered method will create a new DiscoveredWidget object and use the Protocol Module to listen for changes to the Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
The method uses the Protocol Module and two ways to identify the Widget. We must pass these in as&lt;br /&gt;
parameters:&lt;br /&gt;
&lt;br /&gt;
 public void WidgetDiscovered(string aWidgetUdn,&lt;br /&gt;
                              uint aWidgetClass,&lt;br /&gt;
                              ISimpleUpnpWidget&lt;br /&gt;
                                  aSimpleUpnpWidget)&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
Every Widget that uses this driver must be uniquely identifiable:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]    string newUdn = aWidgetUdn;&lt;br /&gt;
&lt;br /&gt;
Each new Widget is represented by a DiscoveredWidget object. Create the new DiscoveredWidget and pass in the required parameters we created earlier:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
     DiscoveredWidget discoveredWidget =&lt;br /&gt;
                 new DiscoveredWidget(iDeviceFactory,&lt;br /&gt;
                                      newUdn,&lt;br /&gt;
  &lt;br /&gt;
 [[File:Warning.png]]                                    aSimpleUpnpWidget,&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Registering the callbacks ===&lt;br /&gt;
&lt;br /&gt;
Finally, we ask the Widget's protocol interface to listen for calls to the handler methods we defined earlier in DiscoveredWidget. We do this by registering those methods as callbacks for the Protocol Module&lt;br /&gt;
to listen for:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                        discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                        discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                        discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You have now met 100% of the driver responsibility requirements and have a working driver to use with your SimpleUPnP Widget.&lt;br /&gt;
&lt;br /&gt;
= Appendix A. Sample XML =&lt;br /&gt;
&lt;br /&gt;
== Binary Light.xml ==&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
  &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
  &amp;lt;version&amp;gt;&lt;br /&gt;
   &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
   &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/version&amp;gt;&lt;br /&gt;
  &amp;lt;propertylist&amp;gt;&lt;br /&gt;
   &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
       illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
   &amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix B. Sample Provider = &lt;br /&gt;
&lt;br /&gt;
== DvWidgetOpenhomeOrgBasicLight1.cs ==&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Runtime.InteropServices;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Core;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Utils.Binary;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
 {&lt;br /&gt;
    public interface IDvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
        IDisposable&lt;br /&gt;
    {&lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous value&lt;br /&gt;
        /// &amp;lt;/returns&amp;gt;&lt;br /&gt;
        bool SetPropertyOn(bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;Property's value will be copied&lt;br /&gt;
        /// here&amp;lt;/param&amp;gt;&lt;br /&gt;
        bool PropertyOn();&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt; summary&amp;gt;&lt;br /&gt;
    /// Provider for the openhome.org:BinaryLight:1 UPnP service&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public abstract class DvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
               DvProvider,&lt;br /&gt;
               IDisposable,&lt;br /&gt;
               IDvProviderOpenhomeOrgBinaryLight1&lt;br /&gt;
    {&lt;br /&gt;
        private GCHandle iGch;&lt;br /&gt;
        private PropertyBool iPropertyOn;&lt;br /&gt;
        private PropertyUint iPropertyPrimarySeq;&lt;br /&gt;
        private PropertyUint iPropertySecondarySeq;&lt;br /&gt;
        private ActionDelegate iDelegateSetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetPrimaryProperty;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Constructor&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aDevice&amp;quot;&amp;gt;Device which owns this&lt;br /&gt;
        /// provider&amp;lt;/param&amp;gt;&lt;br /&gt;
        protected DvProviderOpenhomeOrgBinaryLight1(DvDevice aDevice)&lt;br /&gt;
            : base(aDevice, &amp;quot;openhome.org&amp;quot;, &amp;quot;GenericWidget&amp;quot;, 1)&lt;br /&gt;
        {&lt;br /&gt;
            iGch = GCHandle.Alloc(this);&lt;br /&gt;
            List&amp;lt;String&amp;gt; allowedValues = new List&amp;lt;String&amp;gt;();&lt;br /&gt;
            iPropertyOn = new PropertyBool(new ParameterBool(&amp;quot;On&amp;quot;));&lt;br /&gt;
            iPropertyPrimarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;PrimarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertyPrimarySeq);&lt;br /&gt;
            iPropertySecondarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;SecondarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertySecondarySeq);&lt;br /&gt;
            SetPropertyUint(iPropertyPrimarySeq, 0);&lt;br /&gt;
            SetPropertyUint(iPropertySecondarySeq, 0);&lt;br /&gt;
  &lt;br /&gt;
            Zapp.Core.Action action = new Zapp.Core.Action&lt;br /&gt;
                (&amp;quot;SetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;FireAndForget&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddInputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateSetProperty = new ActionDelegate(DoSetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateSetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateGetProperty = new ActionDelegate(DoGetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetPrimaryProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                 (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;integer&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;boolean&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;string&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;binary&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Type&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;readWrite&amp;quot;);allowedValues.Add&lt;br /&gt;
                (&amp;quot;readOnly&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;writeOnly&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString(&amp;quot;Access&amp;quot;,&lt;br /&gt;
                allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            iDelegateGetPrimaryProperty = new&lt;br /&gt;
            ActionDelegate(DoGetPrimaryProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetPrimaryProperty,&lt;br /&gt;
            GCHandle.ToIntPtr(iGch));&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous&lt;br /&gt;
        /// value&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool SetPropertyOn(bool aValue)&lt;br /&gt;
        {&lt;br /&gt;
            if (iPropertyOn.SetValue(aValue))&lt;br /&gt;
            {&lt;br /&gt;
                lock (iPropertyPrimarySeq)&lt;br /&gt;
                {&lt;br /&gt;
                    SetPropertyUint(iPropertyPrimarySeq,&lt;br /&gt;
                        iPropertyPrimarySeq.Value() + 1);&lt;br /&gt;
                } return true;&lt;br /&gt;
            } return false;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;The value of the property&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool PropertyOn()&lt;br /&gt;
        {&lt;br /&gt;
            return iPropertyOn.Value();&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the On property.&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aVersion&amp;quot;&amp;gt;Version of the service being&lt;br /&gt;
        /// requested (will be &amp;lt;= the version advertised)&amp;lt;/param&amp;gt; &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the On property.&lt;br /&gt;
        /// &amp;lt;/param&amp;gt;&lt;br /&gt;
        protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        private static int DoSetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                byte[] valBin = invocation.ReadBinary(&amp;quot;Value&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                switch (name)&lt;br /&gt;
                {&lt;br /&gt;
                    case &amp;quot;On&amp;quot;:&lt;br /&gt;
                        self.SetOn(aVersion, Converter.&lt;br /&gt;
                            BinaryToBoolean(valBin));&lt;br /&gt;
                        break;&lt;br /&gt;
                    default:&lt;br /&gt;
                        throw new ActionError();&lt;br /&gt;
                }&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
                invocation.WriteEnd();&lt;br /&gt;
            }&lt;br /&gt;
            catch (ActionError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
            catch (PropertyUpdateError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
        return 0;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        private static int DoGetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
            switch (name)&lt;br /&gt;
            {&lt;br /&gt;
                case &amp;quot;On&amp;quot;:&lt;br /&gt;
                invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                    Converter.BooleanToBinary(self.iPropertyOn.&lt;br /&gt;
                        Value()));&lt;br /&gt;
                break;&lt;br /&gt;
                default:&lt;br /&gt;
                throw new ActionError();&lt;br /&gt;
            }&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    private static int DoGetPrimaryProperty(IntPtr aPtr,&lt;br /&gt;
                    IntPtr aInvocation,&lt;br /&gt;
                    uint aVersion)&lt;br /&gt;
    {&lt;br /&gt;
        GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
        DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
            (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
        DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
  &lt;br /&gt;
        try&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReadStart();&lt;br /&gt;
            invocation.ReadEnd();&lt;br /&gt;
            invocation.WriteStart();&lt;br /&gt;
            invocation.WriteString(&amp;quot;Name&amp;quot;, &amp;quot;On&amp;quot;);&lt;br /&gt;
            invocation.WriteString(&amp;quot;Type&amp;quot;, &amp;quot;boolean&amp;quot;);&lt;br /&gt;
            invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                Converter.BooleanToBinary(self.iPropertyOn.Value()));&lt;br /&gt;
            invocation.WriteString(&amp;quot;Access&amp;quot;, &amp;quot;readWrite&amp;quot;);&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt;summary&amp;gt;&lt;br /&gt;
    /// Must be called for each class instance. Must be called before&lt;br /&gt;
    /// Core.Library.Close().&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public void Dispose()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
        GC.SuppressFinalize(this);&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
    ~DvProviderOpenhomeOrgBinaryLight1()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
        private void DoDispose()&lt;br /&gt;
        {&lt;br /&gt;
            lock (this)&lt;br /&gt;
            {&lt;br /&gt;
                if (iHandle == IntPtr.Zero)&lt;br /&gt;
            {&lt;br /&gt;
                    return;&lt;br /&gt;
            }&lt;br /&gt;
            DisposeProvider();&lt;br /&gt;
            iPropertyOn.Dispose();&lt;br /&gt;
            iHandle = IntPtr.Zero;&lt;br /&gt;
            }&lt;br /&gt;
            iGch.Free();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix C. Sample Driver = &lt;br /&gt;
&lt;br /&gt;
== BasicLightDriver.cs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.hWidget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
     class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
     {&lt;br /&gt;
         private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
         public BinaryLightProvider(DvDevice aDevice, &lt;br /&gt;
             ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol = aProtocol;&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
     {&lt;br /&gt;
         private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
         {&lt;br /&gt;
             private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
             private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
             private readonly ISimpleUpnpWidget iProtocol; &lt;br /&gt;
 &lt;br /&gt;
             private readonly BinaryLightProvider iProvider;&lt;br /&gt;
             private readonly DvDevice iDvDevice;&lt;br /&gt;
             private IPublishedWidget iPublishedWidget; &lt;br /&gt;
 &lt;br /&gt;
             public DvDevice DvDevice&lt;br /&gt;
             {&lt;br /&gt;
                 get { return iDvDevice; }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             public string WidgetClass&lt;br /&gt;
             {&lt;br /&gt;
                 get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public DiscoveredWidget(&lt;br /&gt;
                 IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                 string aUdn,&lt;br /&gt;
                 ISimpleUpnpWidget aProxy,&lt;br /&gt;
                 IWidgetPublisher aPublisher)&lt;br /&gt;
             {&lt;br /&gt;
                 iDeviceFactory = aDeviceFactory;&lt;br /&gt;
                 iProtocol = aProtocol;&lt;br /&gt;
 &lt;br /&gt;
                 iPublisher = aPublisher;&lt;br /&gt;
                 iDvDevice = iDeviceFactory.CreateDevice(aUdn);  &lt;br /&gt;
                 iProvider = new BinaryLightProvider(iDvDevice, &lt;br /&gt;
                                                     iProtocol);&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             public void HandleInitialEvent()&lt;br /&gt;
             {&lt;br /&gt;
                 iDvDevice.SetEnabled();&lt;br /&gt;
                 iPublisher.TryPublishWidget(iDvDevice.iUdn(), this,&lt;br /&gt;
                     out iPublishedWidget);&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
             {&lt;br /&gt;
                 if (iPublishedWidget != null)&lt;br /&gt;
                 {&lt;br /&gt;
                     iPublishedWidget.Unpublish();&lt;br /&gt;
                 } &lt;br /&gt;
                 iProvider.Dispose();&lt;br /&gt;
                 iDvDevice.Dispose();&lt;br /&gt;
             }  &lt;br /&gt;
 &lt;br /&gt;
             public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
             {&lt;br /&gt;
                 if (aIndex == 0)&lt;br /&gt;
                 {&lt;br /&gt;
                     iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         private readonly string iName;&lt;br /&gt;
         private readonly IDvDeviceFactory aDeviceFactory;&lt;br /&gt;
         private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
         &lt;br /&gt;
         public BinaryLightDriver(&lt;br /&gt;
             string aName,&lt;br /&gt;
             IWidgetPublisher aPublisher,&lt;br /&gt;
             iDeviceFactory aDeviceFactory)&lt;br /&gt;
         {&lt;br /&gt;
             iWidgetPublisher = aPublisher;&lt;br /&gt;
             iName = aName;&lt;br /&gt;
             iDeviceFactory = aDeviceFactory;&lt;br /&gt;
         } &lt;br /&gt;
 &lt;br /&gt;
         public IEnumerable&amp;amp;lt;uint&amp;amp;gt; WidgetClasses&lt;br /&gt;
         {&lt;br /&gt;
             get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         public void WidgetDiscovered(&lt;br /&gt;
             string aWidgetUdn,&lt;br /&gt;
             uint aWidgetClass,&lt;br /&gt;
             ISimpleUpnpWidget aSimpleUpnpWidget)&lt;br /&gt;
         {&lt;br /&gt;
             string newUdn = aWidgetUdn;&lt;br /&gt;
             DiscoveredWidget discoveredWidget = new DiscoveredWidget&lt;br /&gt;
                 (iDeviceFactory,&lt;br /&gt;
                  newUdn,&lt;br /&gt;
                  aSimpleUpnpWidget,&lt;br /&gt;
                  iWidgetPublisher);&lt;br /&gt;
 &lt;br /&gt;
             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                 discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                 discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                 discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary = &lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in OpenHome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by OpenHome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh - A collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs on ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The OpenHome Operating System. Core software for OpenHome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. &lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. A typical Widget supports only one protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Driver_Development</id>
		<title>OhWidget Driver Development</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Driver_Development"/>
				<updated>2012-03-01T15:19:24Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Constructor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for developers using the OpenHome SDK to integrate a Widget into an OpenHome system. Each Widget must have its own driver to allow it to communicate with the OpenHome Nodes. &lt;br /&gt;
&lt;br /&gt;
To help you write your driver, this document provides high level descriptions of the core responsibilities of a Widget driver and gives a detailed walk-through using example code.&lt;br /&gt;
&lt;br /&gt;
Full versions of each file used in the development of the example driver are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin development of your Widget driver you must be in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* your Widget Service XML that describes the properties on your Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document does not contain advice on how to write Widget Service XML. Refer to the OpenHome Widget Service XML definition document for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK&lt;br /&gt;
* your chosen communication protocol's API&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The protocol you choose for your Widgets must be the same protocol used on your choice of Node.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document focuses on the development of the Widget driver. Details about the communications protocol used are beyond the scope of this document. This document assumes you are familiar with your chosen protocol's code libraries and are able to use them in the driver code you write.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Related Documents ==&lt;br /&gt;
&lt;br /&gt;
The following related OpenHome documentation may be of interest to you:&lt;br /&gt;
&lt;br /&gt;
* [[ohWidget Technical Overview|ohWidget Technical Overview]]&lt;br /&gt;
* [[OpenHome Widget Service XML definition|OpenHome Widget Service XML definition]]&lt;br /&gt;
* [http://www.openhome.org/releases/ohNet_DeviceStack.pdf  OpenHome ohNet Device Stack]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
None of the related documents listed above is mandatory reading for Widget driver development.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
== Widget Service XML ==&lt;br /&gt;
OpenHome Widget driver writing relies heavily on the use of code generated from a single source — the Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
The service and actions your Widget provides are represented in code in a file called a Provider. The Provider is automatically generated from the Widget Service XML and produces an abstract class for you to inherit when you write your concrete class driver.&lt;br /&gt;
&lt;br /&gt;
To aid in the explanation of how the Provider is created and put to use we will follow the development of&lt;br /&gt;
a driver for a simple light Widget; taking the defined Widget Service XML and stepping through how it is used to generate the other files. Examples of code are used throughout this document to show you how each one is created and used in an OpenHome system. &lt;br /&gt;
&lt;br /&gt;
It is essential that you start with a well-formed Widget Service XML, conforming to the schema defined&lt;br /&gt;
in the WidgetService.xsd. The following diagram shows the significance of the Widget Service XML in&lt;br /&gt;
relation to the generated files you will use when writing your driver:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarchy, highlighting the areas specifically used in driver development]]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* The grayed-out files are not relevant to Widget driver development but can also be generated from the Widget Service XML.&lt;br /&gt;
* The Provider is generated in C#, meaning your driver must be written in C# as well. The use of managed code is mandatory for driver writing in the OpenHome framework.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Code sample used in this document ==&lt;br /&gt;
&lt;br /&gt;
Our examples in this document use a Widget Service XML definition for a light Widget called&lt;br /&gt;
BasicLight.xml.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Full versions of all the example files used in this document are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We will see how the Provider is generated from this XML and how it is used to aid the driver writing process. The examples also show how your chosen communication protocol should be used in the body of the driver code.&lt;br /&gt;
&lt;br /&gt;
Implementation details of specific protocols you choose to use are beyond the scope of this document. However, the samples used in this document show the use of the SimpleUPnP protocol to aid you in your development process.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol during the early stages of the OpenHome project. It is included in the OpenHome SDK and can be used as a public resource. &lt;br /&gt;
&lt;br /&gt;
The use of SimpleUPnP in the example files and the code snippets within the following sections is highlighted by the [[File:Warning.png]] icon. The lines of code marked by [[File:Warning.png]] must be changed to code from your chosen communication protocol's library. SimpleUPnP is left in to help you understand how a protocol is used in a working example.&lt;br /&gt;
&lt;br /&gt;
The sample code provided attempts to show best-practice coding standards. There are several sections of code that have a mandatory layout or that call specifically named methods and functions. These areas of the code are highlighted where required. &lt;br /&gt;
&lt;br /&gt;
Where the examples do not explicitly state that the code shown is mandatory, you are free to implement it in a different way according to your own coding style and practices.&lt;br /&gt;
&lt;br /&gt;
= Driver responsibilities = &lt;br /&gt;
&lt;br /&gt;
== Driver responsibilities ==&lt;br /&gt;
&lt;br /&gt;
An OpenHome Widget driver has several responsibilities which must be met before it can be used on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
These responsibilities are listed R1 to R7 and are defined here, explaining what each one must do. &lt;br /&gt;
&lt;br /&gt;
=== R1 Specifying the type of Widget the driver controls ===&lt;br /&gt;
A driver must know which type of Widget it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
=== R2 Reacting to a discovered Widget on the network ===&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== R3 Setting the initial values for the Widget's properties ===&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
=== R4 Publishing discovered Widgets in the Local Widget Registry on the Node ===&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object.&lt;br /&gt;
&lt;br /&gt;
=== R5 Reacting to an event reported from the Widget ===&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
=== R6 Reacting to actions sent to the Widget ===&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== R7 Reacting to a Widget's departure ===&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no&lt;br /&gt;
longer available.&lt;br /&gt;
&lt;br /&gt;
The sections of example code that follow show you how to write a driver from beginning to end. The accompanying text explaining the example code highlights when a responsibility, or part of a responsibility, has been met.&lt;br /&gt;
&lt;br /&gt;
= Driver Architecture = &lt;br /&gt;
&lt;br /&gt;
== Driver Architecture ==&lt;br /&gt;
&lt;br /&gt;
Drivers are installed on the Node and used when the Node needs to communicate with the Widget. Drivers&lt;br /&gt;
use several objects to communicate with Widgets over the Widget's lifetime. Figure 2 shows the objects&lt;br /&gt;
used by the driver and how the responsibilities listed above relate to each one:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture.png|800px|thumb|center|Figure 2: The architecture of a driver, showing the driver's relationship to the objects used to communicate with a Widget. Lines between objects show message flow.]]&lt;br /&gt;
&lt;br /&gt;
The objects contained in the dotted boundary must appear in the code you write to define your driver. The Driver, Provider and IWidgetRegistryEntry objects are all contained in the same driver file. We begin discussing this on page 12. &lt;br /&gt;
&lt;br /&gt;
The other objects are provided by the OpenHome SDK or as installed components on the Node.&lt;br /&gt;
&lt;br /&gt;
The Discovery Module informs the driver of the presence of an available Widget.&lt;br /&gt;
&lt;br /&gt;
Each Node has a Protocol Module which contains the protocol's API. Widgets can communicate with OpenHome Nodes using any one of the set of communications protocols the Node supports. The driver uses your chosen protocol's Protocol Module to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
Both the Protocol Module and the Discovery Module are installed on the Node. When you write your&lt;br /&gt;
driver you will use your Protocol Module to allow the driver to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
IWidgetPublisher, IPublishedWidget and DvDevice are objects provided in the OpenHome&lt;br /&gt;
API. You can read about them in the APIs.&lt;br /&gt;
&lt;br /&gt;
= Generating the Provider = &lt;br /&gt;
&lt;br /&gt;
== Generating the Provider ==&lt;br /&gt;
&lt;br /&gt;
You must generate your provider before you can begin writing your Widget driver. You use your provider as a guide to implement the functions your Widget needs to set the values of its properties.&lt;br /&gt;
&lt;br /&gt;
The current provider generation process is a manual one involving the use of a text transform tool.&lt;br /&gt;
&lt;br /&gt;
Speak to your OpenHome contact who will help you generate your provider.&lt;br /&gt;
&lt;br /&gt;
Future releases of the OpenHome SDK will include a tool to help you generate the provider.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
You must be in possession of:&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK, unpacked on your computer&lt;br /&gt;
* your Widget Service XML file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Writing a SimpleUPnP driver = &lt;br /&gt;
&lt;br /&gt;
== Introduction to the SimpleUPnP protocol ==&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol used to control emulated Widgets over a custom UPnP service.&lt;br /&gt;
&lt;br /&gt;
This chapter shows how a driver is written using the SimpleUPnP communications protocol. The aim is to show the code using as generic a protocol as possible so that you can see where your own protocol specific code needs to go.&lt;br /&gt;
&lt;br /&gt;
The use of code specific to the SimpleUPnP implementation is highlighted by the use of the [[File:Warning.png]] icon. The lines of code are marked by this icon to make it easier for you to see where the protocol-specific code must go and what parts of the code are generic.&lt;br /&gt;
&lt;br /&gt;
=== Register model ===&lt;br /&gt;
&lt;br /&gt;
SimpleUPnP is modeled on 8 physical registers available on the Widget. Each register is 32-bits wide. They are indexed from 0 to 7 and the last register (register 7) is reserved for storing the Widget's class.&lt;br /&gt;
&lt;br /&gt;
This detail is used by the Protocol Module on the Node to determine which driver is needed to run the new Widget when it has been discovered.&lt;br /&gt;
&lt;br /&gt;
The remaining 7 registers (registers 0 to 6) are free for Widget engineers to assign to the Widget's functions.&lt;br /&gt;
&lt;br /&gt;
Registers 0, 1, 2 and 3 are available as read/write registers. Registers 4, 5 and 6 are readonly registers.&lt;br /&gt;
&lt;br /&gt;
Only the emulated hardware (running on the Node) can change the values held in registers 4, 5 and 6.&lt;br /&gt;
&lt;br /&gt;
=== Register use in drivers ===&lt;br /&gt;
&lt;br /&gt;
In the example that follows we have a Basic Light Widget with a very simple function: it can be turned on and turned off. The on/off value is stored in register 0, with values 0=OFF and 1=ON. Register 0 is a read/write register. This means we can change the value stored there using messages passed to the Widget from the Node, and by reacting to physical interactions at the Widget (such as someone manually switching the light on or off). &lt;br /&gt;
&lt;br /&gt;
The mapping of registers to properties on the Widget is decided by the engineers who manufacture the device. You must be provided with the mapping before you begin developing your driver.&lt;br /&gt;
&lt;br /&gt;
== Starting the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-BoxHighlight.png|800px|thumb|center|Figure 3 The driver architecture highlighting the Widget driver and its component parts.]]&lt;br /&gt;
&lt;br /&gt;
When you have generated the abstract provider you can put it to use in the Widget driver. A Widget driver&lt;br /&gt;
has three distinct components:&lt;br /&gt;
&lt;br /&gt;
* an implementation of your abstract provider&lt;br /&gt;
* a definition of the Widget driver&lt;br /&gt;
* an implementation of the IWidgetRegistryEntry interface&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must manually write the code for your Widget driver. The differences in implementation of Widget properties and communication protocols means that the driver code cannot be autogenerated.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This section takes you through how to write a Widget driver by implementing the auto-generated provider,&lt;br /&gt;
starting from a new blank file and finishing with a working driver for the Basic Light Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
No assumptions have been made about the type of editor you use to write your code. Shortcuts&lt;br /&gt;
or macros that you use as standard will not appear in the instructions below. A full example&lt;br /&gt;
BinaryLightDriver.cs is available to review in Appendix C.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a new C# file in your IDE. Ensure the following libraries are used:&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 [[File:Warning.png]]using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 namespace OpenHome.Widget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must use the libraries listed above for this specific example.&lt;br /&gt;
&lt;br /&gt;
In general, drivers require the following libraries:&lt;br /&gt;
* System*&lt;br /&gt;
* System.Collections.Generic*&lt;br /&gt;
* OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
&lt;br /&gt;
Your driver will fail to compile if you miss any of these listed libraries. Libraries marked * are typically added by default by most modern IDEs. &lt;br /&gt;
&lt;br /&gt;
The OpenHome.Widget.Protocols.SimpleUpnp library is required only in this SimpleUPnP example. Drivers using a different protocol will use their own protocol library.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Implementing the provider ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-ProviderHighlight.png|800px|thumb|center|Figure 4 The driver architecture highlighting the Provider's place]]&lt;br /&gt;
&lt;br /&gt;
You use your auto-generated abstract provider by writing an implementation of it in the driver file. Responsibilities met by implementing your auto-generated provider are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R6 Reacting to actions sent to the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
Begin by creating a new class. It will subclass the abstract auto-generated provider:&lt;br /&gt;
&lt;br /&gt;
 class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
The Protocol Module will provide an API for the Provider to use to communicate with the Widget. In&lt;br /&gt;
SimpleUPnP we are provided with an interface called ISimpleUpnpWidget. The provider is supplied&lt;br /&gt;
with the required instance of the interface by the Discovery Module on the Node.&lt;br /&gt;
&lt;br /&gt;
The mechanisms for registering providers with specific Protocol Modules, and for the way the module gives each provider its required interface are covered later when writing the discovery method.&lt;br /&gt;
&lt;br /&gt;
For now, we need to give the Provider a place to store the interface that it will later use to communicate&lt;br /&gt;
with the Widget:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]] private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
&lt;br /&gt;
The interface from the Protocol Module is passed in as a parameter in the Provider's constructor and then&lt;br /&gt;
assigned to the variable we just created:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightProvider(DvDevice aDevice,&lt;br /&gt;
 [[File:Warning.png]]         ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
 {&lt;br /&gt;
       iProtocol = aProtocol;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
To satisfy R3 we would normally set the Widget's properties here, giving them an initial value.&lt;br /&gt;
However, in this specific example we cannot set the value of Basic Light's only property because&lt;br /&gt;
we will never know, in advance, what the state of the light will be (either on or off) when we&lt;br /&gt;
create the DiscoveredWidget.&lt;br /&gt;
&lt;br /&gt;
When you cannot set the properties ahead of time, and you are using an eventing protocol like SimpleUPnP, you can instead set them in the HandleRegisterEvent method in the driver class. This also satisfies the requirements for R3. You must set the Widget's properties before you enable it using SetEnabled(). &lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The abstract provider includes an abstract method called SetOn. This method is invoked by the Node when passing a message to the Widget, specifically to set the on property of the Widget to either 0 or 1. The implementation of this method will meet the requirements for R6.&lt;br /&gt;
&lt;br /&gt;
We must override this method and provide the protocol module a way of passing a message on to the Widget to perform the required action, in this case turn the light on or off:&lt;br /&gt;
&lt;br /&gt;
          protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
          {&lt;br /&gt;
     [[File:Warning.png]]        iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
In this example the Basic Light's SetOn property (the boolean property that controls whether the light is&lt;br /&gt;
on or off) is represented in the physical Widget by the register that has an index of 0.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* This method is an example of an action on a Widget. Actions are messages sent from the Node to the Widget. We will see later how to handle events that need to be passed back from the Widget&lt;br /&gt;
to the Node.&lt;br /&gt;
* Your own Widget will likely provide more than a single property. Your auto-generated provider will contain one abstract method to represent each writable property. Read-only properties are not provided an abstract method.&lt;br /&gt;
&lt;br /&gt;
You must implement each abstract method in your driver to ensure the relevant property on&lt;br /&gt;
the Widget can be set.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We have now finished implementing the provider. The next step is to implement the driver.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Implementing the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-DriverHighlight.png|800px|thumb|center|Figure 4: The driver architecture highlighting the implemented driver's place.]]&lt;br /&gt;
&lt;br /&gt;
The code for your Widget driver must provide an implementation of the IWidgetRegistryInterface,&lt;br /&gt;
including the following tasks:&lt;br /&gt;
&lt;br /&gt;
* methods to expose identifying details about the Widget for the Node to access&lt;br /&gt;
* providing methods to handle events reported by the Widget&lt;br /&gt;
&lt;br /&gt;
The driver is implemented as a public class within the same file as the provider code. Each driver must use the interface for the protocol you are using. For the SimpleUPnP protocol the interface is ISimple-UpnpWidgetDriver.&lt;br /&gt;
&lt;br /&gt;
=== Writing code ===&lt;br /&gt;
&lt;br /&gt;
Create your new driver class and subclass the ISimpleUpnpWidgetDriver interface:&lt;br /&gt;
&lt;br /&gt;
 public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Implementing IWidgetRegistryEntry ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry is the interface you use to represent physical Widgets. It is implemented as a subclass of your driver class. We are going to implement this interface in a class called '''DiscoveredWidget'''.&lt;br /&gt;
&lt;br /&gt;
Let's return to our driver architecture diagram for a moment:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-IRegistryEntryHighlight.png|800px|thumb|center|Figure 5 The driver architecture highlighting the IWidgetRegistryEntry object you will now implement]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry uses several other objects to help create it and respond to messages sent to and from it. These objects will be created in our implementation of DiscoveredWidget. &lt;br /&gt;
&lt;br /&gt;
When successfully created and published, the DiscoveredWidget objects are stored in a list on the Node called the Local Widget Registry. The Local Widget Registry is used by Nodes to maintain contact with the Widgets they control.&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry is shown at the top of Figure 5, marked plainly as (Registry). The path to the Local Widget Registry goes through several layers of Node architecture which are not relevant to Widget driver writing, so are not shown in the diagrams.&lt;br /&gt;
&lt;br /&gt;
==== Writing code ====&lt;br /&gt;
&lt;br /&gt;
Start by subclassing the IWidgetRegistryEntry interface in your new class:&lt;br /&gt;
&lt;br /&gt;
      private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
      {&lt;br /&gt;
&lt;br /&gt;
A DiscoveredWidget must provide the driver with the objects required to present the Widget and its&lt;br /&gt;
properties to the Node:&lt;br /&gt;
&lt;br /&gt;
           private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
           private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
           private readonly ISimpleUpnpWidget iProtocol;&lt;br /&gt;
           private readonly BinaryLightProvider iProvider;&lt;br /&gt;
           private readonly DvDevice iDvDevice;&lt;br /&gt;
           private IPublishedWidget iPublishedWidget;&lt;br /&gt;
&lt;br /&gt;
Each of the attributes in the example above are defined as follows:&lt;br /&gt;
&lt;br /&gt;
iDeviceFactory — used by the driver to create a single instance of DvDevice to represent a single Widget&lt;br /&gt;
&lt;br /&gt;
iPublisher — used by the driver to publish the Widget to the Node&lt;br /&gt;
&lt;br /&gt;
iProtocol — the object used by the Widget to communicate with the Protocol Module on the Node&lt;br /&gt;
&lt;br /&gt;
iProvider — an instantiated provider of the type you defined earlier&lt;br /&gt;
&lt;br /&gt;
iDvDevice — a representation of a Widget to which the provider is attached, created using iDevice-Factory above&lt;br /&gt;
&lt;br /&gt;
iPublishedWidget — used to contain the returned object from a successful publishing of the Widget&lt;br /&gt;
If we look again at the driver architecture diagram, we ca highlight the objects we've just defined:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-Highlight.png|800px|thumb|center|Figure 6: The driver architecture highlighting the objects used by the IWidgetRegistryEntry implementation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The DeviceFactory, defined above in the member variable iDeviceFactory, is used to create new DvDevice objects. The DeviceFactory is only ever used to do this once. It is not shown in the driver architecture diagrams due to its minimal role in the operation of a driver, but it would normally appear between the IWidgetRegistryEntry and DvDevice objects.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
A driver requires methods to expose identifying details about the Widget. We must provide access to two of the attributes we just defined above:&lt;br /&gt;
&lt;br /&gt;
 public DvDevice DvDevice&lt;br /&gt;
 {&lt;br /&gt;
     get { return iDvDevice; }&lt;br /&gt;
 }&lt;br /&gt;
 public string WidgetClass&lt;br /&gt;
 {&lt;br /&gt;
     get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The WidgetClass string is formed using a combination of the vendor name and the Widget's name in the&lt;br /&gt;
format:&lt;br /&gt;
&lt;br /&gt;
 [vendor_domain]:[widget_name]&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry can now query both the DvDevice object representing the Widget, and the specific class of Widget this driver represents. The other member variables we defined do not need their own accessor methods.&lt;br /&gt;
&lt;br /&gt;
Now we must write a constructor for DiscoveredWidget and assign the parameters accordingly: &lt;br /&gt;
&lt;br /&gt;
 public DiscoveredWidget(IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                            string aUdn,&lt;br /&gt;
                            ISimpleUpnpWidget aProxy,&lt;br /&gt;
                            IWidgetPublisher aPublisher)&lt;br /&gt;
 {&lt;br /&gt;
      iDeviceFactory = aDeviceFactory;&lt;br /&gt;
      iProtocol = aProtocol;&lt;br /&gt;
      iPublisher = aPublisher;&lt;br /&gt;
      iDvDevice = iDeviceFactory.CreateDevice(aUdn);&lt;br /&gt;
      iProvider = new BinaryLightProvider(iDvDevice,&lt;br /&gt;
      iProtocol);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Event handling ===&lt;br /&gt;
&lt;br /&gt;
A Widget's state can change in one of three significant ways:&lt;br /&gt;
&lt;br /&gt;
* when the Widget needs to be published on the Node&lt;br /&gt;
* when the Widget disappears from the network (by losing power or similar)&lt;br /&gt;
* when a property's state changes and must be updated to a new value&lt;br /&gt;
&lt;br /&gt;
We now need methods to handle these changes.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The methods we define here will be used as callbacks, rather than invoked as method calls. We define the methods here first and then use them later on. We will use the Protocol Module to listen for changes in the Widget's state and register these methods as callbacks there. See Writing the SimpleUPnP Widget discovery method for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this section of the driver are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R4 Publishing discovered Widgets in the Local Widget Registry on the Node'''&lt;br /&gt;
&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object. &lt;br /&gt;
&lt;br /&gt;
'''R5 Reacting to an event reported from the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
'''R7 Reacting to a Widget's departure'''&lt;br /&gt;
&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no longer available.&lt;br /&gt;
&lt;br /&gt;
==== Enabling and publishing a discovered Widget ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first method initializes the Widget by enabling the device and then using the IWidgetPublisher&lt;br /&gt;
to make it available on the Node:&lt;br /&gt;
&lt;br /&gt;
 public void HandleInitialEvent()&lt;br /&gt;
 {&lt;br /&gt;
      iDvDevice.SetEnabled();&lt;br /&gt;
      iPublisher.TryPublishWidget(iDvDevice.iUdn(),&lt;br /&gt;
                              this,&lt;br /&gt;
                              out iPublishedWidget);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This method meets the requirements for R4.&lt;br /&gt;
&lt;br /&gt;
The call to TryPublishWidget returns an iPublishedWidget object. We use this object later to satisfy the requirements of R7.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The ordering of the calls to SetEnabled and TryPublishWidget is vitally important. You&lt;br /&gt;
must enable the device before you attempt to publish it. Your Widget will not be available to the&lt;br /&gt;
Nodes unless SetEnabled is called first. Nodes will not be able to access a published device&lt;br /&gt;
that has not been enabled.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
R3 requires that you set the Widget's properties before you enable and publish the device. We&lt;br /&gt;
discussed on page 14 how some properties can only be set after the Widget reports what their&lt;br /&gt;
state is. We do this in HandleRegisterEvent.&lt;br /&gt;
&lt;br /&gt;
We rely on the SimpleUPnP Protocol Module guaranteeing a call to HandleRegisterEvent first before HandleInitialEvent. This is informed by guarantees made by the Control Point stack that the calls will be made in that order.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
==== Removing a Widget ====&lt;br /&gt;
&lt;br /&gt;
Removing a Widget involves unpublishing it from the Node. The IPublishedWidget interface provides us with a method we can call to manage that for us:&lt;br /&gt;
&lt;br /&gt;
 public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
 {&lt;br /&gt;
     if (iPublishedWidget != null)&lt;br /&gt;
     { iPublishedWidget.Unpublish(); }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assuming that the Widget was successfully published earlier, it is removed from the Node's Local Widget Registry.&lt;br /&gt;
&lt;br /&gt;
We must also properly handle the resources we used to create and maintain the Widget object while it was published:&lt;br /&gt;
&lt;br /&gt;
      iProvider.Dispose();&lt;br /&gt;
      iDvDevice.Dispose();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The calls to Dispose are made regardless of the Widget's published state, ensuring that any created device and associated provider are properly disposed. This implementation satisfies R7.&lt;br /&gt;
&lt;br /&gt;
====Event handling ====&lt;br /&gt;
&lt;br /&gt;
We need a method to handle changes to the state of the Widget's properties.&lt;br /&gt;
&lt;br /&gt;
If the property changes at the Widget, it needs to pass the new state back to the Node so that it is kept up-to-date on the Widget's status. This is called an event. An example in the case of our Basic Light is someone manually switching the light from on to off. This is in contrast to actions, which are passed from the Node to the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Other examples of events involve no human interaction, such as a thermometer Widget updating its current temperature based on environmental changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Our Basic Light Widget has only one property that needs to be handled:&lt;br /&gt;
&lt;br /&gt;
 public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
 {&lt;br /&gt;
     if (aIndex == 0)&lt;br /&gt;
     {&lt;br /&gt;
         iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We use our instance of the provider to update the register on the Widget that is mapped to the On property. This in turn updates the Node with the new state of the Widget.&lt;br /&gt;
&lt;br /&gt;
This method provides implementations to satisfy two driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
* R3 is now completely satisfied, as we can now set the values of all the previously unknown properties here.&lt;br /&gt;
* R5 is also satisfied as this method allows us to update the Widget's status on the Node when a property is changed on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Not all protocols pass messages back to the Node in this manner. The way we have satisfied R3 and R5 here only applies to protocols and Widgets that support this behavior.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Widgets that do not use an eventing protocol need to have their properties set in the provider's constructor to satisfy R3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To satisfy R5, the over-ridden method SetOn in the provider must include the call to SetPropertyOn. Non-eventing protocols do not require a HandleRegisterEvent method.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Constructor ===&lt;br /&gt;
&lt;br /&gt;
The final requirement for the driver is the constructor so that new DiscoveredWidget objects can be created. &lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this area of code are:&lt;br /&gt;
&lt;br /&gt;
'''R1 Specifying the type of Widget the driver controls'''&lt;br /&gt;
&lt;br /&gt;
A driver must know which type of Widget that it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
==== Writing the code ====&lt;br /&gt;
&lt;br /&gt;
We begin by defining the variables we will use to store the objects used by the driver:&lt;br /&gt;
&lt;br /&gt;
 private readonly string iName;&lt;br /&gt;
 private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
 private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now write the constructor for the driver and assign the passed in parameters appropriately:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightDriver(string aName,&lt;br /&gt;
                IWidgetPublisher aPublisher,&lt;br /&gt;
                IDvDeviceFactory aDeviceFactory)&lt;br /&gt;
 {&lt;br /&gt;
     iWidgetPublisher = aPublisher;&lt;br /&gt;
     iName = aName;&lt;br /&gt;
     iDeviceFactory = aDeviceFactory;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally we need to provide the driver a way to publish the class of Widget it controls. This information is requested by the Discovery Module and is used to ensure the Node uses the correct driver when a new Widget appears.&lt;br /&gt;
&lt;br /&gt;
The implementation for this details will be different for each protocol. The SimpleUPnP protocol library provides a file that contains the SimpleUPnP definitions as integers. Each integer represents a particular class of identified Widget.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP implementation of that method is as follows:&lt;br /&gt;
&lt;br /&gt;
 public IEnumerable&amp;lt;uint&amp;gt; WidgetClasses&lt;br /&gt;
 {&lt;br /&gt;
 [[File:Warning.png]]        get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The body of this method is specifically written for the Widget class we are defining (in this case a binary light). This method completes the driver's requirements for R1.&lt;br /&gt;
&lt;br /&gt;
== Writing the SimpleUPnP Widget discovery method ==&lt;br /&gt;
&lt;br /&gt;
Every driver must contain a method which creates new objects to represent newly discovered Widgets.&lt;br /&gt;
The Discovery Module invokes this method to begin the process of creating the objects required to allow the Node to access the Widget. &lt;br /&gt;
&lt;br /&gt;
The name of this method is dictated by your chosen protocol's API. The SimpleUPnP protocol requires a method called WidgetDiscovered.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The method's name will not always be the same for each protocol. Your protocol's documentation will contain the details of what this method must be called.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This method and its implementation will meet the following driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
'''R2 Reacting to a discovered Widget on the network'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
Our implementation of the WidgetDiscovered method will create a new DiscoveredWidget object and use the Protocol Module to listen for changes to the Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
The method uses the Protocol Module and two ways to identify the Widget. We must pass these in as&lt;br /&gt;
parameters:&lt;br /&gt;
&lt;br /&gt;
 public void WidgetDiscovered(string aWidgetUdn,&lt;br /&gt;
                              uint aWidgetClass,&lt;br /&gt;
                              ISimpleUpnpWidget&lt;br /&gt;
                                  aSimpleUpnpWidget)&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
Every Widget that uses this driver must be uniquely identifiable:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]    string newUdn = aWidgetUdn;&lt;br /&gt;
&lt;br /&gt;
Each new Widget is represented by a DiscoveredWidget object. Create the new DiscoveredWidget and pass in the required parameters we created earlier:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
     DiscoveredWidget discoveredWidget =&lt;br /&gt;
                 new DiscoveredWidget(iDeviceFactory,&lt;br /&gt;
                                      newUdn,&lt;br /&gt;
  &lt;br /&gt;
 [[File:Warning.png]]                                    aSimpleUpnpWidget,&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Registering the callbacks ===&lt;br /&gt;
&lt;br /&gt;
Finally, we ask the Widget's protocol interface to listen for calls to the handler methods we defined earlier in DiscoveredWidget. We do this by registering those methods as callbacks for the Protocol Module&lt;br /&gt;
to listen for:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                        discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                        discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                        discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You have now met 100% of the driver responsibility requirements and have a working driver to use with your SimpleUPnP Widget.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix A. Sample XML =&lt;br /&gt;
&lt;br /&gt;
== Binary Light.xml ==&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
  &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
  &amp;lt;version&amp;gt;&lt;br /&gt;
   &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
   &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/version&amp;gt;&lt;br /&gt;
  &amp;lt;propertylist&amp;gt;&lt;br /&gt;
   &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
       illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
   &amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix B. Sample Provider = &lt;br /&gt;
&lt;br /&gt;
== DvWidgetOpenhomeOrgBasicLight1.cs ==&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Runtime.InteropServices;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Core;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Utils.Binary;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
 {&lt;br /&gt;
    public interface IDvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
        IDisposable&lt;br /&gt;
    {&lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous value&lt;br /&gt;
        /// &amp;lt;/returns&amp;gt;&lt;br /&gt;
        bool SetPropertyOn(bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;Property's value will be copied&lt;br /&gt;
        /// here&amp;lt;/param&amp;gt;&lt;br /&gt;
        bool PropertyOn();&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt; summary&amp;gt;&lt;br /&gt;
    /// Provider for the openhome.org:BinaryLight:1 UPnP service&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public abstract class DvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
               DvProvider,&lt;br /&gt;
               IDisposable,&lt;br /&gt;
               IDvProviderOpenhomeOrgBinaryLight1&lt;br /&gt;
    {&lt;br /&gt;
        private GCHandle iGch;&lt;br /&gt;
        private PropertyBool iPropertyOn;&lt;br /&gt;
        private PropertyUint iPropertyPrimarySeq;&lt;br /&gt;
        private PropertyUint iPropertySecondarySeq;&lt;br /&gt;
        private ActionDelegate iDelegateSetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetPrimaryProperty;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Constructor&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aDevice&amp;quot;&amp;gt;Device which owns this&lt;br /&gt;
        /// provider&amp;lt;/param&amp;gt;&lt;br /&gt;
        protected DvProviderOpenhomeOrgBinaryLight1(DvDevice aDevice)&lt;br /&gt;
            : base(aDevice, &amp;quot;openhome.org&amp;quot;, &amp;quot;GenericWidget&amp;quot;, 1)&lt;br /&gt;
        {&lt;br /&gt;
            iGch = GCHandle.Alloc(this);&lt;br /&gt;
            List&amp;lt;String&amp;gt; allowedValues = new List&amp;lt;String&amp;gt;();&lt;br /&gt;
            iPropertyOn = new PropertyBool(new ParameterBool(&amp;quot;On&amp;quot;));&lt;br /&gt;
            iPropertyPrimarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;PrimarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertyPrimarySeq);&lt;br /&gt;
            iPropertySecondarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;SecondarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertySecondarySeq);&lt;br /&gt;
            SetPropertyUint(iPropertyPrimarySeq, 0);&lt;br /&gt;
            SetPropertyUint(iPropertySecondarySeq, 0);&lt;br /&gt;
  &lt;br /&gt;
            Zapp.Core.Action action = new Zapp.Core.Action&lt;br /&gt;
                (&amp;quot;SetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;FireAndForget&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddInputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateSetProperty = new ActionDelegate(DoSetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateSetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateGetProperty = new ActionDelegate(DoGetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetPrimaryProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                 (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;integer&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;boolean&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;string&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;binary&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Type&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;readWrite&amp;quot;);allowedValues.Add&lt;br /&gt;
                (&amp;quot;readOnly&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;writeOnly&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString(&amp;quot;Access&amp;quot;,&lt;br /&gt;
                allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            iDelegateGetPrimaryProperty = new&lt;br /&gt;
            ActionDelegate(DoGetPrimaryProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetPrimaryProperty,&lt;br /&gt;
            GCHandle.ToIntPtr(iGch));&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous&lt;br /&gt;
        /// value&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool SetPropertyOn(bool aValue)&lt;br /&gt;
        {&lt;br /&gt;
            if (iPropertyOn.SetValue(aValue))&lt;br /&gt;
            {&lt;br /&gt;
                lock (iPropertyPrimarySeq)&lt;br /&gt;
                {&lt;br /&gt;
                    SetPropertyUint(iPropertyPrimarySeq,&lt;br /&gt;
                        iPropertyPrimarySeq.Value() + 1);&lt;br /&gt;
                } return true;&lt;br /&gt;
            } return false;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;The value of the property&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool PropertyOn()&lt;br /&gt;
        {&lt;br /&gt;
            return iPropertyOn.Value();&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the On property.&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aVersion&amp;quot;&amp;gt;Version of the service being&lt;br /&gt;
        /// requested (will be &amp;lt;= the version advertised)&amp;lt;/param&amp;gt; &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the On property.&lt;br /&gt;
        /// &amp;lt;/param&amp;gt;&lt;br /&gt;
        protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        private static int DoSetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                byte[] valBin = invocation.ReadBinary(&amp;quot;Value&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                switch (name)&lt;br /&gt;
                {&lt;br /&gt;
                    case &amp;quot;On&amp;quot;:&lt;br /&gt;
                        self.SetOn(aVersion, Converter.&lt;br /&gt;
                            BinaryToBoolean(valBin));&lt;br /&gt;
                        break;&lt;br /&gt;
                    default:&lt;br /&gt;
                        throw new ActionError();&lt;br /&gt;
                }&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
                invocation.WriteEnd();&lt;br /&gt;
            }&lt;br /&gt;
            catch (ActionError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
            catch (PropertyUpdateError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
        return 0;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        private static int DoGetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
            switch (name)&lt;br /&gt;
            {&lt;br /&gt;
                case &amp;quot;On&amp;quot;:&lt;br /&gt;
                invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                    Converter.BooleanToBinary(self.iPropertyOn.&lt;br /&gt;
                        Value()));&lt;br /&gt;
                break;&lt;br /&gt;
                default:&lt;br /&gt;
                throw new ActionError();&lt;br /&gt;
            }&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    private static int DoGetPrimaryProperty(IntPtr aPtr,&lt;br /&gt;
                    IntPtr aInvocation,&lt;br /&gt;
                    uint aVersion)&lt;br /&gt;
    {&lt;br /&gt;
        GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
        DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
            (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
        DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
  &lt;br /&gt;
        try&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReadStart();&lt;br /&gt;
            invocation.ReadEnd();&lt;br /&gt;
            invocation.WriteStart();&lt;br /&gt;
            invocation.WriteString(&amp;quot;Name&amp;quot;, &amp;quot;On&amp;quot;);&lt;br /&gt;
            invocation.WriteString(&amp;quot;Type&amp;quot;, &amp;quot;boolean&amp;quot;);&lt;br /&gt;
            invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                Converter.BooleanToBinary(self.iPropertyOn.Value()));&lt;br /&gt;
            invocation.WriteString(&amp;quot;Access&amp;quot;, &amp;quot;readWrite&amp;quot;);&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt;summary&amp;gt;&lt;br /&gt;
    /// Must be called for each class instance. Must be called before&lt;br /&gt;
    /// Core.Library.Close().&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public void Dispose()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
        GC.SuppressFinalize(this);&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
    ~DvProviderOpenhomeOrgBinaryLight1()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
        private void DoDispose()&lt;br /&gt;
        {&lt;br /&gt;
            lock (this)&lt;br /&gt;
            {&lt;br /&gt;
                if (iHandle == IntPtr.Zero)&lt;br /&gt;
            {&lt;br /&gt;
                    return;&lt;br /&gt;
            }&lt;br /&gt;
            DisposeProvider();&lt;br /&gt;
            iPropertyOn.Dispose();&lt;br /&gt;
            iHandle = IntPtr.Zero;&lt;br /&gt;
            }&lt;br /&gt;
            iGch.Free();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix C. Sample Driver = &lt;br /&gt;
&lt;br /&gt;
== BasicLightDriver.cs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.hWidget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
     class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
     {&lt;br /&gt;
         private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
         public BinaryLightProvider(DvDevice aDevice, &lt;br /&gt;
             ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol = aProtocol;&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
     {&lt;br /&gt;
         private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
         {&lt;br /&gt;
             private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
             private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
             private readonly ISimpleUpnpWidget iProtocol; &lt;br /&gt;
 &lt;br /&gt;
             private readonly BinaryLightProvider iProvider;&lt;br /&gt;
             private readonly DvDevice iDvDevice;&lt;br /&gt;
             private IPublishedWidget iPublishedWidget; &lt;br /&gt;
 &lt;br /&gt;
             public DvDevice DvDevice&lt;br /&gt;
             {&lt;br /&gt;
                 get { return iDvDevice; }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             public string WidgetClass&lt;br /&gt;
             {&lt;br /&gt;
                 get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public DiscoveredWidget(&lt;br /&gt;
                 IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                 string aUdn,&lt;br /&gt;
                 ISimpleUpnpWidget aProxy,&lt;br /&gt;
                 IWidgetPublisher aPublisher)&lt;br /&gt;
             {&lt;br /&gt;
                 iDeviceFactory = aDeviceFactory;&lt;br /&gt;
                 iProtocol = aProtocol;&lt;br /&gt;
 &lt;br /&gt;
                 iPublisher = aPublisher;&lt;br /&gt;
                 iDvDevice = iDeviceFactory.CreateDevice(aUdn);  &lt;br /&gt;
                 iProvider = new BinaryLightProvider(iDvDevice, &lt;br /&gt;
                                                     iProtocol);&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             public void HandleInitialEvent()&lt;br /&gt;
             {&lt;br /&gt;
                 iDvDevice.SetEnabled();&lt;br /&gt;
                 iPublisher.TryPublishWidget(iDvDevice.iUdn(), this,&lt;br /&gt;
                     out iPublishedWidget);&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
             {&lt;br /&gt;
                 if (iPublishedWidget != null)&lt;br /&gt;
                 {&lt;br /&gt;
                     iPublishedWidget.Unpublish();&lt;br /&gt;
                 } &lt;br /&gt;
                 iProvider.Dispose();&lt;br /&gt;
                 iDvDevice.Dispose();&lt;br /&gt;
             }  &lt;br /&gt;
 &lt;br /&gt;
             public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
             {&lt;br /&gt;
                 if (aIndex == 0)&lt;br /&gt;
                 {&lt;br /&gt;
                     iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         private readonly string iName;&lt;br /&gt;
         private readonly IDvDeviceFactory aDeviceFactory;&lt;br /&gt;
         private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
         &lt;br /&gt;
         public BinaryLightDriver(&lt;br /&gt;
             string aName,&lt;br /&gt;
             IWidgetPublisher aPublisher,&lt;br /&gt;
             iDeviceFactory aDeviceFactory)&lt;br /&gt;
         {&lt;br /&gt;
             iWidgetPublisher = aPublisher;&lt;br /&gt;
             iName = aName;&lt;br /&gt;
             iDeviceFactory = aDeviceFactory;&lt;br /&gt;
         } &lt;br /&gt;
 &lt;br /&gt;
         public IEnumerable&amp;amp;lt;uint&amp;amp;gt; WidgetClasses&lt;br /&gt;
         {&lt;br /&gt;
             get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         public void WidgetDiscovered(&lt;br /&gt;
             string aWidgetUdn,&lt;br /&gt;
             uint aWidgetClass,&lt;br /&gt;
             ISimpleUpnpWidget aSimpleUpnpWidget)&lt;br /&gt;
         {&lt;br /&gt;
             string newUdn = aWidgetUdn;&lt;br /&gt;
             DiscoveredWidget discoveredWidget = new DiscoveredWidget&lt;br /&gt;
                 (iDeviceFactory,&lt;br /&gt;
                  newUdn,&lt;br /&gt;
                  aSimpleUpnpWidget,&lt;br /&gt;
                  iWidgetPublisher);&lt;br /&gt;
 &lt;br /&gt;
             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                 discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                 discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                 discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary = &lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in OpenHome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by OpenHome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh - A collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs on ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The OpenHome Operating System. Core software for OpenHome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. &lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. A typical Widget supports only one protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Driver_Development</id>
		<title>OhWidget Driver Development</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Driver_Development"/>
				<updated>2012-03-01T15:19:09Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Removing a Widget */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for developers using the OpenHome SDK to integrate a Widget into an OpenHome system. Each Widget must have its own driver to allow it to communicate with the OpenHome Nodes. &lt;br /&gt;
&lt;br /&gt;
To help you write your driver, this document provides high level descriptions of the core responsibilities of a Widget driver and gives a detailed walk-through using example code.&lt;br /&gt;
&lt;br /&gt;
Full versions of each file used in the development of the example driver are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin development of your Widget driver you must be in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* your Widget Service XML that describes the properties on your Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document does not contain advice on how to write Widget Service XML. Refer to the OpenHome Widget Service XML definition document for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK&lt;br /&gt;
* your chosen communication protocol's API&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The protocol you choose for your Widgets must be the same protocol used on your choice of Node.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document focuses on the development of the Widget driver. Details about the communications protocol used are beyond the scope of this document. This document assumes you are familiar with your chosen protocol's code libraries and are able to use them in the driver code you write.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Related Documents ==&lt;br /&gt;
&lt;br /&gt;
The following related OpenHome documentation may be of interest to you:&lt;br /&gt;
&lt;br /&gt;
* [[ohWidget Technical Overview|ohWidget Technical Overview]]&lt;br /&gt;
* [[OpenHome Widget Service XML definition|OpenHome Widget Service XML definition]]&lt;br /&gt;
* [http://www.openhome.org/releases/ohNet_DeviceStack.pdf  OpenHome ohNet Device Stack]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
None of the related documents listed above is mandatory reading for Widget driver development.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
== Widget Service XML ==&lt;br /&gt;
OpenHome Widget driver writing relies heavily on the use of code generated from a single source — the Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
The service and actions your Widget provides are represented in code in a file called a Provider. The Provider is automatically generated from the Widget Service XML and produces an abstract class for you to inherit when you write your concrete class driver.&lt;br /&gt;
&lt;br /&gt;
To aid in the explanation of how the Provider is created and put to use we will follow the development of&lt;br /&gt;
a driver for a simple light Widget; taking the defined Widget Service XML and stepping through how it is used to generate the other files. Examples of code are used throughout this document to show you how each one is created and used in an OpenHome system. &lt;br /&gt;
&lt;br /&gt;
It is essential that you start with a well-formed Widget Service XML, conforming to the schema defined&lt;br /&gt;
in the WidgetService.xsd. The following diagram shows the significance of the Widget Service XML in&lt;br /&gt;
relation to the generated files you will use when writing your driver:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarchy, highlighting the areas specifically used in driver development]]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* The grayed-out files are not relevant to Widget driver development but can also be generated from the Widget Service XML.&lt;br /&gt;
* The Provider is generated in C#, meaning your driver must be written in C# as well. The use of managed code is mandatory for driver writing in the OpenHome framework.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Code sample used in this document ==&lt;br /&gt;
&lt;br /&gt;
Our examples in this document use a Widget Service XML definition for a light Widget called&lt;br /&gt;
BasicLight.xml.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Full versions of all the example files used in this document are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We will see how the Provider is generated from this XML and how it is used to aid the driver writing process. The examples also show how your chosen communication protocol should be used in the body of the driver code.&lt;br /&gt;
&lt;br /&gt;
Implementation details of specific protocols you choose to use are beyond the scope of this document. However, the samples used in this document show the use of the SimpleUPnP protocol to aid you in your development process.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol during the early stages of the OpenHome project. It is included in the OpenHome SDK and can be used as a public resource. &lt;br /&gt;
&lt;br /&gt;
The use of SimpleUPnP in the example files and the code snippets within the following sections is highlighted by the [[File:Warning.png]] icon. The lines of code marked by [[File:Warning.png]] must be changed to code from your chosen communication protocol's library. SimpleUPnP is left in to help you understand how a protocol is used in a working example.&lt;br /&gt;
&lt;br /&gt;
The sample code provided attempts to show best-practice coding standards. There are several sections of code that have a mandatory layout or that call specifically named methods and functions. These areas of the code are highlighted where required. &lt;br /&gt;
&lt;br /&gt;
Where the examples do not explicitly state that the code shown is mandatory, you are free to implement it in a different way according to your own coding style and practices.&lt;br /&gt;
&lt;br /&gt;
= Driver responsibilities = &lt;br /&gt;
&lt;br /&gt;
== Driver responsibilities ==&lt;br /&gt;
&lt;br /&gt;
An OpenHome Widget driver has several responsibilities which must be met before it can be used on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
These responsibilities are listed R1 to R7 and are defined here, explaining what each one must do. &lt;br /&gt;
&lt;br /&gt;
=== R1 Specifying the type of Widget the driver controls ===&lt;br /&gt;
A driver must know which type of Widget it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
=== R2 Reacting to a discovered Widget on the network ===&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== R3 Setting the initial values for the Widget's properties ===&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
=== R4 Publishing discovered Widgets in the Local Widget Registry on the Node ===&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object.&lt;br /&gt;
&lt;br /&gt;
=== R5 Reacting to an event reported from the Widget ===&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
=== R6 Reacting to actions sent to the Widget ===&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== R7 Reacting to a Widget's departure ===&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no&lt;br /&gt;
longer available.&lt;br /&gt;
&lt;br /&gt;
The sections of example code that follow show you how to write a driver from beginning to end. The accompanying text explaining the example code highlights when a responsibility, or part of a responsibility, has been met.&lt;br /&gt;
&lt;br /&gt;
= Driver Architecture = &lt;br /&gt;
&lt;br /&gt;
== Driver Architecture ==&lt;br /&gt;
&lt;br /&gt;
Drivers are installed on the Node and used when the Node needs to communicate with the Widget. Drivers&lt;br /&gt;
use several objects to communicate with Widgets over the Widget's lifetime. Figure 2 shows the objects&lt;br /&gt;
used by the driver and how the responsibilities listed above relate to each one:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture.png|800px|thumb|center|Figure 2: The architecture of a driver, showing the driver's relationship to the objects used to communicate with a Widget. Lines between objects show message flow.]]&lt;br /&gt;
&lt;br /&gt;
The objects contained in the dotted boundary must appear in the code you write to define your driver. The Driver, Provider and IWidgetRegistryEntry objects are all contained in the same driver file. We begin discussing this on page 12. &lt;br /&gt;
&lt;br /&gt;
The other objects are provided by the OpenHome SDK or as installed components on the Node.&lt;br /&gt;
&lt;br /&gt;
The Discovery Module informs the driver of the presence of an available Widget.&lt;br /&gt;
&lt;br /&gt;
Each Node has a Protocol Module which contains the protocol's API. Widgets can communicate with OpenHome Nodes using any one of the set of communications protocols the Node supports. The driver uses your chosen protocol's Protocol Module to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
Both the Protocol Module and the Discovery Module are installed on the Node. When you write your&lt;br /&gt;
driver you will use your Protocol Module to allow the driver to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
IWidgetPublisher, IPublishedWidget and DvDevice are objects provided in the OpenHome&lt;br /&gt;
API. You can read about them in the APIs.&lt;br /&gt;
&lt;br /&gt;
= Generating the Provider = &lt;br /&gt;
&lt;br /&gt;
== Generating the Provider ==&lt;br /&gt;
&lt;br /&gt;
You must generate your provider before you can begin writing your Widget driver. You use your provider as a guide to implement the functions your Widget needs to set the values of its properties.&lt;br /&gt;
&lt;br /&gt;
The current provider generation process is a manual one involving the use of a text transform tool.&lt;br /&gt;
&lt;br /&gt;
Speak to your OpenHome contact who will help you generate your provider.&lt;br /&gt;
&lt;br /&gt;
Future releases of the OpenHome SDK will include a tool to help you generate the provider.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
You must be in possession of:&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK, unpacked on your computer&lt;br /&gt;
* your Widget Service XML file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Writing a SimpleUPnP driver = &lt;br /&gt;
&lt;br /&gt;
== Introduction to the SimpleUPnP protocol ==&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol used to control emulated Widgets over a custom UPnP service.&lt;br /&gt;
&lt;br /&gt;
This chapter shows how a driver is written using the SimpleUPnP communications protocol. The aim is to show the code using as generic a protocol as possible so that you can see where your own protocol specific code needs to go.&lt;br /&gt;
&lt;br /&gt;
The use of code specific to the SimpleUPnP implementation is highlighted by the use of the [[File:Warning.png]] icon. The lines of code are marked by this icon to make it easier for you to see where the protocol-specific code must go and what parts of the code are generic.&lt;br /&gt;
&lt;br /&gt;
=== Register model ===&lt;br /&gt;
&lt;br /&gt;
SimpleUPnP is modeled on 8 physical registers available on the Widget. Each register is 32-bits wide. They are indexed from 0 to 7 and the last register (register 7) is reserved for storing the Widget's class.&lt;br /&gt;
&lt;br /&gt;
This detail is used by the Protocol Module on the Node to determine which driver is needed to run the new Widget when it has been discovered.&lt;br /&gt;
&lt;br /&gt;
The remaining 7 registers (registers 0 to 6) are free for Widget engineers to assign to the Widget's functions.&lt;br /&gt;
&lt;br /&gt;
Registers 0, 1, 2 and 3 are available as read/write registers. Registers 4, 5 and 6 are readonly registers.&lt;br /&gt;
&lt;br /&gt;
Only the emulated hardware (running on the Node) can change the values held in registers 4, 5 and 6.&lt;br /&gt;
&lt;br /&gt;
=== Register use in drivers ===&lt;br /&gt;
&lt;br /&gt;
In the example that follows we have a Basic Light Widget with a very simple function: it can be turned on and turned off. The on/off value is stored in register 0, with values 0=OFF and 1=ON. Register 0 is a read/write register. This means we can change the value stored there using messages passed to the Widget from the Node, and by reacting to physical interactions at the Widget (such as someone manually switching the light on or off). &lt;br /&gt;
&lt;br /&gt;
The mapping of registers to properties on the Widget is decided by the engineers who manufacture the device. You must be provided with the mapping before you begin developing your driver.&lt;br /&gt;
&lt;br /&gt;
== Starting the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-BoxHighlight.png|800px|thumb|center|Figure 3 The driver architecture highlighting the Widget driver and its component parts.]]&lt;br /&gt;
&lt;br /&gt;
When you have generated the abstract provider you can put it to use in the Widget driver. A Widget driver&lt;br /&gt;
has three distinct components:&lt;br /&gt;
&lt;br /&gt;
* an implementation of your abstract provider&lt;br /&gt;
* a definition of the Widget driver&lt;br /&gt;
* an implementation of the IWidgetRegistryEntry interface&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must manually write the code for your Widget driver. The differences in implementation of Widget properties and communication protocols means that the driver code cannot be autogenerated.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This section takes you through how to write a Widget driver by implementing the auto-generated provider,&lt;br /&gt;
starting from a new blank file and finishing with a working driver for the Basic Light Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
No assumptions have been made about the type of editor you use to write your code. Shortcuts&lt;br /&gt;
or macros that you use as standard will not appear in the instructions below. A full example&lt;br /&gt;
BinaryLightDriver.cs is available to review in Appendix C.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a new C# file in your IDE. Ensure the following libraries are used:&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 [[File:Warning.png]]using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 namespace OpenHome.Widget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must use the libraries listed above for this specific example.&lt;br /&gt;
&lt;br /&gt;
In general, drivers require the following libraries:&lt;br /&gt;
* System*&lt;br /&gt;
* System.Collections.Generic*&lt;br /&gt;
* OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
&lt;br /&gt;
Your driver will fail to compile if you miss any of these listed libraries. Libraries marked * are typically added by default by most modern IDEs. &lt;br /&gt;
&lt;br /&gt;
The OpenHome.Widget.Protocols.SimpleUpnp library is required only in this SimpleUPnP example. Drivers using a different protocol will use their own protocol library.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Implementing the provider ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-ProviderHighlight.png|800px|thumb|center|Figure 4 The driver architecture highlighting the Provider's place]]&lt;br /&gt;
&lt;br /&gt;
You use your auto-generated abstract provider by writing an implementation of it in the driver file. Responsibilities met by implementing your auto-generated provider are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R6 Reacting to actions sent to the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
Begin by creating a new class. It will subclass the abstract auto-generated provider:&lt;br /&gt;
&lt;br /&gt;
 class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
The Protocol Module will provide an API for the Provider to use to communicate with the Widget. In&lt;br /&gt;
SimpleUPnP we are provided with an interface called ISimpleUpnpWidget. The provider is supplied&lt;br /&gt;
with the required instance of the interface by the Discovery Module on the Node.&lt;br /&gt;
&lt;br /&gt;
The mechanisms for registering providers with specific Protocol Modules, and for the way the module gives each provider its required interface are covered later when writing the discovery method.&lt;br /&gt;
&lt;br /&gt;
For now, we need to give the Provider a place to store the interface that it will later use to communicate&lt;br /&gt;
with the Widget:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]] private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
&lt;br /&gt;
The interface from the Protocol Module is passed in as a parameter in the Provider's constructor and then&lt;br /&gt;
assigned to the variable we just created:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightProvider(DvDevice aDevice,&lt;br /&gt;
 [[File:Warning.png]]         ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
 {&lt;br /&gt;
       iProtocol = aProtocol;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
To satisfy R3 we would normally set the Widget's properties here, giving them an initial value.&lt;br /&gt;
However, in this specific example we cannot set the value of Basic Light's only property because&lt;br /&gt;
we will never know, in advance, what the state of the light will be (either on or off) when we&lt;br /&gt;
create the DiscoveredWidget.&lt;br /&gt;
&lt;br /&gt;
When you cannot set the properties ahead of time, and you are using an eventing protocol like SimpleUPnP, you can instead set them in the HandleRegisterEvent method in the driver class. This also satisfies the requirements for R3. You must set the Widget's properties before you enable it using SetEnabled(). &lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The abstract provider includes an abstract method called SetOn. This method is invoked by the Node when passing a message to the Widget, specifically to set the on property of the Widget to either 0 or 1. The implementation of this method will meet the requirements for R6.&lt;br /&gt;
&lt;br /&gt;
We must override this method and provide the protocol module a way of passing a message on to the Widget to perform the required action, in this case turn the light on or off:&lt;br /&gt;
&lt;br /&gt;
          protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
          {&lt;br /&gt;
     [[File:Warning.png]]        iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
In this example the Basic Light's SetOn property (the boolean property that controls whether the light is&lt;br /&gt;
on or off) is represented in the physical Widget by the register that has an index of 0.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* This method is an example of an action on a Widget. Actions are messages sent from the Node to the Widget. We will see later how to handle events that need to be passed back from the Widget&lt;br /&gt;
to the Node.&lt;br /&gt;
* Your own Widget will likely provide more than a single property. Your auto-generated provider will contain one abstract method to represent each writable property. Read-only properties are not provided an abstract method.&lt;br /&gt;
&lt;br /&gt;
You must implement each abstract method in your driver to ensure the relevant property on&lt;br /&gt;
the Widget can be set.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We have now finished implementing the provider. The next step is to implement the driver.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Implementing the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-DriverHighlight.png|800px|thumb|center|Figure 4: The driver architecture highlighting the implemented driver's place.]]&lt;br /&gt;
&lt;br /&gt;
The code for your Widget driver must provide an implementation of the IWidgetRegistryInterface,&lt;br /&gt;
including the following tasks:&lt;br /&gt;
&lt;br /&gt;
* methods to expose identifying details about the Widget for the Node to access&lt;br /&gt;
* providing methods to handle events reported by the Widget&lt;br /&gt;
&lt;br /&gt;
The driver is implemented as a public class within the same file as the provider code. Each driver must use the interface for the protocol you are using. For the SimpleUPnP protocol the interface is ISimple-UpnpWidgetDriver.&lt;br /&gt;
&lt;br /&gt;
=== Writing code ===&lt;br /&gt;
&lt;br /&gt;
Create your new driver class and subclass the ISimpleUpnpWidgetDriver interface:&lt;br /&gt;
&lt;br /&gt;
 public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Implementing IWidgetRegistryEntry ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry is the interface you use to represent physical Widgets. It is implemented as a subclass of your driver class. We are going to implement this interface in a class called '''DiscoveredWidget'''.&lt;br /&gt;
&lt;br /&gt;
Let's return to our driver architecture diagram for a moment:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-IRegistryEntryHighlight.png|800px|thumb|center|Figure 5 The driver architecture highlighting the IWidgetRegistryEntry object you will now implement]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry uses several other objects to help create it and respond to messages sent to and from it. These objects will be created in our implementation of DiscoveredWidget. &lt;br /&gt;
&lt;br /&gt;
When successfully created and published, the DiscoveredWidget objects are stored in a list on the Node called the Local Widget Registry. The Local Widget Registry is used by Nodes to maintain contact with the Widgets they control.&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry is shown at the top of Figure 5, marked plainly as (Registry). The path to the Local Widget Registry goes through several layers of Node architecture which are not relevant to Widget driver writing, so are not shown in the diagrams.&lt;br /&gt;
&lt;br /&gt;
==== Writing code ====&lt;br /&gt;
&lt;br /&gt;
Start by subclassing the IWidgetRegistryEntry interface in your new class:&lt;br /&gt;
&lt;br /&gt;
      private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
      {&lt;br /&gt;
&lt;br /&gt;
A DiscoveredWidget must provide the driver with the objects required to present the Widget and its&lt;br /&gt;
properties to the Node:&lt;br /&gt;
&lt;br /&gt;
           private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
           private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
           private readonly ISimpleUpnpWidget iProtocol;&lt;br /&gt;
           private readonly BinaryLightProvider iProvider;&lt;br /&gt;
           private readonly DvDevice iDvDevice;&lt;br /&gt;
           private IPublishedWidget iPublishedWidget;&lt;br /&gt;
&lt;br /&gt;
Each of the attributes in the example above are defined as follows:&lt;br /&gt;
&lt;br /&gt;
iDeviceFactory — used by the driver to create a single instance of DvDevice to represent a single Widget&lt;br /&gt;
&lt;br /&gt;
iPublisher — used by the driver to publish the Widget to the Node&lt;br /&gt;
&lt;br /&gt;
iProtocol — the object used by the Widget to communicate with the Protocol Module on the Node&lt;br /&gt;
&lt;br /&gt;
iProvider — an instantiated provider of the type you defined earlier&lt;br /&gt;
&lt;br /&gt;
iDvDevice — a representation of a Widget to which the provider is attached, created using iDevice-Factory above&lt;br /&gt;
&lt;br /&gt;
iPublishedWidget — used to contain the returned object from a successful publishing of the Widget&lt;br /&gt;
If we look again at the driver architecture diagram, we ca highlight the objects we've just defined:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-Highlight.png|800px|thumb|center|Figure 6: The driver architecture highlighting the objects used by the IWidgetRegistryEntry implementation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The DeviceFactory, defined above in the member variable iDeviceFactory, is used to create new DvDevice objects. The DeviceFactory is only ever used to do this once. It is not shown in the driver architecture diagrams due to its minimal role in the operation of a driver, but it would normally appear between the IWidgetRegistryEntry and DvDevice objects.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
A driver requires methods to expose identifying details about the Widget. We must provide access to two of the attributes we just defined above:&lt;br /&gt;
&lt;br /&gt;
 public DvDevice DvDevice&lt;br /&gt;
 {&lt;br /&gt;
     get { return iDvDevice; }&lt;br /&gt;
 }&lt;br /&gt;
 public string WidgetClass&lt;br /&gt;
 {&lt;br /&gt;
     get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The WidgetClass string is formed using a combination of the vendor name and the Widget's name in the&lt;br /&gt;
format:&lt;br /&gt;
&lt;br /&gt;
 [vendor_domain]:[widget_name]&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry can now query both the DvDevice object representing the Widget, and the specific class of Widget this driver represents. The other member variables we defined do not need their own accessor methods.&lt;br /&gt;
&lt;br /&gt;
Now we must write a constructor for DiscoveredWidget and assign the parameters accordingly: &lt;br /&gt;
&lt;br /&gt;
 public DiscoveredWidget(IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                            string aUdn,&lt;br /&gt;
                            ISimpleUpnpWidget aProxy,&lt;br /&gt;
                            IWidgetPublisher aPublisher)&lt;br /&gt;
 {&lt;br /&gt;
      iDeviceFactory = aDeviceFactory;&lt;br /&gt;
      iProtocol = aProtocol;&lt;br /&gt;
      iPublisher = aPublisher;&lt;br /&gt;
      iDvDevice = iDeviceFactory.CreateDevice(aUdn);&lt;br /&gt;
      iProvider = new BinaryLightProvider(iDvDevice,&lt;br /&gt;
      iProtocol);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Event handling ===&lt;br /&gt;
&lt;br /&gt;
A Widget's state can change in one of three significant ways:&lt;br /&gt;
&lt;br /&gt;
* when the Widget needs to be published on the Node&lt;br /&gt;
* when the Widget disappears from the network (by losing power or similar)&lt;br /&gt;
* when a property's state changes and must be updated to a new value&lt;br /&gt;
&lt;br /&gt;
We now need methods to handle these changes.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The methods we define here will be used as callbacks, rather than invoked as method calls. We define the methods here first and then use them later on. We will use the Protocol Module to listen for changes in the Widget's state and register these methods as callbacks there. See Writing the SimpleUPnP Widget discovery method for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this section of the driver are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R4 Publishing discovered Widgets in the Local Widget Registry on the Node'''&lt;br /&gt;
&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object. &lt;br /&gt;
&lt;br /&gt;
'''R5 Reacting to an event reported from the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
'''R7 Reacting to a Widget's departure'''&lt;br /&gt;
&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no longer available.&lt;br /&gt;
&lt;br /&gt;
==== Enabling and publishing a discovered Widget ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first method initializes the Widget by enabling the device and then using the IWidgetPublisher&lt;br /&gt;
to make it available on the Node:&lt;br /&gt;
&lt;br /&gt;
 public void HandleInitialEvent()&lt;br /&gt;
 {&lt;br /&gt;
      iDvDevice.SetEnabled();&lt;br /&gt;
      iPublisher.TryPublishWidget(iDvDevice.iUdn(),&lt;br /&gt;
                              this,&lt;br /&gt;
                              out iPublishedWidget);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This method meets the requirements for R4.&lt;br /&gt;
&lt;br /&gt;
The call to TryPublishWidget returns an iPublishedWidget object. We use this object later to satisfy the requirements of R7.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The ordering of the calls to SetEnabled and TryPublishWidget is vitally important. You&lt;br /&gt;
must enable the device before you attempt to publish it. Your Widget will not be available to the&lt;br /&gt;
Nodes unless SetEnabled is called first. Nodes will not be able to access a published device&lt;br /&gt;
that has not been enabled.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
R3 requires that you set the Widget's properties before you enable and publish the device. We&lt;br /&gt;
discussed on page 14 how some properties can only be set after the Widget reports what their&lt;br /&gt;
state is. We do this in HandleRegisterEvent.&lt;br /&gt;
&lt;br /&gt;
We rely on the SimpleUPnP Protocol Module guaranteeing a call to HandleRegisterEvent first before HandleInitialEvent. This is informed by guarantees made by the Control Point stack that the calls will be made in that order.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
==== Removing a Widget ====&lt;br /&gt;
&lt;br /&gt;
Removing a Widget involves unpublishing it from the Node. The IPublishedWidget interface provides us with a method we can call to manage that for us:&lt;br /&gt;
&lt;br /&gt;
 public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
 {&lt;br /&gt;
     if (iPublishedWidget != null)&lt;br /&gt;
     { iPublishedWidget.Unpublish(); }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assuming that the Widget was successfully published earlier, it is removed from the Node's Local Widget Registry.&lt;br /&gt;
&lt;br /&gt;
We must also properly handle the resources we used to create and maintain the Widget object while it was published:&lt;br /&gt;
&lt;br /&gt;
      iProvider.Dispose();&lt;br /&gt;
      iDvDevice.Dispose();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The calls to Dispose are made regardless of the Widget's published state, ensuring that any created device and associated provider are properly disposed. This implementation satisfies R7.&lt;br /&gt;
&lt;br /&gt;
====Event handling ====&lt;br /&gt;
&lt;br /&gt;
We need a method to handle changes to the state of the Widget's properties.&lt;br /&gt;
&lt;br /&gt;
If the property changes at the Widget, it needs to pass the new state back to the Node so that it is kept up-to-date on the Widget's status. This is called an event. An example in the case of our Basic Light is someone manually switching the light from on to off. This is in contrast to actions, which are passed from the Node to the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Other examples of events involve no human interaction, such as a thermometer Widget updating its current temperature based on environmental changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Our Basic Light Widget has only one property that needs to be handled:&lt;br /&gt;
&lt;br /&gt;
 public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
 {&lt;br /&gt;
     if (aIndex == 0)&lt;br /&gt;
     {&lt;br /&gt;
         iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We use our instance of the provider to update the register on the Widget that is mapped to the On property. This in turn updates the Node with the new state of the Widget.&lt;br /&gt;
&lt;br /&gt;
This method provides implementations to satisfy two driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
* R3 is now completely satisfied, as we can now set the values of all the previously unknown properties here.&lt;br /&gt;
* R5 is also satisfied as this method allows us to update the Widget's status on the Node when a property is changed on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Not all protocols pass messages back to the Node in this manner. The way we have satisfied R3 and R5 here only applies to protocols and Widgets that support this behavior.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Widgets that do not use an eventing protocol need to have their properties set in the provider's constructor to satisfy R3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To satisfy R5, the over-ridden method SetOn in the provider must include the call to SetPropertyOn. Non-eventing protocols do not require a HandleRegisterEvent method.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Constructor ===&lt;br /&gt;
&lt;br /&gt;
The final requirement for the driver is the constructor so that new DiscoveredWidget objects can be created. &lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this area of code are:&lt;br /&gt;
&lt;br /&gt;
'''R1 Specifying the type of Widget the driver controls'''&lt;br /&gt;
&lt;br /&gt;
A driver must know which type of Widget that it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Writing the code ====&lt;br /&gt;
&lt;br /&gt;
We begin by defining the variables we will use to store the objects used by the driver:&lt;br /&gt;
&lt;br /&gt;
 private readonly string iName;&lt;br /&gt;
 private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
 private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now write the constructor for the driver and assign the passed in parameters appropriately:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightDriver(string aName,&lt;br /&gt;
                IWidgetPublisher aPublisher,&lt;br /&gt;
                IDvDeviceFactory aDeviceFactory)&lt;br /&gt;
 {&lt;br /&gt;
     iWidgetPublisher = aPublisher;&lt;br /&gt;
     iName = aName;&lt;br /&gt;
     iDeviceFactory = aDeviceFactory;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally we need to provide the driver a way to publish the class of Widget it controls. This information is requested by the Discovery Module and is used to ensure the Node uses the correct driver when a new Widget appears.&lt;br /&gt;
&lt;br /&gt;
The implementation for this details will be different for each protocol. The SimpleUPnP protocol library provides a file that contains the SimpleUPnP definitions as integers. Each integer represents a particular class of identified Widget.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP implementation of that method is as follows:&lt;br /&gt;
&lt;br /&gt;
 public IEnumerable&amp;lt;uint&amp;gt; WidgetClasses&lt;br /&gt;
 {&lt;br /&gt;
 [[File:Warning.png]]        get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The body of this method is specifically written for the Widget class we are defining (in this case a binary light). This method completes the driver's requirements for R1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Writing the SimpleUPnP Widget discovery method ==&lt;br /&gt;
&lt;br /&gt;
Every driver must contain a method which creates new objects to represent newly discovered Widgets.&lt;br /&gt;
The Discovery Module invokes this method to begin the process of creating the objects required to allow the Node to access the Widget. &lt;br /&gt;
&lt;br /&gt;
The name of this method is dictated by your chosen protocol's API. The SimpleUPnP protocol requires a method called WidgetDiscovered.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The method's name will not always be the same for each protocol. Your protocol's documentation will contain the details of what this method must be called.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This method and its implementation will meet the following driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
'''R2 Reacting to a discovered Widget on the network'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
Our implementation of the WidgetDiscovered method will create a new DiscoveredWidget object and use the Protocol Module to listen for changes to the Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
The method uses the Protocol Module and two ways to identify the Widget. We must pass these in as&lt;br /&gt;
parameters:&lt;br /&gt;
&lt;br /&gt;
 public void WidgetDiscovered(string aWidgetUdn,&lt;br /&gt;
                              uint aWidgetClass,&lt;br /&gt;
                              ISimpleUpnpWidget&lt;br /&gt;
                                  aSimpleUpnpWidget)&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
Every Widget that uses this driver must be uniquely identifiable:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]    string newUdn = aWidgetUdn;&lt;br /&gt;
&lt;br /&gt;
Each new Widget is represented by a DiscoveredWidget object. Create the new DiscoveredWidget and pass in the required parameters we created earlier:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
     DiscoveredWidget discoveredWidget =&lt;br /&gt;
                 new DiscoveredWidget(iDeviceFactory,&lt;br /&gt;
                                      newUdn,&lt;br /&gt;
  &lt;br /&gt;
 [[File:Warning.png]]                                    aSimpleUpnpWidget,&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Registering the callbacks ===&lt;br /&gt;
&lt;br /&gt;
Finally, we ask the Widget's protocol interface to listen for calls to the handler methods we defined earlier in DiscoveredWidget. We do this by registering those methods as callbacks for the Protocol Module&lt;br /&gt;
to listen for:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                        discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                        discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                        discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You have now met 100% of the driver responsibility requirements and have a working driver to use with your SimpleUPnP Widget.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix A. Sample XML =&lt;br /&gt;
&lt;br /&gt;
== Binary Light.xml ==&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
  &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
  &amp;lt;version&amp;gt;&lt;br /&gt;
   &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
   &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/version&amp;gt;&lt;br /&gt;
  &amp;lt;propertylist&amp;gt;&lt;br /&gt;
   &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
       illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
   &amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix B. Sample Provider = &lt;br /&gt;
&lt;br /&gt;
== DvWidgetOpenhomeOrgBasicLight1.cs ==&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Runtime.InteropServices;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Core;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Utils.Binary;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
 {&lt;br /&gt;
    public interface IDvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
        IDisposable&lt;br /&gt;
    {&lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous value&lt;br /&gt;
        /// &amp;lt;/returns&amp;gt;&lt;br /&gt;
        bool SetPropertyOn(bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;Property's value will be copied&lt;br /&gt;
        /// here&amp;lt;/param&amp;gt;&lt;br /&gt;
        bool PropertyOn();&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt; summary&amp;gt;&lt;br /&gt;
    /// Provider for the openhome.org:BinaryLight:1 UPnP service&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public abstract class DvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
               DvProvider,&lt;br /&gt;
               IDisposable,&lt;br /&gt;
               IDvProviderOpenhomeOrgBinaryLight1&lt;br /&gt;
    {&lt;br /&gt;
        private GCHandle iGch;&lt;br /&gt;
        private PropertyBool iPropertyOn;&lt;br /&gt;
        private PropertyUint iPropertyPrimarySeq;&lt;br /&gt;
        private PropertyUint iPropertySecondarySeq;&lt;br /&gt;
        private ActionDelegate iDelegateSetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetPrimaryProperty;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Constructor&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aDevice&amp;quot;&amp;gt;Device which owns this&lt;br /&gt;
        /// provider&amp;lt;/param&amp;gt;&lt;br /&gt;
        protected DvProviderOpenhomeOrgBinaryLight1(DvDevice aDevice)&lt;br /&gt;
            : base(aDevice, &amp;quot;openhome.org&amp;quot;, &amp;quot;GenericWidget&amp;quot;, 1)&lt;br /&gt;
        {&lt;br /&gt;
            iGch = GCHandle.Alloc(this);&lt;br /&gt;
            List&amp;lt;String&amp;gt; allowedValues = new List&amp;lt;String&amp;gt;();&lt;br /&gt;
            iPropertyOn = new PropertyBool(new ParameterBool(&amp;quot;On&amp;quot;));&lt;br /&gt;
            iPropertyPrimarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;PrimarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertyPrimarySeq);&lt;br /&gt;
            iPropertySecondarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;SecondarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertySecondarySeq);&lt;br /&gt;
            SetPropertyUint(iPropertyPrimarySeq, 0);&lt;br /&gt;
            SetPropertyUint(iPropertySecondarySeq, 0);&lt;br /&gt;
  &lt;br /&gt;
            Zapp.Core.Action action = new Zapp.Core.Action&lt;br /&gt;
                (&amp;quot;SetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;FireAndForget&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddInputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateSetProperty = new ActionDelegate(DoSetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateSetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateGetProperty = new ActionDelegate(DoGetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetPrimaryProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                 (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;integer&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;boolean&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;string&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;binary&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Type&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;readWrite&amp;quot;);allowedValues.Add&lt;br /&gt;
                (&amp;quot;readOnly&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;writeOnly&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString(&amp;quot;Access&amp;quot;,&lt;br /&gt;
                allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            iDelegateGetPrimaryProperty = new&lt;br /&gt;
            ActionDelegate(DoGetPrimaryProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetPrimaryProperty,&lt;br /&gt;
            GCHandle.ToIntPtr(iGch));&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous&lt;br /&gt;
        /// value&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool SetPropertyOn(bool aValue)&lt;br /&gt;
        {&lt;br /&gt;
            if (iPropertyOn.SetValue(aValue))&lt;br /&gt;
            {&lt;br /&gt;
                lock (iPropertyPrimarySeq)&lt;br /&gt;
                {&lt;br /&gt;
                    SetPropertyUint(iPropertyPrimarySeq,&lt;br /&gt;
                        iPropertyPrimarySeq.Value() + 1);&lt;br /&gt;
                } return true;&lt;br /&gt;
            } return false;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;The value of the property&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool PropertyOn()&lt;br /&gt;
        {&lt;br /&gt;
            return iPropertyOn.Value();&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the On property.&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aVersion&amp;quot;&amp;gt;Version of the service being&lt;br /&gt;
        /// requested (will be &amp;lt;= the version advertised)&amp;lt;/param&amp;gt; &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the On property.&lt;br /&gt;
        /// &amp;lt;/param&amp;gt;&lt;br /&gt;
        protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        private static int DoSetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                byte[] valBin = invocation.ReadBinary(&amp;quot;Value&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                switch (name)&lt;br /&gt;
                {&lt;br /&gt;
                    case &amp;quot;On&amp;quot;:&lt;br /&gt;
                        self.SetOn(aVersion, Converter.&lt;br /&gt;
                            BinaryToBoolean(valBin));&lt;br /&gt;
                        break;&lt;br /&gt;
                    default:&lt;br /&gt;
                        throw new ActionError();&lt;br /&gt;
                }&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
                invocation.WriteEnd();&lt;br /&gt;
            }&lt;br /&gt;
            catch (ActionError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
            catch (PropertyUpdateError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
        return 0;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        private static int DoGetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
            switch (name)&lt;br /&gt;
            {&lt;br /&gt;
                case &amp;quot;On&amp;quot;:&lt;br /&gt;
                invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                    Converter.BooleanToBinary(self.iPropertyOn.&lt;br /&gt;
                        Value()));&lt;br /&gt;
                break;&lt;br /&gt;
                default:&lt;br /&gt;
                throw new ActionError();&lt;br /&gt;
            }&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    private static int DoGetPrimaryProperty(IntPtr aPtr,&lt;br /&gt;
                    IntPtr aInvocation,&lt;br /&gt;
                    uint aVersion)&lt;br /&gt;
    {&lt;br /&gt;
        GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
        DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
            (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
        DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
  &lt;br /&gt;
        try&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReadStart();&lt;br /&gt;
            invocation.ReadEnd();&lt;br /&gt;
            invocation.WriteStart();&lt;br /&gt;
            invocation.WriteString(&amp;quot;Name&amp;quot;, &amp;quot;On&amp;quot;);&lt;br /&gt;
            invocation.WriteString(&amp;quot;Type&amp;quot;, &amp;quot;boolean&amp;quot;);&lt;br /&gt;
            invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                Converter.BooleanToBinary(self.iPropertyOn.Value()));&lt;br /&gt;
            invocation.WriteString(&amp;quot;Access&amp;quot;, &amp;quot;readWrite&amp;quot;);&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt;summary&amp;gt;&lt;br /&gt;
    /// Must be called for each class instance. Must be called before&lt;br /&gt;
    /// Core.Library.Close().&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public void Dispose()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
        GC.SuppressFinalize(this);&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
    ~DvProviderOpenhomeOrgBinaryLight1()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
        private void DoDispose()&lt;br /&gt;
        {&lt;br /&gt;
            lock (this)&lt;br /&gt;
            {&lt;br /&gt;
                if (iHandle == IntPtr.Zero)&lt;br /&gt;
            {&lt;br /&gt;
                    return;&lt;br /&gt;
            }&lt;br /&gt;
            DisposeProvider();&lt;br /&gt;
            iPropertyOn.Dispose();&lt;br /&gt;
            iHandle = IntPtr.Zero;&lt;br /&gt;
            }&lt;br /&gt;
            iGch.Free();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix C. Sample Driver = &lt;br /&gt;
&lt;br /&gt;
== BasicLightDriver.cs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.hWidget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
     class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
     {&lt;br /&gt;
         private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
         public BinaryLightProvider(DvDevice aDevice, &lt;br /&gt;
             ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol = aProtocol;&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
     {&lt;br /&gt;
         private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
         {&lt;br /&gt;
             private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
             private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
             private readonly ISimpleUpnpWidget iProtocol; &lt;br /&gt;
 &lt;br /&gt;
             private readonly BinaryLightProvider iProvider;&lt;br /&gt;
             private readonly DvDevice iDvDevice;&lt;br /&gt;
             private IPublishedWidget iPublishedWidget; &lt;br /&gt;
 &lt;br /&gt;
             public DvDevice DvDevice&lt;br /&gt;
             {&lt;br /&gt;
                 get { return iDvDevice; }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             public string WidgetClass&lt;br /&gt;
             {&lt;br /&gt;
                 get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public DiscoveredWidget(&lt;br /&gt;
                 IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                 string aUdn,&lt;br /&gt;
                 ISimpleUpnpWidget aProxy,&lt;br /&gt;
                 IWidgetPublisher aPublisher)&lt;br /&gt;
             {&lt;br /&gt;
                 iDeviceFactory = aDeviceFactory;&lt;br /&gt;
                 iProtocol = aProtocol;&lt;br /&gt;
 &lt;br /&gt;
                 iPublisher = aPublisher;&lt;br /&gt;
                 iDvDevice = iDeviceFactory.CreateDevice(aUdn);  &lt;br /&gt;
                 iProvider = new BinaryLightProvider(iDvDevice, &lt;br /&gt;
                                                     iProtocol);&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             public void HandleInitialEvent()&lt;br /&gt;
             {&lt;br /&gt;
                 iDvDevice.SetEnabled();&lt;br /&gt;
                 iPublisher.TryPublishWidget(iDvDevice.iUdn(), this,&lt;br /&gt;
                     out iPublishedWidget);&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
             {&lt;br /&gt;
                 if (iPublishedWidget != null)&lt;br /&gt;
                 {&lt;br /&gt;
                     iPublishedWidget.Unpublish();&lt;br /&gt;
                 } &lt;br /&gt;
                 iProvider.Dispose();&lt;br /&gt;
                 iDvDevice.Dispose();&lt;br /&gt;
             }  &lt;br /&gt;
 &lt;br /&gt;
             public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
             {&lt;br /&gt;
                 if (aIndex == 0)&lt;br /&gt;
                 {&lt;br /&gt;
                     iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         private readonly string iName;&lt;br /&gt;
         private readonly IDvDeviceFactory aDeviceFactory;&lt;br /&gt;
         private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
         &lt;br /&gt;
         public BinaryLightDriver(&lt;br /&gt;
             string aName,&lt;br /&gt;
             IWidgetPublisher aPublisher,&lt;br /&gt;
             iDeviceFactory aDeviceFactory)&lt;br /&gt;
         {&lt;br /&gt;
             iWidgetPublisher = aPublisher;&lt;br /&gt;
             iName = aName;&lt;br /&gt;
             iDeviceFactory = aDeviceFactory;&lt;br /&gt;
         } &lt;br /&gt;
 &lt;br /&gt;
         public IEnumerable&amp;amp;lt;uint&amp;amp;gt; WidgetClasses&lt;br /&gt;
         {&lt;br /&gt;
             get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         public void WidgetDiscovered(&lt;br /&gt;
             string aWidgetUdn,&lt;br /&gt;
             uint aWidgetClass,&lt;br /&gt;
             ISimpleUpnpWidget aSimpleUpnpWidget)&lt;br /&gt;
         {&lt;br /&gt;
             string newUdn = aWidgetUdn;&lt;br /&gt;
             DiscoveredWidget discoveredWidget = new DiscoveredWidget&lt;br /&gt;
                 (iDeviceFactory,&lt;br /&gt;
                  newUdn,&lt;br /&gt;
                  aSimpleUpnpWidget,&lt;br /&gt;
                  iWidgetPublisher);&lt;br /&gt;
 &lt;br /&gt;
             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                 discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                 discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                 discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary = &lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in OpenHome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by OpenHome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh - A collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs on ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The OpenHome Operating System. Core software for OpenHome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. &lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. A typical Widget supports only one protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Driver_Development</id>
		<title>OhWidget Driver Development</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Driver_Development"/>
				<updated>2012-03-01T15:18:53Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Event handling */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for developers using the OpenHome SDK to integrate a Widget into an OpenHome system. Each Widget must have its own driver to allow it to communicate with the OpenHome Nodes. &lt;br /&gt;
&lt;br /&gt;
To help you write your driver, this document provides high level descriptions of the core responsibilities of a Widget driver and gives a detailed walk-through using example code.&lt;br /&gt;
&lt;br /&gt;
Full versions of each file used in the development of the example driver are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin development of your Widget driver you must be in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* your Widget Service XML that describes the properties on your Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document does not contain advice on how to write Widget Service XML. Refer to the OpenHome Widget Service XML definition document for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK&lt;br /&gt;
* your chosen communication protocol's API&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The protocol you choose for your Widgets must be the same protocol used on your choice of Node.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document focuses on the development of the Widget driver. Details about the communications protocol used are beyond the scope of this document. This document assumes you are familiar with your chosen protocol's code libraries and are able to use them in the driver code you write.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Related Documents ==&lt;br /&gt;
&lt;br /&gt;
The following related OpenHome documentation may be of interest to you:&lt;br /&gt;
&lt;br /&gt;
* [[ohWidget Technical Overview|ohWidget Technical Overview]]&lt;br /&gt;
* [[OpenHome Widget Service XML definition|OpenHome Widget Service XML definition]]&lt;br /&gt;
* [http://www.openhome.org/releases/ohNet_DeviceStack.pdf  OpenHome ohNet Device Stack]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
None of the related documents listed above is mandatory reading for Widget driver development.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
== Widget Service XML ==&lt;br /&gt;
OpenHome Widget driver writing relies heavily on the use of code generated from a single source — the Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
The service and actions your Widget provides are represented in code in a file called a Provider. The Provider is automatically generated from the Widget Service XML and produces an abstract class for you to inherit when you write your concrete class driver.&lt;br /&gt;
&lt;br /&gt;
To aid in the explanation of how the Provider is created and put to use we will follow the development of&lt;br /&gt;
a driver for a simple light Widget; taking the defined Widget Service XML and stepping through how it is used to generate the other files. Examples of code are used throughout this document to show you how each one is created and used in an OpenHome system. &lt;br /&gt;
&lt;br /&gt;
It is essential that you start with a well-formed Widget Service XML, conforming to the schema defined&lt;br /&gt;
in the WidgetService.xsd. The following diagram shows the significance of the Widget Service XML in&lt;br /&gt;
relation to the generated files you will use when writing your driver:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarchy, highlighting the areas specifically used in driver development]]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* The grayed-out files are not relevant to Widget driver development but can also be generated from the Widget Service XML.&lt;br /&gt;
* The Provider is generated in C#, meaning your driver must be written in C# as well. The use of managed code is mandatory for driver writing in the OpenHome framework.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Code sample used in this document ==&lt;br /&gt;
&lt;br /&gt;
Our examples in this document use a Widget Service XML definition for a light Widget called&lt;br /&gt;
BasicLight.xml.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Full versions of all the example files used in this document are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We will see how the Provider is generated from this XML and how it is used to aid the driver writing process. The examples also show how your chosen communication protocol should be used in the body of the driver code.&lt;br /&gt;
&lt;br /&gt;
Implementation details of specific protocols you choose to use are beyond the scope of this document. However, the samples used in this document show the use of the SimpleUPnP protocol to aid you in your development process.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol during the early stages of the OpenHome project. It is included in the OpenHome SDK and can be used as a public resource. &lt;br /&gt;
&lt;br /&gt;
The use of SimpleUPnP in the example files and the code snippets within the following sections is highlighted by the [[File:Warning.png]] icon. The lines of code marked by [[File:Warning.png]] must be changed to code from your chosen communication protocol's library. SimpleUPnP is left in to help you understand how a protocol is used in a working example.&lt;br /&gt;
&lt;br /&gt;
The sample code provided attempts to show best-practice coding standards. There are several sections of code that have a mandatory layout or that call specifically named methods and functions. These areas of the code are highlighted where required. &lt;br /&gt;
&lt;br /&gt;
Where the examples do not explicitly state that the code shown is mandatory, you are free to implement it in a different way according to your own coding style and practices.&lt;br /&gt;
&lt;br /&gt;
= Driver responsibilities = &lt;br /&gt;
&lt;br /&gt;
== Driver responsibilities ==&lt;br /&gt;
&lt;br /&gt;
An OpenHome Widget driver has several responsibilities which must be met before it can be used on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
These responsibilities are listed R1 to R7 and are defined here, explaining what each one must do. &lt;br /&gt;
&lt;br /&gt;
=== R1 Specifying the type of Widget the driver controls ===&lt;br /&gt;
A driver must know which type of Widget it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
=== R2 Reacting to a discovered Widget on the network ===&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== R3 Setting the initial values for the Widget's properties ===&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
=== R4 Publishing discovered Widgets in the Local Widget Registry on the Node ===&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object.&lt;br /&gt;
&lt;br /&gt;
=== R5 Reacting to an event reported from the Widget ===&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
=== R6 Reacting to actions sent to the Widget ===&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== R7 Reacting to a Widget's departure ===&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no&lt;br /&gt;
longer available.&lt;br /&gt;
&lt;br /&gt;
The sections of example code that follow show you how to write a driver from beginning to end. The accompanying text explaining the example code highlights when a responsibility, or part of a responsibility, has been met.&lt;br /&gt;
&lt;br /&gt;
= Driver Architecture = &lt;br /&gt;
&lt;br /&gt;
== Driver Architecture ==&lt;br /&gt;
&lt;br /&gt;
Drivers are installed on the Node and used when the Node needs to communicate with the Widget. Drivers&lt;br /&gt;
use several objects to communicate with Widgets over the Widget's lifetime. Figure 2 shows the objects&lt;br /&gt;
used by the driver and how the responsibilities listed above relate to each one:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture.png|800px|thumb|center|Figure 2: The architecture of a driver, showing the driver's relationship to the objects used to communicate with a Widget. Lines between objects show message flow.]]&lt;br /&gt;
&lt;br /&gt;
The objects contained in the dotted boundary must appear in the code you write to define your driver. The Driver, Provider and IWidgetRegistryEntry objects are all contained in the same driver file. We begin discussing this on page 12. &lt;br /&gt;
&lt;br /&gt;
The other objects are provided by the OpenHome SDK or as installed components on the Node.&lt;br /&gt;
&lt;br /&gt;
The Discovery Module informs the driver of the presence of an available Widget.&lt;br /&gt;
&lt;br /&gt;
Each Node has a Protocol Module which contains the protocol's API. Widgets can communicate with OpenHome Nodes using any one of the set of communications protocols the Node supports. The driver uses your chosen protocol's Protocol Module to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
Both the Protocol Module and the Discovery Module are installed on the Node. When you write your&lt;br /&gt;
driver you will use your Protocol Module to allow the driver to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
IWidgetPublisher, IPublishedWidget and DvDevice are objects provided in the OpenHome&lt;br /&gt;
API. You can read about them in the APIs.&lt;br /&gt;
&lt;br /&gt;
= Generating the Provider = &lt;br /&gt;
&lt;br /&gt;
== Generating the Provider ==&lt;br /&gt;
&lt;br /&gt;
You must generate your provider before you can begin writing your Widget driver. You use your provider as a guide to implement the functions your Widget needs to set the values of its properties.&lt;br /&gt;
&lt;br /&gt;
The current provider generation process is a manual one involving the use of a text transform tool.&lt;br /&gt;
&lt;br /&gt;
Speak to your OpenHome contact who will help you generate your provider.&lt;br /&gt;
&lt;br /&gt;
Future releases of the OpenHome SDK will include a tool to help you generate the provider.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
You must be in possession of:&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK, unpacked on your computer&lt;br /&gt;
* your Widget Service XML file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Writing a SimpleUPnP driver = &lt;br /&gt;
&lt;br /&gt;
== Introduction to the SimpleUPnP protocol ==&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol used to control emulated Widgets over a custom UPnP service.&lt;br /&gt;
&lt;br /&gt;
This chapter shows how a driver is written using the SimpleUPnP communications protocol. The aim is to show the code using as generic a protocol as possible so that you can see where your own protocol specific code needs to go.&lt;br /&gt;
&lt;br /&gt;
The use of code specific to the SimpleUPnP implementation is highlighted by the use of the [[File:Warning.png]] icon. The lines of code are marked by this icon to make it easier for you to see where the protocol-specific code must go and what parts of the code are generic.&lt;br /&gt;
&lt;br /&gt;
=== Register model ===&lt;br /&gt;
&lt;br /&gt;
SimpleUPnP is modeled on 8 physical registers available on the Widget. Each register is 32-bits wide. They are indexed from 0 to 7 and the last register (register 7) is reserved for storing the Widget's class.&lt;br /&gt;
&lt;br /&gt;
This detail is used by the Protocol Module on the Node to determine which driver is needed to run the new Widget when it has been discovered.&lt;br /&gt;
&lt;br /&gt;
The remaining 7 registers (registers 0 to 6) are free for Widget engineers to assign to the Widget's functions.&lt;br /&gt;
&lt;br /&gt;
Registers 0, 1, 2 and 3 are available as read/write registers. Registers 4, 5 and 6 are readonly registers.&lt;br /&gt;
&lt;br /&gt;
Only the emulated hardware (running on the Node) can change the values held in registers 4, 5 and 6.&lt;br /&gt;
&lt;br /&gt;
=== Register use in drivers ===&lt;br /&gt;
&lt;br /&gt;
In the example that follows we have a Basic Light Widget with a very simple function: it can be turned on and turned off. The on/off value is stored in register 0, with values 0=OFF and 1=ON. Register 0 is a read/write register. This means we can change the value stored there using messages passed to the Widget from the Node, and by reacting to physical interactions at the Widget (such as someone manually switching the light on or off). &lt;br /&gt;
&lt;br /&gt;
The mapping of registers to properties on the Widget is decided by the engineers who manufacture the device. You must be provided with the mapping before you begin developing your driver.&lt;br /&gt;
&lt;br /&gt;
== Starting the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-BoxHighlight.png|800px|thumb|center|Figure 3 The driver architecture highlighting the Widget driver and its component parts.]]&lt;br /&gt;
&lt;br /&gt;
When you have generated the abstract provider you can put it to use in the Widget driver. A Widget driver&lt;br /&gt;
has three distinct components:&lt;br /&gt;
&lt;br /&gt;
* an implementation of your abstract provider&lt;br /&gt;
* a definition of the Widget driver&lt;br /&gt;
* an implementation of the IWidgetRegistryEntry interface&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must manually write the code for your Widget driver. The differences in implementation of Widget properties and communication protocols means that the driver code cannot be autogenerated.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This section takes you through how to write a Widget driver by implementing the auto-generated provider,&lt;br /&gt;
starting from a new blank file and finishing with a working driver for the Basic Light Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
No assumptions have been made about the type of editor you use to write your code. Shortcuts&lt;br /&gt;
or macros that you use as standard will not appear in the instructions below. A full example&lt;br /&gt;
BinaryLightDriver.cs is available to review in Appendix C.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a new C# file in your IDE. Ensure the following libraries are used:&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 [[File:Warning.png]]using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 namespace OpenHome.Widget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must use the libraries listed above for this specific example.&lt;br /&gt;
&lt;br /&gt;
In general, drivers require the following libraries:&lt;br /&gt;
* System*&lt;br /&gt;
* System.Collections.Generic*&lt;br /&gt;
* OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
&lt;br /&gt;
Your driver will fail to compile if you miss any of these listed libraries. Libraries marked * are typically added by default by most modern IDEs. &lt;br /&gt;
&lt;br /&gt;
The OpenHome.Widget.Protocols.SimpleUpnp library is required only in this SimpleUPnP example. Drivers using a different protocol will use their own protocol library.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Implementing the provider ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-ProviderHighlight.png|800px|thumb|center|Figure 4 The driver architecture highlighting the Provider's place]]&lt;br /&gt;
&lt;br /&gt;
You use your auto-generated abstract provider by writing an implementation of it in the driver file. Responsibilities met by implementing your auto-generated provider are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R6 Reacting to actions sent to the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
Begin by creating a new class. It will subclass the abstract auto-generated provider:&lt;br /&gt;
&lt;br /&gt;
 class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
The Protocol Module will provide an API for the Provider to use to communicate with the Widget. In&lt;br /&gt;
SimpleUPnP we are provided with an interface called ISimpleUpnpWidget. The provider is supplied&lt;br /&gt;
with the required instance of the interface by the Discovery Module on the Node.&lt;br /&gt;
&lt;br /&gt;
The mechanisms for registering providers with specific Protocol Modules, and for the way the module gives each provider its required interface are covered later when writing the discovery method.&lt;br /&gt;
&lt;br /&gt;
For now, we need to give the Provider a place to store the interface that it will later use to communicate&lt;br /&gt;
with the Widget:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]] private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
&lt;br /&gt;
The interface from the Protocol Module is passed in as a parameter in the Provider's constructor and then&lt;br /&gt;
assigned to the variable we just created:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightProvider(DvDevice aDevice,&lt;br /&gt;
 [[File:Warning.png]]         ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
 {&lt;br /&gt;
       iProtocol = aProtocol;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
To satisfy R3 we would normally set the Widget's properties here, giving them an initial value.&lt;br /&gt;
However, in this specific example we cannot set the value of Basic Light's only property because&lt;br /&gt;
we will never know, in advance, what the state of the light will be (either on or off) when we&lt;br /&gt;
create the DiscoveredWidget.&lt;br /&gt;
&lt;br /&gt;
When you cannot set the properties ahead of time, and you are using an eventing protocol like SimpleUPnP, you can instead set them in the HandleRegisterEvent method in the driver class. This also satisfies the requirements for R3. You must set the Widget's properties before you enable it using SetEnabled(). &lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The abstract provider includes an abstract method called SetOn. This method is invoked by the Node when passing a message to the Widget, specifically to set the on property of the Widget to either 0 or 1. The implementation of this method will meet the requirements for R6.&lt;br /&gt;
&lt;br /&gt;
We must override this method and provide the protocol module a way of passing a message on to the Widget to perform the required action, in this case turn the light on or off:&lt;br /&gt;
&lt;br /&gt;
          protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
          {&lt;br /&gt;
     [[File:Warning.png]]        iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
In this example the Basic Light's SetOn property (the boolean property that controls whether the light is&lt;br /&gt;
on or off) is represented in the physical Widget by the register that has an index of 0.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* This method is an example of an action on a Widget. Actions are messages sent from the Node to the Widget. We will see later how to handle events that need to be passed back from the Widget&lt;br /&gt;
to the Node.&lt;br /&gt;
* Your own Widget will likely provide more than a single property. Your auto-generated provider will contain one abstract method to represent each writable property. Read-only properties are not provided an abstract method.&lt;br /&gt;
&lt;br /&gt;
You must implement each abstract method in your driver to ensure the relevant property on&lt;br /&gt;
the Widget can be set.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We have now finished implementing the provider. The next step is to implement the driver.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Implementing the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-DriverHighlight.png|800px|thumb|center|Figure 4: The driver architecture highlighting the implemented driver's place.]]&lt;br /&gt;
&lt;br /&gt;
The code for your Widget driver must provide an implementation of the IWidgetRegistryInterface,&lt;br /&gt;
including the following tasks:&lt;br /&gt;
&lt;br /&gt;
* methods to expose identifying details about the Widget for the Node to access&lt;br /&gt;
* providing methods to handle events reported by the Widget&lt;br /&gt;
&lt;br /&gt;
The driver is implemented as a public class within the same file as the provider code. Each driver must use the interface for the protocol you are using. For the SimpleUPnP protocol the interface is ISimple-UpnpWidgetDriver.&lt;br /&gt;
&lt;br /&gt;
=== Writing code ===&lt;br /&gt;
&lt;br /&gt;
Create your new driver class and subclass the ISimpleUpnpWidgetDriver interface:&lt;br /&gt;
&lt;br /&gt;
 public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Implementing IWidgetRegistryEntry ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry is the interface you use to represent physical Widgets. It is implemented as a subclass of your driver class. We are going to implement this interface in a class called '''DiscoveredWidget'''.&lt;br /&gt;
&lt;br /&gt;
Let's return to our driver architecture diagram for a moment:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-IRegistryEntryHighlight.png|800px|thumb|center|Figure 5 The driver architecture highlighting the IWidgetRegistryEntry object you will now implement]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry uses several other objects to help create it and respond to messages sent to and from it. These objects will be created in our implementation of DiscoveredWidget. &lt;br /&gt;
&lt;br /&gt;
When successfully created and published, the DiscoveredWidget objects are stored in a list on the Node called the Local Widget Registry. The Local Widget Registry is used by Nodes to maintain contact with the Widgets they control.&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry is shown at the top of Figure 5, marked plainly as (Registry). The path to the Local Widget Registry goes through several layers of Node architecture which are not relevant to Widget driver writing, so are not shown in the diagrams.&lt;br /&gt;
&lt;br /&gt;
==== Writing code ====&lt;br /&gt;
&lt;br /&gt;
Start by subclassing the IWidgetRegistryEntry interface in your new class:&lt;br /&gt;
&lt;br /&gt;
      private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
      {&lt;br /&gt;
&lt;br /&gt;
A DiscoveredWidget must provide the driver with the objects required to present the Widget and its&lt;br /&gt;
properties to the Node:&lt;br /&gt;
&lt;br /&gt;
           private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
           private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
           private readonly ISimpleUpnpWidget iProtocol;&lt;br /&gt;
           private readonly BinaryLightProvider iProvider;&lt;br /&gt;
           private readonly DvDevice iDvDevice;&lt;br /&gt;
           private IPublishedWidget iPublishedWidget;&lt;br /&gt;
&lt;br /&gt;
Each of the attributes in the example above are defined as follows:&lt;br /&gt;
&lt;br /&gt;
iDeviceFactory — used by the driver to create a single instance of DvDevice to represent a single Widget&lt;br /&gt;
&lt;br /&gt;
iPublisher — used by the driver to publish the Widget to the Node&lt;br /&gt;
&lt;br /&gt;
iProtocol — the object used by the Widget to communicate with the Protocol Module on the Node&lt;br /&gt;
&lt;br /&gt;
iProvider — an instantiated provider of the type you defined earlier&lt;br /&gt;
&lt;br /&gt;
iDvDevice — a representation of a Widget to which the provider is attached, created using iDevice-Factory above&lt;br /&gt;
&lt;br /&gt;
iPublishedWidget — used to contain the returned object from a successful publishing of the Widget&lt;br /&gt;
If we look again at the driver architecture diagram, we ca highlight the objects we've just defined:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-Highlight.png|800px|thumb|center|Figure 6: The driver architecture highlighting the objects used by the IWidgetRegistryEntry implementation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The DeviceFactory, defined above in the member variable iDeviceFactory, is used to create new DvDevice objects. The DeviceFactory is only ever used to do this once. It is not shown in the driver architecture diagrams due to its minimal role in the operation of a driver, but it would normally appear between the IWidgetRegistryEntry and DvDevice objects.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
A driver requires methods to expose identifying details about the Widget. We must provide access to two of the attributes we just defined above:&lt;br /&gt;
&lt;br /&gt;
 public DvDevice DvDevice&lt;br /&gt;
 {&lt;br /&gt;
     get { return iDvDevice; }&lt;br /&gt;
 }&lt;br /&gt;
 public string WidgetClass&lt;br /&gt;
 {&lt;br /&gt;
     get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The WidgetClass string is formed using a combination of the vendor name and the Widget's name in the&lt;br /&gt;
format:&lt;br /&gt;
&lt;br /&gt;
 [vendor_domain]:[widget_name]&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry can now query both the DvDevice object representing the Widget, and the specific class of Widget this driver represents. The other member variables we defined do not need their own accessor methods.&lt;br /&gt;
&lt;br /&gt;
Now we must write a constructor for DiscoveredWidget and assign the parameters accordingly: &lt;br /&gt;
&lt;br /&gt;
 public DiscoveredWidget(IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                            string aUdn,&lt;br /&gt;
                            ISimpleUpnpWidget aProxy,&lt;br /&gt;
                            IWidgetPublisher aPublisher)&lt;br /&gt;
 {&lt;br /&gt;
      iDeviceFactory = aDeviceFactory;&lt;br /&gt;
      iProtocol = aProtocol;&lt;br /&gt;
      iPublisher = aPublisher;&lt;br /&gt;
      iDvDevice = iDeviceFactory.CreateDevice(aUdn);&lt;br /&gt;
      iProvider = new BinaryLightProvider(iDvDevice,&lt;br /&gt;
      iProtocol);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Event handling ===&lt;br /&gt;
&lt;br /&gt;
A Widget's state can change in one of three significant ways:&lt;br /&gt;
&lt;br /&gt;
* when the Widget needs to be published on the Node&lt;br /&gt;
* when the Widget disappears from the network (by losing power or similar)&lt;br /&gt;
* when a property's state changes and must be updated to a new value&lt;br /&gt;
&lt;br /&gt;
We now need methods to handle these changes.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The methods we define here will be used as callbacks, rather than invoked as method calls. We define the methods here first and then use them later on. We will use the Protocol Module to listen for changes in the Widget's state and register these methods as callbacks there. See Writing the SimpleUPnP Widget discovery method for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this section of the driver are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R4 Publishing discovered Widgets in the Local Widget Registry on the Node'''&lt;br /&gt;
&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object. &lt;br /&gt;
&lt;br /&gt;
'''R5 Reacting to an event reported from the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
'''R7 Reacting to a Widget's departure'''&lt;br /&gt;
&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no longer available.&lt;br /&gt;
&lt;br /&gt;
==== Enabling and publishing a discovered Widget ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first method initializes the Widget by enabling the device and then using the IWidgetPublisher&lt;br /&gt;
to make it available on the Node:&lt;br /&gt;
&lt;br /&gt;
 public void HandleInitialEvent()&lt;br /&gt;
 {&lt;br /&gt;
      iDvDevice.SetEnabled();&lt;br /&gt;
      iPublisher.TryPublishWidget(iDvDevice.iUdn(),&lt;br /&gt;
                              this,&lt;br /&gt;
                              out iPublishedWidget);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This method meets the requirements for R4.&lt;br /&gt;
&lt;br /&gt;
The call to TryPublishWidget returns an iPublishedWidget object. We use this object later to satisfy the requirements of R7.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The ordering of the calls to SetEnabled and TryPublishWidget is vitally important. You&lt;br /&gt;
must enable the device before you attempt to publish it. Your Widget will not be available to the&lt;br /&gt;
Nodes unless SetEnabled is called first. Nodes will not be able to access a published device&lt;br /&gt;
that has not been enabled.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
R3 requires that you set the Widget's properties before you enable and publish the device. We&lt;br /&gt;
discussed on page 14 how some properties can only be set after the Widget reports what their&lt;br /&gt;
state is. We do this in HandleRegisterEvent.&lt;br /&gt;
&lt;br /&gt;
We rely on the SimpleUPnP Protocol Module guaranteeing a call to HandleRegisterEvent first before HandleInitialEvent. This is informed by guarantees made by the Control Point stack that the calls will be made in that order.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
==== Removing a Widget ====&lt;br /&gt;
&lt;br /&gt;
Removing a Widget involves unpublishing it from the Node. The IPublishedWidget interface provides us with a method we can call to manage that for us:&lt;br /&gt;
&lt;br /&gt;
 public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
 {&lt;br /&gt;
     if (iPublishedWidget != null)&lt;br /&gt;
     { iPublishedWidget.Unpublish(); }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assuming that the Widget was successfully published earlier, it is removed from the Node's Local Widget Registry.&lt;br /&gt;
&lt;br /&gt;
We must also properly handle the resources we used to create and maintain the Widget object while it was published:&lt;br /&gt;
&lt;br /&gt;
      iProvider.Dispose();&lt;br /&gt;
      iDvDevice.Dispose();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The calls to Dispose are made regardless of the Widget's published state, ensuring that any created device and associated provider are properly disposed. This implementation satisfies R7.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Event handling ====&lt;br /&gt;
&lt;br /&gt;
We need a method to handle changes to the state of the Widget's properties.&lt;br /&gt;
&lt;br /&gt;
If the property changes at the Widget, it needs to pass the new state back to the Node so that it is kept up-to-date on the Widget's status. This is called an event. An example in the case of our Basic Light is someone manually switching the light from on to off. This is in contrast to actions, which are passed from the Node to the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Other examples of events involve no human interaction, such as a thermometer Widget updating its current temperature based on environmental changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Our Basic Light Widget has only one property that needs to be handled:&lt;br /&gt;
&lt;br /&gt;
 public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
 {&lt;br /&gt;
     if (aIndex == 0)&lt;br /&gt;
     {&lt;br /&gt;
         iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We use our instance of the provider to update the register on the Widget that is mapped to the On property. This in turn updates the Node with the new state of the Widget.&lt;br /&gt;
&lt;br /&gt;
This method provides implementations to satisfy two driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
* R3 is now completely satisfied, as we can now set the values of all the previously unknown properties here.&lt;br /&gt;
* R5 is also satisfied as this method allows us to update the Widget's status on the Node when a property is changed on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Not all protocols pass messages back to the Node in this manner. The way we have satisfied R3 and R5 here only applies to protocols and Widgets that support this behavior.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Widgets that do not use an eventing protocol need to have their properties set in the provider's constructor to satisfy R3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To satisfy R5, the over-ridden method SetOn in the provider must include the call to SetPropertyOn. Non-eventing protocols do not require a HandleRegisterEvent method.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Constructor ===&lt;br /&gt;
&lt;br /&gt;
The final requirement for the driver is the constructor so that new DiscoveredWidget objects can be created. &lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this area of code are:&lt;br /&gt;
&lt;br /&gt;
'''R1 Specifying the type of Widget the driver controls'''&lt;br /&gt;
&lt;br /&gt;
A driver must know which type of Widget that it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Writing the code ====&lt;br /&gt;
&lt;br /&gt;
We begin by defining the variables we will use to store the objects used by the driver:&lt;br /&gt;
&lt;br /&gt;
 private readonly string iName;&lt;br /&gt;
 private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
 private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now write the constructor for the driver and assign the passed in parameters appropriately:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightDriver(string aName,&lt;br /&gt;
                IWidgetPublisher aPublisher,&lt;br /&gt;
                IDvDeviceFactory aDeviceFactory)&lt;br /&gt;
 {&lt;br /&gt;
     iWidgetPublisher = aPublisher;&lt;br /&gt;
     iName = aName;&lt;br /&gt;
     iDeviceFactory = aDeviceFactory;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally we need to provide the driver a way to publish the class of Widget it controls. This information is requested by the Discovery Module and is used to ensure the Node uses the correct driver when a new Widget appears.&lt;br /&gt;
&lt;br /&gt;
The implementation for this details will be different for each protocol. The SimpleUPnP protocol library provides a file that contains the SimpleUPnP definitions as integers. Each integer represents a particular class of identified Widget.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP implementation of that method is as follows:&lt;br /&gt;
&lt;br /&gt;
 public IEnumerable&amp;lt;uint&amp;gt; WidgetClasses&lt;br /&gt;
 {&lt;br /&gt;
 [[File:Warning.png]]        get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The body of this method is specifically written for the Widget class we are defining (in this case a binary light). This method completes the driver's requirements for R1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Writing the SimpleUPnP Widget discovery method ==&lt;br /&gt;
&lt;br /&gt;
Every driver must contain a method which creates new objects to represent newly discovered Widgets.&lt;br /&gt;
The Discovery Module invokes this method to begin the process of creating the objects required to allow the Node to access the Widget. &lt;br /&gt;
&lt;br /&gt;
The name of this method is dictated by your chosen protocol's API. The SimpleUPnP protocol requires a method called WidgetDiscovered.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The method's name will not always be the same for each protocol. Your protocol's documentation will contain the details of what this method must be called.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This method and its implementation will meet the following driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
'''R2 Reacting to a discovered Widget on the network'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
Our implementation of the WidgetDiscovered method will create a new DiscoveredWidget object and use the Protocol Module to listen for changes to the Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
The method uses the Protocol Module and two ways to identify the Widget. We must pass these in as&lt;br /&gt;
parameters:&lt;br /&gt;
&lt;br /&gt;
 public void WidgetDiscovered(string aWidgetUdn,&lt;br /&gt;
                              uint aWidgetClass,&lt;br /&gt;
                              ISimpleUpnpWidget&lt;br /&gt;
                                  aSimpleUpnpWidget)&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
Every Widget that uses this driver must be uniquely identifiable:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]    string newUdn = aWidgetUdn;&lt;br /&gt;
&lt;br /&gt;
Each new Widget is represented by a DiscoveredWidget object. Create the new DiscoveredWidget and pass in the required parameters we created earlier:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
     DiscoveredWidget discoveredWidget =&lt;br /&gt;
                 new DiscoveredWidget(iDeviceFactory,&lt;br /&gt;
                                      newUdn,&lt;br /&gt;
  &lt;br /&gt;
 [[File:Warning.png]]                                    aSimpleUpnpWidget,&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Registering the callbacks ===&lt;br /&gt;
&lt;br /&gt;
Finally, we ask the Widget's protocol interface to listen for calls to the handler methods we defined earlier in DiscoveredWidget. We do this by registering those methods as callbacks for the Protocol Module&lt;br /&gt;
to listen for:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                        discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                        discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                        discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You have now met 100% of the driver responsibility requirements and have a working driver to use with your SimpleUPnP Widget.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix A. Sample XML =&lt;br /&gt;
&lt;br /&gt;
== Binary Light.xml ==&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
  &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
  &amp;lt;version&amp;gt;&lt;br /&gt;
   &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
   &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/version&amp;gt;&lt;br /&gt;
  &amp;lt;propertylist&amp;gt;&lt;br /&gt;
   &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
       illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
   &amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix B. Sample Provider = &lt;br /&gt;
&lt;br /&gt;
== DvWidgetOpenhomeOrgBasicLight1.cs ==&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Runtime.InteropServices;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Core;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Utils.Binary;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
 {&lt;br /&gt;
    public interface IDvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
        IDisposable&lt;br /&gt;
    {&lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous value&lt;br /&gt;
        /// &amp;lt;/returns&amp;gt;&lt;br /&gt;
        bool SetPropertyOn(bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;Property's value will be copied&lt;br /&gt;
        /// here&amp;lt;/param&amp;gt;&lt;br /&gt;
        bool PropertyOn();&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt; summary&amp;gt;&lt;br /&gt;
    /// Provider for the openhome.org:BinaryLight:1 UPnP service&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public abstract class DvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
               DvProvider,&lt;br /&gt;
               IDisposable,&lt;br /&gt;
               IDvProviderOpenhomeOrgBinaryLight1&lt;br /&gt;
    {&lt;br /&gt;
        private GCHandle iGch;&lt;br /&gt;
        private PropertyBool iPropertyOn;&lt;br /&gt;
        private PropertyUint iPropertyPrimarySeq;&lt;br /&gt;
        private PropertyUint iPropertySecondarySeq;&lt;br /&gt;
        private ActionDelegate iDelegateSetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetPrimaryProperty;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Constructor&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aDevice&amp;quot;&amp;gt;Device which owns this&lt;br /&gt;
        /// provider&amp;lt;/param&amp;gt;&lt;br /&gt;
        protected DvProviderOpenhomeOrgBinaryLight1(DvDevice aDevice)&lt;br /&gt;
            : base(aDevice, &amp;quot;openhome.org&amp;quot;, &amp;quot;GenericWidget&amp;quot;, 1)&lt;br /&gt;
        {&lt;br /&gt;
            iGch = GCHandle.Alloc(this);&lt;br /&gt;
            List&amp;lt;String&amp;gt; allowedValues = new List&amp;lt;String&amp;gt;();&lt;br /&gt;
            iPropertyOn = new PropertyBool(new ParameterBool(&amp;quot;On&amp;quot;));&lt;br /&gt;
            iPropertyPrimarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;PrimarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertyPrimarySeq);&lt;br /&gt;
            iPropertySecondarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;SecondarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertySecondarySeq);&lt;br /&gt;
            SetPropertyUint(iPropertyPrimarySeq, 0);&lt;br /&gt;
            SetPropertyUint(iPropertySecondarySeq, 0);&lt;br /&gt;
  &lt;br /&gt;
            Zapp.Core.Action action = new Zapp.Core.Action&lt;br /&gt;
                (&amp;quot;SetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;FireAndForget&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddInputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateSetProperty = new ActionDelegate(DoSetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateSetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateGetProperty = new ActionDelegate(DoGetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetPrimaryProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                 (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;integer&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;boolean&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;string&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;binary&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Type&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;readWrite&amp;quot;);allowedValues.Add&lt;br /&gt;
                (&amp;quot;readOnly&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;writeOnly&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString(&amp;quot;Access&amp;quot;,&lt;br /&gt;
                allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            iDelegateGetPrimaryProperty = new&lt;br /&gt;
            ActionDelegate(DoGetPrimaryProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetPrimaryProperty,&lt;br /&gt;
            GCHandle.ToIntPtr(iGch));&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous&lt;br /&gt;
        /// value&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool SetPropertyOn(bool aValue)&lt;br /&gt;
        {&lt;br /&gt;
            if (iPropertyOn.SetValue(aValue))&lt;br /&gt;
            {&lt;br /&gt;
                lock (iPropertyPrimarySeq)&lt;br /&gt;
                {&lt;br /&gt;
                    SetPropertyUint(iPropertyPrimarySeq,&lt;br /&gt;
                        iPropertyPrimarySeq.Value() + 1);&lt;br /&gt;
                } return true;&lt;br /&gt;
            } return false;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;The value of the property&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool PropertyOn()&lt;br /&gt;
        {&lt;br /&gt;
            return iPropertyOn.Value();&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the On property.&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aVersion&amp;quot;&amp;gt;Version of the service being&lt;br /&gt;
        /// requested (will be &amp;lt;= the version advertised)&amp;lt;/param&amp;gt; &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the On property.&lt;br /&gt;
        /// &amp;lt;/param&amp;gt;&lt;br /&gt;
        protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        private static int DoSetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                byte[] valBin = invocation.ReadBinary(&amp;quot;Value&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                switch (name)&lt;br /&gt;
                {&lt;br /&gt;
                    case &amp;quot;On&amp;quot;:&lt;br /&gt;
                        self.SetOn(aVersion, Converter.&lt;br /&gt;
                            BinaryToBoolean(valBin));&lt;br /&gt;
                        break;&lt;br /&gt;
                    default:&lt;br /&gt;
                        throw new ActionError();&lt;br /&gt;
                }&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
                invocation.WriteEnd();&lt;br /&gt;
            }&lt;br /&gt;
            catch (ActionError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
            catch (PropertyUpdateError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
        return 0;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        private static int DoGetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
            switch (name)&lt;br /&gt;
            {&lt;br /&gt;
                case &amp;quot;On&amp;quot;:&lt;br /&gt;
                invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                    Converter.BooleanToBinary(self.iPropertyOn.&lt;br /&gt;
                        Value()));&lt;br /&gt;
                break;&lt;br /&gt;
                default:&lt;br /&gt;
                throw new ActionError();&lt;br /&gt;
            }&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    private static int DoGetPrimaryProperty(IntPtr aPtr,&lt;br /&gt;
                    IntPtr aInvocation,&lt;br /&gt;
                    uint aVersion)&lt;br /&gt;
    {&lt;br /&gt;
        GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
        DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
            (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
        DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
  &lt;br /&gt;
        try&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReadStart();&lt;br /&gt;
            invocation.ReadEnd();&lt;br /&gt;
            invocation.WriteStart();&lt;br /&gt;
            invocation.WriteString(&amp;quot;Name&amp;quot;, &amp;quot;On&amp;quot;);&lt;br /&gt;
            invocation.WriteString(&amp;quot;Type&amp;quot;, &amp;quot;boolean&amp;quot;);&lt;br /&gt;
            invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                Converter.BooleanToBinary(self.iPropertyOn.Value()));&lt;br /&gt;
            invocation.WriteString(&amp;quot;Access&amp;quot;, &amp;quot;readWrite&amp;quot;);&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt;summary&amp;gt;&lt;br /&gt;
    /// Must be called for each class instance. Must be called before&lt;br /&gt;
    /// Core.Library.Close().&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public void Dispose()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
        GC.SuppressFinalize(this);&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
    ~DvProviderOpenhomeOrgBinaryLight1()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
        private void DoDispose()&lt;br /&gt;
        {&lt;br /&gt;
            lock (this)&lt;br /&gt;
            {&lt;br /&gt;
                if (iHandle == IntPtr.Zero)&lt;br /&gt;
            {&lt;br /&gt;
                    return;&lt;br /&gt;
            }&lt;br /&gt;
            DisposeProvider();&lt;br /&gt;
            iPropertyOn.Dispose();&lt;br /&gt;
            iHandle = IntPtr.Zero;&lt;br /&gt;
            }&lt;br /&gt;
            iGch.Free();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix C. Sample Driver = &lt;br /&gt;
&lt;br /&gt;
== BasicLightDriver.cs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.hWidget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
     class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
     {&lt;br /&gt;
         private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
         public BinaryLightProvider(DvDevice aDevice, &lt;br /&gt;
             ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol = aProtocol;&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
     {&lt;br /&gt;
         private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
         {&lt;br /&gt;
             private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
             private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
             private readonly ISimpleUpnpWidget iProtocol; &lt;br /&gt;
 &lt;br /&gt;
             private readonly BinaryLightProvider iProvider;&lt;br /&gt;
             private readonly DvDevice iDvDevice;&lt;br /&gt;
             private IPublishedWidget iPublishedWidget; &lt;br /&gt;
 &lt;br /&gt;
             public DvDevice DvDevice&lt;br /&gt;
             {&lt;br /&gt;
                 get { return iDvDevice; }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             public string WidgetClass&lt;br /&gt;
             {&lt;br /&gt;
                 get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public DiscoveredWidget(&lt;br /&gt;
                 IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                 string aUdn,&lt;br /&gt;
                 ISimpleUpnpWidget aProxy,&lt;br /&gt;
                 IWidgetPublisher aPublisher)&lt;br /&gt;
             {&lt;br /&gt;
                 iDeviceFactory = aDeviceFactory;&lt;br /&gt;
                 iProtocol = aProtocol;&lt;br /&gt;
 &lt;br /&gt;
                 iPublisher = aPublisher;&lt;br /&gt;
                 iDvDevice = iDeviceFactory.CreateDevice(aUdn);  &lt;br /&gt;
                 iProvider = new BinaryLightProvider(iDvDevice, &lt;br /&gt;
                                                     iProtocol);&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             public void HandleInitialEvent()&lt;br /&gt;
             {&lt;br /&gt;
                 iDvDevice.SetEnabled();&lt;br /&gt;
                 iPublisher.TryPublishWidget(iDvDevice.iUdn(), this,&lt;br /&gt;
                     out iPublishedWidget);&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
             {&lt;br /&gt;
                 if (iPublishedWidget != null)&lt;br /&gt;
                 {&lt;br /&gt;
                     iPublishedWidget.Unpublish();&lt;br /&gt;
                 } &lt;br /&gt;
                 iProvider.Dispose();&lt;br /&gt;
                 iDvDevice.Dispose();&lt;br /&gt;
             }  &lt;br /&gt;
 &lt;br /&gt;
             public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
             {&lt;br /&gt;
                 if (aIndex == 0)&lt;br /&gt;
                 {&lt;br /&gt;
                     iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         private readonly string iName;&lt;br /&gt;
         private readonly IDvDeviceFactory aDeviceFactory;&lt;br /&gt;
         private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
         &lt;br /&gt;
         public BinaryLightDriver(&lt;br /&gt;
             string aName,&lt;br /&gt;
             IWidgetPublisher aPublisher,&lt;br /&gt;
             iDeviceFactory aDeviceFactory)&lt;br /&gt;
         {&lt;br /&gt;
             iWidgetPublisher = aPublisher;&lt;br /&gt;
             iName = aName;&lt;br /&gt;
             iDeviceFactory = aDeviceFactory;&lt;br /&gt;
         } &lt;br /&gt;
 &lt;br /&gt;
         public IEnumerable&amp;amp;lt;uint&amp;amp;gt; WidgetClasses&lt;br /&gt;
         {&lt;br /&gt;
             get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         public void WidgetDiscovered(&lt;br /&gt;
             string aWidgetUdn,&lt;br /&gt;
             uint aWidgetClass,&lt;br /&gt;
             ISimpleUpnpWidget aSimpleUpnpWidget)&lt;br /&gt;
         {&lt;br /&gt;
             string newUdn = aWidgetUdn;&lt;br /&gt;
             DiscoveredWidget discoveredWidget = new DiscoveredWidget&lt;br /&gt;
                 (iDeviceFactory,&lt;br /&gt;
                  newUdn,&lt;br /&gt;
                  aSimpleUpnpWidget,&lt;br /&gt;
                  iWidgetPublisher);&lt;br /&gt;
 &lt;br /&gt;
             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                 discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                 discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                 discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary = &lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in OpenHome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by OpenHome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh - A collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs on ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The OpenHome Operating System. Core software for OpenHome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. &lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. A typical Widget supports only one protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Driver_Development</id>
		<title>OhWidget Driver Development</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Driver_Development"/>
				<updated>2012-03-01T15:17:58Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Register model */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for developers using the OpenHome SDK to integrate a Widget into an OpenHome system. Each Widget must have its own driver to allow it to communicate with the OpenHome Nodes. &lt;br /&gt;
&lt;br /&gt;
To help you write your driver, this document provides high level descriptions of the core responsibilities of a Widget driver and gives a detailed walk-through using example code.&lt;br /&gt;
&lt;br /&gt;
Full versions of each file used in the development of the example driver are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin development of your Widget driver you must be in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* your Widget Service XML that describes the properties on your Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document does not contain advice on how to write Widget Service XML. Refer to the OpenHome Widget Service XML definition document for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK&lt;br /&gt;
* your chosen communication protocol's API&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The protocol you choose for your Widgets must be the same protocol used on your choice of Node.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document focuses on the development of the Widget driver. Details about the communications protocol used are beyond the scope of this document. This document assumes you are familiar with your chosen protocol's code libraries and are able to use them in the driver code you write.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Related Documents ==&lt;br /&gt;
&lt;br /&gt;
The following related OpenHome documentation may be of interest to you:&lt;br /&gt;
&lt;br /&gt;
* [[ohWidget Technical Overview|ohWidget Technical Overview]]&lt;br /&gt;
* [[OpenHome Widget Service XML definition|OpenHome Widget Service XML definition]]&lt;br /&gt;
* [http://www.openhome.org/releases/ohNet_DeviceStack.pdf  OpenHome ohNet Device Stack]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
None of the related documents listed above is mandatory reading for Widget driver development.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
== Widget Service XML ==&lt;br /&gt;
OpenHome Widget driver writing relies heavily on the use of code generated from a single source — the Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
The service and actions your Widget provides are represented in code in a file called a Provider. The Provider is automatically generated from the Widget Service XML and produces an abstract class for you to inherit when you write your concrete class driver.&lt;br /&gt;
&lt;br /&gt;
To aid in the explanation of how the Provider is created and put to use we will follow the development of&lt;br /&gt;
a driver for a simple light Widget; taking the defined Widget Service XML and stepping through how it is used to generate the other files. Examples of code are used throughout this document to show you how each one is created and used in an OpenHome system. &lt;br /&gt;
&lt;br /&gt;
It is essential that you start with a well-formed Widget Service XML, conforming to the schema defined&lt;br /&gt;
in the WidgetService.xsd. The following diagram shows the significance of the Widget Service XML in&lt;br /&gt;
relation to the generated files you will use when writing your driver:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarchy, highlighting the areas specifically used in driver development]]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* The grayed-out files are not relevant to Widget driver development but can also be generated from the Widget Service XML.&lt;br /&gt;
* The Provider is generated in C#, meaning your driver must be written in C# as well. The use of managed code is mandatory for driver writing in the OpenHome framework.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Code sample used in this document ==&lt;br /&gt;
&lt;br /&gt;
Our examples in this document use a Widget Service XML definition for a light Widget called&lt;br /&gt;
BasicLight.xml.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Full versions of all the example files used in this document are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We will see how the Provider is generated from this XML and how it is used to aid the driver writing process. The examples also show how your chosen communication protocol should be used in the body of the driver code.&lt;br /&gt;
&lt;br /&gt;
Implementation details of specific protocols you choose to use are beyond the scope of this document. However, the samples used in this document show the use of the SimpleUPnP protocol to aid you in your development process.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol during the early stages of the OpenHome project. It is included in the OpenHome SDK and can be used as a public resource. &lt;br /&gt;
&lt;br /&gt;
The use of SimpleUPnP in the example files and the code snippets within the following sections is highlighted by the [[File:Warning.png]] icon. The lines of code marked by [[File:Warning.png]] must be changed to code from your chosen communication protocol's library. SimpleUPnP is left in to help you understand how a protocol is used in a working example.&lt;br /&gt;
&lt;br /&gt;
The sample code provided attempts to show best-practice coding standards. There are several sections of code that have a mandatory layout or that call specifically named methods and functions. These areas of the code are highlighted where required. &lt;br /&gt;
&lt;br /&gt;
Where the examples do not explicitly state that the code shown is mandatory, you are free to implement it in a different way according to your own coding style and practices.&lt;br /&gt;
&lt;br /&gt;
= Driver responsibilities = &lt;br /&gt;
&lt;br /&gt;
== Driver responsibilities ==&lt;br /&gt;
&lt;br /&gt;
An OpenHome Widget driver has several responsibilities which must be met before it can be used on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
These responsibilities are listed R1 to R7 and are defined here, explaining what each one must do. &lt;br /&gt;
&lt;br /&gt;
=== R1 Specifying the type of Widget the driver controls ===&lt;br /&gt;
A driver must know which type of Widget it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
=== R2 Reacting to a discovered Widget on the network ===&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== R3 Setting the initial values for the Widget's properties ===&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
=== R4 Publishing discovered Widgets in the Local Widget Registry on the Node ===&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object.&lt;br /&gt;
&lt;br /&gt;
=== R5 Reacting to an event reported from the Widget ===&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
=== R6 Reacting to actions sent to the Widget ===&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== R7 Reacting to a Widget's departure ===&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no&lt;br /&gt;
longer available.&lt;br /&gt;
&lt;br /&gt;
The sections of example code that follow show you how to write a driver from beginning to end. The accompanying text explaining the example code highlights when a responsibility, or part of a responsibility, has been met.&lt;br /&gt;
&lt;br /&gt;
= Driver Architecture = &lt;br /&gt;
&lt;br /&gt;
== Driver Architecture ==&lt;br /&gt;
&lt;br /&gt;
Drivers are installed on the Node and used when the Node needs to communicate with the Widget. Drivers&lt;br /&gt;
use several objects to communicate with Widgets over the Widget's lifetime. Figure 2 shows the objects&lt;br /&gt;
used by the driver and how the responsibilities listed above relate to each one:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture.png|800px|thumb|center|Figure 2: The architecture of a driver, showing the driver's relationship to the objects used to communicate with a Widget. Lines between objects show message flow.]]&lt;br /&gt;
&lt;br /&gt;
The objects contained in the dotted boundary must appear in the code you write to define your driver. The Driver, Provider and IWidgetRegistryEntry objects are all contained in the same driver file. We begin discussing this on page 12. &lt;br /&gt;
&lt;br /&gt;
The other objects are provided by the OpenHome SDK or as installed components on the Node.&lt;br /&gt;
&lt;br /&gt;
The Discovery Module informs the driver of the presence of an available Widget.&lt;br /&gt;
&lt;br /&gt;
Each Node has a Protocol Module which contains the protocol's API. Widgets can communicate with OpenHome Nodes using any one of the set of communications protocols the Node supports. The driver uses your chosen protocol's Protocol Module to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
Both the Protocol Module and the Discovery Module are installed on the Node. When you write your&lt;br /&gt;
driver you will use your Protocol Module to allow the driver to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
IWidgetPublisher, IPublishedWidget and DvDevice are objects provided in the OpenHome&lt;br /&gt;
API. You can read about them in the APIs.&lt;br /&gt;
&lt;br /&gt;
= Generating the Provider = &lt;br /&gt;
&lt;br /&gt;
== Generating the Provider ==&lt;br /&gt;
&lt;br /&gt;
You must generate your provider before you can begin writing your Widget driver. You use your provider as a guide to implement the functions your Widget needs to set the values of its properties.&lt;br /&gt;
&lt;br /&gt;
The current provider generation process is a manual one involving the use of a text transform tool.&lt;br /&gt;
&lt;br /&gt;
Speak to your OpenHome contact who will help you generate your provider.&lt;br /&gt;
&lt;br /&gt;
Future releases of the OpenHome SDK will include a tool to help you generate the provider.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
You must be in possession of:&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK, unpacked on your computer&lt;br /&gt;
* your Widget Service XML file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Writing a SimpleUPnP driver = &lt;br /&gt;
&lt;br /&gt;
== Introduction to the SimpleUPnP protocol ==&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol used to control emulated Widgets over a custom UPnP service.&lt;br /&gt;
&lt;br /&gt;
This chapter shows how a driver is written using the SimpleUPnP communications protocol. The aim is to show the code using as generic a protocol as possible so that you can see where your own protocol specific code needs to go.&lt;br /&gt;
&lt;br /&gt;
The use of code specific to the SimpleUPnP implementation is highlighted by the use of the [[File:Warning.png]] icon. The lines of code are marked by this icon to make it easier for you to see where the protocol-specific code must go and what parts of the code are generic.&lt;br /&gt;
&lt;br /&gt;
=== Register model ===&lt;br /&gt;
&lt;br /&gt;
SimpleUPnP is modeled on 8 physical registers available on the Widget. Each register is 32-bits wide. They are indexed from 0 to 7 and the last register (register 7) is reserved for storing the Widget's class.&lt;br /&gt;
&lt;br /&gt;
This detail is used by the Protocol Module on the Node to determine which driver is needed to run the new Widget when it has been discovered.&lt;br /&gt;
&lt;br /&gt;
The remaining 7 registers (registers 0 to 6) are free for Widget engineers to assign to the Widget's functions.&lt;br /&gt;
&lt;br /&gt;
Registers 0, 1, 2 and 3 are available as read/write registers. Registers 4, 5 and 6 are readonly registers.&lt;br /&gt;
&lt;br /&gt;
Only the emulated hardware (running on the Node) can change the values held in registers 4, 5 and 6.&lt;br /&gt;
&lt;br /&gt;
=== Register use in drivers ===&lt;br /&gt;
&lt;br /&gt;
In the example that follows we have a Basic Light Widget with a very simple function: it can be turned on and turned off. The on/off value is stored in register 0, with values 0=OFF and 1=ON. Register 0 is a read/write register. This means we can change the value stored there using messages passed to the Widget from the Node, and by reacting to physical interactions at the Widget (such as someone manually switching the light on or off). &lt;br /&gt;
&lt;br /&gt;
The mapping of registers to properties on the Widget is decided by the engineers who manufacture the device. You must be provided with the mapping before you begin developing your driver.&lt;br /&gt;
&lt;br /&gt;
== Starting the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-BoxHighlight.png|800px|thumb|center|Figure 3 The driver architecture highlighting the Widget driver and its component parts.]]&lt;br /&gt;
&lt;br /&gt;
When you have generated the abstract provider you can put it to use in the Widget driver. A Widget driver&lt;br /&gt;
has three distinct components:&lt;br /&gt;
&lt;br /&gt;
* an implementation of your abstract provider&lt;br /&gt;
* a definition of the Widget driver&lt;br /&gt;
* an implementation of the IWidgetRegistryEntry interface&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must manually write the code for your Widget driver. The differences in implementation of Widget properties and communication protocols means that the driver code cannot be autogenerated.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This section takes you through how to write a Widget driver by implementing the auto-generated provider,&lt;br /&gt;
starting from a new blank file and finishing with a working driver for the Basic Light Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
No assumptions have been made about the type of editor you use to write your code. Shortcuts&lt;br /&gt;
or macros that you use as standard will not appear in the instructions below. A full example&lt;br /&gt;
BinaryLightDriver.cs is available to review in Appendix C.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a new C# file in your IDE. Ensure the following libraries are used:&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 [[File:Warning.png]]using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 namespace OpenHome.Widget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must use the libraries listed above for this specific example.&lt;br /&gt;
&lt;br /&gt;
In general, drivers require the following libraries:&lt;br /&gt;
* System*&lt;br /&gt;
* System.Collections.Generic*&lt;br /&gt;
* OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
&lt;br /&gt;
Your driver will fail to compile if you miss any of these listed libraries. Libraries marked * are typically added by default by most modern IDEs. &lt;br /&gt;
&lt;br /&gt;
The OpenHome.Widget.Protocols.SimpleUpnp library is required only in this SimpleUPnP example. Drivers using a different protocol will use their own protocol library.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Implementing the provider ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-ProviderHighlight.png|800px|thumb|center|Figure 4 The driver architecture highlighting the Provider's place]]&lt;br /&gt;
&lt;br /&gt;
You use your auto-generated abstract provider by writing an implementation of it in the driver file. Responsibilities met by implementing your auto-generated provider are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R6 Reacting to actions sent to the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
Begin by creating a new class. It will subclass the abstract auto-generated provider:&lt;br /&gt;
&lt;br /&gt;
 class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
The Protocol Module will provide an API for the Provider to use to communicate with the Widget. In&lt;br /&gt;
SimpleUPnP we are provided with an interface called ISimpleUpnpWidget. The provider is supplied&lt;br /&gt;
with the required instance of the interface by the Discovery Module on the Node.&lt;br /&gt;
&lt;br /&gt;
The mechanisms for registering providers with specific Protocol Modules, and for the way the module gives each provider its required interface are covered later when writing the discovery method.&lt;br /&gt;
&lt;br /&gt;
For now, we need to give the Provider a place to store the interface that it will later use to communicate&lt;br /&gt;
with the Widget:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]] private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
&lt;br /&gt;
The interface from the Protocol Module is passed in as a parameter in the Provider's constructor and then&lt;br /&gt;
assigned to the variable we just created:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightProvider(DvDevice aDevice,&lt;br /&gt;
 [[File:Warning.png]]         ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
 {&lt;br /&gt;
       iProtocol = aProtocol;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
To satisfy R3 we would normally set the Widget's properties here, giving them an initial value.&lt;br /&gt;
However, in this specific example we cannot set the value of Basic Light's only property because&lt;br /&gt;
we will never know, in advance, what the state of the light will be (either on or off) when we&lt;br /&gt;
create the DiscoveredWidget.&lt;br /&gt;
&lt;br /&gt;
When you cannot set the properties ahead of time, and you are using an eventing protocol like SimpleUPnP, you can instead set them in the HandleRegisterEvent method in the driver class. This also satisfies the requirements for R3. You must set the Widget's properties before you enable it using SetEnabled(). &lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The abstract provider includes an abstract method called SetOn. This method is invoked by the Node when passing a message to the Widget, specifically to set the on property of the Widget to either 0 or 1. The implementation of this method will meet the requirements for R6.&lt;br /&gt;
&lt;br /&gt;
We must override this method and provide the protocol module a way of passing a message on to the Widget to perform the required action, in this case turn the light on or off:&lt;br /&gt;
&lt;br /&gt;
          protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
          {&lt;br /&gt;
     [[File:Warning.png]]        iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
In this example the Basic Light's SetOn property (the boolean property that controls whether the light is&lt;br /&gt;
on or off) is represented in the physical Widget by the register that has an index of 0.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* This method is an example of an action on a Widget. Actions are messages sent from the Node to the Widget. We will see later how to handle events that need to be passed back from the Widget&lt;br /&gt;
to the Node.&lt;br /&gt;
* Your own Widget will likely provide more than a single property. Your auto-generated provider will contain one abstract method to represent each writable property. Read-only properties are not provided an abstract method.&lt;br /&gt;
&lt;br /&gt;
You must implement each abstract method in your driver to ensure the relevant property on&lt;br /&gt;
the Widget can be set.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We have now finished implementing the provider. The next step is to implement the driver.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Implementing the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-DriverHighlight.png|800px|thumb|center|Figure 4: The driver architecture highlighting the implemented driver's place.]]&lt;br /&gt;
&lt;br /&gt;
The code for your Widget driver must provide an implementation of the IWidgetRegistryInterface,&lt;br /&gt;
including the following tasks:&lt;br /&gt;
&lt;br /&gt;
* methods to expose identifying details about the Widget for the Node to access&lt;br /&gt;
* providing methods to handle events reported by the Widget&lt;br /&gt;
&lt;br /&gt;
The driver is implemented as a public class within the same file as the provider code. Each driver must use the interface for the protocol you are using. For the SimpleUPnP protocol the interface is ISimple-UpnpWidgetDriver.&lt;br /&gt;
&lt;br /&gt;
=== Writing code ===&lt;br /&gt;
&lt;br /&gt;
Create your new driver class and subclass the ISimpleUpnpWidgetDriver interface:&lt;br /&gt;
&lt;br /&gt;
 public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Implementing IWidgetRegistryEntry ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry is the interface you use to represent physical Widgets. It is implemented as a subclass of your driver class. We are going to implement this interface in a class called '''DiscoveredWidget'''.&lt;br /&gt;
&lt;br /&gt;
Let's return to our driver architecture diagram for a moment:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-IRegistryEntryHighlight.png|800px|thumb|center|Figure 5 The driver architecture highlighting the IWidgetRegistryEntry object you will now implement]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry uses several other objects to help create it and respond to messages sent to and from it. These objects will be created in our implementation of DiscoveredWidget. &lt;br /&gt;
&lt;br /&gt;
When successfully created and published, the DiscoveredWidget objects are stored in a list on the Node called the Local Widget Registry. The Local Widget Registry is used by Nodes to maintain contact with the Widgets they control.&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry is shown at the top of Figure 5, marked plainly as (Registry). The path to the Local Widget Registry goes through several layers of Node architecture which are not relevant to Widget driver writing, so are not shown in the diagrams.&lt;br /&gt;
&lt;br /&gt;
==== Writing code ====&lt;br /&gt;
&lt;br /&gt;
Start by subclassing the IWidgetRegistryEntry interface in your new class:&lt;br /&gt;
&lt;br /&gt;
      private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
      {&lt;br /&gt;
&lt;br /&gt;
A DiscoveredWidget must provide the driver with the objects required to present the Widget and its&lt;br /&gt;
properties to the Node:&lt;br /&gt;
&lt;br /&gt;
           private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
           private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
           private readonly ISimpleUpnpWidget iProtocol;&lt;br /&gt;
           private readonly BinaryLightProvider iProvider;&lt;br /&gt;
           private readonly DvDevice iDvDevice;&lt;br /&gt;
           private IPublishedWidget iPublishedWidget;&lt;br /&gt;
&lt;br /&gt;
Each of the attributes in the example above are defined as follows:&lt;br /&gt;
&lt;br /&gt;
iDeviceFactory — used by the driver to create a single instance of DvDevice to represent a single Widget&lt;br /&gt;
&lt;br /&gt;
iPublisher — used by the driver to publish the Widget to the Node&lt;br /&gt;
&lt;br /&gt;
iProtocol — the object used by the Widget to communicate with the Protocol Module on the Node&lt;br /&gt;
&lt;br /&gt;
iProvider — an instantiated provider of the type you defined earlier&lt;br /&gt;
&lt;br /&gt;
iDvDevice — a representation of a Widget to which the provider is attached, created using iDevice-Factory above&lt;br /&gt;
&lt;br /&gt;
iPublishedWidget — used to contain the returned object from a successful publishing of the Widget&lt;br /&gt;
If we look again at the driver architecture diagram, we ca highlight the objects we've just defined:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-Highlight.png|800px|thumb|center|Figure 6: The driver architecture highlighting the objects used by the IWidgetRegistryEntry implementation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The DeviceFactory, defined above in the member variable iDeviceFactory, is used to create new DvDevice objects. The DeviceFactory is only ever used to do this once. It is not shown in the driver architecture diagrams due to its minimal role in the operation of a driver, but it would normally appear between the IWidgetRegistryEntry and DvDevice objects.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
A driver requires methods to expose identifying details about the Widget. We must provide access to two of the attributes we just defined above:&lt;br /&gt;
&lt;br /&gt;
 public DvDevice DvDevice&lt;br /&gt;
 {&lt;br /&gt;
     get { return iDvDevice; }&lt;br /&gt;
 }&lt;br /&gt;
 public string WidgetClass&lt;br /&gt;
 {&lt;br /&gt;
     get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The WidgetClass string is formed using a combination of the vendor name and the Widget's name in the&lt;br /&gt;
format:&lt;br /&gt;
&lt;br /&gt;
 [vendor_domain]:[widget_name]&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry can now query both the DvDevice object representing the Widget, and the specific class of Widget this driver represents. The other member variables we defined do not need their own accessor methods.&lt;br /&gt;
&lt;br /&gt;
Now we must write a constructor for DiscoveredWidget and assign the parameters accordingly: &lt;br /&gt;
&lt;br /&gt;
 public DiscoveredWidget(IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                            string aUdn,&lt;br /&gt;
                            ISimpleUpnpWidget aProxy,&lt;br /&gt;
                            IWidgetPublisher aPublisher)&lt;br /&gt;
 {&lt;br /&gt;
      iDeviceFactory = aDeviceFactory;&lt;br /&gt;
      iProtocol = aProtocol;&lt;br /&gt;
      iPublisher = aPublisher;&lt;br /&gt;
      iDvDevice = iDeviceFactory.CreateDevice(aUdn);&lt;br /&gt;
      iProvider = new BinaryLightProvider(iDvDevice,&lt;br /&gt;
      iProtocol);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Event handling ===&lt;br /&gt;
&lt;br /&gt;
A Widget's state can change in one of three significant ways:&lt;br /&gt;
&lt;br /&gt;
* when the Widget needs to be published on the Node&lt;br /&gt;
* when the Widget disappears from the network (by losing power or similar)&lt;br /&gt;
* when a property's state changes and must be updated to a new value&lt;br /&gt;
&lt;br /&gt;
We now need methods to handle these changes.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The methods we define here will be used as callbacks, rather than invoked as method calls. We define the methods here first and then use them later on. We will use the Protocol Module to listen for changes in the Widget's state and register these methods as callbacks there. See Writing the SimpleUPnP Widget discovery method for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this section of the driver are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R4 Publishing discovered Widgets in the Local Widget Registry on the Node'''&lt;br /&gt;
&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object. &lt;br /&gt;
&lt;br /&gt;
'''R5 Reacting to an event reported from the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
'''R7 Reacting to a Widget's departure'''&lt;br /&gt;
&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no longer available.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Enabling and publishing a discovered Widget ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first method initializes the Widget by enabling the device and then using the IWidgetPublisher&lt;br /&gt;
to make it available on the Node:&lt;br /&gt;
&lt;br /&gt;
 public void HandleInitialEvent()&lt;br /&gt;
 {&lt;br /&gt;
      iDvDevice.SetEnabled();&lt;br /&gt;
      iPublisher.TryPublishWidget(iDvDevice.iUdn(),&lt;br /&gt;
                              this,&lt;br /&gt;
                              out iPublishedWidget);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This method meets the requirements for R4.&lt;br /&gt;
&lt;br /&gt;
The call to TryPublishWidget returns an iPublishedWidget object. We use this object later to satisfy the requirements of R7.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The ordering of the calls to SetEnabled and TryPublishWidget is vitally important. You&lt;br /&gt;
must enable the device before you attempt to publish it. Your Widget will not be available to the&lt;br /&gt;
Nodes unless SetEnabled is called first. Nodes will not be able to access a published device&lt;br /&gt;
that has not been enabled.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
R3 requires that you set the Widget's properties before you enable and publish the device. We&lt;br /&gt;
discussed on page 14 how some properties can only be set after the Widget reports what their&lt;br /&gt;
state is. We do this in HandleRegisterEvent.&lt;br /&gt;
&lt;br /&gt;
We rely on the SimpleUPnP Protocol Module guaranteeing a call to HandleRegisterEvent first before HandleInitialEvent. This is informed by guarantees made by the Control Point stack that the calls will be made in that order.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
==== Removing a Widget ====&lt;br /&gt;
&lt;br /&gt;
Removing a Widget involves unpublishing it from the Node. The IPublishedWidget interface provides us with a method we can call to manage that for us:&lt;br /&gt;
&lt;br /&gt;
 public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
 {&lt;br /&gt;
     if (iPublishedWidget != null)&lt;br /&gt;
     { iPublishedWidget.Unpublish(); }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assuming that the Widget was successfully published earlier, it is removed from the Node's Local Widget Registry.&lt;br /&gt;
&lt;br /&gt;
We must also properly handle the resources we used to create and maintain the Widget object while it was published:&lt;br /&gt;
&lt;br /&gt;
      iProvider.Dispose();&lt;br /&gt;
      iDvDevice.Dispose();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The calls to Dispose are made regardless of the Widget's published state, ensuring that any created device and associated provider are properly disposed. This implementation satisfies R7.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Event handling ====&lt;br /&gt;
&lt;br /&gt;
We need a method to handle changes to the state of the Widget's properties.&lt;br /&gt;
&lt;br /&gt;
If the property changes at the Widget, it needs to pass the new state back to the Node so that it is kept up-to-date on the Widget's status. This is called an event. An example in the case of our Basic Light is someone manually switching the light from on to off. This is in contrast to actions, which are passed from the Node to the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Other examples of events involve no human interaction, such as a thermometer Widget updating its current temperature based on environmental changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Our Basic Light Widget has only one property that needs to be handled:&lt;br /&gt;
&lt;br /&gt;
 public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
 {&lt;br /&gt;
     if (aIndex == 0)&lt;br /&gt;
     {&lt;br /&gt;
         iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We use our instance of the provider to update the register on the Widget that is mapped to the On property. This in turn updates the Node with the new state of the Widget.&lt;br /&gt;
&lt;br /&gt;
This method provides implementations to satisfy two driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
* R3 is now completely satisfied, as we can now set the values of all the previously unknown properties here.&lt;br /&gt;
* R5 is also satisfied as this method allows us to update the Widget's status on the Node when a property is changed on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Not all protocols pass messages back to the Node in this manner. The way we have satisfied R3 and R5 here only applies to protocols and Widgets that support this behavior.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Widgets that do not use an eventing protocol need to have their properties set in the provider's constructor to satisfy R3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To satisfy R5, the over-ridden method SetOn in the provider must include the call to SetPropertyOn. Non-eventing protocols do not require a HandleRegisterEvent method.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Constructor ===&lt;br /&gt;
&lt;br /&gt;
The final requirement for the driver is the constructor so that new DiscoveredWidget objects can be created. &lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this area of code are:&lt;br /&gt;
&lt;br /&gt;
'''R1 Specifying the type of Widget the driver controls'''&lt;br /&gt;
&lt;br /&gt;
A driver must know which type of Widget that it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Writing the code ====&lt;br /&gt;
&lt;br /&gt;
We begin by defining the variables we will use to store the objects used by the driver:&lt;br /&gt;
&lt;br /&gt;
 private readonly string iName;&lt;br /&gt;
 private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
 private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now write the constructor for the driver and assign the passed in parameters appropriately:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightDriver(string aName,&lt;br /&gt;
                IWidgetPublisher aPublisher,&lt;br /&gt;
                IDvDeviceFactory aDeviceFactory)&lt;br /&gt;
 {&lt;br /&gt;
     iWidgetPublisher = aPublisher;&lt;br /&gt;
     iName = aName;&lt;br /&gt;
     iDeviceFactory = aDeviceFactory;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally we need to provide the driver a way to publish the class of Widget it controls. This information is requested by the Discovery Module and is used to ensure the Node uses the correct driver when a new Widget appears.&lt;br /&gt;
&lt;br /&gt;
The implementation for this details will be different for each protocol. The SimpleUPnP protocol library provides a file that contains the SimpleUPnP definitions as integers. Each integer represents a particular class of identified Widget.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP implementation of that method is as follows:&lt;br /&gt;
&lt;br /&gt;
 public IEnumerable&amp;lt;uint&amp;gt; WidgetClasses&lt;br /&gt;
 {&lt;br /&gt;
 [[File:Warning.png]]        get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The body of this method is specifically written for the Widget class we are defining (in this case a binary light). This method completes the driver's requirements for R1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Writing the SimpleUPnP Widget discovery method ==&lt;br /&gt;
&lt;br /&gt;
Every driver must contain a method which creates new objects to represent newly discovered Widgets.&lt;br /&gt;
The Discovery Module invokes this method to begin the process of creating the objects required to allow the Node to access the Widget. &lt;br /&gt;
&lt;br /&gt;
The name of this method is dictated by your chosen protocol's API. The SimpleUPnP protocol requires a method called WidgetDiscovered.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The method's name will not always be the same for each protocol. Your protocol's documentation will contain the details of what this method must be called.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This method and its implementation will meet the following driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
'''R2 Reacting to a discovered Widget on the network'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
Our implementation of the WidgetDiscovered method will create a new DiscoveredWidget object and use the Protocol Module to listen for changes to the Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
The method uses the Protocol Module and two ways to identify the Widget. We must pass these in as&lt;br /&gt;
parameters:&lt;br /&gt;
&lt;br /&gt;
 public void WidgetDiscovered(string aWidgetUdn,&lt;br /&gt;
                              uint aWidgetClass,&lt;br /&gt;
                              ISimpleUpnpWidget&lt;br /&gt;
                                  aSimpleUpnpWidget)&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
Every Widget that uses this driver must be uniquely identifiable:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]    string newUdn = aWidgetUdn;&lt;br /&gt;
&lt;br /&gt;
Each new Widget is represented by a DiscoveredWidget object. Create the new DiscoveredWidget and pass in the required parameters we created earlier:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
     DiscoveredWidget discoveredWidget =&lt;br /&gt;
                 new DiscoveredWidget(iDeviceFactory,&lt;br /&gt;
                                      newUdn,&lt;br /&gt;
  &lt;br /&gt;
 [[File:Warning.png]]                                    aSimpleUpnpWidget,&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Registering the callbacks ===&lt;br /&gt;
&lt;br /&gt;
Finally, we ask the Widget's protocol interface to listen for calls to the handler methods we defined earlier in DiscoveredWidget. We do this by registering those methods as callbacks for the Protocol Module&lt;br /&gt;
to listen for:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                        discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                        discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                        discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You have now met 100% of the driver responsibility requirements and have a working driver to use with your SimpleUPnP Widget.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix A. Sample XML =&lt;br /&gt;
&lt;br /&gt;
== Binary Light.xml ==&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
  &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
  &amp;lt;version&amp;gt;&lt;br /&gt;
   &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
   &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/version&amp;gt;&lt;br /&gt;
  &amp;lt;propertylist&amp;gt;&lt;br /&gt;
   &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
       illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
   &amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix B. Sample Provider = &lt;br /&gt;
&lt;br /&gt;
== DvWidgetOpenhomeOrgBasicLight1.cs ==&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Runtime.InteropServices;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Core;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Utils.Binary;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
 {&lt;br /&gt;
    public interface IDvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
        IDisposable&lt;br /&gt;
    {&lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous value&lt;br /&gt;
        /// &amp;lt;/returns&amp;gt;&lt;br /&gt;
        bool SetPropertyOn(bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;Property's value will be copied&lt;br /&gt;
        /// here&amp;lt;/param&amp;gt;&lt;br /&gt;
        bool PropertyOn();&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt; summary&amp;gt;&lt;br /&gt;
    /// Provider for the openhome.org:BinaryLight:1 UPnP service&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public abstract class DvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
               DvProvider,&lt;br /&gt;
               IDisposable,&lt;br /&gt;
               IDvProviderOpenhomeOrgBinaryLight1&lt;br /&gt;
    {&lt;br /&gt;
        private GCHandle iGch;&lt;br /&gt;
        private PropertyBool iPropertyOn;&lt;br /&gt;
        private PropertyUint iPropertyPrimarySeq;&lt;br /&gt;
        private PropertyUint iPropertySecondarySeq;&lt;br /&gt;
        private ActionDelegate iDelegateSetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetPrimaryProperty;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Constructor&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aDevice&amp;quot;&amp;gt;Device which owns this&lt;br /&gt;
        /// provider&amp;lt;/param&amp;gt;&lt;br /&gt;
        protected DvProviderOpenhomeOrgBinaryLight1(DvDevice aDevice)&lt;br /&gt;
            : base(aDevice, &amp;quot;openhome.org&amp;quot;, &amp;quot;GenericWidget&amp;quot;, 1)&lt;br /&gt;
        {&lt;br /&gt;
            iGch = GCHandle.Alloc(this);&lt;br /&gt;
            List&amp;lt;String&amp;gt; allowedValues = new List&amp;lt;String&amp;gt;();&lt;br /&gt;
            iPropertyOn = new PropertyBool(new ParameterBool(&amp;quot;On&amp;quot;));&lt;br /&gt;
            iPropertyPrimarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;PrimarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertyPrimarySeq);&lt;br /&gt;
            iPropertySecondarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;SecondarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertySecondarySeq);&lt;br /&gt;
            SetPropertyUint(iPropertyPrimarySeq, 0);&lt;br /&gt;
            SetPropertyUint(iPropertySecondarySeq, 0);&lt;br /&gt;
  &lt;br /&gt;
            Zapp.Core.Action action = new Zapp.Core.Action&lt;br /&gt;
                (&amp;quot;SetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;FireAndForget&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddInputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateSetProperty = new ActionDelegate(DoSetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateSetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateGetProperty = new ActionDelegate(DoGetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetPrimaryProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                 (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;integer&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;boolean&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;string&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;binary&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Type&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;readWrite&amp;quot;);allowedValues.Add&lt;br /&gt;
                (&amp;quot;readOnly&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;writeOnly&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString(&amp;quot;Access&amp;quot;,&lt;br /&gt;
                allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            iDelegateGetPrimaryProperty = new&lt;br /&gt;
            ActionDelegate(DoGetPrimaryProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetPrimaryProperty,&lt;br /&gt;
            GCHandle.ToIntPtr(iGch));&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous&lt;br /&gt;
        /// value&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool SetPropertyOn(bool aValue)&lt;br /&gt;
        {&lt;br /&gt;
            if (iPropertyOn.SetValue(aValue))&lt;br /&gt;
            {&lt;br /&gt;
                lock (iPropertyPrimarySeq)&lt;br /&gt;
                {&lt;br /&gt;
                    SetPropertyUint(iPropertyPrimarySeq,&lt;br /&gt;
                        iPropertyPrimarySeq.Value() + 1);&lt;br /&gt;
                } return true;&lt;br /&gt;
            } return false;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;The value of the property&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool PropertyOn()&lt;br /&gt;
        {&lt;br /&gt;
            return iPropertyOn.Value();&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the On property.&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aVersion&amp;quot;&amp;gt;Version of the service being&lt;br /&gt;
        /// requested (will be &amp;lt;= the version advertised)&amp;lt;/param&amp;gt; &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the On property.&lt;br /&gt;
        /// &amp;lt;/param&amp;gt;&lt;br /&gt;
        protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        private static int DoSetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                byte[] valBin = invocation.ReadBinary(&amp;quot;Value&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                switch (name)&lt;br /&gt;
                {&lt;br /&gt;
                    case &amp;quot;On&amp;quot;:&lt;br /&gt;
                        self.SetOn(aVersion, Converter.&lt;br /&gt;
                            BinaryToBoolean(valBin));&lt;br /&gt;
                        break;&lt;br /&gt;
                    default:&lt;br /&gt;
                        throw new ActionError();&lt;br /&gt;
                }&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
                invocation.WriteEnd();&lt;br /&gt;
            }&lt;br /&gt;
            catch (ActionError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
            catch (PropertyUpdateError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
        return 0;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        private static int DoGetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
            switch (name)&lt;br /&gt;
            {&lt;br /&gt;
                case &amp;quot;On&amp;quot;:&lt;br /&gt;
                invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                    Converter.BooleanToBinary(self.iPropertyOn.&lt;br /&gt;
                        Value()));&lt;br /&gt;
                break;&lt;br /&gt;
                default:&lt;br /&gt;
                throw new ActionError();&lt;br /&gt;
            }&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    private static int DoGetPrimaryProperty(IntPtr aPtr,&lt;br /&gt;
                    IntPtr aInvocation,&lt;br /&gt;
                    uint aVersion)&lt;br /&gt;
    {&lt;br /&gt;
        GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
        DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
            (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
        DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
  &lt;br /&gt;
        try&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReadStart();&lt;br /&gt;
            invocation.ReadEnd();&lt;br /&gt;
            invocation.WriteStart();&lt;br /&gt;
            invocation.WriteString(&amp;quot;Name&amp;quot;, &amp;quot;On&amp;quot;);&lt;br /&gt;
            invocation.WriteString(&amp;quot;Type&amp;quot;, &amp;quot;boolean&amp;quot;);&lt;br /&gt;
            invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                Converter.BooleanToBinary(self.iPropertyOn.Value()));&lt;br /&gt;
            invocation.WriteString(&amp;quot;Access&amp;quot;, &amp;quot;readWrite&amp;quot;);&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt;summary&amp;gt;&lt;br /&gt;
    /// Must be called for each class instance. Must be called before&lt;br /&gt;
    /// Core.Library.Close().&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public void Dispose()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
        GC.SuppressFinalize(this);&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
    ~DvProviderOpenhomeOrgBinaryLight1()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
        private void DoDispose()&lt;br /&gt;
        {&lt;br /&gt;
            lock (this)&lt;br /&gt;
            {&lt;br /&gt;
                if (iHandle == IntPtr.Zero)&lt;br /&gt;
            {&lt;br /&gt;
                    return;&lt;br /&gt;
            }&lt;br /&gt;
            DisposeProvider();&lt;br /&gt;
            iPropertyOn.Dispose();&lt;br /&gt;
            iHandle = IntPtr.Zero;&lt;br /&gt;
            }&lt;br /&gt;
            iGch.Free();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix C. Sample Driver = &lt;br /&gt;
&lt;br /&gt;
== BasicLightDriver.cs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.hWidget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
     class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
     {&lt;br /&gt;
         private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
         public BinaryLightProvider(DvDevice aDevice, &lt;br /&gt;
             ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol = aProtocol;&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
     {&lt;br /&gt;
         private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
         {&lt;br /&gt;
             private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
             private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
             private readonly ISimpleUpnpWidget iProtocol; &lt;br /&gt;
 &lt;br /&gt;
             private readonly BinaryLightProvider iProvider;&lt;br /&gt;
             private readonly DvDevice iDvDevice;&lt;br /&gt;
             private IPublishedWidget iPublishedWidget; &lt;br /&gt;
 &lt;br /&gt;
             public DvDevice DvDevice&lt;br /&gt;
             {&lt;br /&gt;
                 get { return iDvDevice; }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             public string WidgetClass&lt;br /&gt;
             {&lt;br /&gt;
                 get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public DiscoveredWidget(&lt;br /&gt;
                 IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                 string aUdn,&lt;br /&gt;
                 ISimpleUpnpWidget aProxy,&lt;br /&gt;
                 IWidgetPublisher aPublisher)&lt;br /&gt;
             {&lt;br /&gt;
                 iDeviceFactory = aDeviceFactory;&lt;br /&gt;
                 iProtocol = aProtocol;&lt;br /&gt;
 &lt;br /&gt;
                 iPublisher = aPublisher;&lt;br /&gt;
                 iDvDevice = iDeviceFactory.CreateDevice(aUdn);  &lt;br /&gt;
                 iProvider = new BinaryLightProvider(iDvDevice, &lt;br /&gt;
                                                     iProtocol);&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             public void HandleInitialEvent()&lt;br /&gt;
             {&lt;br /&gt;
                 iDvDevice.SetEnabled();&lt;br /&gt;
                 iPublisher.TryPublishWidget(iDvDevice.iUdn(), this,&lt;br /&gt;
                     out iPublishedWidget);&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
             {&lt;br /&gt;
                 if (iPublishedWidget != null)&lt;br /&gt;
                 {&lt;br /&gt;
                     iPublishedWidget.Unpublish();&lt;br /&gt;
                 } &lt;br /&gt;
                 iProvider.Dispose();&lt;br /&gt;
                 iDvDevice.Dispose();&lt;br /&gt;
             }  &lt;br /&gt;
 &lt;br /&gt;
             public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
             {&lt;br /&gt;
                 if (aIndex == 0)&lt;br /&gt;
                 {&lt;br /&gt;
                     iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         private readonly string iName;&lt;br /&gt;
         private readonly IDvDeviceFactory aDeviceFactory;&lt;br /&gt;
         private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
         &lt;br /&gt;
         public BinaryLightDriver(&lt;br /&gt;
             string aName,&lt;br /&gt;
             IWidgetPublisher aPublisher,&lt;br /&gt;
             iDeviceFactory aDeviceFactory)&lt;br /&gt;
         {&lt;br /&gt;
             iWidgetPublisher = aPublisher;&lt;br /&gt;
             iName = aName;&lt;br /&gt;
             iDeviceFactory = aDeviceFactory;&lt;br /&gt;
         } &lt;br /&gt;
 &lt;br /&gt;
         public IEnumerable&amp;amp;lt;uint&amp;amp;gt; WidgetClasses&lt;br /&gt;
         {&lt;br /&gt;
             get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         public void WidgetDiscovered(&lt;br /&gt;
             string aWidgetUdn,&lt;br /&gt;
             uint aWidgetClass,&lt;br /&gt;
             ISimpleUpnpWidget aSimpleUpnpWidget)&lt;br /&gt;
         {&lt;br /&gt;
             string newUdn = aWidgetUdn;&lt;br /&gt;
             DiscoveredWidget discoveredWidget = new DiscoveredWidget&lt;br /&gt;
                 (iDeviceFactory,&lt;br /&gt;
                  newUdn,&lt;br /&gt;
                  aSimpleUpnpWidget,&lt;br /&gt;
                  iWidgetPublisher);&lt;br /&gt;
 &lt;br /&gt;
             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                 discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                 discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                 discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary = &lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in OpenHome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by OpenHome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh - A collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs on ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The OpenHome Operating System. Core software for OpenHome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. &lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. A typical Widget supports only one protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Driver_Development</id>
		<title>OhWidget Driver Development</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Driver_Development"/>
				<updated>2012-03-01T15:17:44Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Generating the Provider */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for developers using the OpenHome SDK to integrate a Widget into an OpenHome system. Each Widget must have its own driver to allow it to communicate with the OpenHome Nodes. &lt;br /&gt;
&lt;br /&gt;
To help you write your driver, this document provides high level descriptions of the core responsibilities of a Widget driver and gives a detailed walk-through using example code.&lt;br /&gt;
&lt;br /&gt;
Full versions of each file used in the development of the example driver are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin development of your Widget driver you must be in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* your Widget Service XML that describes the properties on your Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document does not contain advice on how to write Widget Service XML. Refer to the OpenHome Widget Service XML definition document for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK&lt;br /&gt;
* your chosen communication protocol's API&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The protocol you choose for your Widgets must be the same protocol used on your choice of Node.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document focuses on the development of the Widget driver. Details about the communications protocol used are beyond the scope of this document. This document assumes you are familiar with your chosen protocol's code libraries and are able to use them in the driver code you write.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Related Documents ==&lt;br /&gt;
&lt;br /&gt;
The following related OpenHome documentation may be of interest to you:&lt;br /&gt;
&lt;br /&gt;
* [[ohWidget Technical Overview|ohWidget Technical Overview]]&lt;br /&gt;
* [[OpenHome Widget Service XML definition|OpenHome Widget Service XML definition]]&lt;br /&gt;
* [http://www.openhome.org/releases/ohNet_DeviceStack.pdf  OpenHome ohNet Device Stack]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
None of the related documents listed above is mandatory reading for Widget driver development.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
== Widget Service XML ==&lt;br /&gt;
OpenHome Widget driver writing relies heavily on the use of code generated from a single source — the Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
The service and actions your Widget provides are represented in code in a file called a Provider. The Provider is automatically generated from the Widget Service XML and produces an abstract class for you to inherit when you write your concrete class driver.&lt;br /&gt;
&lt;br /&gt;
To aid in the explanation of how the Provider is created and put to use we will follow the development of&lt;br /&gt;
a driver for a simple light Widget; taking the defined Widget Service XML and stepping through how it is used to generate the other files. Examples of code are used throughout this document to show you how each one is created and used in an OpenHome system. &lt;br /&gt;
&lt;br /&gt;
It is essential that you start with a well-formed Widget Service XML, conforming to the schema defined&lt;br /&gt;
in the WidgetService.xsd. The following diagram shows the significance of the Widget Service XML in&lt;br /&gt;
relation to the generated files you will use when writing your driver:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarchy, highlighting the areas specifically used in driver development]]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* The grayed-out files are not relevant to Widget driver development but can also be generated from the Widget Service XML.&lt;br /&gt;
* The Provider is generated in C#, meaning your driver must be written in C# as well. The use of managed code is mandatory for driver writing in the OpenHome framework.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Code sample used in this document ==&lt;br /&gt;
&lt;br /&gt;
Our examples in this document use a Widget Service XML definition for a light Widget called&lt;br /&gt;
BasicLight.xml.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Full versions of all the example files used in this document are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We will see how the Provider is generated from this XML and how it is used to aid the driver writing process. The examples also show how your chosen communication protocol should be used in the body of the driver code.&lt;br /&gt;
&lt;br /&gt;
Implementation details of specific protocols you choose to use are beyond the scope of this document. However, the samples used in this document show the use of the SimpleUPnP protocol to aid you in your development process.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol during the early stages of the OpenHome project. It is included in the OpenHome SDK and can be used as a public resource. &lt;br /&gt;
&lt;br /&gt;
The use of SimpleUPnP in the example files and the code snippets within the following sections is highlighted by the [[File:Warning.png]] icon. The lines of code marked by [[File:Warning.png]] must be changed to code from your chosen communication protocol's library. SimpleUPnP is left in to help you understand how a protocol is used in a working example.&lt;br /&gt;
&lt;br /&gt;
The sample code provided attempts to show best-practice coding standards. There are several sections of code that have a mandatory layout or that call specifically named methods and functions. These areas of the code are highlighted where required. &lt;br /&gt;
&lt;br /&gt;
Where the examples do not explicitly state that the code shown is mandatory, you are free to implement it in a different way according to your own coding style and practices.&lt;br /&gt;
&lt;br /&gt;
= Driver responsibilities = &lt;br /&gt;
&lt;br /&gt;
== Driver responsibilities ==&lt;br /&gt;
&lt;br /&gt;
An OpenHome Widget driver has several responsibilities which must be met before it can be used on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
These responsibilities are listed R1 to R7 and are defined here, explaining what each one must do. &lt;br /&gt;
&lt;br /&gt;
=== R1 Specifying the type of Widget the driver controls ===&lt;br /&gt;
A driver must know which type of Widget it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
=== R2 Reacting to a discovered Widget on the network ===&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== R3 Setting the initial values for the Widget's properties ===&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
=== R4 Publishing discovered Widgets in the Local Widget Registry on the Node ===&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object.&lt;br /&gt;
&lt;br /&gt;
=== R5 Reacting to an event reported from the Widget ===&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
=== R6 Reacting to actions sent to the Widget ===&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== R7 Reacting to a Widget's departure ===&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no&lt;br /&gt;
longer available.&lt;br /&gt;
&lt;br /&gt;
The sections of example code that follow show you how to write a driver from beginning to end. The accompanying text explaining the example code highlights when a responsibility, or part of a responsibility, has been met.&lt;br /&gt;
&lt;br /&gt;
= Driver Architecture = &lt;br /&gt;
&lt;br /&gt;
== Driver Architecture ==&lt;br /&gt;
&lt;br /&gt;
Drivers are installed on the Node and used when the Node needs to communicate with the Widget. Drivers&lt;br /&gt;
use several objects to communicate with Widgets over the Widget's lifetime. Figure 2 shows the objects&lt;br /&gt;
used by the driver and how the responsibilities listed above relate to each one:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture.png|800px|thumb|center|Figure 2: The architecture of a driver, showing the driver's relationship to the objects used to communicate with a Widget. Lines between objects show message flow.]]&lt;br /&gt;
&lt;br /&gt;
The objects contained in the dotted boundary must appear in the code you write to define your driver. The Driver, Provider and IWidgetRegistryEntry objects are all contained in the same driver file. We begin discussing this on page 12. &lt;br /&gt;
&lt;br /&gt;
The other objects are provided by the OpenHome SDK or as installed components on the Node.&lt;br /&gt;
&lt;br /&gt;
The Discovery Module informs the driver of the presence of an available Widget.&lt;br /&gt;
&lt;br /&gt;
Each Node has a Protocol Module which contains the protocol's API. Widgets can communicate with OpenHome Nodes using any one of the set of communications protocols the Node supports. The driver uses your chosen protocol's Protocol Module to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
Both the Protocol Module and the Discovery Module are installed on the Node. When you write your&lt;br /&gt;
driver you will use your Protocol Module to allow the driver to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
IWidgetPublisher, IPublishedWidget and DvDevice are objects provided in the OpenHome&lt;br /&gt;
API. You can read about them in the APIs.&lt;br /&gt;
&lt;br /&gt;
= Generating the Provider = &lt;br /&gt;
&lt;br /&gt;
== Generating the Provider ==&lt;br /&gt;
&lt;br /&gt;
You must generate your provider before you can begin writing your Widget driver. You use your provider as a guide to implement the functions your Widget needs to set the values of its properties.&lt;br /&gt;
&lt;br /&gt;
The current provider generation process is a manual one involving the use of a text transform tool.&lt;br /&gt;
&lt;br /&gt;
Speak to your OpenHome contact who will help you generate your provider.&lt;br /&gt;
&lt;br /&gt;
Future releases of the OpenHome SDK will include a tool to help you generate the provider.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
You must be in possession of:&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK, unpacked on your computer&lt;br /&gt;
* your Widget Service XML file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Writing a SimpleUPnP driver = &lt;br /&gt;
&lt;br /&gt;
== Introduction to the SimpleUPnP protocol ==&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol used to control emulated Widgets over a custom UPnP service.&lt;br /&gt;
&lt;br /&gt;
This chapter shows how a driver is written using the SimpleUPnP communications protocol. The aim is to show the code using as generic a protocol as possible so that you can see where your own protocol specific code needs to go.&lt;br /&gt;
&lt;br /&gt;
The use of code specific to the SimpleUPnP implementation is highlighted by the use of the [[File:Warning.png]] icon. The lines of code are marked by this icon to make it easier for you to see where the protocol-specific code must go and what parts of the code are generic.&lt;br /&gt;
&lt;br /&gt;
=== Register model ===&lt;br /&gt;
&lt;br /&gt;
SimpleUPnP is modeled on 8 physical registers available on the Widget. Each register is 32-bits wide. They are indexed from 0 to 7 and the last register (register 7) is reserved for storing the Widget's class.&lt;br /&gt;
&lt;br /&gt;
This detail is used by the Protocol Module on the Node to determine which driver is needed to run the new Widget when it has been discovered.&lt;br /&gt;
&lt;br /&gt;
The remaining 7 registers (registers 0 to 6) are free for Widget engineers to assign to the Widget's functions.&lt;br /&gt;
&lt;br /&gt;
Registers 0, 1, 2 and 3 are available as read/write registers. Registers 4, 5 and 6 are readonly registers.&lt;br /&gt;
&lt;br /&gt;
Only the emulated hardware (running on the Node) can change the values held in registers 4, 5 and 6.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Register use in drivers ===&lt;br /&gt;
&lt;br /&gt;
In the example that follows we have a Basic Light Widget with a very simple function: it can be turned on and turned off. The on/off value is stored in register 0, with values 0=OFF and 1=ON. Register 0 is a read/write register. This means we can change the value stored there using messages passed to the Widget from the Node, and by reacting to physical interactions at the Widget (such as someone manually switching the light on or off). &lt;br /&gt;
&lt;br /&gt;
The mapping of registers to properties on the Widget is decided by the engineers who manufacture the device. You must be provided with the mapping before you begin developing your driver.&lt;br /&gt;
&lt;br /&gt;
== Starting the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-BoxHighlight.png|800px|thumb|center|Figure 3 The driver architecture highlighting the Widget driver and its component parts.]]&lt;br /&gt;
&lt;br /&gt;
When you have generated the abstract provider you can put it to use in the Widget driver. A Widget driver&lt;br /&gt;
has three distinct components:&lt;br /&gt;
&lt;br /&gt;
* an implementation of your abstract provider&lt;br /&gt;
* a definition of the Widget driver&lt;br /&gt;
* an implementation of the IWidgetRegistryEntry interface&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must manually write the code for your Widget driver. The differences in implementation of Widget properties and communication protocols means that the driver code cannot be autogenerated.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This section takes you through how to write a Widget driver by implementing the auto-generated provider,&lt;br /&gt;
starting from a new blank file and finishing with a working driver for the Basic Light Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
No assumptions have been made about the type of editor you use to write your code. Shortcuts&lt;br /&gt;
or macros that you use as standard will not appear in the instructions below. A full example&lt;br /&gt;
BinaryLightDriver.cs is available to review in Appendix C.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a new C# file in your IDE. Ensure the following libraries are used:&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 [[File:Warning.png]]using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 namespace OpenHome.Widget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must use the libraries listed above for this specific example.&lt;br /&gt;
&lt;br /&gt;
In general, drivers require the following libraries:&lt;br /&gt;
* System*&lt;br /&gt;
* System.Collections.Generic*&lt;br /&gt;
* OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
&lt;br /&gt;
Your driver will fail to compile if you miss any of these listed libraries. Libraries marked * are typically added by default by most modern IDEs. &lt;br /&gt;
&lt;br /&gt;
The OpenHome.Widget.Protocols.SimpleUpnp library is required only in this SimpleUPnP example. Drivers using a different protocol will use their own protocol library.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Implementing the provider ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-ProviderHighlight.png|800px|thumb|center|Figure 4 The driver architecture highlighting the Provider's place]]&lt;br /&gt;
&lt;br /&gt;
You use your auto-generated abstract provider by writing an implementation of it in the driver file. Responsibilities met by implementing your auto-generated provider are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R6 Reacting to actions sent to the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
Begin by creating a new class. It will subclass the abstract auto-generated provider:&lt;br /&gt;
&lt;br /&gt;
 class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
The Protocol Module will provide an API for the Provider to use to communicate with the Widget. In&lt;br /&gt;
SimpleUPnP we are provided with an interface called ISimpleUpnpWidget. The provider is supplied&lt;br /&gt;
with the required instance of the interface by the Discovery Module on the Node.&lt;br /&gt;
&lt;br /&gt;
The mechanisms for registering providers with specific Protocol Modules, and for the way the module gives each provider its required interface are covered later when writing the discovery method.&lt;br /&gt;
&lt;br /&gt;
For now, we need to give the Provider a place to store the interface that it will later use to communicate&lt;br /&gt;
with the Widget:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]] private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
&lt;br /&gt;
The interface from the Protocol Module is passed in as a parameter in the Provider's constructor and then&lt;br /&gt;
assigned to the variable we just created:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightProvider(DvDevice aDevice,&lt;br /&gt;
 [[File:Warning.png]]         ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
 {&lt;br /&gt;
       iProtocol = aProtocol;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
To satisfy R3 we would normally set the Widget's properties here, giving them an initial value.&lt;br /&gt;
However, in this specific example we cannot set the value of Basic Light's only property because&lt;br /&gt;
we will never know, in advance, what the state of the light will be (either on or off) when we&lt;br /&gt;
create the DiscoveredWidget.&lt;br /&gt;
&lt;br /&gt;
When you cannot set the properties ahead of time, and you are using an eventing protocol like SimpleUPnP, you can instead set them in the HandleRegisterEvent method in the driver class. This also satisfies the requirements for R3. You must set the Widget's properties before you enable it using SetEnabled(). &lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The abstract provider includes an abstract method called SetOn. This method is invoked by the Node when passing a message to the Widget, specifically to set the on property of the Widget to either 0 or 1. The implementation of this method will meet the requirements for R6.&lt;br /&gt;
&lt;br /&gt;
We must override this method and provide the protocol module a way of passing a message on to the Widget to perform the required action, in this case turn the light on or off:&lt;br /&gt;
&lt;br /&gt;
          protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
          {&lt;br /&gt;
     [[File:Warning.png]]        iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
In this example the Basic Light's SetOn property (the boolean property that controls whether the light is&lt;br /&gt;
on or off) is represented in the physical Widget by the register that has an index of 0.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* This method is an example of an action on a Widget. Actions are messages sent from the Node to the Widget. We will see later how to handle events that need to be passed back from the Widget&lt;br /&gt;
to the Node.&lt;br /&gt;
* Your own Widget will likely provide more than a single property. Your auto-generated provider will contain one abstract method to represent each writable property. Read-only properties are not provided an abstract method.&lt;br /&gt;
&lt;br /&gt;
You must implement each abstract method in your driver to ensure the relevant property on&lt;br /&gt;
the Widget can be set.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We have now finished implementing the provider. The next step is to implement the driver.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Implementing the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-DriverHighlight.png|800px|thumb|center|Figure 4: The driver architecture highlighting the implemented driver's place.]]&lt;br /&gt;
&lt;br /&gt;
The code for your Widget driver must provide an implementation of the IWidgetRegistryInterface,&lt;br /&gt;
including the following tasks:&lt;br /&gt;
&lt;br /&gt;
* methods to expose identifying details about the Widget for the Node to access&lt;br /&gt;
* providing methods to handle events reported by the Widget&lt;br /&gt;
&lt;br /&gt;
The driver is implemented as a public class within the same file as the provider code. Each driver must use the interface for the protocol you are using. For the SimpleUPnP protocol the interface is ISimple-UpnpWidgetDriver.&lt;br /&gt;
&lt;br /&gt;
=== Writing code ===&lt;br /&gt;
&lt;br /&gt;
Create your new driver class and subclass the ISimpleUpnpWidgetDriver interface:&lt;br /&gt;
&lt;br /&gt;
 public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Implementing IWidgetRegistryEntry ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry is the interface you use to represent physical Widgets. It is implemented as a subclass of your driver class. We are going to implement this interface in a class called '''DiscoveredWidget'''.&lt;br /&gt;
&lt;br /&gt;
Let's return to our driver architecture diagram for a moment:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-IRegistryEntryHighlight.png|800px|thumb|center|Figure 5 The driver architecture highlighting the IWidgetRegistryEntry object you will now implement]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry uses several other objects to help create it and respond to messages sent to and from it. These objects will be created in our implementation of DiscoveredWidget. &lt;br /&gt;
&lt;br /&gt;
When successfully created and published, the DiscoveredWidget objects are stored in a list on the Node called the Local Widget Registry. The Local Widget Registry is used by Nodes to maintain contact with the Widgets they control.&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry is shown at the top of Figure 5, marked plainly as (Registry). The path to the Local Widget Registry goes through several layers of Node architecture which are not relevant to Widget driver writing, so are not shown in the diagrams.&lt;br /&gt;
&lt;br /&gt;
==== Writing code ====&lt;br /&gt;
&lt;br /&gt;
Start by subclassing the IWidgetRegistryEntry interface in your new class:&lt;br /&gt;
&lt;br /&gt;
      private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
      {&lt;br /&gt;
&lt;br /&gt;
A DiscoveredWidget must provide the driver with the objects required to present the Widget and its&lt;br /&gt;
properties to the Node:&lt;br /&gt;
&lt;br /&gt;
           private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
           private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
           private readonly ISimpleUpnpWidget iProtocol;&lt;br /&gt;
           private readonly BinaryLightProvider iProvider;&lt;br /&gt;
           private readonly DvDevice iDvDevice;&lt;br /&gt;
           private IPublishedWidget iPublishedWidget;&lt;br /&gt;
&lt;br /&gt;
Each of the attributes in the example above are defined as follows:&lt;br /&gt;
&lt;br /&gt;
iDeviceFactory — used by the driver to create a single instance of DvDevice to represent a single Widget&lt;br /&gt;
&lt;br /&gt;
iPublisher — used by the driver to publish the Widget to the Node&lt;br /&gt;
&lt;br /&gt;
iProtocol — the object used by the Widget to communicate with the Protocol Module on the Node&lt;br /&gt;
&lt;br /&gt;
iProvider — an instantiated provider of the type you defined earlier&lt;br /&gt;
&lt;br /&gt;
iDvDevice — a representation of a Widget to which the provider is attached, created using iDevice-Factory above&lt;br /&gt;
&lt;br /&gt;
iPublishedWidget — used to contain the returned object from a successful publishing of the Widget&lt;br /&gt;
If we look again at the driver architecture diagram, we ca highlight the objects we've just defined:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-Highlight.png|800px|thumb|center|Figure 6: The driver architecture highlighting the objects used by the IWidgetRegistryEntry implementation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The DeviceFactory, defined above in the member variable iDeviceFactory, is used to create new DvDevice objects. The DeviceFactory is only ever used to do this once. It is not shown in the driver architecture diagrams due to its minimal role in the operation of a driver, but it would normally appear between the IWidgetRegistryEntry and DvDevice objects.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
A driver requires methods to expose identifying details about the Widget. We must provide access to two of the attributes we just defined above:&lt;br /&gt;
&lt;br /&gt;
 public DvDevice DvDevice&lt;br /&gt;
 {&lt;br /&gt;
     get { return iDvDevice; }&lt;br /&gt;
 }&lt;br /&gt;
 public string WidgetClass&lt;br /&gt;
 {&lt;br /&gt;
     get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The WidgetClass string is formed using a combination of the vendor name and the Widget's name in the&lt;br /&gt;
format:&lt;br /&gt;
&lt;br /&gt;
 [vendor_domain]:[widget_name]&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry can now query both the DvDevice object representing the Widget, and the specific class of Widget this driver represents. The other member variables we defined do not need their own accessor methods.&lt;br /&gt;
&lt;br /&gt;
Now we must write a constructor for DiscoveredWidget and assign the parameters accordingly: &lt;br /&gt;
&lt;br /&gt;
 public DiscoveredWidget(IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                            string aUdn,&lt;br /&gt;
                            ISimpleUpnpWidget aProxy,&lt;br /&gt;
                            IWidgetPublisher aPublisher)&lt;br /&gt;
 {&lt;br /&gt;
      iDeviceFactory = aDeviceFactory;&lt;br /&gt;
      iProtocol = aProtocol;&lt;br /&gt;
      iPublisher = aPublisher;&lt;br /&gt;
      iDvDevice = iDeviceFactory.CreateDevice(aUdn);&lt;br /&gt;
      iProvider = new BinaryLightProvider(iDvDevice,&lt;br /&gt;
      iProtocol);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Event handling ===&lt;br /&gt;
&lt;br /&gt;
A Widget's state can change in one of three significant ways:&lt;br /&gt;
&lt;br /&gt;
* when the Widget needs to be published on the Node&lt;br /&gt;
* when the Widget disappears from the network (by losing power or similar)&lt;br /&gt;
* when a property's state changes and must be updated to a new value&lt;br /&gt;
&lt;br /&gt;
We now need methods to handle these changes.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The methods we define here will be used as callbacks, rather than invoked as method calls. We define the methods here first and then use them later on. We will use the Protocol Module to listen for changes in the Widget's state and register these methods as callbacks there. See Writing the SimpleUPnP Widget discovery method for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this section of the driver are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R4 Publishing discovered Widgets in the Local Widget Registry on the Node'''&lt;br /&gt;
&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object. &lt;br /&gt;
&lt;br /&gt;
'''R5 Reacting to an event reported from the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
'''R7 Reacting to a Widget's departure'''&lt;br /&gt;
&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no longer available.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Enabling and publishing a discovered Widget ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first method initializes the Widget by enabling the device and then using the IWidgetPublisher&lt;br /&gt;
to make it available on the Node:&lt;br /&gt;
&lt;br /&gt;
 public void HandleInitialEvent()&lt;br /&gt;
 {&lt;br /&gt;
      iDvDevice.SetEnabled();&lt;br /&gt;
      iPublisher.TryPublishWidget(iDvDevice.iUdn(),&lt;br /&gt;
                              this,&lt;br /&gt;
                              out iPublishedWidget);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This method meets the requirements for R4.&lt;br /&gt;
&lt;br /&gt;
The call to TryPublishWidget returns an iPublishedWidget object. We use this object later to satisfy the requirements of R7.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The ordering of the calls to SetEnabled and TryPublishWidget is vitally important. You&lt;br /&gt;
must enable the device before you attempt to publish it. Your Widget will not be available to the&lt;br /&gt;
Nodes unless SetEnabled is called first. Nodes will not be able to access a published device&lt;br /&gt;
that has not been enabled.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
R3 requires that you set the Widget's properties before you enable and publish the device. We&lt;br /&gt;
discussed on page 14 how some properties can only be set after the Widget reports what their&lt;br /&gt;
state is. We do this in HandleRegisterEvent.&lt;br /&gt;
&lt;br /&gt;
We rely on the SimpleUPnP Protocol Module guaranteeing a call to HandleRegisterEvent first before HandleInitialEvent. This is informed by guarantees made by the Control Point stack that the calls will be made in that order.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
==== Removing a Widget ====&lt;br /&gt;
&lt;br /&gt;
Removing a Widget involves unpublishing it from the Node. The IPublishedWidget interface provides us with a method we can call to manage that for us:&lt;br /&gt;
&lt;br /&gt;
 public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
 {&lt;br /&gt;
     if (iPublishedWidget != null)&lt;br /&gt;
     { iPublishedWidget.Unpublish(); }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assuming that the Widget was successfully published earlier, it is removed from the Node's Local Widget Registry.&lt;br /&gt;
&lt;br /&gt;
We must also properly handle the resources we used to create and maintain the Widget object while it was published:&lt;br /&gt;
&lt;br /&gt;
      iProvider.Dispose();&lt;br /&gt;
      iDvDevice.Dispose();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The calls to Dispose are made regardless of the Widget's published state, ensuring that any created device and associated provider are properly disposed. This implementation satisfies R7.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Event handling ====&lt;br /&gt;
&lt;br /&gt;
We need a method to handle changes to the state of the Widget's properties.&lt;br /&gt;
&lt;br /&gt;
If the property changes at the Widget, it needs to pass the new state back to the Node so that it is kept up-to-date on the Widget's status. This is called an event. An example in the case of our Basic Light is someone manually switching the light from on to off. This is in contrast to actions, which are passed from the Node to the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Other examples of events involve no human interaction, such as a thermometer Widget updating its current temperature based on environmental changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Our Basic Light Widget has only one property that needs to be handled:&lt;br /&gt;
&lt;br /&gt;
 public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
 {&lt;br /&gt;
     if (aIndex == 0)&lt;br /&gt;
     {&lt;br /&gt;
         iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We use our instance of the provider to update the register on the Widget that is mapped to the On property. This in turn updates the Node with the new state of the Widget.&lt;br /&gt;
&lt;br /&gt;
This method provides implementations to satisfy two driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
* R3 is now completely satisfied, as we can now set the values of all the previously unknown properties here.&lt;br /&gt;
* R5 is also satisfied as this method allows us to update the Widget's status on the Node when a property is changed on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Not all protocols pass messages back to the Node in this manner. The way we have satisfied R3 and R5 here only applies to protocols and Widgets that support this behavior.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Widgets that do not use an eventing protocol need to have their properties set in the provider's constructor to satisfy R3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To satisfy R5, the over-ridden method SetOn in the provider must include the call to SetPropertyOn. Non-eventing protocols do not require a HandleRegisterEvent method.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Constructor ===&lt;br /&gt;
&lt;br /&gt;
The final requirement for the driver is the constructor so that new DiscoveredWidget objects can be created. &lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this area of code are:&lt;br /&gt;
&lt;br /&gt;
'''R1 Specifying the type of Widget the driver controls'''&lt;br /&gt;
&lt;br /&gt;
A driver must know which type of Widget that it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Writing the code ====&lt;br /&gt;
&lt;br /&gt;
We begin by defining the variables we will use to store the objects used by the driver:&lt;br /&gt;
&lt;br /&gt;
 private readonly string iName;&lt;br /&gt;
 private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
 private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now write the constructor for the driver and assign the passed in parameters appropriately:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightDriver(string aName,&lt;br /&gt;
                IWidgetPublisher aPublisher,&lt;br /&gt;
                IDvDeviceFactory aDeviceFactory)&lt;br /&gt;
 {&lt;br /&gt;
     iWidgetPublisher = aPublisher;&lt;br /&gt;
     iName = aName;&lt;br /&gt;
     iDeviceFactory = aDeviceFactory;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally we need to provide the driver a way to publish the class of Widget it controls. This information is requested by the Discovery Module and is used to ensure the Node uses the correct driver when a new Widget appears.&lt;br /&gt;
&lt;br /&gt;
The implementation for this details will be different for each protocol. The SimpleUPnP protocol library provides a file that contains the SimpleUPnP definitions as integers. Each integer represents a particular class of identified Widget.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP implementation of that method is as follows:&lt;br /&gt;
&lt;br /&gt;
 public IEnumerable&amp;lt;uint&amp;gt; WidgetClasses&lt;br /&gt;
 {&lt;br /&gt;
 [[File:Warning.png]]        get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The body of this method is specifically written for the Widget class we are defining (in this case a binary light). This method completes the driver's requirements for R1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Writing the SimpleUPnP Widget discovery method ==&lt;br /&gt;
&lt;br /&gt;
Every driver must contain a method which creates new objects to represent newly discovered Widgets.&lt;br /&gt;
The Discovery Module invokes this method to begin the process of creating the objects required to allow the Node to access the Widget. &lt;br /&gt;
&lt;br /&gt;
The name of this method is dictated by your chosen protocol's API. The SimpleUPnP protocol requires a method called WidgetDiscovered.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The method's name will not always be the same for each protocol. Your protocol's documentation will contain the details of what this method must be called.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This method and its implementation will meet the following driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
'''R2 Reacting to a discovered Widget on the network'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
Our implementation of the WidgetDiscovered method will create a new DiscoveredWidget object and use the Protocol Module to listen for changes to the Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
The method uses the Protocol Module and two ways to identify the Widget. We must pass these in as&lt;br /&gt;
parameters:&lt;br /&gt;
&lt;br /&gt;
 public void WidgetDiscovered(string aWidgetUdn,&lt;br /&gt;
                              uint aWidgetClass,&lt;br /&gt;
                              ISimpleUpnpWidget&lt;br /&gt;
                                  aSimpleUpnpWidget)&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
Every Widget that uses this driver must be uniquely identifiable:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]    string newUdn = aWidgetUdn;&lt;br /&gt;
&lt;br /&gt;
Each new Widget is represented by a DiscoveredWidget object. Create the new DiscoveredWidget and pass in the required parameters we created earlier:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
     DiscoveredWidget discoveredWidget =&lt;br /&gt;
                 new DiscoveredWidget(iDeviceFactory,&lt;br /&gt;
                                      newUdn,&lt;br /&gt;
  &lt;br /&gt;
 [[File:Warning.png]]                                    aSimpleUpnpWidget,&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Registering the callbacks ===&lt;br /&gt;
&lt;br /&gt;
Finally, we ask the Widget's protocol interface to listen for calls to the handler methods we defined earlier in DiscoveredWidget. We do this by registering those methods as callbacks for the Protocol Module&lt;br /&gt;
to listen for:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                        discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                        discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                        discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You have now met 100% of the driver responsibility requirements and have a working driver to use with your SimpleUPnP Widget.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix A. Sample XML =&lt;br /&gt;
&lt;br /&gt;
== Binary Light.xml ==&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
  &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
  &amp;lt;version&amp;gt;&lt;br /&gt;
   &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
   &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/version&amp;gt;&lt;br /&gt;
  &amp;lt;propertylist&amp;gt;&lt;br /&gt;
   &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
       illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
   &amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix B. Sample Provider = &lt;br /&gt;
&lt;br /&gt;
== DvWidgetOpenhomeOrgBasicLight1.cs ==&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Runtime.InteropServices;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Core;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Utils.Binary;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
 {&lt;br /&gt;
    public interface IDvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
        IDisposable&lt;br /&gt;
    {&lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous value&lt;br /&gt;
        /// &amp;lt;/returns&amp;gt;&lt;br /&gt;
        bool SetPropertyOn(bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;Property's value will be copied&lt;br /&gt;
        /// here&amp;lt;/param&amp;gt;&lt;br /&gt;
        bool PropertyOn();&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt; summary&amp;gt;&lt;br /&gt;
    /// Provider for the openhome.org:BinaryLight:1 UPnP service&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public abstract class DvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
               DvProvider,&lt;br /&gt;
               IDisposable,&lt;br /&gt;
               IDvProviderOpenhomeOrgBinaryLight1&lt;br /&gt;
    {&lt;br /&gt;
        private GCHandle iGch;&lt;br /&gt;
        private PropertyBool iPropertyOn;&lt;br /&gt;
        private PropertyUint iPropertyPrimarySeq;&lt;br /&gt;
        private PropertyUint iPropertySecondarySeq;&lt;br /&gt;
        private ActionDelegate iDelegateSetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetPrimaryProperty;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Constructor&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aDevice&amp;quot;&amp;gt;Device which owns this&lt;br /&gt;
        /// provider&amp;lt;/param&amp;gt;&lt;br /&gt;
        protected DvProviderOpenhomeOrgBinaryLight1(DvDevice aDevice)&lt;br /&gt;
            : base(aDevice, &amp;quot;openhome.org&amp;quot;, &amp;quot;GenericWidget&amp;quot;, 1)&lt;br /&gt;
        {&lt;br /&gt;
            iGch = GCHandle.Alloc(this);&lt;br /&gt;
            List&amp;lt;String&amp;gt; allowedValues = new List&amp;lt;String&amp;gt;();&lt;br /&gt;
            iPropertyOn = new PropertyBool(new ParameterBool(&amp;quot;On&amp;quot;));&lt;br /&gt;
            iPropertyPrimarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;PrimarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertyPrimarySeq);&lt;br /&gt;
            iPropertySecondarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;SecondarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertySecondarySeq);&lt;br /&gt;
            SetPropertyUint(iPropertyPrimarySeq, 0);&lt;br /&gt;
            SetPropertyUint(iPropertySecondarySeq, 0);&lt;br /&gt;
  &lt;br /&gt;
            Zapp.Core.Action action = new Zapp.Core.Action&lt;br /&gt;
                (&amp;quot;SetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;FireAndForget&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddInputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateSetProperty = new ActionDelegate(DoSetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateSetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateGetProperty = new ActionDelegate(DoGetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetPrimaryProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                 (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;integer&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;boolean&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;string&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;binary&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Type&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;readWrite&amp;quot;);allowedValues.Add&lt;br /&gt;
                (&amp;quot;readOnly&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;writeOnly&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString(&amp;quot;Access&amp;quot;,&lt;br /&gt;
                allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            iDelegateGetPrimaryProperty = new&lt;br /&gt;
            ActionDelegate(DoGetPrimaryProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetPrimaryProperty,&lt;br /&gt;
            GCHandle.ToIntPtr(iGch));&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous&lt;br /&gt;
        /// value&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool SetPropertyOn(bool aValue)&lt;br /&gt;
        {&lt;br /&gt;
            if (iPropertyOn.SetValue(aValue))&lt;br /&gt;
            {&lt;br /&gt;
                lock (iPropertyPrimarySeq)&lt;br /&gt;
                {&lt;br /&gt;
                    SetPropertyUint(iPropertyPrimarySeq,&lt;br /&gt;
                        iPropertyPrimarySeq.Value() + 1);&lt;br /&gt;
                } return true;&lt;br /&gt;
            } return false;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;The value of the property&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool PropertyOn()&lt;br /&gt;
        {&lt;br /&gt;
            return iPropertyOn.Value();&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the On property.&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aVersion&amp;quot;&amp;gt;Version of the service being&lt;br /&gt;
        /// requested (will be &amp;lt;= the version advertised)&amp;lt;/param&amp;gt; &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the On property.&lt;br /&gt;
        /// &amp;lt;/param&amp;gt;&lt;br /&gt;
        protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        private static int DoSetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                byte[] valBin = invocation.ReadBinary(&amp;quot;Value&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                switch (name)&lt;br /&gt;
                {&lt;br /&gt;
                    case &amp;quot;On&amp;quot;:&lt;br /&gt;
                        self.SetOn(aVersion, Converter.&lt;br /&gt;
                            BinaryToBoolean(valBin));&lt;br /&gt;
                        break;&lt;br /&gt;
                    default:&lt;br /&gt;
                        throw new ActionError();&lt;br /&gt;
                }&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
                invocation.WriteEnd();&lt;br /&gt;
            }&lt;br /&gt;
            catch (ActionError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
            catch (PropertyUpdateError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
        return 0;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        private static int DoGetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
            switch (name)&lt;br /&gt;
            {&lt;br /&gt;
                case &amp;quot;On&amp;quot;:&lt;br /&gt;
                invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                    Converter.BooleanToBinary(self.iPropertyOn.&lt;br /&gt;
                        Value()));&lt;br /&gt;
                break;&lt;br /&gt;
                default:&lt;br /&gt;
                throw new ActionError();&lt;br /&gt;
            }&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    private static int DoGetPrimaryProperty(IntPtr aPtr,&lt;br /&gt;
                    IntPtr aInvocation,&lt;br /&gt;
                    uint aVersion)&lt;br /&gt;
    {&lt;br /&gt;
        GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
        DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
            (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
        DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
  &lt;br /&gt;
        try&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReadStart();&lt;br /&gt;
            invocation.ReadEnd();&lt;br /&gt;
            invocation.WriteStart();&lt;br /&gt;
            invocation.WriteString(&amp;quot;Name&amp;quot;, &amp;quot;On&amp;quot;);&lt;br /&gt;
            invocation.WriteString(&amp;quot;Type&amp;quot;, &amp;quot;boolean&amp;quot;);&lt;br /&gt;
            invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                Converter.BooleanToBinary(self.iPropertyOn.Value()));&lt;br /&gt;
            invocation.WriteString(&amp;quot;Access&amp;quot;, &amp;quot;readWrite&amp;quot;);&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt;summary&amp;gt;&lt;br /&gt;
    /// Must be called for each class instance. Must be called before&lt;br /&gt;
    /// Core.Library.Close().&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public void Dispose()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
        GC.SuppressFinalize(this);&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
    ~DvProviderOpenhomeOrgBinaryLight1()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
        private void DoDispose()&lt;br /&gt;
        {&lt;br /&gt;
            lock (this)&lt;br /&gt;
            {&lt;br /&gt;
                if (iHandle == IntPtr.Zero)&lt;br /&gt;
            {&lt;br /&gt;
                    return;&lt;br /&gt;
            }&lt;br /&gt;
            DisposeProvider();&lt;br /&gt;
            iPropertyOn.Dispose();&lt;br /&gt;
            iHandle = IntPtr.Zero;&lt;br /&gt;
            }&lt;br /&gt;
            iGch.Free();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix C. Sample Driver = &lt;br /&gt;
&lt;br /&gt;
== BasicLightDriver.cs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.hWidget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
     class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
     {&lt;br /&gt;
         private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
         public BinaryLightProvider(DvDevice aDevice, &lt;br /&gt;
             ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol = aProtocol;&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
     {&lt;br /&gt;
         private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
         {&lt;br /&gt;
             private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
             private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
             private readonly ISimpleUpnpWidget iProtocol; &lt;br /&gt;
 &lt;br /&gt;
             private readonly BinaryLightProvider iProvider;&lt;br /&gt;
             private readonly DvDevice iDvDevice;&lt;br /&gt;
             private IPublishedWidget iPublishedWidget; &lt;br /&gt;
 &lt;br /&gt;
             public DvDevice DvDevice&lt;br /&gt;
             {&lt;br /&gt;
                 get { return iDvDevice; }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             public string WidgetClass&lt;br /&gt;
             {&lt;br /&gt;
                 get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public DiscoveredWidget(&lt;br /&gt;
                 IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                 string aUdn,&lt;br /&gt;
                 ISimpleUpnpWidget aProxy,&lt;br /&gt;
                 IWidgetPublisher aPublisher)&lt;br /&gt;
             {&lt;br /&gt;
                 iDeviceFactory = aDeviceFactory;&lt;br /&gt;
                 iProtocol = aProtocol;&lt;br /&gt;
 &lt;br /&gt;
                 iPublisher = aPublisher;&lt;br /&gt;
                 iDvDevice = iDeviceFactory.CreateDevice(aUdn);  &lt;br /&gt;
                 iProvider = new BinaryLightProvider(iDvDevice, &lt;br /&gt;
                                                     iProtocol);&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             public void HandleInitialEvent()&lt;br /&gt;
             {&lt;br /&gt;
                 iDvDevice.SetEnabled();&lt;br /&gt;
                 iPublisher.TryPublishWidget(iDvDevice.iUdn(), this,&lt;br /&gt;
                     out iPublishedWidget);&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
             {&lt;br /&gt;
                 if (iPublishedWidget != null)&lt;br /&gt;
                 {&lt;br /&gt;
                     iPublishedWidget.Unpublish();&lt;br /&gt;
                 } &lt;br /&gt;
                 iProvider.Dispose();&lt;br /&gt;
                 iDvDevice.Dispose();&lt;br /&gt;
             }  &lt;br /&gt;
 &lt;br /&gt;
             public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
             {&lt;br /&gt;
                 if (aIndex == 0)&lt;br /&gt;
                 {&lt;br /&gt;
                     iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         private readonly string iName;&lt;br /&gt;
         private readonly IDvDeviceFactory aDeviceFactory;&lt;br /&gt;
         private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
         &lt;br /&gt;
         public BinaryLightDriver(&lt;br /&gt;
             string aName,&lt;br /&gt;
             IWidgetPublisher aPublisher,&lt;br /&gt;
             iDeviceFactory aDeviceFactory)&lt;br /&gt;
         {&lt;br /&gt;
             iWidgetPublisher = aPublisher;&lt;br /&gt;
             iName = aName;&lt;br /&gt;
             iDeviceFactory = aDeviceFactory;&lt;br /&gt;
         } &lt;br /&gt;
 &lt;br /&gt;
         public IEnumerable&amp;amp;lt;uint&amp;amp;gt; WidgetClasses&lt;br /&gt;
         {&lt;br /&gt;
             get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         public void WidgetDiscovered(&lt;br /&gt;
             string aWidgetUdn,&lt;br /&gt;
             uint aWidgetClass,&lt;br /&gt;
             ISimpleUpnpWidget aSimpleUpnpWidget)&lt;br /&gt;
         {&lt;br /&gt;
             string newUdn = aWidgetUdn;&lt;br /&gt;
             DiscoveredWidget discoveredWidget = new DiscoveredWidget&lt;br /&gt;
                 (iDeviceFactory,&lt;br /&gt;
                  newUdn,&lt;br /&gt;
                  aSimpleUpnpWidget,&lt;br /&gt;
                  iWidgetPublisher);&lt;br /&gt;
 &lt;br /&gt;
             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                 discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                 discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                 discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary = &lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in OpenHome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by OpenHome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh - A collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs on ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The OpenHome Operating System. Core software for OpenHome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. &lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. A typical Widget supports only one protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Driver_Development</id>
		<title>OhWidget Driver Development</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Driver_Development"/>
				<updated>2012-03-01T15:17:34Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Driver Architecture */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for developers using the OpenHome SDK to integrate a Widget into an OpenHome system. Each Widget must have its own driver to allow it to communicate with the OpenHome Nodes. &lt;br /&gt;
&lt;br /&gt;
To help you write your driver, this document provides high level descriptions of the core responsibilities of a Widget driver and gives a detailed walk-through using example code.&lt;br /&gt;
&lt;br /&gt;
Full versions of each file used in the development of the example driver are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin development of your Widget driver you must be in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* your Widget Service XML that describes the properties on your Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document does not contain advice on how to write Widget Service XML. Refer to the OpenHome Widget Service XML definition document for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK&lt;br /&gt;
* your chosen communication protocol's API&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The protocol you choose for your Widgets must be the same protocol used on your choice of Node.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document focuses on the development of the Widget driver. Details about the communications protocol used are beyond the scope of this document. This document assumes you are familiar with your chosen protocol's code libraries and are able to use them in the driver code you write.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Related Documents ==&lt;br /&gt;
&lt;br /&gt;
The following related OpenHome documentation may be of interest to you:&lt;br /&gt;
&lt;br /&gt;
* [[ohWidget Technical Overview|ohWidget Technical Overview]]&lt;br /&gt;
* [[OpenHome Widget Service XML definition|OpenHome Widget Service XML definition]]&lt;br /&gt;
* [http://www.openhome.org/releases/ohNet_DeviceStack.pdf  OpenHome ohNet Device Stack]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
None of the related documents listed above is mandatory reading for Widget driver development.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
== Widget Service XML ==&lt;br /&gt;
OpenHome Widget driver writing relies heavily on the use of code generated from a single source — the Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
The service and actions your Widget provides are represented in code in a file called a Provider. The Provider is automatically generated from the Widget Service XML and produces an abstract class for you to inherit when you write your concrete class driver.&lt;br /&gt;
&lt;br /&gt;
To aid in the explanation of how the Provider is created and put to use we will follow the development of&lt;br /&gt;
a driver for a simple light Widget; taking the defined Widget Service XML and stepping through how it is used to generate the other files. Examples of code are used throughout this document to show you how each one is created and used in an OpenHome system. &lt;br /&gt;
&lt;br /&gt;
It is essential that you start with a well-formed Widget Service XML, conforming to the schema defined&lt;br /&gt;
in the WidgetService.xsd. The following diagram shows the significance of the Widget Service XML in&lt;br /&gt;
relation to the generated files you will use when writing your driver:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarchy, highlighting the areas specifically used in driver development]]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* The grayed-out files are not relevant to Widget driver development but can also be generated from the Widget Service XML.&lt;br /&gt;
* The Provider is generated in C#, meaning your driver must be written in C# as well. The use of managed code is mandatory for driver writing in the OpenHome framework.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Code sample used in this document ==&lt;br /&gt;
&lt;br /&gt;
Our examples in this document use a Widget Service XML definition for a light Widget called&lt;br /&gt;
BasicLight.xml.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Full versions of all the example files used in this document are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We will see how the Provider is generated from this XML and how it is used to aid the driver writing process. The examples also show how your chosen communication protocol should be used in the body of the driver code.&lt;br /&gt;
&lt;br /&gt;
Implementation details of specific protocols you choose to use are beyond the scope of this document. However, the samples used in this document show the use of the SimpleUPnP protocol to aid you in your development process.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol during the early stages of the OpenHome project. It is included in the OpenHome SDK and can be used as a public resource. &lt;br /&gt;
&lt;br /&gt;
The use of SimpleUPnP in the example files and the code snippets within the following sections is highlighted by the [[File:Warning.png]] icon. The lines of code marked by [[File:Warning.png]] must be changed to code from your chosen communication protocol's library. SimpleUPnP is left in to help you understand how a protocol is used in a working example.&lt;br /&gt;
&lt;br /&gt;
The sample code provided attempts to show best-practice coding standards. There are several sections of code that have a mandatory layout or that call specifically named methods and functions. These areas of the code are highlighted where required. &lt;br /&gt;
&lt;br /&gt;
Where the examples do not explicitly state that the code shown is mandatory, you are free to implement it in a different way according to your own coding style and practices.&lt;br /&gt;
&lt;br /&gt;
= Driver responsibilities = &lt;br /&gt;
&lt;br /&gt;
== Driver responsibilities ==&lt;br /&gt;
&lt;br /&gt;
An OpenHome Widget driver has several responsibilities which must be met before it can be used on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
These responsibilities are listed R1 to R7 and are defined here, explaining what each one must do. &lt;br /&gt;
&lt;br /&gt;
=== R1 Specifying the type of Widget the driver controls ===&lt;br /&gt;
A driver must know which type of Widget it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
=== R2 Reacting to a discovered Widget on the network ===&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== R3 Setting the initial values for the Widget's properties ===&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
=== R4 Publishing discovered Widgets in the Local Widget Registry on the Node ===&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object.&lt;br /&gt;
&lt;br /&gt;
=== R5 Reacting to an event reported from the Widget ===&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
=== R6 Reacting to actions sent to the Widget ===&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== R7 Reacting to a Widget's departure ===&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no&lt;br /&gt;
longer available.&lt;br /&gt;
&lt;br /&gt;
The sections of example code that follow show you how to write a driver from beginning to end. The accompanying text explaining the example code highlights when a responsibility, or part of a responsibility, has been met.&lt;br /&gt;
&lt;br /&gt;
= Driver Architecture = &lt;br /&gt;
&lt;br /&gt;
== Driver Architecture ==&lt;br /&gt;
&lt;br /&gt;
Drivers are installed on the Node and used when the Node needs to communicate with the Widget. Drivers&lt;br /&gt;
use several objects to communicate with Widgets over the Widget's lifetime. Figure 2 shows the objects&lt;br /&gt;
used by the driver and how the responsibilities listed above relate to each one:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture.png|800px|thumb|center|Figure 2: The architecture of a driver, showing the driver's relationship to the objects used to communicate with a Widget. Lines between objects show message flow.]]&lt;br /&gt;
&lt;br /&gt;
The objects contained in the dotted boundary must appear in the code you write to define your driver. The Driver, Provider and IWidgetRegistryEntry objects are all contained in the same driver file. We begin discussing this on page 12. &lt;br /&gt;
&lt;br /&gt;
The other objects are provided by the OpenHome SDK or as installed components on the Node.&lt;br /&gt;
&lt;br /&gt;
The Discovery Module informs the driver of the presence of an available Widget.&lt;br /&gt;
&lt;br /&gt;
Each Node has a Protocol Module which contains the protocol's API. Widgets can communicate with OpenHome Nodes using any one of the set of communications protocols the Node supports. The driver uses your chosen protocol's Protocol Module to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
Both the Protocol Module and the Discovery Module are installed on the Node. When you write your&lt;br /&gt;
driver you will use your Protocol Module to allow the driver to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
IWidgetPublisher, IPublishedWidget and DvDevice are objects provided in the OpenHome&lt;br /&gt;
API. You can read about them in the APIs.&lt;br /&gt;
&lt;br /&gt;
= Generating the Provider = &lt;br /&gt;
&lt;br /&gt;
== Generating the Provider ==&lt;br /&gt;
&lt;br /&gt;
You must generate your provider before you can begin writing your Widget driver. You use your provider as a guide to implement the functions your Widget needs to set the values of its properties.&lt;br /&gt;
&lt;br /&gt;
The current provider generation process is a manual one involving the use of a text transform tool.&lt;br /&gt;
&lt;br /&gt;
Speak to your OpenHome contact who will help you generate your provider.&lt;br /&gt;
&lt;br /&gt;
Future releases of the OpenHome SDK will include a tool to help you generate the provider.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
You must be in possession of:&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK, unpacked on your computer&lt;br /&gt;
* your Widget Service XML file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Writing a SimpleUPnP driver = &lt;br /&gt;
&lt;br /&gt;
== Introduction to the SimpleUPnP protocol ==&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol used to control emulated Widgets over a custom UPnP service.&lt;br /&gt;
&lt;br /&gt;
This chapter shows how a driver is written using the SimpleUPnP communications protocol. The aim is to show the code using as generic a protocol as possible so that you can see where your own protocol specific code needs to go.&lt;br /&gt;
&lt;br /&gt;
The use of code specific to the SimpleUPnP implementation is highlighted by the use of the [[File:Warning.png]] icon. The lines of code are marked by this icon to make it easier for you to see where the protocol-specific code must go and what parts of the code are generic.&lt;br /&gt;
&lt;br /&gt;
=== Register model ===&lt;br /&gt;
&lt;br /&gt;
SimpleUPnP is modeled on 8 physical registers available on the Widget. Each register is 32-bits wide. They are indexed from 0 to 7 and the last register (register 7) is reserved for storing the Widget's class.&lt;br /&gt;
&lt;br /&gt;
This detail is used by the Protocol Module on the Node to determine which driver is needed to run the new Widget when it has been discovered.&lt;br /&gt;
&lt;br /&gt;
The remaining 7 registers (registers 0 to 6) are free for Widget engineers to assign to the Widget's functions.&lt;br /&gt;
&lt;br /&gt;
Registers 0, 1, 2 and 3 are available as read/write registers. Registers 4, 5 and 6 are readonly registers.&lt;br /&gt;
&lt;br /&gt;
Only the emulated hardware (running on the Node) can change the values held in registers 4, 5 and 6.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Register use in drivers ===&lt;br /&gt;
&lt;br /&gt;
In the example that follows we have a Basic Light Widget with a very simple function: it can be turned on and turned off. The on/off value is stored in register 0, with values 0=OFF and 1=ON. Register 0 is a read/write register. This means we can change the value stored there using messages passed to the Widget from the Node, and by reacting to physical interactions at the Widget (such as someone manually switching the light on or off). &lt;br /&gt;
&lt;br /&gt;
The mapping of registers to properties on the Widget is decided by the engineers who manufacture the device. You must be provided with the mapping before you begin developing your driver.&lt;br /&gt;
&lt;br /&gt;
== Starting the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-BoxHighlight.png|800px|thumb|center|Figure 3 The driver architecture highlighting the Widget driver and its component parts.]]&lt;br /&gt;
&lt;br /&gt;
When you have generated the abstract provider you can put it to use in the Widget driver. A Widget driver&lt;br /&gt;
has three distinct components:&lt;br /&gt;
&lt;br /&gt;
* an implementation of your abstract provider&lt;br /&gt;
* a definition of the Widget driver&lt;br /&gt;
* an implementation of the IWidgetRegistryEntry interface&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must manually write the code for your Widget driver. The differences in implementation of Widget properties and communication protocols means that the driver code cannot be autogenerated.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This section takes you through how to write a Widget driver by implementing the auto-generated provider,&lt;br /&gt;
starting from a new blank file and finishing with a working driver for the Basic Light Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
No assumptions have been made about the type of editor you use to write your code. Shortcuts&lt;br /&gt;
or macros that you use as standard will not appear in the instructions below. A full example&lt;br /&gt;
BinaryLightDriver.cs is available to review in Appendix C.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a new C# file in your IDE. Ensure the following libraries are used:&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 [[File:Warning.png]]using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 namespace OpenHome.Widget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must use the libraries listed above for this specific example.&lt;br /&gt;
&lt;br /&gt;
In general, drivers require the following libraries:&lt;br /&gt;
* System*&lt;br /&gt;
* System.Collections.Generic*&lt;br /&gt;
* OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
&lt;br /&gt;
Your driver will fail to compile if you miss any of these listed libraries. Libraries marked * are typically added by default by most modern IDEs. &lt;br /&gt;
&lt;br /&gt;
The OpenHome.Widget.Protocols.SimpleUpnp library is required only in this SimpleUPnP example. Drivers using a different protocol will use their own protocol library.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Implementing the provider ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-ProviderHighlight.png|800px|thumb|center|Figure 4 The driver architecture highlighting the Provider's place]]&lt;br /&gt;
&lt;br /&gt;
You use your auto-generated abstract provider by writing an implementation of it in the driver file. Responsibilities met by implementing your auto-generated provider are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R6 Reacting to actions sent to the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
Begin by creating a new class. It will subclass the abstract auto-generated provider:&lt;br /&gt;
&lt;br /&gt;
 class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
The Protocol Module will provide an API for the Provider to use to communicate with the Widget. In&lt;br /&gt;
SimpleUPnP we are provided with an interface called ISimpleUpnpWidget. The provider is supplied&lt;br /&gt;
with the required instance of the interface by the Discovery Module on the Node.&lt;br /&gt;
&lt;br /&gt;
The mechanisms for registering providers with specific Protocol Modules, and for the way the module gives each provider its required interface are covered later when writing the discovery method.&lt;br /&gt;
&lt;br /&gt;
For now, we need to give the Provider a place to store the interface that it will later use to communicate&lt;br /&gt;
with the Widget:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]] private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
&lt;br /&gt;
The interface from the Protocol Module is passed in as a parameter in the Provider's constructor and then&lt;br /&gt;
assigned to the variable we just created:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightProvider(DvDevice aDevice,&lt;br /&gt;
 [[File:Warning.png]]         ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
 {&lt;br /&gt;
       iProtocol = aProtocol;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
To satisfy R3 we would normally set the Widget's properties here, giving them an initial value.&lt;br /&gt;
However, in this specific example we cannot set the value of Basic Light's only property because&lt;br /&gt;
we will never know, in advance, what the state of the light will be (either on or off) when we&lt;br /&gt;
create the DiscoveredWidget.&lt;br /&gt;
&lt;br /&gt;
When you cannot set the properties ahead of time, and you are using an eventing protocol like SimpleUPnP, you can instead set them in the HandleRegisterEvent method in the driver class. This also satisfies the requirements for R3. You must set the Widget's properties before you enable it using SetEnabled(). &lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The abstract provider includes an abstract method called SetOn. This method is invoked by the Node when passing a message to the Widget, specifically to set the on property of the Widget to either 0 or 1. The implementation of this method will meet the requirements for R6.&lt;br /&gt;
&lt;br /&gt;
We must override this method and provide the protocol module a way of passing a message on to the Widget to perform the required action, in this case turn the light on or off:&lt;br /&gt;
&lt;br /&gt;
          protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
          {&lt;br /&gt;
     [[File:Warning.png]]        iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
In this example the Basic Light's SetOn property (the boolean property that controls whether the light is&lt;br /&gt;
on or off) is represented in the physical Widget by the register that has an index of 0.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* This method is an example of an action on a Widget. Actions are messages sent from the Node to the Widget. We will see later how to handle events that need to be passed back from the Widget&lt;br /&gt;
to the Node.&lt;br /&gt;
* Your own Widget will likely provide more than a single property. Your auto-generated provider will contain one abstract method to represent each writable property. Read-only properties are not provided an abstract method.&lt;br /&gt;
&lt;br /&gt;
You must implement each abstract method in your driver to ensure the relevant property on&lt;br /&gt;
the Widget can be set.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We have now finished implementing the provider. The next step is to implement the driver.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Implementing the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-DriverHighlight.png|800px|thumb|center|Figure 4: The driver architecture highlighting the implemented driver's place.]]&lt;br /&gt;
&lt;br /&gt;
The code for your Widget driver must provide an implementation of the IWidgetRegistryInterface,&lt;br /&gt;
including the following tasks:&lt;br /&gt;
&lt;br /&gt;
* methods to expose identifying details about the Widget for the Node to access&lt;br /&gt;
* providing methods to handle events reported by the Widget&lt;br /&gt;
&lt;br /&gt;
The driver is implemented as a public class within the same file as the provider code. Each driver must use the interface for the protocol you are using. For the SimpleUPnP protocol the interface is ISimple-UpnpWidgetDriver.&lt;br /&gt;
&lt;br /&gt;
=== Writing code ===&lt;br /&gt;
&lt;br /&gt;
Create your new driver class and subclass the ISimpleUpnpWidgetDriver interface:&lt;br /&gt;
&lt;br /&gt;
 public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Implementing IWidgetRegistryEntry ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry is the interface you use to represent physical Widgets. It is implemented as a subclass of your driver class. We are going to implement this interface in a class called '''DiscoveredWidget'''.&lt;br /&gt;
&lt;br /&gt;
Let's return to our driver architecture diagram for a moment:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-IRegistryEntryHighlight.png|800px|thumb|center|Figure 5 The driver architecture highlighting the IWidgetRegistryEntry object you will now implement]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry uses several other objects to help create it and respond to messages sent to and from it. These objects will be created in our implementation of DiscoveredWidget. &lt;br /&gt;
&lt;br /&gt;
When successfully created and published, the DiscoveredWidget objects are stored in a list on the Node called the Local Widget Registry. The Local Widget Registry is used by Nodes to maintain contact with the Widgets they control.&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry is shown at the top of Figure 5, marked plainly as (Registry). The path to the Local Widget Registry goes through several layers of Node architecture which are not relevant to Widget driver writing, so are not shown in the diagrams.&lt;br /&gt;
&lt;br /&gt;
==== Writing code ====&lt;br /&gt;
&lt;br /&gt;
Start by subclassing the IWidgetRegistryEntry interface in your new class:&lt;br /&gt;
&lt;br /&gt;
      private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
      {&lt;br /&gt;
&lt;br /&gt;
A DiscoveredWidget must provide the driver with the objects required to present the Widget and its&lt;br /&gt;
properties to the Node:&lt;br /&gt;
&lt;br /&gt;
           private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
           private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
           private readonly ISimpleUpnpWidget iProtocol;&lt;br /&gt;
           private readonly BinaryLightProvider iProvider;&lt;br /&gt;
           private readonly DvDevice iDvDevice;&lt;br /&gt;
           private IPublishedWidget iPublishedWidget;&lt;br /&gt;
&lt;br /&gt;
Each of the attributes in the example above are defined as follows:&lt;br /&gt;
&lt;br /&gt;
iDeviceFactory — used by the driver to create a single instance of DvDevice to represent a single Widget&lt;br /&gt;
&lt;br /&gt;
iPublisher — used by the driver to publish the Widget to the Node&lt;br /&gt;
&lt;br /&gt;
iProtocol — the object used by the Widget to communicate with the Protocol Module on the Node&lt;br /&gt;
&lt;br /&gt;
iProvider — an instantiated provider of the type you defined earlier&lt;br /&gt;
&lt;br /&gt;
iDvDevice — a representation of a Widget to which the provider is attached, created using iDevice-Factory above&lt;br /&gt;
&lt;br /&gt;
iPublishedWidget — used to contain the returned object from a successful publishing of the Widget&lt;br /&gt;
If we look again at the driver architecture diagram, we ca highlight the objects we've just defined:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-Highlight.png|800px|thumb|center|Figure 6: The driver architecture highlighting the objects used by the IWidgetRegistryEntry implementation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The DeviceFactory, defined above in the member variable iDeviceFactory, is used to create new DvDevice objects. The DeviceFactory is only ever used to do this once. It is not shown in the driver architecture diagrams due to its minimal role in the operation of a driver, but it would normally appear between the IWidgetRegistryEntry and DvDevice objects.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
A driver requires methods to expose identifying details about the Widget. We must provide access to two of the attributes we just defined above:&lt;br /&gt;
&lt;br /&gt;
 public DvDevice DvDevice&lt;br /&gt;
 {&lt;br /&gt;
     get { return iDvDevice; }&lt;br /&gt;
 }&lt;br /&gt;
 public string WidgetClass&lt;br /&gt;
 {&lt;br /&gt;
     get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The WidgetClass string is formed using a combination of the vendor name and the Widget's name in the&lt;br /&gt;
format:&lt;br /&gt;
&lt;br /&gt;
 [vendor_domain]:[widget_name]&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry can now query both the DvDevice object representing the Widget, and the specific class of Widget this driver represents. The other member variables we defined do not need their own accessor methods.&lt;br /&gt;
&lt;br /&gt;
Now we must write a constructor for DiscoveredWidget and assign the parameters accordingly: &lt;br /&gt;
&lt;br /&gt;
 public DiscoveredWidget(IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                            string aUdn,&lt;br /&gt;
                            ISimpleUpnpWidget aProxy,&lt;br /&gt;
                            IWidgetPublisher aPublisher)&lt;br /&gt;
 {&lt;br /&gt;
      iDeviceFactory = aDeviceFactory;&lt;br /&gt;
      iProtocol = aProtocol;&lt;br /&gt;
      iPublisher = aPublisher;&lt;br /&gt;
      iDvDevice = iDeviceFactory.CreateDevice(aUdn);&lt;br /&gt;
      iProvider = new BinaryLightProvider(iDvDevice,&lt;br /&gt;
      iProtocol);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Event handling ===&lt;br /&gt;
&lt;br /&gt;
A Widget's state can change in one of three significant ways:&lt;br /&gt;
&lt;br /&gt;
* when the Widget needs to be published on the Node&lt;br /&gt;
* when the Widget disappears from the network (by losing power or similar)&lt;br /&gt;
* when a property's state changes and must be updated to a new value&lt;br /&gt;
&lt;br /&gt;
We now need methods to handle these changes.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The methods we define here will be used as callbacks, rather than invoked as method calls. We define the methods here first and then use them later on. We will use the Protocol Module to listen for changes in the Widget's state and register these methods as callbacks there. See Writing the SimpleUPnP Widget discovery method for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this section of the driver are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R4 Publishing discovered Widgets in the Local Widget Registry on the Node'''&lt;br /&gt;
&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object. &lt;br /&gt;
&lt;br /&gt;
'''R5 Reacting to an event reported from the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
'''R7 Reacting to a Widget's departure'''&lt;br /&gt;
&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no longer available.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Enabling and publishing a discovered Widget ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first method initializes the Widget by enabling the device and then using the IWidgetPublisher&lt;br /&gt;
to make it available on the Node:&lt;br /&gt;
&lt;br /&gt;
 public void HandleInitialEvent()&lt;br /&gt;
 {&lt;br /&gt;
      iDvDevice.SetEnabled();&lt;br /&gt;
      iPublisher.TryPublishWidget(iDvDevice.iUdn(),&lt;br /&gt;
                              this,&lt;br /&gt;
                              out iPublishedWidget);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This method meets the requirements for R4.&lt;br /&gt;
&lt;br /&gt;
The call to TryPublishWidget returns an iPublishedWidget object. We use this object later to satisfy the requirements of R7.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The ordering of the calls to SetEnabled and TryPublishWidget is vitally important. You&lt;br /&gt;
must enable the device before you attempt to publish it. Your Widget will not be available to the&lt;br /&gt;
Nodes unless SetEnabled is called first. Nodes will not be able to access a published device&lt;br /&gt;
that has not been enabled.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
R3 requires that you set the Widget's properties before you enable and publish the device. We&lt;br /&gt;
discussed on page 14 how some properties can only be set after the Widget reports what their&lt;br /&gt;
state is. We do this in HandleRegisterEvent.&lt;br /&gt;
&lt;br /&gt;
We rely on the SimpleUPnP Protocol Module guaranteeing a call to HandleRegisterEvent first before HandleInitialEvent. This is informed by guarantees made by the Control Point stack that the calls will be made in that order.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
==== Removing a Widget ====&lt;br /&gt;
&lt;br /&gt;
Removing a Widget involves unpublishing it from the Node. The IPublishedWidget interface provides us with a method we can call to manage that for us:&lt;br /&gt;
&lt;br /&gt;
 public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
 {&lt;br /&gt;
     if (iPublishedWidget != null)&lt;br /&gt;
     { iPublishedWidget.Unpublish(); }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assuming that the Widget was successfully published earlier, it is removed from the Node's Local Widget Registry.&lt;br /&gt;
&lt;br /&gt;
We must also properly handle the resources we used to create and maintain the Widget object while it was published:&lt;br /&gt;
&lt;br /&gt;
      iProvider.Dispose();&lt;br /&gt;
      iDvDevice.Dispose();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The calls to Dispose are made regardless of the Widget's published state, ensuring that any created device and associated provider are properly disposed. This implementation satisfies R7.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Event handling ====&lt;br /&gt;
&lt;br /&gt;
We need a method to handle changes to the state of the Widget's properties.&lt;br /&gt;
&lt;br /&gt;
If the property changes at the Widget, it needs to pass the new state back to the Node so that it is kept up-to-date on the Widget's status. This is called an event. An example in the case of our Basic Light is someone manually switching the light from on to off. This is in contrast to actions, which are passed from the Node to the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Other examples of events involve no human interaction, such as a thermometer Widget updating its current temperature based on environmental changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Our Basic Light Widget has only one property that needs to be handled:&lt;br /&gt;
&lt;br /&gt;
 public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
 {&lt;br /&gt;
     if (aIndex == 0)&lt;br /&gt;
     {&lt;br /&gt;
         iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We use our instance of the provider to update the register on the Widget that is mapped to the On property. This in turn updates the Node with the new state of the Widget.&lt;br /&gt;
&lt;br /&gt;
This method provides implementations to satisfy two driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
* R3 is now completely satisfied, as we can now set the values of all the previously unknown properties here.&lt;br /&gt;
* R5 is also satisfied as this method allows us to update the Widget's status on the Node when a property is changed on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Not all protocols pass messages back to the Node in this manner. The way we have satisfied R3 and R5 here only applies to protocols and Widgets that support this behavior.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Widgets that do not use an eventing protocol need to have their properties set in the provider's constructor to satisfy R3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To satisfy R5, the over-ridden method SetOn in the provider must include the call to SetPropertyOn. Non-eventing protocols do not require a HandleRegisterEvent method.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Constructor ===&lt;br /&gt;
&lt;br /&gt;
The final requirement for the driver is the constructor so that new DiscoveredWidget objects can be created. &lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this area of code are:&lt;br /&gt;
&lt;br /&gt;
'''R1 Specifying the type of Widget the driver controls'''&lt;br /&gt;
&lt;br /&gt;
A driver must know which type of Widget that it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Writing the code ====&lt;br /&gt;
&lt;br /&gt;
We begin by defining the variables we will use to store the objects used by the driver:&lt;br /&gt;
&lt;br /&gt;
 private readonly string iName;&lt;br /&gt;
 private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
 private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now write the constructor for the driver and assign the passed in parameters appropriately:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightDriver(string aName,&lt;br /&gt;
                IWidgetPublisher aPublisher,&lt;br /&gt;
                IDvDeviceFactory aDeviceFactory)&lt;br /&gt;
 {&lt;br /&gt;
     iWidgetPublisher = aPublisher;&lt;br /&gt;
     iName = aName;&lt;br /&gt;
     iDeviceFactory = aDeviceFactory;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally we need to provide the driver a way to publish the class of Widget it controls. This information is requested by the Discovery Module and is used to ensure the Node uses the correct driver when a new Widget appears.&lt;br /&gt;
&lt;br /&gt;
The implementation for this details will be different for each protocol. The SimpleUPnP protocol library provides a file that contains the SimpleUPnP definitions as integers. Each integer represents a particular class of identified Widget.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP implementation of that method is as follows:&lt;br /&gt;
&lt;br /&gt;
 public IEnumerable&amp;lt;uint&amp;gt; WidgetClasses&lt;br /&gt;
 {&lt;br /&gt;
 [[File:Warning.png]]        get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The body of this method is specifically written for the Widget class we are defining (in this case a binary light). This method completes the driver's requirements for R1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Writing the SimpleUPnP Widget discovery method ==&lt;br /&gt;
&lt;br /&gt;
Every driver must contain a method which creates new objects to represent newly discovered Widgets.&lt;br /&gt;
The Discovery Module invokes this method to begin the process of creating the objects required to allow the Node to access the Widget. &lt;br /&gt;
&lt;br /&gt;
The name of this method is dictated by your chosen protocol's API. The SimpleUPnP protocol requires a method called WidgetDiscovered.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The method's name will not always be the same for each protocol. Your protocol's documentation will contain the details of what this method must be called.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This method and its implementation will meet the following driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
'''R2 Reacting to a discovered Widget on the network'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
Our implementation of the WidgetDiscovered method will create a new DiscoveredWidget object and use the Protocol Module to listen for changes to the Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
The method uses the Protocol Module and two ways to identify the Widget. We must pass these in as&lt;br /&gt;
parameters:&lt;br /&gt;
&lt;br /&gt;
 public void WidgetDiscovered(string aWidgetUdn,&lt;br /&gt;
                              uint aWidgetClass,&lt;br /&gt;
                              ISimpleUpnpWidget&lt;br /&gt;
                                  aSimpleUpnpWidget)&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
Every Widget that uses this driver must be uniquely identifiable:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]    string newUdn = aWidgetUdn;&lt;br /&gt;
&lt;br /&gt;
Each new Widget is represented by a DiscoveredWidget object. Create the new DiscoveredWidget and pass in the required parameters we created earlier:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
     DiscoveredWidget discoveredWidget =&lt;br /&gt;
                 new DiscoveredWidget(iDeviceFactory,&lt;br /&gt;
                                      newUdn,&lt;br /&gt;
  &lt;br /&gt;
 [[File:Warning.png]]                                    aSimpleUpnpWidget,&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Registering the callbacks ===&lt;br /&gt;
&lt;br /&gt;
Finally, we ask the Widget's protocol interface to listen for calls to the handler methods we defined earlier in DiscoveredWidget. We do this by registering those methods as callbacks for the Protocol Module&lt;br /&gt;
to listen for:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                        discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                        discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                        discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You have now met 100% of the driver responsibility requirements and have a working driver to use with your SimpleUPnP Widget.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix A. Sample XML =&lt;br /&gt;
&lt;br /&gt;
== Binary Light.xml ==&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
  &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
  &amp;lt;version&amp;gt;&lt;br /&gt;
   &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
   &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/version&amp;gt;&lt;br /&gt;
  &amp;lt;propertylist&amp;gt;&lt;br /&gt;
   &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
       illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
   &amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix B. Sample Provider = &lt;br /&gt;
&lt;br /&gt;
== DvWidgetOpenhomeOrgBasicLight1.cs ==&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Runtime.InteropServices;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Core;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Utils.Binary;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
 {&lt;br /&gt;
    public interface IDvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
        IDisposable&lt;br /&gt;
    {&lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous value&lt;br /&gt;
        /// &amp;lt;/returns&amp;gt;&lt;br /&gt;
        bool SetPropertyOn(bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;Property's value will be copied&lt;br /&gt;
        /// here&amp;lt;/param&amp;gt;&lt;br /&gt;
        bool PropertyOn();&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt; summary&amp;gt;&lt;br /&gt;
    /// Provider for the openhome.org:BinaryLight:1 UPnP service&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public abstract class DvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
               DvProvider,&lt;br /&gt;
               IDisposable,&lt;br /&gt;
               IDvProviderOpenhomeOrgBinaryLight1&lt;br /&gt;
    {&lt;br /&gt;
        private GCHandle iGch;&lt;br /&gt;
        private PropertyBool iPropertyOn;&lt;br /&gt;
        private PropertyUint iPropertyPrimarySeq;&lt;br /&gt;
        private PropertyUint iPropertySecondarySeq;&lt;br /&gt;
        private ActionDelegate iDelegateSetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetPrimaryProperty;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Constructor&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aDevice&amp;quot;&amp;gt;Device which owns this&lt;br /&gt;
        /// provider&amp;lt;/param&amp;gt;&lt;br /&gt;
        protected DvProviderOpenhomeOrgBinaryLight1(DvDevice aDevice)&lt;br /&gt;
            : base(aDevice, &amp;quot;openhome.org&amp;quot;, &amp;quot;GenericWidget&amp;quot;, 1)&lt;br /&gt;
        {&lt;br /&gt;
            iGch = GCHandle.Alloc(this);&lt;br /&gt;
            List&amp;lt;String&amp;gt; allowedValues = new List&amp;lt;String&amp;gt;();&lt;br /&gt;
            iPropertyOn = new PropertyBool(new ParameterBool(&amp;quot;On&amp;quot;));&lt;br /&gt;
            iPropertyPrimarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;PrimarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertyPrimarySeq);&lt;br /&gt;
            iPropertySecondarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;SecondarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertySecondarySeq);&lt;br /&gt;
            SetPropertyUint(iPropertyPrimarySeq, 0);&lt;br /&gt;
            SetPropertyUint(iPropertySecondarySeq, 0);&lt;br /&gt;
  &lt;br /&gt;
            Zapp.Core.Action action = new Zapp.Core.Action&lt;br /&gt;
                (&amp;quot;SetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;FireAndForget&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddInputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateSetProperty = new ActionDelegate(DoSetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateSetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateGetProperty = new ActionDelegate(DoGetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetPrimaryProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                 (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;integer&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;boolean&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;string&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;binary&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Type&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;readWrite&amp;quot;);allowedValues.Add&lt;br /&gt;
                (&amp;quot;readOnly&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;writeOnly&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString(&amp;quot;Access&amp;quot;,&lt;br /&gt;
                allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            iDelegateGetPrimaryProperty = new&lt;br /&gt;
            ActionDelegate(DoGetPrimaryProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetPrimaryProperty,&lt;br /&gt;
            GCHandle.ToIntPtr(iGch));&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous&lt;br /&gt;
        /// value&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool SetPropertyOn(bool aValue)&lt;br /&gt;
        {&lt;br /&gt;
            if (iPropertyOn.SetValue(aValue))&lt;br /&gt;
            {&lt;br /&gt;
                lock (iPropertyPrimarySeq)&lt;br /&gt;
                {&lt;br /&gt;
                    SetPropertyUint(iPropertyPrimarySeq,&lt;br /&gt;
                        iPropertyPrimarySeq.Value() + 1);&lt;br /&gt;
                } return true;&lt;br /&gt;
            } return false;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;The value of the property&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool PropertyOn()&lt;br /&gt;
        {&lt;br /&gt;
            return iPropertyOn.Value();&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the On property.&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aVersion&amp;quot;&amp;gt;Version of the service being&lt;br /&gt;
        /// requested (will be &amp;lt;= the version advertised)&amp;lt;/param&amp;gt; &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the On property.&lt;br /&gt;
        /// &amp;lt;/param&amp;gt;&lt;br /&gt;
        protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        private static int DoSetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                byte[] valBin = invocation.ReadBinary(&amp;quot;Value&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                switch (name)&lt;br /&gt;
                {&lt;br /&gt;
                    case &amp;quot;On&amp;quot;:&lt;br /&gt;
                        self.SetOn(aVersion, Converter.&lt;br /&gt;
                            BinaryToBoolean(valBin));&lt;br /&gt;
                        break;&lt;br /&gt;
                    default:&lt;br /&gt;
                        throw new ActionError();&lt;br /&gt;
                }&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
                invocation.WriteEnd();&lt;br /&gt;
            }&lt;br /&gt;
            catch (ActionError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
            catch (PropertyUpdateError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
        return 0;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        private static int DoGetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
            switch (name)&lt;br /&gt;
            {&lt;br /&gt;
                case &amp;quot;On&amp;quot;:&lt;br /&gt;
                invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                    Converter.BooleanToBinary(self.iPropertyOn.&lt;br /&gt;
                        Value()));&lt;br /&gt;
                break;&lt;br /&gt;
                default:&lt;br /&gt;
                throw new ActionError();&lt;br /&gt;
            }&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    private static int DoGetPrimaryProperty(IntPtr aPtr,&lt;br /&gt;
                    IntPtr aInvocation,&lt;br /&gt;
                    uint aVersion)&lt;br /&gt;
    {&lt;br /&gt;
        GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
        DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
            (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
        DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
  &lt;br /&gt;
        try&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReadStart();&lt;br /&gt;
            invocation.ReadEnd();&lt;br /&gt;
            invocation.WriteStart();&lt;br /&gt;
            invocation.WriteString(&amp;quot;Name&amp;quot;, &amp;quot;On&amp;quot;);&lt;br /&gt;
            invocation.WriteString(&amp;quot;Type&amp;quot;, &amp;quot;boolean&amp;quot;);&lt;br /&gt;
            invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                Converter.BooleanToBinary(self.iPropertyOn.Value()));&lt;br /&gt;
            invocation.WriteString(&amp;quot;Access&amp;quot;, &amp;quot;readWrite&amp;quot;);&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt;summary&amp;gt;&lt;br /&gt;
    /// Must be called for each class instance. Must be called before&lt;br /&gt;
    /// Core.Library.Close().&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public void Dispose()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
        GC.SuppressFinalize(this);&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
    ~DvProviderOpenhomeOrgBinaryLight1()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
        private void DoDispose()&lt;br /&gt;
        {&lt;br /&gt;
            lock (this)&lt;br /&gt;
            {&lt;br /&gt;
                if (iHandle == IntPtr.Zero)&lt;br /&gt;
            {&lt;br /&gt;
                    return;&lt;br /&gt;
            }&lt;br /&gt;
            DisposeProvider();&lt;br /&gt;
            iPropertyOn.Dispose();&lt;br /&gt;
            iHandle = IntPtr.Zero;&lt;br /&gt;
            }&lt;br /&gt;
            iGch.Free();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix C. Sample Driver = &lt;br /&gt;
&lt;br /&gt;
== BasicLightDriver.cs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.hWidget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
     class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
     {&lt;br /&gt;
         private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
         public BinaryLightProvider(DvDevice aDevice, &lt;br /&gt;
             ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol = aProtocol;&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
     {&lt;br /&gt;
         private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
         {&lt;br /&gt;
             private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
             private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
             private readonly ISimpleUpnpWidget iProtocol; &lt;br /&gt;
 &lt;br /&gt;
             private readonly BinaryLightProvider iProvider;&lt;br /&gt;
             private readonly DvDevice iDvDevice;&lt;br /&gt;
             private IPublishedWidget iPublishedWidget; &lt;br /&gt;
 &lt;br /&gt;
             public DvDevice DvDevice&lt;br /&gt;
             {&lt;br /&gt;
                 get { return iDvDevice; }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             public string WidgetClass&lt;br /&gt;
             {&lt;br /&gt;
                 get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public DiscoveredWidget(&lt;br /&gt;
                 IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                 string aUdn,&lt;br /&gt;
                 ISimpleUpnpWidget aProxy,&lt;br /&gt;
                 IWidgetPublisher aPublisher)&lt;br /&gt;
             {&lt;br /&gt;
                 iDeviceFactory = aDeviceFactory;&lt;br /&gt;
                 iProtocol = aProtocol;&lt;br /&gt;
 &lt;br /&gt;
                 iPublisher = aPublisher;&lt;br /&gt;
                 iDvDevice = iDeviceFactory.CreateDevice(aUdn);  &lt;br /&gt;
                 iProvider = new BinaryLightProvider(iDvDevice, &lt;br /&gt;
                                                     iProtocol);&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             public void HandleInitialEvent()&lt;br /&gt;
             {&lt;br /&gt;
                 iDvDevice.SetEnabled();&lt;br /&gt;
                 iPublisher.TryPublishWidget(iDvDevice.iUdn(), this,&lt;br /&gt;
                     out iPublishedWidget);&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
             {&lt;br /&gt;
                 if (iPublishedWidget != null)&lt;br /&gt;
                 {&lt;br /&gt;
                     iPublishedWidget.Unpublish();&lt;br /&gt;
                 } &lt;br /&gt;
                 iProvider.Dispose();&lt;br /&gt;
                 iDvDevice.Dispose();&lt;br /&gt;
             }  &lt;br /&gt;
 &lt;br /&gt;
             public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
             {&lt;br /&gt;
                 if (aIndex == 0)&lt;br /&gt;
                 {&lt;br /&gt;
                     iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         private readonly string iName;&lt;br /&gt;
         private readonly IDvDeviceFactory aDeviceFactory;&lt;br /&gt;
         private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
         &lt;br /&gt;
         public BinaryLightDriver(&lt;br /&gt;
             string aName,&lt;br /&gt;
             IWidgetPublisher aPublisher,&lt;br /&gt;
             iDeviceFactory aDeviceFactory)&lt;br /&gt;
         {&lt;br /&gt;
             iWidgetPublisher = aPublisher;&lt;br /&gt;
             iName = aName;&lt;br /&gt;
             iDeviceFactory = aDeviceFactory;&lt;br /&gt;
         } &lt;br /&gt;
 &lt;br /&gt;
         public IEnumerable&amp;amp;lt;uint&amp;amp;gt; WidgetClasses&lt;br /&gt;
         {&lt;br /&gt;
             get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         public void WidgetDiscovered(&lt;br /&gt;
             string aWidgetUdn,&lt;br /&gt;
             uint aWidgetClass,&lt;br /&gt;
             ISimpleUpnpWidget aSimpleUpnpWidget)&lt;br /&gt;
         {&lt;br /&gt;
             string newUdn = aWidgetUdn;&lt;br /&gt;
             DiscoveredWidget discoveredWidget = new DiscoveredWidget&lt;br /&gt;
                 (iDeviceFactory,&lt;br /&gt;
                  newUdn,&lt;br /&gt;
                  aSimpleUpnpWidget,&lt;br /&gt;
                  iWidgetPublisher);&lt;br /&gt;
 &lt;br /&gt;
             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                 discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                 discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                 discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary = &lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in OpenHome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by OpenHome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh - A collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs on ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The OpenHome Operating System. Core software for OpenHome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. &lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. A typical Widget supports only one protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Driver_Development</id>
		<title>OhWidget Driver Development</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Driver_Development"/>
				<updated>2012-03-01T15:17:19Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* R7 Reacting to a Widget's departure */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for developers using the OpenHome SDK to integrate a Widget into an OpenHome system. Each Widget must have its own driver to allow it to communicate with the OpenHome Nodes. &lt;br /&gt;
&lt;br /&gt;
To help you write your driver, this document provides high level descriptions of the core responsibilities of a Widget driver and gives a detailed walk-through using example code.&lt;br /&gt;
&lt;br /&gt;
Full versions of each file used in the development of the example driver are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin development of your Widget driver you must be in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* your Widget Service XML that describes the properties on your Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document does not contain advice on how to write Widget Service XML. Refer to the OpenHome Widget Service XML definition document for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK&lt;br /&gt;
* your chosen communication protocol's API&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The protocol you choose for your Widgets must be the same protocol used on your choice of Node.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document focuses on the development of the Widget driver. Details about the communications protocol used are beyond the scope of this document. This document assumes you are familiar with your chosen protocol's code libraries and are able to use them in the driver code you write.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Related Documents ==&lt;br /&gt;
&lt;br /&gt;
The following related OpenHome documentation may be of interest to you:&lt;br /&gt;
&lt;br /&gt;
* [[ohWidget Technical Overview|ohWidget Technical Overview]]&lt;br /&gt;
* [[OpenHome Widget Service XML definition|OpenHome Widget Service XML definition]]&lt;br /&gt;
* [http://www.openhome.org/releases/ohNet_DeviceStack.pdf  OpenHome ohNet Device Stack]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
None of the related documents listed above is mandatory reading for Widget driver development.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
== Widget Service XML ==&lt;br /&gt;
OpenHome Widget driver writing relies heavily on the use of code generated from a single source — the Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
The service and actions your Widget provides are represented in code in a file called a Provider. The Provider is automatically generated from the Widget Service XML and produces an abstract class for you to inherit when you write your concrete class driver.&lt;br /&gt;
&lt;br /&gt;
To aid in the explanation of how the Provider is created and put to use we will follow the development of&lt;br /&gt;
a driver for a simple light Widget; taking the defined Widget Service XML and stepping through how it is used to generate the other files. Examples of code are used throughout this document to show you how each one is created and used in an OpenHome system. &lt;br /&gt;
&lt;br /&gt;
It is essential that you start with a well-formed Widget Service XML, conforming to the schema defined&lt;br /&gt;
in the WidgetService.xsd. The following diagram shows the significance of the Widget Service XML in&lt;br /&gt;
relation to the generated files you will use when writing your driver:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarchy, highlighting the areas specifically used in driver development]]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* The grayed-out files are not relevant to Widget driver development but can also be generated from the Widget Service XML.&lt;br /&gt;
* The Provider is generated in C#, meaning your driver must be written in C# as well. The use of managed code is mandatory for driver writing in the OpenHome framework.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Code sample used in this document ==&lt;br /&gt;
&lt;br /&gt;
Our examples in this document use a Widget Service XML definition for a light Widget called&lt;br /&gt;
BasicLight.xml.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Full versions of all the example files used in this document are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We will see how the Provider is generated from this XML and how it is used to aid the driver writing process. The examples also show how your chosen communication protocol should be used in the body of the driver code.&lt;br /&gt;
&lt;br /&gt;
Implementation details of specific protocols you choose to use are beyond the scope of this document. However, the samples used in this document show the use of the SimpleUPnP protocol to aid you in your development process.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol during the early stages of the OpenHome project. It is included in the OpenHome SDK and can be used as a public resource. &lt;br /&gt;
&lt;br /&gt;
The use of SimpleUPnP in the example files and the code snippets within the following sections is highlighted by the [[File:Warning.png]] icon. The lines of code marked by [[File:Warning.png]] must be changed to code from your chosen communication protocol's library. SimpleUPnP is left in to help you understand how a protocol is used in a working example.&lt;br /&gt;
&lt;br /&gt;
The sample code provided attempts to show best-practice coding standards. There are several sections of code that have a mandatory layout or that call specifically named methods and functions. These areas of the code are highlighted where required. &lt;br /&gt;
&lt;br /&gt;
Where the examples do not explicitly state that the code shown is mandatory, you are free to implement it in a different way according to your own coding style and practices.&lt;br /&gt;
&lt;br /&gt;
= Driver responsibilities = &lt;br /&gt;
&lt;br /&gt;
== Driver responsibilities ==&lt;br /&gt;
&lt;br /&gt;
An OpenHome Widget driver has several responsibilities which must be met before it can be used on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
These responsibilities are listed R1 to R7 and are defined here, explaining what each one must do. &lt;br /&gt;
&lt;br /&gt;
=== R1 Specifying the type of Widget the driver controls ===&lt;br /&gt;
A driver must know which type of Widget it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
=== R2 Reacting to a discovered Widget on the network ===&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== R3 Setting the initial values for the Widget's properties ===&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
=== R4 Publishing discovered Widgets in the Local Widget Registry on the Node ===&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object.&lt;br /&gt;
&lt;br /&gt;
=== R5 Reacting to an event reported from the Widget ===&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
=== R6 Reacting to actions sent to the Widget ===&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== R7 Reacting to a Widget's departure ===&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no&lt;br /&gt;
longer available.&lt;br /&gt;
&lt;br /&gt;
The sections of example code that follow show you how to write a driver from beginning to end. The accompanying text explaining the example code highlights when a responsibility, or part of a responsibility, has been met.&lt;br /&gt;
&lt;br /&gt;
= Driver Architecture = &lt;br /&gt;
&lt;br /&gt;
== Driver Architecture ==&lt;br /&gt;
&lt;br /&gt;
Drivers are installed on the Node and used when the Node needs to communicate with the Widget. Drivers&lt;br /&gt;
use several objects to communicate with Widgets over the Widget's lifetime. Figure 2 shows the objects&lt;br /&gt;
used by the driver and how the responsibilities listed above relate to each one:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture.png|800px|thumb|center|Figure 2: The architecture of a driver, showing the driver's relationship to the objects used to communicate with a Widget. Lines between objects show message flow.]]&lt;br /&gt;
&lt;br /&gt;
The objects contained in the dotted boundary must appear in the code you write to define your driver. The Driver, Provider and IWidgetRegistryEntry objects are all contained in the same driver file. We begin discussing this on page 12. &lt;br /&gt;
&lt;br /&gt;
The other objects are provided by the OpenHome SDK or as installed components on the Node.&lt;br /&gt;
&lt;br /&gt;
The Discovery Module informs the driver of the presence of an available Widget.&lt;br /&gt;
&lt;br /&gt;
Each Node has a Protocol Module which contains the protocol's API. Widgets can communicate with OpenHome Nodes using any one of the set of communications protocols the Node supports. The driver uses your chosen protocol's Protocol Module to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
Both the Protocol Module and the Discovery Module are installed on the Node. When you write your&lt;br /&gt;
driver you will use your Protocol Module to allow the driver to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
IWidgetPublisher, IPublishedWidget and DvDevice are objects provided in the OpenHome&lt;br /&gt;
API. You can read about them in the APIs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Generating the Provider = &lt;br /&gt;
&lt;br /&gt;
== Generating the Provider ==&lt;br /&gt;
&lt;br /&gt;
You must generate your provider before you can begin writing your Widget driver. You use your provider as a guide to implement the functions your Widget needs to set the values of its properties.&lt;br /&gt;
&lt;br /&gt;
The current provider generation process is a manual one involving the use of a text transform tool.&lt;br /&gt;
&lt;br /&gt;
Speak to your OpenHome contact who will help you generate your provider.&lt;br /&gt;
&lt;br /&gt;
Future releases of the OpenHome SDK will include a tool to help you generate the provider.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
You must be in possession of:&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK, unpacked on your computer&lt;br /&gt;
* your Widget Service XML file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Writing a SimpleUPnP driver = &lt;br /&gt;
&lt;br /&gt;
== Introduction to the SimpleUPnP protocol ==&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol used to control emulated Widgets over a custom UPnP service.&lt;br /&gt;
&lt;br /&gt;
This chapter shows how a driver is written using the SimpleUPnP communications protocol. The aim is to show the code using as generic a protocol as possible so that you can see where your own protocol specific code needs to go.&lt;br /&gt;
&lt;br /&gt;
The use of code specific to the SimpleUPnP implementation is highlighted by the use of the [[File:Warning.png]] icon. The lines of code are marked by this icon to make it easier for you to see where the protocol-specific code must go and what parts of the code are generic.&lt;br /&gt;
&lt;br /&gt;
=== Register model ===&lt;br /&gt;
&lt;br /&gt;
SimpleUPnP is modeled on 8 physical registers available on the Widget. Each register is 32-bits wide. They are indexed from 0 to 7 and the last register (register 7) is reserved for storing the Widget's class.&lt;br /&gt;
&lt;br /&gt;
This detail is used by the Protocol Module on the Node to determine which driver is needed to run the new Widget when it has been discovered.&lt;br /&gt;
&lt;br /&gt;
The remaining 7 registers (registers 0 to 6) are free for Widget engineers to assign to the Widget's functions.&lt;br /&gt;
&lt;br /&gt;
Registers 0, 1, 2 and 3 are available as read/write registers. Registers 4, 5 and 6 are readonly registers.&lt;br /&gt;
&lt;br /&gt;
Only the emulated hardware (running on the Node) can change the values held in registers 4, 5 and 6.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Register use in drivers ===&lt;br /&gt;
&lt;br /&gt;
In the example that follows we have a Basic Light Widget with a very simple function: it can be turned on and turned off. The on/off value is stored in register 0, with values 0=OFF and 1=ON. Register 0 is a read/write register. This means we can change the value stored there using messages passed to the Widget from the Node, and by reacting to physical interactions at the Widget (such as someone manually switching the light on or off). &lt;br /&gt;
&lt;br /&gt;
The mapping of registers to properties on the Widget is decided by the engineers who manufacture the device. You must be provided with the mapping before you begin developing your driver.&lt;br /&gt;
&lt;br /&gt;
== Starting the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-BoxHighlight.png|800px|thumb|center|Figure 3 The driver architecture highlighting the Widget driver and its component parts.]]&lt;br /&gt;
&lt;br /&gt;
When you have generated the abstract provider you can put it to use in the Widget driver. A Widget driver&lt;br /&gt;
has three distinct components:&lt;br /&gt;
&lt;br /&gt;
* an implementation of your abstract provider&lt;br /&gt;
* a definition of the Widget driver&lt;br /&gt;
* an implementation of the IWidgetRegistryEntry interface&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must manually write the code for your Widget driver. The differences in implementation of Widget properties and communication protocols means that the driver code cannot be autogenerated.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This section takes you through how to write a Widget driver by implementing the auto-generated provider,&lt;br /&gt;
starting from a new blank file and finishing with a working driver for the Basic Light Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
No assumptions have been made about the type of editor you use to write your code. Shortcuts&lt;br /&gt;
or macros that you use as standard will not appear in the instructions below. A full example&lt;br /&gt;
BinaryLightDriver.cs is available to review in Appendix C.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a new C# file in your IDE. Ensure the following libraries are used:&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 [[File:Warning.png]]using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 namespace OpenHome.Widget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must use the libraries listed above for this specific example.&lt;br /&gt;
&lt;br /&gt;
In general, drivers require the following libraries:&lt;br /&gt;
* System*&lt;br /&gt;
* System.Collections.Generic*&lt;br /&gt;
* OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
&lt;br /&gt;
Your driver will fail to compile if you miss any of these listed libraries. Libraries marked * are typically added by default by most modern IDEs. &lt;br /&gt;
&lt;br /&gt;
The OpenHome.Widget.Protocols.SimpleUpnp library is required only in this SimpleUPnP example. Drivers using a different protocol will use their own protocol library.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Implementing the provider ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-ProviderHighlight.png|800px|thumb|center|Figure 4 The driver architecture highlighting the Provider's place]]&lt;br /&gt;
&lt;br /&gt;
You use your auto-generated abstract provider by writing an implementation of it in the driver file. Responsibilities met by implementing your auto-generated provider are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R6 Reacting to actions sent to the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
Begin by creating a new class. It will subclass the abstract auto-generated provider:&lt;br /&gt;
&lt;br /&gt;
 class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
The Protocol Module will provide an API for the Provider to use to communicate with the Widget. In&lt;br /&gt;
SimpleUPnP we are provided with an interface called ISimpleUpnpWidget. The provider is supplied&lt;br /&gt;
with the required instance of the interface by the Discovery Module on the Node.&lt;br /&gt;
&lt;br /&gt;
The mechanisms for registering providers with specific Protocol Modules, and for the way the module gives each provider its required interface are covered later when writing the discovery method.&lt;br /&gt;
&lt;br /&gt;
For now, we need to give the Provider a place to store the interface that it will later use to communicate&lt;br /&gt;
with the Widget:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]] private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
&lt;br /&gt;
The interface from the Protocol Module is passed in as a parameter in the Provider's constructor and then&lt;br /&gt;
assigned to the variable we just created:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightProvider(DvDevice aDevice,&lt;br /&gt;
 [[File:Warning.png]]         ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
 {&lt;br /&gt;
       iProtocol = aProtocol;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
To satisfy R3 we would normally set the Widget's properties here, giving them an initial value.&lt;br /&gt;
However, in this specific example we cannot set the value of Basic Light's only property because&lt;br /&gt;
we will never know, in advance, what the state of the light will be (either on or off) when we&lt;br /&gt;
create the DiscoveredWidget.&lt;br /&gt;
&lt;br /&gt;
When you cannot set the properties ahead of time, and you are using an eventing protocol like SimpleUPnP, you can instead set them in the HandleRegisterEvent method in the driver class. This also satisfies the requirements for R3. You must set the Widget's properties before you enable it using SetEnabled(). &lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The abstract provider includes an abstract method called SetOn. This method is invoked by the Node when passing a message to the Widget, specifically to set the on property of the Widget to either 0 or 1. The implementation of this method will meet the requirements for R6.&lt;br /&gt;
&lt;br /&gt;
We must override this method and provide the protocol module a way of passing a message on to the Widget to perform the required action, in this case turn the light on or off:&lt;br /&gt;
&lt;br /&gt;
          protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
          {&lt;br /&gt;
     [[File:Warning.png]]        iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
In this example the Basic Light's SetOn property (the boolean property that controls whether the light is&lt;br /&gt;
on or off) is represented in the physical Widget by the register that has an index of 0.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* This method is an example of an action on a Widget. Actions are messages sent from the Node to the Widget. We will see later how to handle events that need to be passed back from the Widget&lt;br /&gt;
to the Node.&lt;br /&gt;
* Your own Widget will likely provide more than a single property. Your auto-generated provider will contain one abstract method to represent each writable property. Read-only properties are not provided an abstract method.&lt;br /&gt;
&lt;br /&gt;
You must implement each abstract method in your driver to ensure the relevant property on&lt;br /&gt;
the Widget can be set.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We have now finished implementing the provider. The next step is to implement the driver.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Implementing the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-DriverHighlight.png|800px|thumb|center|Figure 4: The driver architecture highlighting the implemented driver's place.]]&lt;br /&gt;
&lt;br /&gt;
The code for your Widget driver must provide an implementation of the IWidgetRegistryInterface,&lt;br /&gt;
including the following tasks:&lt;br /&gt;
&lt;br /&gt;
* methods to expose identifying details about the Widget for the Node to access&lt;br /&gt;
* providing methods to handle events reported by the Widget&lt;br /&gt;
&lt;br /&gt;
The driver is implemented as a public class within the same file as the provider code. Each driver must use the interface for the protocol you are using. For the SimpleUPnP protocol the interface is ISimple-UpnpWidgetDriver.&lt;br /&gt;
&lt;br /&gt;
=== Writing code ===&lt;br /&gt;
&lt;br /&gt;
Create your new driver class and subclass the ISimpleUpnpWidgetDriver interface:&lt;br /&gt;
&lt;br /&gt;
 public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Implementing IWidgetRegistryEntry ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry is the interface you use to represent physical Widgets. It is implemented as a subclass of your driver class. We are going to implement this interface in a class called '''DiscoveredWidget'''.&lt;br /&gt;
&lt;br /&gt;
Let's return to our driver architecture diagram for a moment:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-IRegistryEntryHighlight.png|800px|thumb|center|Figure 5 The driver architecture highlighting the IWidgetRegistryEntry object you will now implement]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry uses several other objects to help create it and respond to messages sent to and from it. These objects will be created in our implementation of DiscoveredWidget. &lt;br /&gt;
&lt;br /&gt;
When successfully created and published, the DiscoveredWidget objects are stored in a list on the Node called the Local Widget Registry. The Local Widget Registry is used by Nodes to maintain contact with the Widgets they control.&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry is shown at the top of Figure 5, marked plainly as (Registry). The path to the Local Widget Registry goes through several layers of Node architecture which are not relevant to Widget driver writing, so are not shown in the diagrams.&lt;br /&gt;
&lt;br /&gt;
==== Writing code ====&lt;br /&gt;
&lt;br /&gt;
Start by subclassing the IWidgetRegistryEntry interface in your new class:&lt;br /&gt;
&lt;br /&gt;
      private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
      {&lt;br /&gt;
&lt;br /&gt;
A DiscoveredWidget must provide the driver with the objects required to present the Widget and its&lt;br /&gt;
properties to the Node:&lt;br /&gt;
&lt;br /&gt;
           private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
           private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
           private readonly ISimpleUpnpWidget iProtocol;&lt;br /&gt;
           private readonly BinaryLightProvider iProvider;&lt;br /&gt;
           private readonly DvDevice iDvDevice;&lt;br /&gt;
           private IPublishedWidget iPublishedWidget;&lt;br /&gt;
&lt;br /&gt;
Each of the attributes in the example above are defined as follows:&lt;br /&gt;
&lt;br /&gt;
iDeviceFactory — used by the driver to create a single instance of DvDevice to represent a single Widget&lt;br /&gt;
&lt;br /&gt;
iPublisher — used by the driver to publish the Widget to the Node&lt;br /&gt;
&lt;br /&gt;
iProtocol — the object used by the Widget to communicate with the Protocol Module on the Node&lt;br /&gt;
&lt;br /&gt;
iProvider — an instantiated provider of the type you defined earlier&lt;br /&gt;
&lt;br /&gt;
iDvDevice — a representation of a Widget to which the provider is attached, created using iDevice-Factory above&lt;br /&gt;
&lt;br /&gt;
iPublishedWidget — used to contain the returned object from a successful publishing of the Widget&lt;br /&gt;
If we look again at the driver architecture diagram, we ca highlight the objects we've just defined:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-Highlight.png|800px|thumb|center|Figure 6: The driver architecture highlighting the objects used by the IWidgetRegistryEntry implementation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The DeviceFactory, defined above in the member variable iDeviceFactory, is used to create new DvDevice objects. The DeviceFactory is only ever used to do this once. It is not shown in the driver architecture diagrams due to its minimal role in the operation of a driver, but it would normally appear between the IWidgetRegistryEntry and DvDevice objects.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
A driver requires methods to expose identifying details about the Widget. We must provide access to two of the attributes we just defined above:&lt;br /&gt;
&lt;br /&gt;
 public DvDevice DvDevice&lt;br /&gt;
 {&lt;br /&gt;
     get { return iDvDevice; }&lt;br /&gt;
 }&lt;br /&gt;
 public string WidgetClass&lt;br /&gt;
 {&lt;br /&gt;
     get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The WidgetClass string is formed using a combination of the vendor name and the Widget's name in the&lt;br /&gt;
format:&lt;br /&gt;
&lt;br /&gt;
 [vendor_domain]:[widget_name]&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry can now query both the DvDevice object representing the Widget, and the specific class of Widget this driver represents. The other member variables we defined do not need their own accessor methods.&lt;br /&gt;
&lt;br /&gt;
Now we must write a constructor for DiscoveredWidget and assign the parameters accordingly: &lt;br /&gt;
&lt;br /&gt;
 public DiscoveredWidget(IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                            string aUdn,&lt;br /&gt;
                            ISimpleUpnpWidget aProxy,&lt;br /&gt;
                            IWidgetPublisher aPublisher)&lt;br /&gt;
 {&lt;br /&gt;
      iDeviceFactory = aDeviceFactory;&lt;br /&gt;
      iProtocol = aProtocol;&lt;br /&gt;
      iPublisher = aPublisher;&lt;br /&gt;
      iDvDevice = iDeviceFactory.CreateDevice(aUdn);&lt;br /&gt;
      iProvider = new BinaryLightProvider(iDvDevice,&lt;br /&gt;
      iProtocol);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Event handling ===&lt;br /&gt;
&lt;br /&gt;
A Widget's state can change in one of three significant ways:&lt;br /&gt;
&lt;br /&gt;
* when the Widget needs to be published on the Node&lt;br /&gt;
* when the Widget disappears from the network (by losing power or similar)&lt;br /&gt;
* when a property's state changes and must be updated to a new value&lt;br /&gt;
&lt;br /&gt;
We now need methods to handle these changes.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The methods we define here will be used as callbacks, rather than invoked as method calls. We define the methods here first and then use them later on. We will use the Protocol Module to listen for changes in the Widget's state and register these methods as callbacks there. See Writing the SimpleUPnP Widget discovery method for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this section of the driver are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R4 Publishing discovered Widgets in the Local Widget Registry on the Node'''&lt;br /&gt;
&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object. &lt;br /&gt;
&lt;br /&gt;
'''R5 Reacting to an event reported from the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
'''R7 Reacting to a Widget's departure'''&lt;br /&gt;
&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no longer available.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Enabling and publishing a discovered Widget ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first method initializes the Widget by enabling the device and then using the IWidgetPublisher&lt;br /&gt;
to make it available on the Node:&lt;br /&gt;
&lt;br /&gt;
 public void HandleInitialEvent()&lt;br /&gt;
 {&lt;br /&gt;
      iDvDevice.SetEnabled();&lt;br /&gt;
      iPublisher.TryPublishWidget(iDvDevice.iUdn(),&lt;br /&gt;
                              this,&lt;br /&gt;
                              out iPublishedWidget);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This method meets the requirements for R4.&lt;br /&gt;
&lt;br /&gt;
The call to TryPublishWidget returns an iPublishedWidget object. We use this object later to satisfy the requirements of R7.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The ordering of the calls to SetEnabled and TryPublishWidget is vitally important. You&lt;br /&gt;
must enable the device before you attempt to publish it. Your Widget will not be available to the&lt;br /&gt;
Nodes unless SetEnabled is called first. Nodes will not be able to access a published device&lt;br /&gt;
that has not been enabled.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
R3 requires that you set the Widget's properties before you enable and publish the device. We&lt;br /&gt;
discussed on page 14 how some properties can only be set after the Widget reports what their&lt;br /&gt;
state is. We do this in HandleRegisterEvent.&lt;br /&gt;
&lt;br /&gt;
We rely on the SimpleUPnP Protocol Module guaranteeing a call to HandleRegisterEvent first before HandleInitialEvent. This is informed by guarantees made by the Control Point stack that the calls will be made in that order.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
==== Removing a Widget ====&lt;br /&gt;
&lt;br /&gt;
Removing a Widget involves unpublishing it from the Node. The IPublishedWidget interface provides us with a method we can call to manage that for us:&lt;br /&gt;
&lt;br /&gt;
 public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
 {&lt;br /&gt;
     if (iPublishedWidget != null)&lt;br /&gt;
     { iPublishedWidget.Unpublish(); }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assuming that the Widget was successfully published earlier, it is removed from the Node's Local Widget Registry.&lt;br /&gt;
&lt;br /&gt;
We must also properly handle the resources we used to create and maintain the Widget object while it was published:&lt;br /&gt;
&lt;br /&gt;
      iProvider.Dispose();&lt;br /&gt;
      iDvDevice.Dispose();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The calls to Dispose are made regardless of the Widget's published state, ensuring that any created device and associated provider are properly disposed. This implementation satisfies R7.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Event handling ====&lt;br /&gt;
&lt;br /&gt;
We need a method to handle changes to the state of the Widget's properties.&lt;br /&gt;
&lt;br /&gt;
If the property changes at the Widget, it needs to pass the new state back to the Node so that it is kept up-to-date on the Widget's status. This is called an event. An example in the case of our Basic Light is someone manually switching the light from on to off. This is in contrast to actions, which are passed from the Node to the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Other examples of events involve no human interaction, such as a thermometer Widget updating its current temperature based on environmental changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Our Basic Light Widget has only one property that needs to be handled:&lt;br /&gt;
&lt;br /&gt;
 public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
 {&lt;br /&gt;
     if (aIndex == 0)&lt;br /&gt;
     {&lt;br /&gt;
         iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We use our instance of the provider to update the register on the Widget that is mapped to the On property. This in turn updates the Node with the new state of the Widget.&lt;br /&gt;
&lt;br /&gt;
This method provides implementations to satisfy two driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
* R3 is now completely satisfied, as we can now set the values of all the previously unknown properties here.&lt;br /&gt;
* R5 is also satisfied as this method allows us to update the Widget's status on the Node when a property is changed on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Not all protocols pass messages back to the Node in this manner. The way we have satisfied R3 and R5 here only applies to protocols and Widgets that support this behavior.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Widgets that do not use an eventing protocol need to have their properties set in the provider's constructor to satisfy R3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To satisfy R5, the over-ridden method SetOn in the provider must include the call to SetPropertyOn. Non-eventing protocols do not require a HandleRegisterEvent method.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Constructor ===&lt;br /&gt;
&lt;br /&gt;
The final requirement for the driver is the constructor so that new DiscoveredWidget objects can be created. &lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this area of code are:&lt;br /&gt;
&lt;br /&gt;
'''R1 Specifying the type of Widget the driver controls'''&lt;br /&gt;
&lt;br /&gt;
A driver must know which type of Widget that it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Writing the code ====&lt;br /&gt;
&lt;br /&gt;
We begin by defining the variables we will use to store the objects used by the driver:&lt;br /&gt;
&lt;br /&gt;
 private readonly string iName;&lt;br /&gt;
 private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
 private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now write the constructor for the driver and assign the passed in parameters appropriately:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightDriver(string aName,&lt;br /&gt;
                IWidgetPublisher aPublisher,&lt;br /&gt;
                IDvDeviceFactory aDeviceFactory)&lt;br /&gt;
 {&lt;br /&gt;
     iWidgetPublisher = aPublisher;&lt;br /&gt;
     iName = aName;&lt;br /&gt;
     iDeviceFactory = aDeviceFactory;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally we need to provide the driver a way to publish the class of Widget it controls. This information is requested by the Discovery Module and is used to ensure the Node uses the correct driver when a new Widget appears.&lt;br /&gt;
&lt;br /&gt;
The implementation for this details will be different for each protocol. The SimpleUPnP protocol library provides a file that contains the SimpleUPnP definitions as integers. Each integer represents a particular class of identified Widget.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP implementation of that method is as follows:&lt;br /&gt;
&lt;br /&gt;
 public IEnumerable&amp;lt;uint&amp;gt; WidgetClasses&lt;br /&gt;
 {&lt;br /&gt;
 [[File:Warning.png]]        get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The body of this method is specifically written for the Widget class we are defining (in this case a binary light). This method completes the driver's requirements for R1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Writing the SimpleUPnP Widget discovery method ==&lt;br /&gt;
&lt;br /&gt;
Every driver must contain a method which creates new objects to represent newly discovered Widgets.&lt;br /&gt;
The Discovery Module invokes this method to begin the process of creating the objects required to allow the Node to access the Widget. &lt;br /&gt;
&lt;br /&gt;
The name of this method is dictated by your chosen protocol's API. The SimpleUPnP protocol requires a method called WidgetDiscovered.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The method's name will not always be the same for each protocol. Your protocol's documentation will contain the details of what this method must be called.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This method and its implementation will meet the following driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
'''R2 Reacting to a discovered Widget on the network'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
Our implementation of the WidgetDiscovered method will create a new DiscoveredWidget object and use the Protocol Module to listen for changes to the Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
The method uses the Protocol Module and two ways to identify the Widget. We must pass these in as&lt;br /&gt;
parameters:&lt;br /&gt;
&lt;br /&gt;
 public void WidgetDiscovered(string aWidgetUdn,&lt;br /&gt;
                              uint aWidgetClass,&lt;br /&gt;
                              ISimpleUpnpWidget&lt;br /&gt;
                                  aSimpleUpnpWidget)&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
Every Widget that uses this driver must be uniquely identifiable:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]    string newUdn = aWidgetUdn;&lt;br /&gt;
&lt;br /&gt;
Each new Widget is represented by a DiscoveredWidget object. Create the new DiscoveredWidget and pass in the required parameters we created earlier:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
     DiscoveredWidget discoveredWidget =&lt;br /&gt;
                 new DiscoveredWidget(iDeviceFactory,&lt;br /&gt;
                                      newUdn,&lt;br /&gt;
  &lt;br /&gt;
 [[File:Warning.png]]                                    aSimpleUpnpWidget,&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Registering the callbacks ===&lt;br /&gt;
&lt;br /&gt;
Finally, we ask the Widget's protocol interface to listen for calls to the handler methods we defined earlier in DiscoveredWidget. We do this by registering those methods as callbacks for the Protocol Module&lt;br /&gt;
to listen for:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                        discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                        discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                        discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You have now met 100% of the driver responsibility requirements and have a working driver to use with your SimpleUPnP Widget.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix A. Sample XML =&lt;br /&gt;
&lt;br /&gt;
== Binary Light.xml ==&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
  &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
  &amp;lt;version&amp;gt;&lt;br /&gt;
   &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
   &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/version&amp;gt;&lt;br /&gt;
  &amp;lt;propertylist&amp;gt;&lt;br /&gt;
   &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
       illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
   &amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix B. Sample Provider = &lt;br /&gt;
&lt;br /&gt;
== DvWidgetOpenhomeOrgBasicLight1.cs ==&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Runtime.InteropServices;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Core;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Utils.Binary;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
 {&lt;br /&gt;
    public interface IDvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
        IDisposable&lt;br /&gt;
    {&lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous value&lt;br /&gt;
        /// &amp;lt;/returns&amp;gt;&lt;br /&gt;
        bool SetPropertyOn(bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;Property's value will be copied&lt;br /&gt;
        /// here&amp;lt;/param&amp;gt;&lt;br /&gt;
        bool PropertyOn();&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt; summary&amp;gt;&lt;br /&gt;
    /// Provider for the openhome.org:BinaryLight:1 UPnP service&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public abstract class DvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
               DvProvider,&lt;br /&gt;
               IDisposable,&lt;br /&gt;
               IDvProviderOpenhomeOrgBinaryLight1&lt;br /&gt;
    {&lt;br /&gt;
        private GCHandle iGch;&lt;br /&gt;
        private PropertyBool iPropertyOn;&lt;br /&gt;
        private PropertyUint iPropertyPrimarySeq;&lt;br /&gt;
        private PropertyUint iPropertySecondarySeq;&lt;br /&gt;
        private ActionDelegate iDelegateSetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetPrimaryProperty;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Constructor&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aDevice&amp;quot;&amp;gt;Device which owns this&lt;br /&gt;
        /// provider&amp;lt;/param&amp;gt;&lt;br /&gt;
        protected DvProviderOpenhomeOrgBinaryLight1(DvDevice aDevice)&lt;br /&gt;
            : base(aDevice, &amp;quot;openhome.org&amp;quot;, &amp;quot;GenericWidget&amp;quot;, 1)&lt;br /&gt;
        {&lt;br /&gt;
            iGch = GCHandle.Alloc(this);&lt;br /&gt;
            List&amp;lt;String&amp;gt; allowedValues = new List&amp;lt;String&amp;gt;();&lt;br /&gt;
            iPropertyOn = new PropertyBool(new ParameterBool(&amp;quot;On&amp;quot;));&lt;br /&gt;
            iPropertyPrimarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;PrimarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertyPrimarySeq);&lt;br /&gt;
            iPropertySecondarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;SecondarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertySecondarySeq);&lt;br /&gt;
            SetPropertyUint(iPropertyPrimarySeq, 0);&lt;br /&gt;
            SetPropertyUint(iPropertySecondarySeq, 0);&lt;br /&gt;
  &lt;br /&gt;
            Zapp.Core.Action action = new Zapp.Core.Action&lt;br /&gt;
                (&amp;quot;SetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;FireAndForget&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddInputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateSetProperty = new ActionDelegate(DoSetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateSetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateGetProperty = new ActionDelegate(DoGetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetPrimaryProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                 (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;integer&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;boolean&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;string&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;binary&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Type&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;readWrite&amp;quot;);allowedValues.Add&lt;br /&gt;
                (&amp;quot;readOnly&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;writeOnly&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString(&amp;quot;Access&amp;quot;,&lt;br /&gt;
                allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            iDelegateGetPrimaryProperty = new&lt;br /&gt;
            ActionDelegate(DoGetPrimaryProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetPrimaryProperty,&lt;br /&gt;
            GCHandle.ToIntPtr(iGch));&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous&lt;br /&gt;
        /// value&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool SetPropertyOn(bool aValue)&lt;br /&gt;
        {&lt;br /&gt;
            if (iPropertyOn.SetValue(aValue))&lt;br /&gt;
            {&lt;br /&gt;
                lock (iPropertyPrimarySeq)&lt;br /&gt;
                {&lt;br /&gt;
                    SetPropertyUint(iPropertyPrimarySeq,&lt;br /&gt;
                        iPropertyPrimarySeq.Value() + 1);&lt;br /&gt;
                } return true;&lt;br /&gt;
            } return false;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;The value of the property&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool PropertyOn()&lt;br /&gt;
        {&lt;br /&gt;
            return iPropertyOn.Value();&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the On property.&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aVersion&amp;quot;&amp;gt;Version of the service being&lt;br /&gt;
        /// requested (will be &amp;lt;= the version advertised)&amp;lt;/param&amp;gt; &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the On property.&lt;br /&gt;
        /// &amp;lt;/param&amp;gt;&lt;br /&gt;
        protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        private static int DoSetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                byte[] valBin = invocation.ReadBinary(&amp;quot;Value&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                switch (name)&lt;br /&gt;
                {&lt;br /&gt;
                    case &amp;quot;On&amp;quot;:&lt;br /&gt;
                        self.SetOn(aVersion, Converter.&lt;br /&gt;
                            BinaryToBoolean(valBin));&lt;br /&gt;
                        break;&lt;br /&gt;
                    default:&lt;br /&gt;
                        throw new ActionError();&lt;br /&gt;
                }&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
                invocation.WriteEnd();&lt;br /&gt;
            }&lt;br /&gt;
            catch (ActionError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
            catch (PropertyUpdateError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
        return 0;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        private static int DoGetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
            switch (name)&lt;br /&gt;
            {&lt;br /&gt;
                case &amp;quot;On&amp;quot;:&lt;br /&gt;
                invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                    Converter.BooleanToBinary(self.iPropertyOn.&lt;br /&gt;
                        Value()));&lt;br /&gt;
                break;&lt;br /&gt;
                default:&lt;br /&gt;
                throw new ActionError();&lt;br /&gt;
            }&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    private static int DoGetPrimaryProperty(IntPtr aPtr,&lt;br /&gt;
                    IntPtr aInvocation,&lt;br /&gt;
                    uint aVersion)&lt;br /&gt;
    {&lt;br /&gt;
        GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
        DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
            (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
        DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
  &lt;br /&gt;
        try&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReadStart();&lt;br /&gt;
            invocation.ReadEnd();&lt;br /&gt;
            invocation.WriteStart();&lt;br /&gt;
            invocation.WriteString(&amp;quot;Name&amp;quot;, &amp;quot;On&amp;quot;);&lt;br /&gt;
            invocation.WriteString(&amp;quot;Type&amp;quot;, &amp;quot;boolean&amp;quot;);&lt;br /&gt;
            invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                Converter.BooleanToBinary(self.iPropertyOn.Value()));&lt;br /&gt;
            invocation.WriteString(&amp;quot;Access&amp;quot;, &amp;quot;readWrite&amp;quot;);&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt;summary&amp;gt;&lt;br /&gt;
    /// Must be called for each class instance. Must be called before&lt;br /&gt;
    /// Core.Library.Close().&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public void Dispose()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
        GC.SuppressFinalize(this);&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
    ~DvProviderOpenhomeOrgBinaryLight1()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
        private void DoDispose()&lt;br /&gt;
        {&lt;br /&gt;
            lock (this)&lt;br /&gt;
            {&lt;br /&gt;
                if (iHandle == IntPtr.Zero)&lt;br /&gt;
            {&lt;br /&gt;
                    return;&lt;br /&gt;
            }&lt;br /&gt;
            DisposeProvider();&lt;br /&gt;
            iPropertyOn.Dispose();&lt;br /&gt;
            iHandle = IntPtr.Zero;&lt;br /&gt;
            }&lt;br /&gt;
            iGch.Free();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix C. Sample Driver = &lt;br /&gt;
&lt;br /&gt;
== BasicLightDriver.cs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.hWidget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
     class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
     {&lt;br /&gt;
         private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
         public BinaryLightProvider(DvDevice aDevice, &lt;br /&gt;
             ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol = aProtocol;&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
     {&lt;br /&gt;
         private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
         {&lt;br /&gt;
             private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
             private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
             private readonly ISimpleUpnpWidget iProtocol; &lt;br /&gt;
 &lt;br /&gt;
             private readonly BinaryLightProvider iProvider;&lt;br /&gt;
             private readonly DvDevice iDvDevice;&lt;br /&gt;
             private IPublishedWidget iPublishedWidget; &lt;br /&gt;
 &lt;br /&gt;
             public DvDevice DvDevice&lt;br /&gt;
             {&lt;br /&gt;
                 get { return iDvDevice; }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             public string WidgetClass&lt;br /&gt;
             {&lt;br /&gt;
                 get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public DiscoveredWidget(&lt;br /&gt;
                 IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                 string aUdn,&lt;br /&gt;
                 ISimpleUpnpWidget aProxy,&lt;br /&gt;
                 IWidgetPublisher aPublisher)&lt;br /&gt;
             {&lt;br /&gt;
                 iDeviceFactory = aDeviceFactory;&lt;br /&gt;
                 iProtocol = aProtocol;&lt;br /&gt;
 &lt;br /&gt;
                 iPublisher = aPublisher;&lt;br /&gt;
                 iDvDevice = iDeviceFactory.CreateDevice(aUdn);  &lt;br /&gt;
                 iProvider = new BinaryLightProvider(iDvDevice, &lt;br /&gt;
                                                     iProtocol);&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             public void HandleInitialEvent()&lt;br /&gt;
             {&lt;br /&gt;
                 iDvDevice.SetEnabled();&lt;br /&gt;
                 iPublisher.TryPublishWidget(iDvDevice.iUdn(), this,&lt;br /&gt;
                     out iPublishedWidget);&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
             {&lt;br /&gt;
                 if (iPublishedWidget != null)&lt;br /&gt;
                 {&lt;br /&gt;
                     iPublishedWidget.Unpublish();&lt;br /&gt;
                 } &lt;br /&gt;
                 iProvider.Dispose();&lt;br /&gt;
                 iDvDevice.Dispose();&lt;br /&gt;
             }  &lt;br /&gt;
 &lt;br /&gt;
             public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
             {&lt;br /&gt;
                 if (aIndex == 0)&lt;br /&gt;
                 {&lt;br /&gt;
                     iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         private readonly string iName;&lt;br /&gt;
         private readonly IDvDeviceFactory aDeviceFactory;&lt;br /&gt;
         private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
         &lt;br /&gt;
         public BinaryLightDriver(&lt;br /&gt;
             string aName,&lt;br /&gt;
             IWidgetPublisher aPublisher,&lt;br /&gt;
             iDeviceFactory aDeviceFactory)&lt;br /&gt;
         {&lt;br /&gt;
             iWidgetPublisher = aPublisher;&lt;br /&gt;
             iName = aName;&lt;br /&gt;
             iDeviceFactory = aDeviceFactory;&lt;br /&gt;
         } &lt;br /&gt;
 &lt;br /&gt;
         public IEnumerable&amp;amp;lt;uint&amp;amp;gt; WidgetClasses&lt;br /&gt;
         {&lt;br /&gt;
             get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         public void WidgetDiscovered(&lt;br /&gt;
             string aWidgetUdn,&lt;br /&gt;
             uint aWidgetClass,&lt;br /&gt;
             ISimpleUpnpWidget aSimpleUpnpWidget)&lt;br /&gt;
         {&lt;br /&gt;
             string newUdn = aWidgetUdn;&lt;br /&gt;
             DiscoveredWidget discoveredWidget = new DiscoveredWidget&lt;br /&gt;
                 (iDeviceFactory,&lt;br /&gt;
                  newUdn,&lt;br /&gt;
                  aSimpleUpnpWidget,&lt;br /&gt;
                  iWidgetPublisher);&lt;br /&gt;
 &lt;br /&gt;
             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                 discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                 discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                 discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary = &lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in OpenHome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by OpenHome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh - A collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs on ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The OpenHome Operating System. Core software for OpenHome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. &lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. A typical Widget supports only one protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Driver_Development</id>
		<title>OhWidget Driver Development</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Driver_Development"/>
				<updated>2012-03-01T15:16:56Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Code sample used in this document */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for developers using the OpenHome SDK to integrate a Widget into an OpenHome system. Each Widget must have its own driver to allow it to communicate with the OpenHome Nodes. &lt;br /&gt;
&lt;br /&gt;
To help you write your driver, this document provides high level descriptions of the core responsibilities of a Widget driver and gives a detailed walk-through using example code.&lt;br /&gt;
&lt;br /&gt;
Full versions of each file used in the development of the example driver are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin development of your Widget driver you must be in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* your Widget Service XML that describes the properties on your Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document does not contain advice on how to write Widget Service XML. Refer to the OpenHome Widget Service XML definition document for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK&lt;br /&gt;
* your chosen communication protocol's API&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The protocol you choose for your Widgets must be the same protocol used on your choice of Node.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document focuses on the development of the Widget driver. Details about the communications protocol used are beyond the scope of this document. This document assumes you are familiar with your chosen protocol's code libraries and are able to use them in the driver code you write.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Related Documents ==&lt;br /&gt;
&lt;br /&gt;
The following related OpenHome documentation may be of interest to you:&lt;br /&gt;
&lt;br /&gt;
* [[ohWidget Technical Overview|ohWidget Technical Overview]]&lt;br /&gt;
* [[OpenHome Widget Service XML definition|OpenHome Widget Service XML definition]]&lt;br /&gt;
* [http://www.openhome.org/releases/ohNet_DeviceStack.pdf  OpenHome ohNet Device Stack]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
None of the related documents listed above is mandatory reading for Widget driver development.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
== Widget Service XML ==&lt;br /&gt;
OpenHome Widget driver writing relies heavily on the use of code generated from a single source — the Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
The service and actions your Widget provides are represented in code in a file called a Provider. The Provider is automatically generated from the Widget Service XML and produces an abstract class for you to inherit when you write your concrete class driver.&lt;br /&gt;
&lt;br /&gt;
To aid in the explanation of how the Provider is created and put to use we will follow the development of&lt;br /&gt;
a driver for a simple light Widget; taking the defined Widget Service XML and stepping through how it is used to generate the other files. Examples of code are used throughout this document to show you how each one is created and used in an OpenHome system. &lt;br /&gt;
&lt;br /&gt;
It is essential that you start with a well-formed Widget Service XML, conforming to the schema defined&lt;br /&gt;
in the WidgetService.xsd. The following diagram shows the significance of the Widget Service XML in&lt;br /&gt;
relation to the generated files you will use when writing your driver:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarchy, highlighting the areas specifically used in driver development]]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* The grayed-out files are not relevant to Widget driver development but can also be generated from the Widget Service XML.&lt;br /&gt;
* The Provider is generated in C#, meaning your driver must be written in C# as well. The use of managed code is mandatory for driver writing in the OpenHome framework.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Code sample used in this document ==&lt;br /&gt;
&lt;br /&gt;
Our examples in this document use a Widget Service XML definition for a light Widget called&lt;br /&gt;
BasicLight.xml.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Full versions of all the example files used in this document are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We will see how the Provider is generated from this XML and how it is used to aid the driver writing process. The examples also show how your chosen communication protocol should be used in the body of the driver code.&lt;br /&gt;
&lt;br /&gt;
Implementation details of specific protocols you choose to use are beyond the scope of this document. However, the samples used in this document show the use of the SimpleUPnP protocol to aid you in your development process.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol during the early stages of the OpenHome project. It is included in the OpenHome SDK and can be used as a public resource. &lt;br /&gt;
&lt;br /&gt;
The use of SimpleUPnP in the example files and the code snippets within the following sections is highlighted by the [[File:Warning.png]] icon. The lines of code marked by [[File:Warning.png]] must be changed to code from your chosen communication protocol's library. SimpleUPnP is left in to help you understand how a protocol is used in a working example.&lt;br /&gt;
&lt;br /&gt;
The sample code provided attempts to show best-practice coding standards. There are several sections of code that have a mandatory layout or that call specifically named methods and functions. These areas of the code are highlighted where required. &lt;br /&gt;
&lt;br /&gt;
Where the examples do not explicitly state that the code shown is mandatory, you are free to implement it in a different way according to your own coding style and practices.&lt;br /&gt;
&lt;br /&gt;
= Driver responsibilities = &lt;br /&gt;
&lt;br /&gt;
== Driver responsibilities ==&lt;br /&gt;
&lt;br /&gt;
An OpenHome Widget driver has several responsibilities which must be met before it can be used on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
These responsibilities are listed R1 to R7 and are defined here, explaining what each one must do. &lt;br /&gt;
&lt;br /&gt;
=== R1 Specifying the type of Widget the driver controls ===&lt;br /&gt;
A driver must know which type of Widget it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
=== R2 Reacting to a discovered Widget on the network ===&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== R3 Setting the initial values for the Widget's properties ===&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
=== R4 Publishing discovered Widgets in the Local Widget Registry on the Node ===&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object.&lt;br /&gt;
&lt;br /&gt;
=== R5 Reacting to an event reported from the Widget ===&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
=== R6 Reacting to actions sent to the Widget ===&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== R7 Reacting to a Widget's departure ===&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no&lt;br /&gt;
longer available.&lt;br /&gt;
&lt;br /&gt;
The sections of example code that follow show you how to write a driver from beginning to end. The accompanying text explaining the example code highlights when a responsibility, or part of a responsibility, has been met.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Driver Architecture = &lt;br /&gt;
&lt;br /&gt;
== Driver Architecture ==&lt;br /&gt;
&lt;br /&gt;
Drivers are installed on the Node and used when the Node needs to communicate with the Widget. Drivers&lt;br /&gt;
use several objects to communicate with Widgets over the Widget's lifetime. Figure 2 shows the objects&lt;br /&gt;
used by the driver and how the responsibilities listed above relate to each one:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture.png|800px|thumb|center|Figure 2: The architecture of a driver, showing the driver's relationship to the objects used to communicate with a Widget. Lines between objects show message flow.]]&lt;br /&gt;
&lt;br /&gt;
The objects contained in the dotted boundary must appear in the code you write to define your driver. The Driver, Provider and IWidgetRegistryEntry objects are all contained in the same driver file. We begin discussing this on page 12. &lt;br /&gt;
&lt;br /&gt;
The other objects are provided by the OpenHome SDK or as installed components on the Node.&lt;br /&gt;
&lt;br /&gt;
The Discovery Module informs the driver of the presence of an available Widget.&lt;br /&gt;
&lt;br /&gt;
Each Node has a Protocol Module which contains the protocol's API. Widgets can communicate with OpenHome Nodes using any one of the set of communications protocols the Node supports. The driver uses your chosen protocol's Protocol Module to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
Both the Protocol Module and the Discovery Module are installed on the Node. When you write your&lt;br /&gt;
driver you will use your Protocol Module to allow the driver to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
IWidgetPublisher, IPublishedWidget and DvDevice are objects provided in the OpenHome&lt;br /&gt;
API. You can read about them in the APIs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Generating the Provider = &lt;br /&gt;
&lt;br /&gt;
== Generating the Provider ==&lt;br /&gt;
&lt;br /&gt;
You must generate your provider before you can begin writing your Widget driver. You use your provider as a guide to implement the functions your Widget needs to set the values of its properties.&lt;br /&gt;
&lt;br /&gt;
The current provider generation process is a manual one involving the use of a text transform tool.&lt;br /&gt;
&lt;br /&gt;
Speak to your OpenHome contact who will help you generate your provider.&lt;br /&gt;
&lt;br /&gt;
Future releases of the OpenHome SDK will include a tool to help you generate the provider.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
You must be in possession of:&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK, unpacked on your computer&lt;br /&gt;
* your Widget Service XML file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Writing a SimpleUPnP driver = &lt;br /&gt;
&lt;br /&gt;
== Introduction to the SimpleUPnP protocol ==&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol used to control emulated Widgets over a custom UPnP service.&lt;br /&gt;
&lt;br /&gt;
This chapter shows how a driver is written using the SimpleUPnP communications protocol. The aim is to show the code using as generic a protocol as possible so that you can see where your own protocol specific code needs to go.&lt;br /&gt;
&lt;br /&gt;
The use of code specific to the SimpleUPnP implementation is highlighted by the use of the [[File:Warning.png]] icon. The lines of code are marked by this icon to make it easier for you to see where the protocol-specific code must go and what parts of the code are generic.&lt;br /&gt;
&lt;br /&gt;
=== Register model ===&lt;br /&gt;
&lt;br /&gt;
SimpleUPnP is modeled on 8 physical registers available on the Widget. Each register is 32-bits wide. They are indexed from 0 to 7 and the last register (register 7) is reserved for storing the Widget's class.&lt;br /&gt;
&lt;br /&gt;
This detail is used by the Protocol Module on the Node to determine which driver is needed to run the new Widget when it has been discovered.&lt;br /&gt;
&lt;br /&gt;
The remaining 7 registers (registers 0 to 6) are free for Widget engineers to assign to the Widget's functions.&lt;br /&gt;
&lt;br /&gt;
Registers 0, 1, 2 and 3 are available as read/write registers. Registers 4, 5 and 6 are readonly registers.&lt;br /&gt;
&lt;br /&gt;
Only the emulated hardware (running on the Node) can change the values held in registers 4, 5 and 6.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Register use in drivers ===&lt;br /&gt;
&lt;br /&gt;
In the example that follows we have a Basic Light Widget with a very simple function: it can be turned on and turned off. The on/off value is stored in register 0, with values 0=OFF and 1=ON. Register 0 is a read/write register. This means we can change the value stored there using messages passed to the Widget from the Node, and by reacting to physical interactions at the Widget (such as someone manually switching the light on or off). &lt;br /&gt;
&lt;br /&gt;
The mapping of registers to properties on the Widget is decided by the engineers who manufacture the device. You must be provided with the mapping before you begin developing your driver.&lt;br /&gt;
&lt;br /&gt;
== Starting the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-BoxHighlight.png|800px|thumb|center|Figure 3 The driver architecture highlighting the Widget driver and its component parts.]]&lt;br /&gt;
&lt;br /&gt;
When you have generated the abstract provider you can put it to use in the Widget driver. A Widget driver&lt;br /&gt;
has three distinct components:&lt;br /&gt;
&lt;br /&gt;
* an implementation of your abstract provider&lt;br /&gt;
* a definition of the Widget driver&lt;br /&gt;
* an implementation of the IWidgetRegistryEntry interface&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must manually write the code for your Widget driver. The differences in implementation of Widget properties and communication protocols means that the driver code cannot be autogenerated.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This section takes you through how to write a Widget driver by implementing the auto-generated provider,&lt;br /&gt;
starting from a new blank file and finishing with a working driver for the Basic Light Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
No assumptions have been made about the type of editor you use to write your code. Shortcuts&lt;br /&gt;
or macros that you use as standard will not appear in the instructions below. A full example&lt;br /&gt;
BinaryLightDriver.cs is available to review in Appendix C.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a new C# file in your IDE. Ensure the following libraries are used:&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 [[File:Warning.png]]using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 namespace OpenHome.Widget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must use the libraries listed above for this specific example.&lt;br /&gt;
&lt;br /&gt;
In general, drivers require the following libraries:&lt;br /&gt;
* System*&lt;br /&gt;
* System.Collections.Generic*&lt;br /&gt;
* OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
&lt;br /&gt;
Your driver will fail to compile if you miss any of these listed libraries. Libraries marked * are typically added by default by most modern IDEs. &lt;br /&gt;
&lt;br /&gt;
The OpenHome.Widget.Protocols.SimpleUpnp library is required only in this SimpleUPnP example. Drivers using a different protocol will use their own protocol library.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Implementing the provider ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-ProviderHighlight.png|800px|thumb|center|Figure 4 The driver architecture highlighting the Provider's place]]&lt;br /&gt;
&lt;br /&gt;
You use your auto-generated abstract provider by writing an implementation of it in the driver file. Responsibilities met by implementing your auto-generated provider are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R6 Reacting to actions sent to the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
Begin by creating a new class. It will subclass the abstract auto-generated provider:&lt;br /&gt;
&lt;br /&gt;
 class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
The Protocol Module will provide an API for the Provider to use to communicate with the Widget. In&lt;br /&gt;
SimpleUPnP we are provided with an interface called ISimpleUpnpWidget. The provider is supplied&lt;br /&gt;
with the required instance of the interface by the Discovery Module on the Node.&lt;br /&gt;
&lt;br /&gt;
The mechanisms for registering providers with specific Protocol Modules, and for the way the module gives each provider its required interface are covered later when writing the discovery method.&lt;br /&gt;
&lt;br /&gt;
For now, we need to give the Provider a place to store the interface that it will later use to communicate&lt;br /&gt;
with the Widget:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]] private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
&lt;br /&gt;
The interface from the Protocol Module is passed in as a parameter in the Provider's constructor and then&lt;br /&gt;
assigned to the variable we just created:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightProvider(DvDevice aDevice,&lt;br /&gt;
 [[File:Warning.png]]         ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
 {&lt;br /&gt;
       iProtocol = aProtocol;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
To satisfy R3 we would normally set the Widget's properties here, giving them an initial value.&lt;br /&gt;
However, in this specific example we cannot set the value of Basic Light's only property because&lt;br /&gt;
we will never know, in advance, what the state of the light will be (either on or off) when we&lt;br /&gt;
create the DiscoveredWidget.&lt;br /&gt;
&lt;br /&gt;
When you cannot set the properties ahead of time, and you are using an eventing protocol like SimpleUPnP, you can instead set them in the HandleRegisterEvent method in the driver class. This also satisfies the requirements for R3. You must set the Widget's properties before you enable it using SetEnabled(). &lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The abstract provider includes an abstract method called SetOn. This method is invoked by the Node when passing a message to the Widget, specifically to set the on property of the Widget to either 0 or 1. The implementation of this method will meet the requirements for R6.&lt;br /&gt;
&lt;br /&gt;
We must override this method and provide the protocol module a way of passing a message on to the Widget to perform the required action, in this case turn the light on or off:&lt;br /&gt;
&lt;br /&gt;
          protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
          {&lt;br /&gt;
     [[File:Warning.png]]        iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
In this example the Basic Light's SetOn property (the boolean property that controls whether the light is&lt;br /&gt;
on or off) is represented in the physical Widget by the register that has an index of 0.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* This method is an example of an action on a Widget. Actions are messages sent from the Node to the Widget. We will see later how to handle events that need to be passed back from the Widget&lt;br /&gt;
to the Node.&lt;br /&gt;
* Your own Widget will likely provide more than a single property. Your auto-generated provider will contain one abstract method to represent each writable property. Read-only properties are not provided an abstract method.&lt;br /&gt;
&lt;br /&gt;
You must implement each abstract method in your driver to ensure the relevant property on&lt;br /&gt;
the Widget can be set.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We have now finished implementing the provider. The next step is to implement the driver.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Implementing the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-DriverHighlight.png|800px|thumb|center|Figure 4: The driver architecture highlighting the implemented driver's place.]]&lt;br /&gt;
&lt;br /&gt;
The code for your Widget driver must provide an implementation of the IWidgetRegistryInterface,&lt;br /&gt;
including the following tasks:&lt;br /&gt;
&lt;br /&gt;
* methods to expose identifying details about the Widget for the Node to access&lt;br /&gt;
* providing methods to handle events reported by the Widget&lt;br /&gt;
&lt;br /&gt;
The driver is implemented as a public class within the same file as the provider code. Each driver must use the interface for the protocol you are using. For the SimpleUPnP protocol the interface is ISimple-UpnpWidgetDriver.&lt;br /&gt;
&lt;br /&gt;
=== Writing code ===&lt;br /&gt;
&lt;br /&gt;
Create your new driver class and subclass the ISimpleUpnpWidgetDriver interface:&lt;br /&gt;
&lt;br /&gt;
 public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Implementing IWidgetRegistryEntry ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry is the interface you use to represent physical Widgets. It is implemented as a subclass of your driver class. We are going to implement this interface in a class called '''DiscoveredWidget'''.&lt;br /&gt;
&lt;br /&gt;
Let's return to our driver architecture diagram for a moment:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-IRegistryEntryHighlight.png|800px|thumb|center|Figure 5 The driver architecture highlighting the IWidgetRegistryEntry object you will now implement]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry uses several other objects to help create it and respond to messages sent to and from it. These objects will be created in our implementation of DiscoveredWidget. &lt;br /&gt;
&lt;br /&gt;
When successfully created and published, the DiscoveredWidget objects are stored in a list on the Node called the Local Widget Registry. The Local Widget Registry is used by Nodes to maintain contact with the Widgets they control.&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry is shown at the top of Figure 5, marked plainly as (Registry). The path to the Local Widget Registry goes through several layers of Node architecture which are not relevant to Widget driver writing, so are not shown in the diagrams.&lt;br /&gt;
&lt;br /&gt;
==== Writing code ====&lt;br /&gt;
&lt;br /&gt;
Start by subclassing the IWidgetRegistryEntry interface in your new class:&lt;br /&gt;
&lt;br /&gt;
      private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
      {&lt;br /&gt;
&lt;br /&gt;
A DiscoveredWidget must provide the driver with the objects required to present the Widget and its&lt;br /&gt;
properties to the Node:&lt;br /&gt;
&lt;br /&gt;
           private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
           private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
           private readonly ISimpleUpnpWidget iProtocol;&lt;br /&gt;
           private readonly BinaryLightProvider iProvider;&lt;br /&gt;
           private readonly DvDevice iDvDevice;&lt;br /&gt;
           private IPublishedWidget iPublishedWidget;&lt;br /&gt;
&lt;br /&gt;
Each of the attributes in the example above are defined as follows:&lt;br /&gt;
&lt;br /&gt;
iDeviceFactory — used by the driver to create a single instance of DvDevice to represent a single Widget&lt;br /&gt;
&lt;br /&gt;
iPublisher — used by the driver to publish the Widget to the Node&lt;br /&gt;
&lt;br /&gt;
iProtocol — the object used by the Widget to communicate with the Protocol Module on the Node&lt;br /&gt;
&lt;br /&gt;
iProvider — an instantiated provider of the type you defined earlier&lt;br /&gt;
&lt;br /&gt;
iDvDevice — a representation of a Widget to which the provider is attached, created using iDevice-Factory above&lt;br /&gt;
&lt;br /&gt;
iPublishedWidget — used to contain the returned object from a successful publishing of the Widget&lt;br /&gt;
If we look again at the driver architecture diagram, we ca highlight the objects we've just defined:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-Highlight.png|800px|thumb|center|Figure 6: The driver architecture highlighting the objects used by the IWidgetRegistryEntry implementation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The DeviceFactory, defined above in the member variable iDeviceFactory, is used to create new DvDevice objects. The DeviceFactory is only ever used to do this once. It is not shown in the driver architecture diagrams due to its minimal role in the operation of a driver, but it would normally appear between the IWidgetRegistryEntry and DvDevice objects.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
A driver requires methods to expose identifying details about the Widget. We must provide access to two of the attributes we just defined above:&lt;br /&gt;
&lt;br /&gt;
 public DvDevice DvDevice&lt;br /&gt;
 {&lt;br /&gt;
     get { return iDvDevice; }&lt;br /&gt;
 }&lt;br /&gt;
 public string WidgetClass&lt;br /&gt;
 {&lt;br /&gt;
     get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The WidgetClass string is formed using a combination of the vendor name and the Widget's name in the&lt;br /&gt;
format:&lt;br /&gt;
&lt;br /&gt;
 [vendor_domain]:[widget_name]&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry can now query both the DvDevice object representing the Widget, and the specific class of Widget this driver represents. The other member variables we defined do not need their own accessor methods.&lt;br /&gt;
&lt;br /&gt;
Now we must write a constructor for DiscoveredWidget and assign the parameters accordingly: &lt;br /&gt;
&lt;br /&gt;
 public DiscoveredWidget(IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                            string aUdn,&lt;br /&gt;
                            ISimpleUpnpWidget aProxy,&lt;br /&gt;
                            IWidgetPublisher aPublisher)&lt;br /&gt;
 {&lt;br /&gt;
      iDeviceFactory = aDeviceFactory;&lt;br /&gt;
      iProtocol = aProtocol;&lt;br /&gt;
      iPublisher = aPublisher;&lt;br /&gt;
      iDvDevice = iDeviceFactory.CreateDevice(aUdn);&lt;br /&gt;
      iProvider = new BinaryLightProvider(iDvDevice,&lt;br /&gt;
      iProtocol);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Event handling ===&lt;br /&gt;
&lt;br /&gt;
A Widget's state can change in one of three significant ways:&lt;br /&gt;
&lt;br /&gt;
* when the Widget needs to be published on the Node&lt;br /&gt;
* when the Widget disappears from the network (by losing power or similar)&lt;br /&gt;
* when a property's state changes and must be updated to a new value&lt;br /&gt;
&lt;br /&gt;
We now need methods to handle these changes.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The methods we define here will be used as callbacks, rather than invoked as method calls. We define the methods here first and then use them later on. We will use the Protocol Module to listen for changes in the Widget's state and register these methods as callbacks there. See Writing the SimpleUPnP Widget discovery method for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this section of the driver are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R4 Publishing discovered Widgets in the Local Widget Registry on the Node'''&lt;br /&gt;
&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object. &lt;br /&gt;
&lt;br /&gt;
'''R5 Reacting to an event reported from the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
'''R7 Reacting to a Widget's departure'''&lt;br /&gt;
&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no longer available.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Enabling and publishing a discovered Widget ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first method initializes the Widget by enabling the device and then using the IWidgetPublisher&lt;br /&gt;
to make it available on the Node:&lt;br /&gt;
&lt;br /&gt;
 public void HandleInitialEvent()&lt;br /&gt;
 {&lt;br /&gt;
      iDvDevice.SetEnabled();&lt;br /&gt;
      iPublisher.TryPublishWidget(iDvDevice.iUdn(),&lt;br /&gt;
                              this,&lt;br /&gt;
                              out iPublishedWidget);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This method meets the requirements for R4.&lt;br /&gt;
&lt;br /&gt;
The call to TryPublishWidget returns an iPublishedWidget object. We use this object later to satisfy the requirements of R7.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The ordering of the calls to SetEnabled and TryPublishWidget is vitally important. You&lt;br /&gt;
must enable the device before you attempt to publish it. Your Widget will not be available to the&lt;br /&gt;
Nodes unless SetEnabled is called first. Nodes will not be able to access a published device&lt;br /&gt;
that has not been enabled.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
R3 requires that you set the Widget's properties before you enable and publish the device. We&lt;br /&gt;
discussed on page 14 how some properties can only be set after the Widget reports what their&lt;br /&gt;
state is. We do this in HandleRegisterEvent.&lt;br /&gt;
&lt;br /&gt;
We rely on the SimpleUPnP Protocol Module guaranteeing a call to HandleRegisterEvent first before HandleInitialEvent. This is informed by guarantees made by the Control Point stack that the calls will be made in that order.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
==== Removing a Widget ====&lt;br /&gt;
&lt;br /&gt;
Removing a Widget involves unpublishing it from the Node. The IPublishedWidget interface provides us with a method we can call to manage that for us:&lt;br /&gt;
&lt;br /&gt;
 public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
 {&lt;br /&gt;
     if (iPublishedWidget != null)&lt;br /&gt;
     { iPublishedWidget.Unpublish(); }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assuming that the Widget was successfully published earlier, it is removed from the Node's Local Widget Registry.&lt;br /&gt;
&lt;br /&gt;
We must also properly handle the resources we used to create and maintain the Widget object while it was published:&lt;br /&gt;
&lt;br /&gt;
      iProvider.Dispose();&lt;br /&gt;
      iDvDevice.Dispose();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The calls to Dispose are made regardless of the Widget's published state, ensuring that any created device and associated provider are properly disposed. This implementation satisfies R7.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Event handling ====&lt;br /&gt;
&lt;br /&gt;
We need a method to handle changes to the state of the Widget's properties.&lt;br /&gt;
&lt;br /&gt;
If the property changes at the Widget, it needs to pass the new state back to the Node so that it is kept up-to-date on the Widget's status. This is called an event. An example in the case of our Basic Light is someone manually switching the light from on to off. This is in contrast to actions, which are passed from the Node to the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Other examples of events involve no human interaction, such as a thermometer Widget updating its current temperature based on environmental changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Our Basic Light Widget has only one property that needs to be handled:&lt;br /&gt;
&lt;br /&gt;
 public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
 {&lt;br /&gt;
     if (aIndex == 0)&lt;br /&gt;
     {&lt;br /&gt;
         iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We use our instance of the provider to update the register on the Widget that is mapped to the On property. This in turn updates the Node with the new state of the Widget.&lt;br /&gt;
&lt;br /&gt;
This method provides implementations to satisfy two driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
* R3 is now completely satisfied, as we can now set the values of all the previously unknown properties here.&lt;br /&gt;
* R5 is also satisfied as this method allows us to update the Widget's status on the Node when a property is changed on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Not all protocols pass messages back to the Node in this manner. The way we have satisfied R3 and R5 here only applies to protocols and Widgets that support this behavior.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Widgets that do not use an eventing protocol need to have their properties set in the provider's constructor to satisfy R3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To satisfy R5, the over-ridden method SetOn in the provider must include the call to SetPropertyOn. Non-eventing protocols do not require a HandleRegisterEvent method.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Constructor ===&lt;br /&gt;
&lt;br /&gt;
The final requirement for the driver is the constructor so that new DiscoveredWidget objects can be created. &lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this area of code are:&lt;br /&gt;
&lt;br /&gt;
'''R1 Specifying the type of Widget the driver controls'''&lt;br /&gt;
&lt;br /&gt;
A driver must know which type of Widget that it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Writing the code ====&lt;br /&gt;
&lt;br /&gt;
We begin by defining the variables we will use to store the objects used by the driver:&lt;br /&gt;
&lt;br /&gt;
 private readonly string iName;&lt;br /&gt;
 private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
 private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now write the constructor for the driver and assign the passed in parameters appropriately:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightDriver(string aName,&lt;br /&gt;
                IWidgetPublisher aPublisher,&lt;br /&gt;
                IDvDeviceFactory aDeviceFactory)&lt;br /&gt;
 {&lt;br /&gt;
     iWidgetPublisher = aPublisher;&lt;br /&gt;
     iName = aName;&lt;br /&gt;
     iDeviceFactory = aDeviceFactory;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally we need to provide the driver a way to publish the class of Widget it controls. This information is requested by the Discovery Module and is used to ensure the Node uses the correct driver when a new Widget appears.&lt;br /&gt;
&lt;br /&gt;
The implementation for this details will be different for each protocol. The SimpleUPnP protocol library provides a file that contains the SimpleUPnP definitions as integers. Each integer represents a particular class of identified Widget.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP implementation of that method is as follows:&lt;br /&gt;
&lt;br /&gt;
 public IEnumerable&amp;lt;uint&amp;gt; WidgetClasses&lt;br /&gt;
 {&lt;br /&gt;
 [[File:Warning.png]]        get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The body of this method is specifically written for the Widget class we are defining (in this case a binary light). This method completes the driver's requirements for R1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Writing the SimpleUPnP Widget discovery method ==&lt;br /&gt;
&lt;br /&gt;
Every driver must contain a method which creates new objects to represent newly discovered Widgets.&lt;br /&gt;
The Discovery Module invokes this method to begin the process of creating the objects required to allow the Node to access the Widget. &lt;br /&gt;
&lt;br /&gt;
The name of this method is dictated by your chosen protocol's API. The SimpleUPnP protocol requires a method called WidgetDiscovered.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The method's name will not always be the same for each protocol. Your protocol's documentation will contain the details of what this method must be called.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This method and its implementation will meet the following driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
'''R2 Reacting to a discovered Widget on the network'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
Our implementation of the WidgetDiscovered method will create a new DiscoveredWidget object and use the Protocol Module to listen for changes to the Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
The method uses the Protocol Module and two ways to identify the Widget. We must pass these in as&lt;br /&gt;
parameters:&lt;br /&gt;
&lt;br /&gt;
 public void WidgetDiscovered(string aWidgetUdn,&lt;br /&gt;
                              uint aWidgetClass,&lt;br /&gt;
                              ISimpleUpnpWidget&lt;br /&gt;
                                  aSimpleUpnpWidget)&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
Every Widget that uses this driver must be uniquely identifiable:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]    string newUdn = aWidgetUdn;&lt;br /&gt;
&lt;br /&gt;
Each new Widget is represented by a DiscoveredWidget object. Create the new DiscoveredWidget and pass in the required parameters we created earlier:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
     DiscoveredWidget discoveredWidget =&lt;br /&gt;
                 new DiscoveredWidget(iDeviceFactory,&lt;br /&gt;
                                      newUdn,&lt;br /&gt;
  &lt;br /&gt;
 [[File:Warning.png]]                                    aSimpleUpnpWidget,&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Registering the callbacks ===&lt;br /&gt;
&lt;br /&gt;
Finally, we ask the Widget's protocol interface to listen for calls to the handler methods we defined earlier in DiscoveredWidget. We do this by registering those methods as callbacks for the Protocol Module&lt;br /&gt;
to listen for:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                        discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                        discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                        discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You have now met 100% of the driver responsibility requirements and have a working driver to use with your SimpleUPnP Widget.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix A. Sample XML =&lt;br /&gt;
&lt;br /&gt;
== Binary Light.xml ==&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
  &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
  &amp;lt;version&amp;gt;&lt;br /&gt;
   &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
   &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/version&amp;gt;&lt;br /&gt;
  &amp;lt;propertylist&amp;gt;&lt;br /&gt;
   &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
       illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
   &amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix B. Sample Provider = &lt;br /&gt;
&lt;br /&gt;
== DvWidgetOpenhomeOrgBasicLight1.cs ==&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Runtime.InteropServices;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Core;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Utils.Binary;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
 {&lt;br /&gt;
    public interface IDvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
        IDisposable&lt;br /&gt;
    {&lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous value&lt;br /&gt;
        /// &amp;lt;/returns&amp;gt;&lt;br /&gt;
        bool SetPropertyOn(bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;Property's value will be copied&lt;br /&gt;
        /// here&amp;lt;/param&amp;gt;&lt;br /&gt;
        bool PropertyOn();&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt; summary&amp;gt;&lt;br /&gt;
    /// Provider for the openhome.org:BinaryLight:1 UPnP service&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public abstract class DvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
               DvProvider,&lt;br /&gt;
               IDisposable,&lt;br /&gt;
               IDvProviderOpenhomeOrgBinaryLight1&lt;br /&gt;
    {&lt;br /&gt;
        private GCHandle iGch;&lt;br /&gt;
        private PropertyBool iPropertyOn;&lt;br /&gt;
        private PropertyUint iPropertyPrimarySeq;&lt;br /&gt;
        private PropertyUint iPropertySecondarySeq;&lt;br /&gt;
        private ActionDelegate iDelegateSetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetPrimaryProperty;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Constructor&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aDevice&amp;quot;&amp;gt;Device which owns this&lt;br /&gt;
        /// provider&amp;lt;/param&amp;gt;&lt;br /&gt;
        protected DvProviderOpenhomeOrgBinaryLight1(DvDevice aDevice)&lt;br /&gt;
            : base(aDevice, &amp;quot;openhome.org&amp;quot;, &amp;quot;GenericWidget&amp;quot;, 1)&lt;br /&gt;
        {&lt;br /&gt;
            iGch = GCHandle.Alloc(this);&lt;br /&gt;
            List&amp;lt;String&amp;gt; allowedValues = new List&amp;lt;String&amp;gt;();&lt;br /&gt;
            iPropertyOn = new PropertyBool(new ParameterBool(&amp;quot;On&amp;quot;));&lt;br /&gt;
            iPropertyPrimarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;PrimarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertyPrimarySeq);&lt;br /&gt;
            iPropertySecondarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;SecondarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertySecondarySeq);&lt;br /&gt;
            SetPropertyUint(iPropertyPrimarySeq, 0);&lt;br /&gt;
            SetPropertyUint(iPropertySecondarySeq, 0);&lt;br /&gt;
  &lt;br /&gt;
            Zapp.Core.Action action = new Zapp.Core.Action&lt;br /&gt;
                (&amp;quot;SetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;FireAndForget&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddInputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateSetProperty = new ActionDelegate(DoSetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateSetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateGetProperty = new ActionDelegate(DoGetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetPrimaryProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                 (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;integer&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;boolean&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;string&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;binary&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Type&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;readWrite&amp;quot;);allowedValues.Add&lt;br /&gt;
                (&amp;quot;readOnly&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;writeOnly&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString(&amp;quot;Access&amp;quot;,&lt;br /&gt;
                allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            iDelegateGetPrimaryProperty = new&lt;br /&gt;
            ActionDelegate(DoGetPrimaryProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetPrimaryProperty,&lt;br /&gt;
            GCHandle.ToIntPtr(iGch));&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous&lt;br /&gt;
        /// value&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool SetPropertyOn(bool aValue)&lt;br /&gt;
        {&lt;br /&gt;
            if (iPropertyOn.SetValue(aValue))&lt;br /&gt;
            {&lt;br /&gt;
                lock (iPropertyPrimarySeq)&lt;br /&gt;
                {&lt;br /&gt;
                    SetPropertyUint(iPropertyPrimarySeq,&lt;br /&gt;
                        iPropertyPrimarySeq.Value() + 1);&lt;br /&gt;
                } return true;&lt;br /&gt;
            } return false;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;The value of the property&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool PropertyOn()&lt;br /&gt;
        {&lt;br /&gt;
            return iPropertyOn.Value();&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the On property.&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aVersion&amp;quot;&amp;gt;Version of the service being&lt;br /&gt;
        /// requested (will be &amp;lt;= the version advertised)&amp;lt;/param&amp;gt; &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the On property.&lt;br /&gt;
        /// &amp;lt;/param&amp;gt;&lt;br /&gt;
        protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        private static int DoSetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                byte[] valBin = invocation.ReadBinary(&amp;quot;Value&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                switch (name)&lt;br /&gt;
                {&lt;br /&gt;
                    case &amp;quot;On&amp;quot;:&lt;br /&gt;
                        self.SetOn(aVersion, Converter.&lt;br /&gt;
                            BinaryToBoolean(valBin));&lt;br /&gt;
                        break;&lt;br /&gt;
                    default:&lt;br /&gt;
                        throw new ActionError();&lt;br /&gt;
                }&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
                invocation.WriteEnd();&lt;br /&gt;
            }&lt;br /&gt;
            catch (ActionError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
            catch (PropertyUpdateError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
        return 0;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        private static int DoGetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
            switch (name)&lt;br /&gt;
            {&lt;br /&gt;
                case &amp;quot;On&amp;quot;:&lt;br /&gt;
                invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                    Converter.BooleanToBinary(self.iPropertyOn.&lt;br /&gt;
                        Value()));&lt;br /&gt;
                break;&lt;br /&gt;
                default:&lt;br /&gt;
                throw new ActionError();&lt;br /&gt;
            }&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    private static int DoGetPrimaryProperty(IntPtr aPtr,&lt;br /&gt;
                    IntPtr aInvocation,&lt;br /&gt;
                    uint aVersion)&lt;br /&gt;
    {&lt;br /&gt;
        GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
        DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
            (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
        DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
  &lt;br /&gt;
        try&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReadStart();&lt;br /&gt;
            invocation.ReadEnd();&lt;br /&gt;
            invocation.WriteStart();&lt;br /&gt;
            invocation.WriteString(&amp;quot;Name&amp;quot;, &amp;quot;On&amp;quot;);&lt;br /&gt;
            invocation.WriteString(&amp;quot;Type&amp;quot;, &amp;quot;boolean&amp;quot;);&lt;br /&gt;
            invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                Converter.BooleanToBinary(self.iPropertyOn.Value()));&lt;br /&gt;
            invocation.WriteString(&amp;quot;Access&amp;quot;, &amp;quot;readWrite&amp;quot;);&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt;summary&amp;gt;&lt;br /&gt;
    /// Must be called for each class instance. Must be called before&lt;br /&gt;
    /// Core.Library.Close().&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public void Dispose()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
        GC.SuppressFinalize(this);&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
    ~DvProviderOpenhomeOrgBinaryLight1()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
        private void DoDispose()&lt;br /&gt;
        {&lt;br /&gt;
            lock (this)&lt;br /&gt;
            {&lt;br /&gt;
                if (iHandle == IntPtr.Zero)&lt;br /&gt;
            {&lt;br /&gt;
                    return;&lt;br /&gt;
            }&lt;br /&gt;
            DisposeProvider();&lt;br /&gt;
            iPropertyOn.Dispose();&lt;br /&gt;
            iHandle = IntPtr.Zero;&lt;br /&gt;
            }&lt;br /&gt;
            iGch.Free();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix C. Sample Driver = &lt;br /&gt;
&lt;br /&gt;
== BasicLightDriver.cs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.hWidget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
     class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
     {&lt;br /&gt;
         private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
         public BinaryLightProvider(DvDevice aDevice, &lt;br /&gt;
             ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol = aProtocol;&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
     {&lt;br /&gt;
         private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
         {&lt;br /&gt;
             private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
             private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
             private readonly ISimpleUpnpWidget iProtocol; &lt;br /&gt;
 &lt;br /&gt;
             private readonly BinaryLightProvider iProvider;&lt;br /&gt;
             private readonly DvDevice iDvDevice;&lt;br /&gt;
             private IPublishedWidget iPublishedWidget; &lt;br /&gt;
 &lt;br /&gt;
             public DvDevice DvDevice&lt;br /&gt;
             {&lt;br /&gt;
                 get { return iDvDevice; }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             public string WidgetClass&lt;br /&gt;
             {&lt;br /&gt;
                 get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public DiscoveredWidget(&lt;br /&gt;
                 IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                 string aUdn,&lt;br /&gt;
                 ISimpleUpnpWidget aProxy,&lt;br /&gt;
                 IWidgetPublisher aPublisher)&lt;br /&gt;
             {&lt;br /&gt;
                 iDeviceFactory = aDeviceFactory;&lt;br /&gt;
                 iProtocol = aProtocol;&lt;br /&gt;
 &lt;br /&gt;
                 iPublisher = aPublisher;&lt;br /&gt;
                 iDvDevice = iDeviceFactory.CreateDevice(aUdn);  &lt;br /&gt;
                 iProvider = new BinaryLightProvider(iDvDevice, &lt;br /&gt;
                                                     iProtocol);&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             public void HandleInitialEvent()&lt;br /&gt;
             {&lt;br /&gt;
                 iDvDevice.SetEnabled();&lt;br /&gt;
                 iPublisher.TryPublishWidget(iDvDevice.iUdn(), this,&lt;br /&gt;
                     out iPublishedWidget);&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
             {&lt;br /&gt;
                 if (iPublishedWidget != null)&lt;br /&gt;
                 {&lt;br /&gt;
                     iPublishedWidget.Unpublish();&lt;br /&gt;
                 } &lt;br /&gt;
                 iProvider.Dispose();&lt;br /&gt;
                 iDvDevice.Dispose();&lt;br /&gt;
             }  &lt;br /&gt;
 &lt;br /&gt;
             public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
             {&lt;br /&gt;
                 if (aIndex == 0)&lt;br /&gt;
                 {&lt;br /&gt;
                     iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         private readonly string iName;&lt;br /&gt;
         private readonly IDvDeviceFactory aDeviceFactory;&lt;br /&gt;
         private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
         &lt;br /&gt;
         public BinaryLightDriver(&lt;br /&gt;
             string aName,&lt;br /&gt;
             IWidgetPublisher aPublisher,&lt;br /&gt;
             iDeviceFactory aDeviceFactory)&lt;br /&gt;
         {&lt;br /&gt;
             iWidgetPublisher = aPublisher;&lt;br /&gt;
             iName = aName;&lt;br /&gt;
             iDeviceFactory = aDeviceFactory;&lt;br /&gt;
         } &lt;br /&gt;
 &lt;br /&gt;
         public IEnumerable&amp;amp;lt;uint&amp;amp;gt; WidgetClasses&lt;br /&gt;
         {&lt;br /&gt;
             get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         public void WidgetDiscovered(&lt;br /&gt;
             string aWidgetUdn,&lt;br /&gt;
             uint aWidgetClass,&lt;br /&gt;
             ISimpleUpnpWidget aSimpleUpnpWidget)&lt;br /&gt;
         {&lt;br /&gt;
             string newUdn = aWidgetUdn;&lt;br /&gt;
             DiscoveredWidget discoveredWidget = new DiscoveredWidget&lt;br /&gt;
                 (iDeviceFactory,&lt;br /&gt;
                  newUdn,&lt;br /&gt;
                  aSimpleUpnpWidget,&lt;br /&gt;
                  iWidgetPublisher);&lt;br /&gt;
 &lt;br /&gt;
             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                 discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                 discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                 discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary = &lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in OpenHome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by OpenHome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh - A collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs on ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The OpenHome Operating System. Core software for OpenHome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. &lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. A typical Widget supports only one protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Driver_Development</id>
		<title>OhWidget Driver Development</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Driver_Development"/>
				<updated>2012-03-01T15:16:39Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Widget Service XML */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for developers using the OpenHome SDK to integrate a Widget into an OpenHome system. Each Widget must have its own driver to allow it to communicate with the OpenHome Nodes. &lt;br /&gt;
&lt;br /&gt;
To help you write your driver, this document provides high level descriptions of the core responsibilities of a Widget driver and gives a detailed walk-through using example code.&lt;br /&gt;
&lt;br /&gt;
Full versions of each file used in the development of the example driver are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin development of your Widget driver you must be in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* your Widget Service XML that describes the properties on your Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document does not contain advice on how to write Widget Service XML. Refer to the OpenHome Widget Service XML definition document for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK&lt;br /&gt;
* your chosen communication protocol's API&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The protocol you choose for your Widgets must be the same protocol used on your choice of Node.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document focuses on the development of the Widget driver. Details about the communications protocol used are beyond the scope of this document. This document assumes you are familiar with your chosen protocol's code libraries and are able to use them in the driver code you write.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Related Documents ==&lt;br /&gt;
&lt;br /&gt;
The following related OpenHome documentation may be of interest to you:&lt;br /&gt;
&lt;br /&gt;
* [[ohWidget Technical Overview|ohWidget Technical Overview]]&lt;br /&gt;
* [[OpenHome Widget Service XML definition|OpenHome Widget Service XML definition]]&lt;br /&gt;
* [http://www.openhome.org/releases/ohNet_DeviceStack.pdf  OpenHome ohNet Device Stack]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
None of the related documents listed above is mandatory reading for Widget driver development.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
== Widget Service XML ==&lt;br /&gt;
OpenHome Widget driver writing relies heavily on the use of code generated from a single source — the Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
The service and actions your Widget provides are represented in code in a file called a Provider. The Provider is automatically generated from the Widget Service XML and produces an abstract class for you to inherit when you write your concrete class driver.&lt;br /&gt;
&lt;br /&gt;
To aid in the explanation of how the Provider is created and put to use we will follow the development of&lt;br /&gt;
a driver for a simple light Widget; taking the defined Widget Service XML and stepping through how it is used to generate the other files. Examples of code are used throughout this document to show you how each one is created and used in an OpenHome system. &lt;br /&gt;
&lt;br /&gt;
It is essential that you start with a well-formed Widget Service XML, conforming to the schema defined&lt;br /&gt;
in the WidgetService.xsd. The following diagram shows the significance of the Widget Service XML in&lt;br /&gt;
relation to the generated files you will use when writing your driver:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarchy, highlighting the areas specifically used in driver development]]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* The grayed-out files are not relevant to Widget driver development but can also be generated from the Widget Service XML.&lt;br /&gt;
* The Provider is generated in C#, meaning your driver must be written in C# as well. The use of managed code is mandatory for driver writing in the OpenHome framework.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Code sample used in this document ==&lt;br /&gt;
&lt;br /&gt;
Our examples in this document use a Widget Service XML definition for a light Widget called&lt;br /&gt;
BasicLight.xml.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Full versions of all the example files used in this document are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We will see how the Provider is generated from this XML and how it is used to aid the driver writing process. The examples also show how your chosen communication protocol should be used in the body of the driver code.&lt;br /&gt;
&lt;br /&gt;
Implementation details of specific protocols you choose to use are beyond the scope of this document. However, the samples used in this document show the use of the SimpleUPnP protocol to aid you in your development process.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol during the early stages of the OpenHome project. It is included in the OpenHome SDK and can be used as a public resource. &lt;br /&gt;
&lt;br /&gt;
The use of SimpleUPnP in the example files and the code snippets within the following sections is highlighted by the [[File:Warning.png]] icon. The lines of code marked by [[File:Warning.png]] must be changed to code from your chosen communication protocol's library. SimpleUPnP is left in to help you understand how a protocol is used in a working example.&lt;br /&gt;
&lt;br /&gt;
The sample code provided attempts to show best-practice coding standards. There are several sections of code that have a mandatory layout or that call specifically named methods and functions. These areas of the code are highlighted where required. &lt;br /&gt;
&lt;br /&gt;
Where the examples do not explicitly state that the code shown is mandatory, you are free to implement it in a different way according to your own coding style and practices.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Driver responsibilities = &lt;br /&gt;
&lt;br /&gt;
== Driver responsibilities ==&lt;br /&gt;
&lt;br /&gt;
An OpenHome Widget driver has several responsibilities which must be met before it can be used on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
These responsibilities are listed R1 to R7 and are defined here, explaining what each one must do. &lt;br /&gt;
&lt;br /&gt;
=== R1 Specifying the type of Widget the driver controls ===&lt;br /&gt;
A driver must know which type of Widget it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
=== R2 Reacting to a discovered Widget on the network ===&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== R3 Setting the initial values for the Widget's properties ===&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
=== R4 Publishing discovered Widgets in the Local Widget Registry on the Node ===&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object.&lt;br /&gt;
&lt;br /&gt;
=== R5 Reacting to an event reported from the Widget ===&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
=== R6 Reacting to actions sent to the Widget ===&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== R7 Reacting to a Widget's departure ===&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no&lt;br /&gt;
longer available.&lt;br /&gt;
&lt;br /&gt;
The sections of example code that follow show you how to write a driver from beginning to end. The accompanying text explaining the example code highlights when a responsibility, or part of a responsibility, has been met.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Driver Architecture = &lt;br /&gt;
&lt;br /&gt;
== Driver Architecture ==&lt;br /&gt;
&lt;br /&gt;
Drivers are installed on the Node and used when the Node needs to communicate with the Widget. Drivers&lt;br /&gt;
use several objects to communicate with Widgets over the Widget's lifetime. Figure 2 shows the objects&lt;br /&gt;
used by the driver and how the responsibilities listed above relate to each one:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture.png|800px|thumb|center|Figure 2: The architecture of a driver, showing the driver's relationship to the objects used to communicate with a Widget. Lines between objects show message flow.]]&lt;br /&gt;
&lt;br /&gt;
The objects contained in the dotted boundary must appear in the code you write to define your driver. The Driver, Provider and IWidgetRegistryEntry objects are all contained in the same driver file. We begin discussing this on page 12. &lt;br /&gt;
&lt;br /&gt;
The other objects are provided by the OpenHome SDK or as installed components on the Node.&lt;br /&gt;
&lt;br /&gt;
The Discovery Module informs the driver of the presence of an available Widget.&lt;br /&gt;
&lt;br /&gt;
Each Node has a Protocol Module which contains the protocol's API. Widgets can communicate with OpenHome Nodes using any one of the set of communications protocols the Node supports. The driver uses your chosen protocol's Protocol Module to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
Both the Protocol Module and the Discovery Module are installed on the Node. When you write your&lt;br /&gt;
driver you will use your Protocol Module to allow the driver to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
IWidgetPublisher, IPublishedWidget and DvDevice are objects provided in the OpenHome&lt;br /&gt;
API. You can read about them in the APIs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Generating the Provider = &lt;br /&gt;
&lt;br /&gt;
== Generating the Provider ==&lt;br /&gt;
&lt;br /&gt;
You must generate your provider before you can begin writing your Widget driver. You use your provider as a guide to implement the functions your Widget needs to set the values of its properties.&lt;br /&gt;
&lt;br /&gt;
The current provider generation process is a manual one involving the use of a text transform tool.&lt;br /&gt;
&lt;br /&gt;
Speak to your OpenHome contact who will help you generate your provider.&lt;br /&gt;
&lt;br /&gt;
Future releases of the OpenHome SDK will include a tool to help you generate the provider.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
You must be in possession of:&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK, unpacked on your computer&lt;br /&gt;
* your Widget Service XML file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Writing a SimpleUPnP driver = &lt;br /&gt;
&lt;br /&gt;
== Introduction to the SimpleUPnP protocol ==&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol used to control emulated Widgets over a custom UPnP service.&lt;br /&gt;
&lt;br /&gt;
This chapter shows how a driver is written using the SimpleUPnP communications protocol. The aim is to show the code using as generic a protocol as possible so that you can see where your own protocol specific code needs to go.&lt;br /&gt;
&lt;br /&gt;
The use of code specific to the SimpleUPnP implementation is highlighted by the use of the [[File:Warning.png]] icon. The lines of code are marked by this icon to make it easier for you to see where the protocol-specific code must go and what parts of the code are generic.&lt;br /&gt;
&lt;br /&gt;
=== Register model ===&lt;br /&gt;
&lt;br /&gt;
SimpleUPnP is modeled on 8 physical registers available on the Widget. Each register is 32-bits wide. They are indexed from 0 to 7 and the last register (register 7) is reserved for storing the Widget's class.&lt;br /&gt;
&lt;br /&gt;
This detail is used by the Protocol Module on the Node to determine which driver is needed to run the new Widget when it has been discovered.&lt;br /&gt;
&lt;br /&gt;
The remaining 7 registers (registers 0 to 6) are free for Widget engineers to assign to the Widget's functions.&lt;br /&gt;
&lt;br /&gt;
Registers 0, 1, 2 and 3 are available as read/write registers. Registers 4, 5 and 6 are readonly registers.&lt;br /&gt;
&lt;br /&gt;
Only the emulated hardware (running on the Node) can change the values held in registers 4, 5 and 6.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Register use in drivers ===&lt;br /&gt;
&lt;br /&gt;
In the example that follows we have a Basic Light Widget with a very simple function: it can be turned on and turned off. The on/off value is stored in register 0, with values 0=OFF and 1=ON. Register 0 is a read/write register. This means we can change the value stored there using messages passed to the Widget from the Node, and by reacting to physical interactions at the Widget (such as someone manually switching the light on or off). &lt;br /&gt;
&lt;br /&gt;
The mapping of registers to properties on the Widget is decided by the engineers who manufacture the device. You must be provided with the mapping before you begin developing your driver.&lt;br /&gt;
&lt;br /&gt;
== Starting the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-BoxHighlight.png|800px|thumb|center|Figure 3 The driver architecture highlighting the Widget driver and its component parts.]]&lt;br /&gt;
&lt;br /&gt;
When you have generated the abstract provider you can put it to use in the Widget driver. A Widget driver&lt;br /&gt;
has three distinct components:&lt;br /&gt;
&lt;br /&gt;
* an implementation of your abstract provider&lt;br /&gt;
* a definition of the Widget driver&lt;br /&gt;
* an implementation of the IWidgetRegistryEntry interface&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must manually write the code for your Widget driver. The differences in implementation of Widget properties and communication protocols means that the driver code cannot be autogenerated.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This section takes you through how to write a Widget driver by implementing the auto-generated provider,&lt;br /&gt;
starting from a new blank file and finishing with a working driver for the Basic Light Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
No assumptions have been made about the type of editor you use to write your code. Shortcuts&lt;br /&gt;
or macros that you use as standard will not appear in the instructions below. A full example&lt;br /&gt;
BinaryLightDriver.cs is available to review in Appendix C.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a new C# file in your IDE. Ensure the following libraries are used:&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 [[File:Warning.png]]using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 namespace OpenHome.Widget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must use the libraries listed above for this specific example.&lt;br /&gt;
&lt;br /&gt;
In general, drivers require the following libraries:&lt;br /&gt;
* System*&lt;br /&gt;
* System.Collections.Generic*&lt;br /&gt;
* OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
&lt;br /&gt;
Your driver will fail to compile if you miss any of these listed libraries. Libraries marked * are typically added by default by most modern IDEs. &lt;br /&gt;
&lt;br /&gt;
The OpenHome.Widget.Protocols.SimpleUpnp library is required only in this SimpleUPnP example. Drivers using a different protocol will use their own protocol library.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Implementing the provider ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-ProviderHighlight.png|800px|thumb|center|Figure 4 The driver architecture highlighting the Provider's place]]&lt;br /&gt;
&lt;br /&gt;
You use your auto-generated abstract provider by writing an implementation of it in the driver file. Responsibilities met by implementing your auto-generated provider are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R6 Reacting to actions sent to the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
Begin by creating a new class. It will subclass the abstract auto-generated provider:&lt;br /&gt;
&lt;br /&gt;
 class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
The Protocol Module will provide an API for the Provider to use to communicate with the Widget. In&lt;br /&gt;
SimpleUPnP we are provided with an interface called ISimpleUpnpWidget. The provider is supplied&lt;br /&gt;
with the required instance of the interface by the Discovery Module on the Node.&lt;br /&gt;
&lt;br /&gt;
The mechanisms for registering providers with specific Protocol Modules, and for the way the module gives each provider its required interface are covered later when writing the discovery method.&lt;br /&gt;
&lt;br /&gt;
For now, we need to give the Provider a place to store the interface that it will later use to communicate&lt;br /&gt;
with the Widget:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]] private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
&lt;br /&gt;
The interface from the Protocol Module is passed in as a parameter in the Provider's constructor and then&lt;br /&gt;
assigned to the variable we just created:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightProvider(DvDevice aDevice,&lt;br /&gt;
 [[File:Warning.png]]         ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
 {&lt;br /&gt;
       iProtocol = aProtocol;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
To satisfy R3 we would normally set the Widget's properties here, giving them an initial value.&lt;br /&gt;
However, in this specific example we cannot set the value of Basic Light's only property because&lt;br /&gt;
we will never know, in advance, what the state of the light will be (either on or off) when we&lt;br /&gt;
create the DiscoveredWidget.&lt;br /&gt;
&lt;br /&gt;
When you cannot set the properties ahead of time, and you are using an eventing protocol like SimpleUPnP, you can instead set them in the HandleRegisterEvent method in the driver class. This also satisfies the requirements for R3. You must set the Widget's properties before you enable it using SetEnabled(). &lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The abstract provider includes an abstract method called SetOn. This method is invoked by the Node when passing a message to the Widget, specifically to set the on property of the Widget to either 0 or 1. The implementation of this method will meet the requirements for R6.&lt;br /&gt;
&lt;br /&gt;
We must override this method and provide the protocol module a way of passing a message on to the Widget to perform the required action, in this case turn the light on or off:&lt;br /&gt;
&lt;br /&gt;
          protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
          {&lt;br /&gt;
     [[File:Warning.png]]        iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
In this example the Basic Light's SetOn property (the boolean property that controls whether the light is&lt;br /&gt;
on or off) is represented in the physical Widget by the register that has an index of 0.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* This method is an example of an action on a Widget. Actions are messages sent from the Node to the Widget. We will see later how to handle events that need to be passed back from the Widget&lt;br /&gt;
to the Node.&lt;br /&gt;
* Your own Widget will likely provide more than a single property. Your auto-generated provider will contain one abstract method to represent each writable property. Read-only properties are not provided an abstract method.&lt;br /&gt;
&lt;br /&gt;
You must implement each abstract method in your driver to ensure the relevant property on&lt;br /&gt;
the Widget can be set.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We have now finished implementing the provider. The next step is to implement the driver.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Implementing the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-DriverHighlight.png|800px|thumb|center|Figure 4: The driver architecture highlighting the implemented driver's place.]]&lt;br /&gt;
&lt;br /&gt;
The code for your Widget driver must provide an implementation of the IWidgetRegistryInterface,&lt;br /&gt;
including the following tasks:&lt;br /&gt;
&lt;br /&gt;
* methods to expose identifying details about the Widget for the Node to access&lt;br /&gt;
* providing methods to handle events reported by the Widget&lt;br /&gt;
&lt;br /&gt;
The driver is implemented as a public class within the same file as the provider code. Each driver must use the interface for the protocol you are using. For the SimpleUPnP protocol the interface is ISimple-UpnpWidgetDriver.&lt;br /&gt;
&lt;br /&gt;
=== Writing code ===&lt;br /&gt;
&lt;br /&gt;
Create your new driver class and subclass the ISimpleUpnpWidgetDriver interface:&lt;br /&gt;
&lt;br /&gt;
 public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Implementing IWidgetRegistryEntry ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry is the interface you use to represent physical Widgets. It is implemented as a subclass of your driver class. We are going to implement this interface in a class called '''DiscoveredWidget'''.&lt;br /&gt;
&lt;br /&gt;
Let's return to our driver architecture diagram for a moment:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-IRegistryEntryHighlight.png|800px|thumb|center|Figure 5 The driver architecture highlighting the IWidgetRegistryEntry object you will now implement]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry uses several other objects to help create it and respond to messages sent to and from it. These objects will be created in our implementation of DiscoveredWidget. &lt;br /&gt;
&lt;br /&gt;
When successfully created and published, the DiscoveredWidget objects are stored in a list on the Node called the Local Widget Registry. The Local Widget Registry is used by Nodes to maintain contact with the Widgets they control.&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry is shown at the top of Figure 5, marked plainly as (Registry). The path to the Local Widget Registry goes through several layers of Node architecture which are not relevant to Widget driver writing, so are not shown in the diagrams.&lt;br /&gt;
&lt;br /&gt;
==== Writing code ====&lt;br /&gt;
&lt;br /&gt;
Start by subclassing the IWidgetRegistryEntry interface in your new class:&lt;br /&gt;
&lt;br /&gt;
      private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
      {&lt;br /&gt;
&lt;br /&gt;
A DiscoveredWidget must provide the driver with the objects required to present the Widget and its&lt;br /&gt;
properties to the Node:&lt;br /&gt;
&lt;br /&gt;
           private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
           private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
           private readonly ISimpleUpnpWidget iProtocol;&lt;br /&gt;
           private readonly BinaryLightProvider iProvider;&lt;br /&gt;
           private readonly DvDevice iDvDevice;&lt;br /&gt;
           private IPublishedWidget iPublishedWidget;&lt;br /&gt;
&lt;br /&gt;
Each of the attributes in the example above are defined as follows:&lt;br /&gt;
&lt;br /&gt;
iDeviceFactory — used by the driver to create a single instance of DvDevice to represent a single Widget&lt;br /&gt;
&lt;br /&gt;
iPublisher — used by the driver to publish the Widget to the Node&lt;br /&gt;
&lt;br /&gt;
iProtocol — the object used by the Widget to communicate with the Protocol Module on the Node&lt;br /&gt;
&lt;br /&gt;
iProvider — an instantiated provider of the type you defined earlier&lt;br /&gt;
&lt;br /&gt;
iDvDevice — a representation of a Widget to which the provider is attached, created using iDevice-Factory above&lt;br /&gt;
&lt;br /&gt;
iPublishedWidget — used to contain the returned object from a successful publishing of the Widget&lt;br /&gt;
If we look again at the driver architecture diagram, we ca highlight the objects we've just defined:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-Highlight.png|800px|thumb|center|Figure 6: The driver architecture highlighting the objects used by the IWidgetRegistryEntry implementation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The DeviceFactory, defined above in the member variable iDeviceFactory, is used to create new DvDevice objects. The DeviceFactory is only ever used to do this once. It is not shown in the driver architecture diagrams due to its minimal role in the operation of a driver, but it would normally appear between the IWidgetRegistryEntry and DvDevice objects.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
A driver requires methods to expose identifying details about the Widget. We must provide access to two of the attributes we just defined above:&lt;br /&gt;
&lt;br /&gt;
 public DvDevice DvDevice&lt;br /&gt;
 {&lt;br /&gt;
     get { return iDvDevice; }&lt;br /&gt;
 }&lt;br /&gt;
 public string WidgetClass&lt;br /&gt;
 {&lt;br /&gt;
     get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The WidgetClass string is formed using a combination of the vendor name and the Widget's name in the&lt;br /&gt;
format:&lt;br /&gt;
&lt;br /&gt;
 [vendor_domain]:[widget_name]&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry can now query both the DvDevice object representing the Widget, and the specific class of Widget this driver represents. The other member variables we defined do not need their own accessor methods.&lt;br /&gt;
&lt;br /&gt;
Now we must write a constructor for DiscoveredWidget and assign the parameters accordingly: &lt;br /&gt;
&lt;br /&gt;
 public DiscoveredWidget(IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                            string aUdn,&lt;br /&gt;
                            ISimpleUpnpWidget aProxy,&lt;br /&gt;
                            IWidgetPublisher aPublisher)&lt;br /&gt;
 {&lt;br /&gt;
      iDeviceFactory = aDeviceFactory;&lt;br /&gt;
      iProtocol = aProtocol;&lt;br /&gt;
      iPublisher = aPublisher;&lt;br /&gt;
      iDvDevice = iDeviceFactory.CreateDevice(aUdn);&lt;br /&gt;
      iProvider = new BinaryLightProvider(iDvDevice,&lt;br /&gt;
      iProtocol);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Event handling ===&lt;br /&gt;
&lt;br /&gt;
A Widget's state can change in one of three significant ways:&lt;br /&gt;
&lt;br /&gt;
* when the Widget needs to be published on the Node&lt;br /&gt;
* when the Widget disappears from the network (by losing power or similar)&lt;br /&gt;
* when a property's state changes and must be updated to a new value&lt;br /&gt;
&lt;br /&gt;
We now need methods to handle these changes.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The methods we define here will be used as callbacks, rather than invoked as method calls. We define the methods here first and then use them later on. We will use the Protocol Module to listen for changes in the Widget's state and register these methods as callbacks there. See Writing the SimpleUPnP Widget discovery method for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this section of the driver are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R4 Publishing discovered Widgets in the Local Widget Registry on the Node'''&lt;br /&gt;
&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object. &lt;br /&gt;
&lt;br /&gt;
'''R5 Reacting to an event reported from the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
'''R7 Reacting to a Widget's departure'''&lt;br /&gt;
&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no longer available.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Enabling and publishing a discovered Widget ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first method initializes the Widget by enabling the device and then using the IWidgetPublisher&lt;br /&gt;
to make it available on the Node:&lt;br /&gt;
&lt;br /&gt;
 public void HandleInitialEvent()&lt;br /&gt;
 {&lt;br /&gt;
      iDvDevice.SetEnabled();&lt;br /&gt;
      iPublisher.TryPublishWidget(iDvDevice.iUdn(),&lt;br /&gt;
                              this,&lt;br /&gt;
                              out iPublishedWidget);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This method meets the requirements for R4.&lt;br /&gt;
&lt;br /&gt;
The call to TryPublishWidget returns an iPublishedWidget object. We use this object later to satisfy the requirements of R7.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The ordering of the calls to SetEnabled and TryPublishWidget is vitally important. You&lt;br /&gt;
must enable the device before you attempt to publish it. Your Widget will not be available to the&lt;br /&gt;
Nodes unless SetEnabled is called first. Nodes will not be able to access a published device&lt;br /&gt;
that has not been enabled.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
R3 requires that you set the Widget's properties before you enable and publish the device. We&lt;br /&gt;
discussed on page 14 how some properties can only be set after the Widget reports what their&lt;br /&gt;
state is. We do this in HandleRegisterEvent.&lt;br /&gt;
&lt;br /&gt;
We rely on the SimpleUPnP Protocol Module guaranteeing a call to HandleRegisterEvent first before HandleInitialEvent. This is informed by guarantees made by the Control Point stack that the calls will be made in that order.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
==== Removing a Widget ====&lt;br /&gt;
&lt;br /&gt;
Removing a Widget involves unpublishing it from the Node. The IPublishedWidget interface provides us with a method we can call to manage that for us:&lt;br /&gt;
&lt;br /&gt;
 public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
 {&lt;br /&gt;
     if (iPublishedWidget != null)&lt;br /&gt;
     { iPublishedWidget.Unpublish(); }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assuming that the Widget was successfully published earlier, it is removed from the Node's Local Widget Registry.&lt;br /&gt;
&lt;br /&gt;
We must also properly handle the resources we used to create and maintain the Widget object while it was published:&lt;br /&gt;
&lt;br /&gt;
      iProvider.Dispose();&lt;br /&gt;
      iDvDevice.Dispose();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The calls to Dispose are made regardless of the Widget's published state, ensuring that any created device and associated provider are properly disposed. This implementation satisfies R7.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Event handling ====&lt;br /&gt;
&lt;br /&gt;
We need a method to handle changes to the state of the Widget's properties.&lt;br /&gt;
&lt;br /&gt;
If the property changes at the Widget, it needs to pass the new state back to the Node so that it is kept up-to-date on the Widget's status. This is called an event. An example in the case of our Basic Light is someone manually switching the light from on to off. This is in contrast to actions, which are passed from the Node to the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Other examples of events involve no human interaction, such as a thermometer Widget updating its current temperature based on environmental changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Our Basic Light Widget has only one property that needs to be handled:&lt;br /&gt;
&lt;br /&gt;
 public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
 {&lt;br /&gt;
     if (aIndex == 0)&lt;br /&gt;
     {&lt;br /&gt;
         iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We use our instance of the provider to update the register on the Widget that is mapped to the On property. This in turn updates the Node with the new state of the Widget.&lt;br /&gt;
&lt;br /&gt;
This method provides implementations to satisfy two driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
* R3 is now completely satisfied, as we can now set the values of all the previously unknown properties here.&lt;br /&gt;
* R5 is also satisfied as this method allows us to update the Widget's status on the Node when a property is changed on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Not all protocols pass messages back to the Node in this manner. The way we have satisfied R3 and R5 here only applies to protocols and Widgets that support this behavior.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Widgets that do not use an eventing protocol need to have their properties set in the provider's constructor to satisfy R3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To satisfy R5, the over-ridden method SetOn in the provider must include the call to SetPropertyOn. Non-eventing protocols do not require a HandleRegisterEvent method.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Constructor ===&lt;br /&gt;
&lt;br /&gt;
The final requirement for the driver is the constructor so that new DiscoveredWidget objects can be created. &lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this area of code are:&lt;br /&gt;
&lt;br /&gt;
'''R1 Specifying the type of Widget the driver controls'''&lt;br /&gt;
&lt;br /&gt;
A driver must know which type of Widget that it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Writing the code ====&lt;br /&gt;
&lt;br /&gt;
We begin by defining the variables we will use to store the objects used by the driver:&lt;br /&gt;
&lt;br /&gt;
 private readonly string iName;&lt;br /&gt;
 private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
 private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now write the constructor for the driver and assign the passed in parameters appropriately:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightDriver(string aName,&lt;br /&gt;
                IWidgetPublisher aPublisher,&lt;br /&gt;
                IDvDeviceFactory aDeviceFactory)&lt;br /&gt;
 {&lt;br /&gt;
     iWidgetPublisher = aPublisher;&lt;br /&gt;
     iName = aName;&lt;br /&gt;
     iDeviceFactory = aDeviceFactory;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally we need to provide the driver a way to publish the class of Widget it controls. This information is requested by the Discovery Module and is used to ensure the Node uses the correct driver when a new Widget appears.&lt;br /&gt;
&lt;br /&gt;
The implementation for this details will be different for each protocol. The SimpleUPnP protocol library provides a file that contains the SimpleUPnP definitions as integers. Each integer represents a particular class of identified Widget.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP implementation of that method is as follows:&lt;br /&gt;
&lt;br /&gt;
 public IEnumerable&amp;lt;uint&amp;gt; WidgetClasses&lt;br /&gt;
 {&lt;br /&gt;
 [[File:Warning.png]]        get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The body of this method is specifically written for the Widget class we are defining (in this case a binary light). This method completes the driver's requirements for R1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Writing the SimpleUPnP Widget discovery method ==&lt;br /&gt;
&lt;br /&gt;
Every driver must contain a method which creates new objects to represent newly discovered Widgets.&lt;br /&gt;
The Discovery Module invokes this method to begin the process of creating the objects required to allow the Node to access the Widget. &lt;br /&gt;
&lt;br /&gt;
The name of this method is dictated by your chosen protocol's API. The SimpleUPnP protocol requires a method called WidgetDiscovered.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The method's name will not always be the same for each protocol. Your protocol's documentation will contain the details of what this method must be called.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This method and its implementation will meet the following driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
'''R2 Reacting to a discovered Widget on the network'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
Our implementation of the WidgetDiscovered method will create a new DiscoveredWidget object and use the Protocol Module to listen for changes to the Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
The method uses the Protocol Module and two ways to identify the Widget. We must pass these in as&lt;br /&gt;
parameters:&lt;br /&gt;
&lt;br /&gt;
 public void WidgetDiscovered(string aWidgetUdn,&lt;br /&gt;
                              uint aWidgetClass,&lt;br /&gt;
                              ISimpleUpnpWidget&lt;br /&gt;
                                  aSimpleUpnpWidget)&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
Every Widget that uses this driver must be uniquely identifiable:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]    string newUdn = aWidgetUdn;&lt;br /&gt;
&lt;br /&gt;
Each new Widget is represented by a DiscoveredWidget object. Create the new DiscoveredWidget and pass in the required parameters we created earlier:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
     DiscoveredWidget discoveredWidget =&lt;br /&gt;
                 new DiscoveredWidget(iDeviceFactory,&lt;br /&gt;
                                      newUdn,&lt;br /&gt;
  &lt;br /&gt;
 [[File:Warning.png]]                                    aSimpleUpnpWidget,&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Registering the callbacks ===&lt;br /&gt;
&lt;br /&gt;
Finally, we ask the Widget's protocol interface to listen for calls to the handler methods we defined earlier in DiscoveredWidget. We do this by registering those methods as callbacks for the Protocol Module&lt;br /&gt;
to listen for:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                        discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                        discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                        discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You have now met 100% of the driver responsibility requirements and have a working driver to use with your SimpleUPnP Widget.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix A. Sample XML =&lt;br /&gt;
&lt;br /&gt;
== Binary Light.xml ==&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
  &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
  &amp;lt;version&amp;gt;&lt;br /&gt;
   &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
   &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/version&amp;gt;&lt;br /&gt;
  &amp;lt;propertylist&amp;gt;&lt;br /&gt;
   &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
       illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
   &amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix B. Sample Provider = &lt;br /&gt;
&lt;br /&gt;
== DvWidgetOpenhomeOrgBasicLight1.cs ==&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Runtime.InteropServices;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Core;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Utils.Binary;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
 {&lt;br /&gt;
    public interface IDvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
        IDisposable&lt;br /&gt;
    {&lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous value&lt;br /&gt;
        /// &amp;lt;/returns&amp;gt;&lt;br /&gt;
        bool SetPropertyOn(bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;Property's value will be copied&lt;br /&gt;
        /// here&amp;lt;/param&amp;gt;&lt;br /&gt;
        bool PropertyOn();&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt; summary&amp;gt;&lt;br /&gt;
    /// Provider for the openhome.org:BinaryLight:1 UPnP service&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public abstract class DvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
               DvProvider,&lt;br /&gt;
               IDisposable,&lt;br /&gt;
               IDvProviderOpenhomeOrgBinaryLight1&lt;br /&gt;
    {&lt;br /&gt;
        private GCHandle iGch;&lt;br /&gt;
        private PropertyBool iPropertyOn;&lt;br /&gt;
        private PropertyUint iPropertyPrimarySeq;&lt;br /&gt;
        private PropertyUint iPropertySecondarySeq;&lt;br /&gt;
        private ActionDelegate iDelegateSetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetPrimaryProperty;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Constructor&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aDevice&amp;quot;&amp;gt;Device which owns this&lt;br /&gt;
        /// provider&amp;lt;/param&amp;gt;&lt;br /&gt;
        protected DvProviderOpenhomeOrgBinaryLight1(DvDevice aDevice)&lt;br /&gt;
            : base(aDevice, &amp;quot;openhome.org&amp;quot;, &amp;quot;GenericWidget&amp;quot;, 1)&lt;br /&gt;
        {&lt;br /&gt;
            iGch = GCHandle.Alloc(this);&lt;br /&gt;
            List&amp;lt;String&amp;gt; allowedValues = new List&amp;lt;String&amp;gt;();&lt;br /&gt;
            iPropertyOn = new PropertyBool(new ParameterBool(&amp;quot;On&amp;quot;));&lt;br /&gt;
            iPropertyPrimarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;PrimarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertyPrimarySeq);&lt;br /&gt;
            iPropertySecondarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;SecondarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertySecondarySeq);&lt;br /&gt;
            SetPropertyUint(iPropertyPrimarySeq, 0);&lt;br /&gt;
            SetPropertyUint(iPropertySecondarySeq, 0);&lt;br /&gt;
  &lt;br /&gt;
            Zapp.Core.Action action = new Zapp.Core.Action&lt;br /&gt;
                (&amp;quot;SetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;FireAndForget&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddInputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateSetProperty = new ActionDelegate(DoSetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateSetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateGetProperty = new ActionDelegate(DoGetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetPrimaryProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                 (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;integer&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;boolean&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;string&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;binary&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Type&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;readWrite&amp;quot;);allowedValues.Add&lt;br /&gt;
                (&amp;quot;readOnly&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;writeOnly&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString(&amp;quot;Access&amp;quot;,&lt;br /&gt;
                allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            iDelegateGetPrimaryProperty = new&lt;br /&gt;
            ActionDelegate(DoGetPrimaryProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetPrimaryProperty,&lt;br /&gt;
            GCHandle.ToIntPtr(iGch));&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous&lt;br /&gt;
        /// value&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool SetPropertyOn(bool aValue)&lt;br /&gt;
        {&lt;br /&gt;
            if (iPropertyOn.SetValue(aValue))&lt;br /&gt;
            {&lt;br /&gt;
                lock (iPropertyPrimarySeq)&lt;br /&gt;
                {&lt;br /&gt;
                    SetPropertyUint(iPropertyPrimarySeq,&lt;br /&gt;
                        iPropertyPrimarySeq.Value() + 1);&lt;br /&gt;
                } return true;&lt;br /&gt;
            } return false;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;The value of the property&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool PropertyOn()&lt;br /&gt;
        {&lt;br /&gt;
            return iPropertyOn.Value();&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the On property.&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aVersion&amp;quot;&amp;gt;Version of the service being&lt;br /&gt;
        /// requested (will be &amp;lt;= the version advertised)&amp;lt;/param&amp;gt; &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the On property.&lt;br /&gt;
        /// &amp;lt;/param&amp;gt;&lt;br /&gt;
        protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        private static int DoSetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                byte[] valBin = invocation.ReadBinary(&amp;quot;Value&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                switch (name)&lt;br /&gt;
                {&lt;br /&gt;
                    case &amp;quot;On&amp;quot;:&lt;br /&gt;
                        self.SetOn(aVersion, Converter.&lt;br /&gt;
                            BinaryToBoolean(valBin));&lt;br /&gt;
                        break;&lt;br /&gt;
                    default:&lt;br /&gt;
                        throw new ActionError();&lt;br /&gt;
                }&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
                invocation.WriteEnd();&lt;br /&gt;
            }&lt;br /&gt;
            catch (ActionError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
            catch (PropertyUpdateError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
        return 0;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        private static int DoGetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
            switch (name)&lt;br /&gt;
            {&lt;br /&gt;
                case &amp;quot;On&amp;quot;:&lt;br /&gt;
                invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                    Converter.BooleanToBinary(self.iPropertyOn.&lt;br /&gt;
                        Value()));&lt;br /&gt;
                break;&lt;br /&gt;
                default:&lt;br /&gt;
                throw new ActionError();&lt;br /&gt;
            }&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    private static int DoGetPrimaryProperty(IntPtr aPtr,&lt;br /&gt;
                    IntPtr aInvocation,&lt;br /&gt;
                    uint aVersion)&lt;br /&gt;
    {&lt;br /&gt;
        GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
        DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
            (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
        DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
  &lt;br /&gt;
        try&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReadStart();&lt;br /&gt;
            invocation.ReadEnd();&lt;br /&gt;
            invocation.WriteStart();&lt;br /&gt;
            invocation.WriteString(&amp;quot;Name&amp;quot;, &amp;quot;On&amp;quot;);&lt;br /&gt;
            invocation.WriteString(&amp;quot;Type&amp;quot;, &amp;quot;boolean&amp;quot;);&lt;br /&gt;
            invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                Converter.BooleanToBinary(self.iPropertyOn.Value()));&lt;br /&gt;
            invocation.WriteString(&amp;quot;Access&amp;quot;, &amp;quot;readWrite&amp;quot;);&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt;summary&amp;gt;&lt;br /&gt;
    /// Must be called for each class instance. Must be called before&lt;br /&gt;
    /// Core.Library.Close().&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public void Dispose()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
        GC.SuppressFinalize(this);&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
    ~DvProviderOpenhomeOrgBinaryLight1()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
        private void DoDispose()&lt;br /&gt;
        {&lt;br /&gt;
            lock (this)&lt;br /&gt;
            {&lt;br /&gt;
                if (iHandle == IntPtr.Zero)&lt;br /&gt;
            {&lt;br /&gt;
                    return;&lt;br /&gt;
            }&lt;br /&gt;
            DisposeProvider();&lt;br /&gt;
            iPropertyOn.Dispose();&lt;br /&gt;
            iHandle = IntPtr.Zero;&lt;br /&gt;
            }&lt;br /&gt;
            iGch.Free();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix C. Sample Driver = &lt;br /&gt;
&lt;br /&gt;
== BasicLightDriver.cs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.hWidget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
     class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
     {&lt;br /&gt;
         private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
         public BinaryLightProvider(DvDevice aDevice, &lt;br /&gt;
             ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol = aProtocol;&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
     {&lt;br /&gt;
         private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
         {&lt;br /&gt;
             private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
             private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
             private readonly ISimpleUpnpWidget iProtocol; &lt;br /&gt;
 &lt;br /&gt;
             private readonly BinaryLightProvider iProvider;&lt;br /&gt;
             private readonly DvDevice iDvDevice;&lt;br /&gt;
             private IPublishedWidget iPublishedWidget; &lt;br /&gt;
 &lt;br /&gt;
             public DvDevice DvDevice&lt;br /&gt;
             {&lt;br /&gt;
                 get { return iDvDevice; }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             public string WidgetClass&lt;br /&gt;
             {&lt;br /&gt;
                 get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public DiscoveredWidget(&lt;br /&gt;
                 IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                 string aUdn,&lt;br /&gt;
                 ISimpleUpnpWidget aProxy,&lt;br /&gt;
                 IWidgetPublisher aPublisher)&lt;br /&gt;
             {&lt;br /&gt;
                 iDeviceFactory = aDeviceFactory;&lt;br /&gt;
                 iProtocol = aProtocol;&lt;br /&gt;
 &lt;br /&gt;
                 iPublisher = aPublisher;&lt;br /&gt;
                 iDvDevice = iDeviceFactory.CreateDevice(aUdn);  &lt;br /&gt;
                 iProvider = new BinaryLightProvider(iDvDevice, &lt;br /&gt;
                                                     iProtocol);&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             public void HandleInitialEvent()&lt;br /&gt;
             {&lt;br /&gt;
                 iDvDevice.SetEnabled();&lt;br /&gt;
                 iPublisher.TryPublishWidget(iDvDevice.iUdn(), this,&lt;br /&gt;
                     out iPublishedWidget);&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
             {&lt;br /&gt;
                 if (iPublishedWidget != null)&lt;br /&gt;
                 {&lt;br /&gt;
                     iPublishedWidget.Unpublish();&lt;br /&gt;
                 } &lt;br /&gt;
                 iProvider.Dispose();&lt;br /&gt;
                 iDvDevice.Dispose();&lt;br /&gt;
             }  &lt;br /&gt;
 &lt;br /&gt;
             public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
             {&lt;br /&gt;
                 if (aIndex == 0)&lt;br /&gt;
                 {&lt;br /&gt;
                     iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         private readonly string iName;&lt;br /&gt;
         private readonly IDvDeviceFactory aDeviceFactory;&lt;br /&gt;
         private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
         &lt;br /&gt;
         public BinaryLightDriver(&lt;br /&gt;
             string aName,&lt;br /&gt;
             IWidgetPublisher aPublisher,&lt;br /&gt;
             iDeviceFactory aDeviceFactory)&lt;br /&gt;
         {&lt;br /&gt;
             iWidgetPublisher = aPublisher;&lt;br /&gt;
             iName = aName;&lt;br /&gt;
             iDeviceFactory = aDeviceFactory;&lt;br /&gt;
         } &lt;br /&gt;
 &lt;br /&gt;
         public IEnumerable&amp;amp;lt;uint&amp;amp;gt; WidgetClasses&lt;br /&gt;
         {&lt;br /&gt;
             get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         public void WidgetDiscovered(&lt;br /&gt;
             string aWidgetUdn,&lt;br /&gt;
             uint aWidgetClass,&lt;br /&gt;
             ISimpleUpnpWidget aSimpleUpnpWidget)&lt;br /&gt;
         {&lt;br /&gt;
             string newUdn = aWidgetUdn;&lt;br /&gt;
             DiscoveredWidget discoveredWidget = new DiscoveredWidget&lt;br /&gt;
                 (iDeviceFactory,&lt;br /&gt;
                  newUdn,&lt;br /&gt;
                  aSimpleUpnpWidget,&lt;br /&gt;
                  iWidgetPublisher);&lt;br /&gt;
 &lt;br /&gt;
             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                 discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                 discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                 discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary = &lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in OpenHome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by OpenHome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh - A collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs on ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The OpenHome Operating System. Core software for OpenHome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. &lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. A typical Widget supports only one protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Driver_Development</id>
		<title>OhWidget Driver Development</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Driver_Development"/>
				<updated>2012-03-01T15:16:20Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Related Documents */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for developers using the OpenHome SDK to integrate a Widget into an OpenHome system. Each Widget must have its own driver to allow it to communicate with the OpenHome Nodes. &lt;br /&gt;
&lt;br /&gt;
To help you write your driver, this document provides high level descriptions of the core responsibilities of a Widget driver and gives a detailed walk-through using example code.&lt;br /&gt;
&lt;br /&gt;
Full versions of each file used in the development of the example driver are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin development of your Widget driver you must be in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* your Widget Service XML that describes the properties on your Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document does not contain advice on how to write Widget Service XML. Refer to the OpenHome Widget Service XML definition document for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK&lt;br /&gt;
* your chosen communication protocol's API&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The protocol you choose for your Widgets must be the same protocol used on your choice of Node.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document focuses on the development of the Widget driver. Details about the communications protocol used are beyond the scope of this document. This document assumes you are familiar with your chosen protocol's code libraries and are able to use them in the driver code you write.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Related Documents ==&lt;br /&gt;
&lt;br /&gt;
The following related OpenHome documentation may be of interest to you:&lt;br /&gt;
&lt;br /&gt;
* [[ohWidget Technical Overview|ohWidget Technical Overview]]&lt;br /&gt;
* [[OpenHome Widget Service XML definition|OpenHome Widget Service XML definition]]&lt;br /&gt;
* [http://www.openhome.org/releases/ohNet_DeviceStack.pdf  OpenHome ohNet Device Stack]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
None of the related documents listed above is mandatory reading for Widget driver development.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
== Widget Service XML ==&lt;br /&gt;
OpenHome Widget driver writing relies heavily on the use of code generated from a single source — the Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
The service and actions your Widget provides are represented in code in a file called a Provider. The Provider is automatically generated from the Widget Service XML and produces an abstract class for you to inherit when you write your concrete class driver.&lt;br /&gt;
&lt;br /&gt;
To aid in the explanation of how the Provider is created and put to use we will follow the development of&lt;br /&gt;
a driver for a simple light Widget; taking the defined Widget Service XML and stepping through how it is used to generate the other files. Examples of code are used throughout this document to show you how each one is created and used in an OpenHome system. &lt;br /&gt;
&lt;br /&gt;
It is essential that you start with a well-formed Widget Service XML, conforming to the schema defined&lt;br /&gt;
in the WidgetService.xsd. The following diagram shows the significance of the Widget Service XML in&lt;br /&gt;
relation to the generated files you will use when writing your driver:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarchy, highlighting the areas specifically used in driver development]]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* The grayed-out files are not relevant to Widget driver development but can also be generated from the Widget Service XML.&lt;br /&gt;
* The Provider is generated in C#, meaning your driver must be written in C# as well. The use of managed code is mandatory for driver writing in the OpenHome framework.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Code sample used in this document ==&lt;br /&gt;
&lt;br /&gt;
Our examples in this document use a Widget Service XML definition for a light Widget called&lt;br /&gt;
BasicLight.xml.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Full versions of all the example files used in this document are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We will see how the Provider is generated from this XML and how it is used to aid the driver writing process. The examples also show how your chosen communication protocol should be used in the body of the driver code.&lt;br /&gt;
&lt;br /&gt;
Implementation details of specific protocols you choose to use are beyond the scope of this document. However, the samples used in this document show the use of the SimpleUPnP protocol to aid you in your development process.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol during the early stages of the OpenHome project. It is included in the OpenHome SDK and can be used as a public resource. &lt;br /&gt;
&lt;br /&gt;
The use of SimpleUPnP in the example files and the code snippets within the following sections is highlighted by the [[File:Warning.png]] icon. The lines of code marked by [[File:Warning.png]] must be changed to code from your chosen communication protocol's library. SimpleUPnP is left in to help you understand how a protocol is used in a working example.&lt;br /&gt;
&lt;br /&gt;
The sample code provided attempts to show best-practice coding standards. There are several sections of code that have a mandatory layout or that call specifically named methods and functions. These areas of the code are highlighted where required. &lt;br /&gt;
&lt;br /&gt;
Where the examples do not explicitly state that the code shown is mandatory, you are free to implement it in a different way according to your own coding style and practices.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Driver responsibilities = &lt;br /&gt;
&lt;br /&gt;
== Driver responsibilities ==&lt;br /&gt;
&lt;br /&gt;
An OpenHome Widget driver has several responsibilities which must be met before it can be used on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
These responsibilities are listed R1 to R7 and are defined here, explaining what each one must do. &lt;br /&gt;
&lt;br /&gt;
=== R1 Specifying the type of Widget the driver controls ===&lt;br /&gt;
A driver must know which type of Widget it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
=== R2 Reacting to a discovered Widget on the network ===&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== R3 Setting the initial values for the Widget's properties ===&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
=== R4 Publishing discovered Widgets in the Local Widget Registry on the Node ===&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object.&lt;br /&gt;
&lt;br /&gt;
=== R5 Reacting to an event reported from the Widget ===&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
=== R6 Reacting to actions sent to the Widget ===&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== R7 Reacting to a Widget's departure ===&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no&lt;br /&gt;
longer available.&lt;br /&gt;
&lt;br /&gt;
The sections of example code that follow show you how to write a driver from beginning to end. The accompanying text explaining the example code highlights when a responsibility, or part of a responsibility, has been met.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Driver Architecture = &lt;br /&gt;
&lt;br /&gt;
== Driver Architecture ==&lt;br /&gt;
&lt;br /&gt;
Drivers are installed on the Node and used when the Node needs to communicate with the Widget. Drivers&lt;br /&gt;
use several objects to communicate with Widgets over the Widget's lifetime. Figure 2 shows the objects&lt;br /&gt;
used by the driver and how the responsibilities listed above relate to each one:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture.png|800px|thumb|center|Figure 2: The architecture of a driver, showing the driver's relationship to the objects used to communicate with a Widget. Lines between objects show message flow.]]&lt;br /&gt;
&lt;br /&gt;
The objects contained in the dotted boundary must appear in the code you write to define your driver. The Driver, Provider and IWidgetRegistryEntry objects are all contained in the same driver file. We begin discussing this on page 12. &lt;br /&gt;
&lt;br /&gt;
The other objects are provided by the OpenHome SDK or as installed components on the Node.&lt;br /&gt;
&lt;br /&gt;
The Discovery Module informs the driver of the presence of an available Widget.&lt;br /&gt;
&lt;br /&gt;
Each Node has a Protocol Module which contains the protocol's API. Widgets can communicate with OpenHome Nodes using any one of the set of communications protocols the Node supports. The driver uses your chosen protocol's Protocol Module to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
Both the Protocol Module and the Discovery Module are installed on the Node. When you write your&lt;br /&gt;
driver you will use your Protocol Module to allow the driver to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
IWidgetPublisher, IPublishedWidget and DvDevice are objects provided in the OpenHome&lt;br /&gt;
API. You can read about them in the APIs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Generating the Provider = &lt;br /&gt;
&lt;br /&gt;
== Generating the Provider ==&lt;br /&gt;
&lt;br /&gt;
You must generate your provider before you can begin writing your Widget driver. You use your provider as a guide to implement the functions your Widget needs to set the values of its properties.&lt;br /&gt;
&lt;br /&gt;
The current provider generation process is a manual one involving the use of a text transform tool.&lt;br /&gt;
&lt;br /&gt;
Speak to your OpenHome contact who will help you generate your provider.&lt;br /&gt;
&lt;br /&gt;
Future releases of the OpenHome SDK will include a tool to help you generate the provider.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
You must be in possession of:&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK, unpacked on your computer&lt;br /&gt;
* your Widget Service XML file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Writing a SimpleUPnP driver = &lt;br /&gt;
&lt;br /&gt;
== Introduction to the SimpleUPnP protocol ==&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol used to control emulated Widgets over a custom UPnP service.&lt;br /&gt;
&lt;br /&gt;
This chapter shows how a driver is written using the SimpleUPnP communications protocol. The aim is to show the code using as generic a protocol as possible so that you can see where your own protocol specific code needs to go.&lt;br /&gt;
&lt;br /&gt;
The use of code specific to the SimpleUPnP implementation is highlighted by the use of the [[File:Warning.png]] icon. The lines of code are marked by this icon to make it easier for you to see where the protocol-specific code must go and what parts of the code are generic.&lt;br /&gt;
&lt;br /&gt;
=== Register model ===&lt;br /&gt;
&lt;br /&gt;
SimpleUPnP is modeled on 8 physical registers available on the Widget. Each register is 32-bits wide. They are indexed from 0 to 7 and the last register (register 7) is reserved for storing the Widget's class.&lt;br /&gt;
&lt;br /&gt;
This detail is used by the Protocol Module on the Node to determine which driver is needed to run the new Widget when it has been discovered.&lt;br /&gt;
&lt;br /&gt;
The remaining 7 registers (registers 0 to 6) are free for Widget engineers to assign to the Widget's functions.&lt;br /&gt;
&lt;br /&gt;
Registers 0, 1, 2 and 3 are available as read/write registers. Registers 4, 5 and 6 are readonly registers.&lt;br /&gt;
&lt;br /&gt;
Only the emulated hardware (running on the Node) can change the values held in registers 4, 5 and 6.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Register use in drivers ===&lt;br /&gt;
&lt;br /&gt;
In the example that follows we have a Basic Light Widget with a very simple function: it can be turned on and turned off. The on/off value is stored in register 0, with values 0=OFF and 1=ON. Register 0 is a read/write register. This means we can change the value stored there using messages passed to the Widget from the Node, and by reacting to physical interactions at the Widget (such as someone manually switching the light on or off). &lt;br /&gt;
&lt;br /&gt;
The mapping of registers to properties on the Widget is decided by the engineers who manufacture the device. You must be provided with the mapping before you begin developing your driver.&lt;br /&gt;
&lt;br /&gt;
== Starting the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-BoxHighlight.png|800px|thumb|center|Figure 3 The driver architecture highlighting the Widget driver and its component parts.]]&lt;br /&gt;
&lt;br /&gt;
When you have generated the abstract provider you can put it to use in the Widget driver. A Widget driver&lt;br /&gt;
has three distinct components:&lt;br /&gt;
&lt;br /&gt;
* an implementation of your abstract provider&lt;br /&gt;
* a definition of the Widget driver&lt;br /&gt;
* an implementation of the IWidgetRegistryEntry interface&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must manually write the code for your Widget driver. The differences in implementation of Widget properties and communication protocols means that the driver code cannot be autogenerated.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This section takes you through how to write a Widget driver by implementing the auto-generated provider,&lt;br /&gt;
starting from a new blank file and finishing with a working driver for the Basic Light Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
No assumptions have been made about the type of editor you use to write your code. Shortcuts&lt;br /&gt;
or macros that you use as standard will not appear in the instructions below. A full example&lt;br /&gt;
BinaryLightDriver.cs is available to review in Appendix C.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a new C# file in your IDE. Ensure the following libraries are used:&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 [[File:Warning.png]]using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 namespace OpenHome.Widget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must use the libraries listed above for this specific example.&lt;br /&gt;
&lt;br /&gt;
In general, drivers require the following libraries:&lt;br /&gt;
* System*&lt;br /&gt;
* System.Collections.Generic*&lt;br /&gt;
* OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
&lt;br /&gt;
Your driver will fail to compile if you miss any of these listed libraries. Libraries marked * are typically added by default by most modern IDEs. &lt;br /&gt;
&lt;br /&gt;
The OpenHome.Widget.Protocols.SimpleUpnp library is required only in this SimpleUPnP example. Drivers using a different protocol will use their own protocol library.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Implementing the provider ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-ProviderHighlight.png|800px|thumb|center|Figure 4 The driver architecture highlighting the Provider's place]]&lt;br /&gt;
&lt;br /&gt;
You use your auto-generated abstract provider by writing an implementation of it in the driver file. Responsibilities met by implementing your auto-generated provider are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R6 Reacting to actions sent to the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
Begin by creating a new class. It will subclass the abstract auto-generated provider:&lt;br /&gt;
&lt;br /&gt;
 class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
The Protocol Module will provide an API for the Provider to use to communicate with the Widget. In&lt;br /&gt;
SimpleUPnP we are provided with an interface called ISimpleUpnpWidget. The provider is supplied&lt;br /&gt;
with the required instance of the interface by the Discovery Module on the Node.&lt;br /&gt;
&lt;br /&gt;
The mechanisms for registering providers with specific Protocol Modules, and for the way the module gives each provider its required interface are covered later when writing the discovery method.&lt;br /&gt;
&lt;br /&gt;
For now, we need to give the Provider a place to store the interface that it will later use to communicate&lt;br /&gt;
with the Widget:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]] private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
&lt;br /&gt;
The interface from the Protocol Module is passed in as a parameter in the Provider's constructor and then&lt;br /&gt;
assigned to the variable we just created:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightProvider(DvDevice aDevice,&lt;br /&gt;
 [[File:Warning.png]]         ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
 {&lt;br /&gt;
       iProtocol = aProtocol;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
To satisfy R3 we would normally set the Widget's properties here, giving them an initial value.&lt;br /&gt;
However, in this specific example we cannot set the value of Basic Light's only property because&lt;br /&gt;
we will never know, in advance, what the state of the light will be (either on or off) when we&lt;br /&gt;
create the DiscoveredWidget.&lt;br /&gt;
&lt;br /&gt;
When you cannot set the properties ahead of time, and you are using an eventing protocol like SimpleUPnP, you can instead set them in the HandleRegisterEvent method in the driver class. This also satisfies the requirements for R3. You must set the Widget's properties before you enable it using SetEnabled(). &lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The abstract provider includes an abstract method called SetOn. This method is invoked by the Node when passing a message to the Widget, specifically to set the on property of the Widget to either 0 or 1. The implementation of this method will meet the requirements for R6.&lt;br /&gt;
&lt;br /&gt;
We must override this method and provide the protocol module a way of passing a message on to the Widget to perform the required action, in this case turn the light on or off:&lt;br /&gt;
&lt;br /&gt;
          protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
          {&lt;br /&gt;
     [[File:Warning.png]]        iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
In this example the Basic Light's SetOn property (the boolean property that controls whether the light is&lt;br /&gt;
on or off) is represented in the physical Widget by the register that has an index of 0.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* This method is an example of an action on a Widget. Actions are messages sent from the Node to the Widget. We will see later how to handle events that need to be passed back from the Widget&lt;br /&gt;
to the Node.&lt;br /&gt;
* Your own Widget will likely provide more than a single property. Your auto-generated provider will contain one abstract method to represent each writable property. Read-only properties are not provided an abstract method.&lt;br /&gt;
&lt;br /&gt;
You must implement each abstract method in your driver to ensure the relevant property on&lt;br /&gt;
the Widget can be set.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We have now finished implementing the provider. The next step is to implement the driver.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Implementing the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-DriverHighlight.png|800px|thumb|center|Figure 4: The driver architecture highlighting the implemented driver's place.]]&lt;br /&gt;
&lt;br /&gt;
The code for your Widget driver must provide an implementation of the IWidgetRegistryInterface,&lt;br /&gt;
including the following tasks:&lt;br /&gt;
&lt;br /&gt;
* methods to expose identifying details about the Widget for the Node to access&lt;br /&gt;
* providing methods to handle events reported by the Widget&lt;br /&gt;
&lt;br /&gt;
The driver is implemented as a public class within the same file as the provider code. Each driver must use the interface for the protocol you are using. For the SimpleUPnP protocol the interface is ISimple-UpnpWidgetDriver.&lt;br /&gt;
&lt;br /&gt;
=== Writing code ===&lt;br /&gt;
&lt;br /&gt;
Create your new driver class and subclass the ISimpleUpnpWidgetDriver interface:&lt;br /&gt;
&lt;br /&gt;
 public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Implementing IWidgetRegistryEntry ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry is the interface you use to represent physical Widgets. It is implemented as a subclass of your driver class. We are going to implement this interface in a class called '''DiscoveredWidget'''.&lt;br /&gt;
&lt;br /&gt;
Let's return to our driver architecture diagram for a moment:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-IRegistryEntryHighlight.png|800px|thumb|center|Figure 5 The driver architecture highlighting the IWidgetRegistryEntry object you will now implement]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry uses several other objects to help create it and respond to messages sent to and from it. These objects will be created in our implementation of DiscoveredWidget. &lt;br /&gt;
&lt;br /&gt;
When successfully created and published, the DiscoveredWidget objects are stored in a list on the Node called the Local Widget Registry. The Local Widget Registry is used by Nodes to maintain contact with the Widgets they control.&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry is shown at the top of Figure 5, marked plainly as (Registry). The path to the Local Widget Registry goes through several layers of Node architecture which are not relevant to Widget driver writing, so are not shown in the diagrams.&lt;br /&gt;
&lt;br /&gt;
==== Writing code ====&lt;br /&gt;
&lt;br /&gt;
Start by subclassing the IWidgetRegistryEntry interface in your new class:&lt;br /&gt;
&lt;br /&gt;
      private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
      {&lt;br /&gt;
&lt;br /&gt;
A DiscoveredWidget must provide the driver with the objects required to present the Widget and its&lt;br /&gt;
properties to the Node:&lt;br /&gt;
&lt;br /&gt;
           private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
           private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
           private readonly ISimpleUpnpWidget iProtocol;&lt;br /&gt;
           private readonly BinaryLightProvider iProvider;&lt;br /&gt;
           private readonly DvDevice iDvDevice;&lt;br /&gt;
           private IPublishedWidget iPublishedWidget;&lt;br /&gt;
&lt;br /&gt;
Each of the attributes in the example above are defined as follows:&lt;br /&gt;
&lt;br /&gt;
iDeviceFactory — used by the driver to create a single instance of DvDevice to represent a single Widget&lt;br /&gt;
&lt;br /&gt;
iPublisher — used by the driver to publish the Widget to the Node&lt;br /&gt;
&lt;br /&gt;
iProtocol — the object used by the Widget to communicate with the Protocol Module on the Node&lt;br /&gt;
&lt;br /&gt;
iProvider — an instantiated provider of the type you defined earlier&lt;br /&gt;
&lt;br /&gt;
iDvDevice — a representation of a Widget to which the provider is attached, created using iDevice-Factory above&lt;br /&gt;
&lt;br /&gt;
iPublishedWidget — used to contain the returned object from a successful publishing of the Widget&lt;br /&gt;
If we look again at the driver architecture diagram, we ca highlight the objects we've just defined:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-Highlight.png|800px|thumb|center|Figure 6: The driver architecture highlighting the objects used by the IWidgetRegistryEntry implementation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The DeviceFactory, defined above in the member variable iDeviceFactory, is used to create new DvDevice objects. The DeviceFactory is only ever used to do this once. It is not shown in the driver architecture diagrams due to its minimal role in the operation of a driver, but it would normally appear between the IWidgetRegistryEntry and DvDevice objects.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
A driver requires methods to expose identifying details about the Widget. We must provide access to two of the attributes we just defined above:&lt;br /&gt;
&lt;br /&gt;
 public DvDevice DvDevice&lt;br /&gt;
 {&lt;br /&gt;
     get { return iDvDevice; }&lt;br /&gt;
 }&lt;br /&gt;
 public string WidgetClass&lt;br /&gt;
 {&lt;br /&gt;
     get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The WidgetClass string is formed using a combination of the vendor name and the Widget's name in the&lt;br /&gt;
format:&lt;br /&gt;
&lt;br /&gt;
 [vendor_domain]:[widget_name]&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry can now query both the DvDevice object representing the Widget, and the specific class of Widget this driver represents. The other member variables we defined do not need their own accessor methods.&lt;br /&gt;
&lt;br /&gt;
Now we must write a constructor for DiscoveredWidget and assign the parameters accordingly: &lt;br /&gt;
&lt;br /&gt;
 public DiscoveredWidget(IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                            string aUdn,&lt;br /&gt;
                            ISimpleUpnpWidget aProxy,&lt;br /&gt;
                            IWidgetPublisher aPublisher)&lt;br /&gt;
 {&lt;br /&gt;
      iDeviceFactory = aDeviceFactory;&lt;br /&gt;
      iProtocol = aProtocol;&lt;br /&gt;
      iPublisher = aPublisher;&lt;br /&gt;
      iDvDevice = iDeviceFactory.CreateDevice(aUdn);&lt;br /&gt;
      iProvider = new BinaryLightProvider(iDvDevice,&lt;br /&gt;
      iProtocol);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Event handling ===&lt;br /&gt;
&lt;br /&gt;
A Widget's state can change in one of three significant ways:&lt;br /&gt;
&lt;br /&gt;
* when the Widget needs to be published on the Node&lt;br /&gt;
* when the Widget disappears from the network (by losing power or similar)&lt;br /&gt;
* when a property's state changes and must be updated to a new value&lt;br /&gt;
&lt;br /&gt;
We now need methods to handle these changes.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The methods we define here will be used as callbacks, rather than invoked as method calls. We define the methods here first and then use them later on. We will use the Protocol Module to listen for changes in the Widget's state and register these methods as callbacks there. See Writing the SimpleUPnP Widget discovery method for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this section of the driver are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R4 Publishing discovered Widgets in the Local Widget Registry on the Node'''&lt;br /&gt;
&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object. &lt;br /&gt;
&lt;br /&gt;
'''R5 Reacting to an event reported from the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
'''R7 Reacting to a Widget's departure'''&lt;br /&gt;
&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no longer available.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Enabling and publishing a discovered Widget ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first method initializes the Widget by enabling the device and then using the IWidgetPublisher&lt;br /&gt;
to make it available on the Node:&lt;br /&gt;
&lt;br /&gt;
 public void HandleInitialEvent()&lt;br /&gt;
 {&lt;br /&gt;
      iDvDevice.SetEnabled();&lt;br /&gt;
      iPublisher.TryPublishWidget(iDvDevice.iUdn(),&lt;br /&gt;
                              this,&lt;br /&gt;
                              out iPublishedWidget);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This method meets the requirements for R4.&lt;br /&gt;
&lt;br /&gt;
The call to TryPublishWidget returns an iPublishedWidget object. We use this object later to satisfy the requirements of R7.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The ordering of the calls to SetEnabled and TryPublishWidget is vitally important. You&lt;br /&gt;
must enable the device before you attempt to publish it. Your Widget will not be available to the&lt;br /&gt;
Nodes unless SetEnabled is called first. Nodes will not be able to access a published device&lt;br /&gt;
that has not been enabled.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
R3 requires that you set the Widget's properties before you enable and publish the device. We&lt;br /&gt;
discussed on page 14 how some properties can only be set after the Widget reports what their&lt;br /&gt;
state is. We do this in HandleRegisterEvent.&lt;br /&gt;
&lt;br /&gt;
We rely on the SimpleUPnP Protocol Module guaranteeing a call to HandleRegisterEvent first before HandleInitialEvent. This is informed by guarantees made by the Control Point stack that the calls will be made in that order.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
==== Removing a Widget ====&lt;br /&gt;
&lt;br /&gt;
Removing a Widget involves unpublishing it from the Node. The IPublishedWidget interface provides us with a method we can call to manage that for us:&lt;br /&gt;
&lt;br /&gt;
 public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
 {&lt;br /&gt;
     if (iPublishedWidget != null)&lt;br /&gt;
     { iPublishedWidget.Unpublish(); }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assuming that the Widget was successfully published earlier, it is removed from the Node's Local Widget Registry.&lt;br /&gt;
&lt;br /&gt;
We must also properly handle the resources we used to create and maintain the Widget object while it was published:&lt;br /&gt;
&lt;br /&gt;
      iProvider.Dispose();&lt;br /&gt;
      iDvDevice.Dispose();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The calls to Dispose are made regardless of the Widget's published state, ensuring that any created device and associated provider are properly disposed. This implementation satisfies R7.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Event handling ====&lt;br /&gt;
&lt;br /&gt;
We need a method to handle changes to the state of the Widget's properties.&lt;br /&gt;
&lt;br /&gt;
If the property changes at the Widget, it needs to pass the new state back to the Node so that it is kept up-to-date on the Widget's status. This is called an event. An example in the case of our Basic Light is someone manually switching the light from on to off. This is in contrast to actions, which are passed from the Node to the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Other examples of events involve no human interaction, such as a thermometer Widget updating its current temperature based on environmental changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Our Basic Light Widget has only one property that needs to be handled:&lt;br /&gt;
&lt;br /&gt;
 public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
 {&lt;br /&gt;
     if (aIndex == 0)&lt;br /&gt;
     {&lt;br /&gt;
         iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We use our instance of the provider to update the register on the Widget that is mapped to the On property. This in turn updates the Node with the new state of the Widget.&lt;br /&gt;
&lt;br /&gt;
This method provides implementations to satisfy two driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
* R3 is now completely satisfied, as we can now set the values of all the previously unknown properties here.&lt;br /&gt;
* R5 is also satisfied as this method allows us to update the Widget's status on the Node when a property is changed on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Not all protocols pass messages back to the Node in this manner. The way we have satisfied R3 and R5 here only applies to protocols and Widgets that support this behavior.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Widgets that do not use an eventing protocol need to have their properties set in the provider's constructor to satisfy R3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To satisfy R5, the over-ridden method SetOn in the provider must include the call to SetPropertyOn. Non-eventing protocols do not require a HandleRegisterEvent method.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Constructor ===&lt;br /&gt;
&lt;br /&gt;
The final requirement for the driver is the constructor so that new DiscoveredWidget objects can be created. &lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this area of code are:&lt;br /&gt;
&lt;br /&gt;
'''R1 Specifying the type of Widget the driver controls'''&lt;br /&gt;
&lt;br /&gt;
A driver must know which type of Widget that it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Writing the code ====&lt;br /&gt;
&lt;br /&gt;
We begin by defining the variables we will use to store the objects used by the driver:&lt;br /&gt;
&lt;br /&gt;
 private readonly string iName;&lt;br /&gt;
 private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
 private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now write the constructor for the driver and assign the passed in parameters appropriately:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightDriver(string aName,&lt;br /&gt;
                IWidgetPublisher aPublisher,&lt;br /&gt;
                IDvDeviceFactory aDeviceFactory)&lt;br /&gt;
 {&lt;br /&gt;
     iWidgetPublisher = aPublisher;&lt;br /&gt;
     iName = aName;&lt;br /&gt;
     iDeviceFactory = aDeviceFactory;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally we need to provide the driver a way to publish the class of Widget it controls. This information is requested by the Discovery Module and is used to ensure the Node uses the correct driver when a new Widget appears.&lt;br /&gt;
&lt;br /&gt;
The implementation for this details will be different for each protocol. The SimpleUPnP protocol library provides a file that contains the SimpleUPnP definitions as integers. Each integer represents a particular class of identified Widget.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP implementation of that method is as follows:&lt;br /&gt;
&lt;br /&gt;
 public IEnumerable&amp;lt;uint&amp;gt; WidgetClasses&lt;br /&gt;
 {&lt;br /&gt;
 [[File:Warning.png]]        get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The body of this method is specifically written for the Widget class we are defining (in this case a binary light). This method completes the driver's requirements for R1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Writing the SimpleUPnP Widget discovery method ==&lt;br /&gt;
&lt;br /&gt;
Every driver must contain a method which creates new objects to represent newly discovered Widgets.&lt;br /&gt;
The Discovery Module invokes this method to begin the process of creating the objects required to allow the Node to access the Widget. &lt;br /&gt;
&lt;br /&gt;
The name of this method is dictated by your chosen protocol's API. The SimpleUPnP protocol requires a method called WidgetDiscovered.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The method's name will not always be the same for each protocol. Your protocol's documentation will contain the details of what this method must be called.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This method and its implementation will meet the following driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
'''R2 Reacting to a discovered Widget on the network'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
Our implementation of the WidgetDiscovered method will create a new DiscoveredWidget object and use the Protocol Module to listen for changes to the Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
The method uses the Protocol Module and two ways to identify the Widget. We must pass these in as&lt;br /&gt;
parameters:&lt;br /&gt;
&lt;br /&gt;
 public void WidgetDiscovered(string aWidgetUdn,&lt;br /&gt;
                              uint aWidgetClass,&lt;br /&gt;
                              ISimpleUpnpWidget&lt;br /&gt;
                                  aSimpleUpnpWidget)&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
Every Widget that uses this driver must be uniquely identifiable:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]    string newUdn = aWidgetUdn;&lt;br /&gt;
&lt;br /&gt;
Each new Widget is represented by a DiscoveredWidget object. Create the new DiscoveredWidget and pass in the required parameters we created earlier:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
     DiscoveredWidget discoveredWidget =&lt;br /&gt;
                 new DiscoveredWidget(iDeviceFactory,&lt;br /&gt;
                                      newUdn,&lt;br /&gt;
  &lt;br /&gt;
 [[File:Warning.png]]                                    aSimpleUpnpWidget,&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Registering the callbacks ===&lt;br /&gt;
&lt;br /&gt;
Finally, we ask the Widget's protocol interface to listen for calls to the handler methods we defined earlier in DiscoveredWidget. We do this by registering those methods as callbacks for the Protocol Module&lt;br /&gt;
to listen for:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                        discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                        discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                        discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You have now met 100% of the driver responsibility requirements and have a working driver to use with your SimpleUPnP Widget.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix A. Sample XML =&lt;br /&gt;
&lt;br /&gt;
== Binary Light.xml ==&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
  &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
  &amp;lt;version&amp;gt;&lt;br /&gt;
   &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
   &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/version&amp;gt;&lt;br /&gt;
  &amp;lt;propertylist&amp;gt;&lt;br /&gt;
   &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
       illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
   &amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix B. Sample Provider = &lt;br /&gt;
&lt;br /&gt;
== DvWidgetOpenhomeOrgBasicLight1.cs ==&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Runtime.InteropServices;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Core;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Utils.Binary;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
 {&lt;br /&gt;
    public interface IDvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
        IDisposable&lt;br /&gt;
    {&lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous value&lt;br /&gt;
        /// &amp;lt;/returns&amp;gt;&lt;br /&gt;
        bool SetPropertyOn(bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;Property's value will be copied&lt;br /&gt;
        /// here&amp;lt;/param&amp;gt;&lt;br /&gt;
        bool PropertyOn();&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt; summary&amp;gt;&lt;br /&gt;
    /// Provider for the openhome.org:BinaryLight:1 UPnP service&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public abstract class DvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
               DvProvider,&lt;br /&gt;
               IDisposable,&lt;br /&gt;
               IDvProviderOpenhomeOrgBinaryLight1&lt;br /&gt;
    {&lt;br /&gt;
        private GCHandle iGch;&lt;br /&gt;
        private PropertyBool iPropertyOn;&lt;br /&gt;
        private PropertyUint iPropertyPrimarySeq;&lt;br /&gt;
        private PropertyUint iPropertySecondarySeq;&lt;br /&gt;
        private ActionDelegate iDelegateSetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetPrimaryProperty;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Constructor&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aDevice&amp;quot;&amp;gt;Device which owns this&lt;br /&gt;
        /// provider&amp;lt;/param&amp;gt;&lt;br /&gt;
        protected DvProviderOpenhomeOrgBinaryLight1(DvDevice aDevice)&lt;br /&gt;
            : base(aDevice, &amp;quot;openhome.org&amp;quot;, &amp;quot;GenericWidget&amp;quot;, 1)&lt;br /&gt;
        {&lt;br /&gt;
            iGch = GCHandle.Alloc(this);&lt;br /&gt;
            List&amp;lt;String&amp;gt; allowedValues = new List&amp;lt;String&amp;gt;();&lt;br /&gt;
            iPropertyOn = new PropertyBool(new ParameterBool(&amp;quot;On&amp;quot;));&lt;br /&gt;
            iPropertyPrimarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;PrimarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertyPrimarySeq);&lt;br /&gt;
            iPropertySecondarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;SecondarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertySecondarySeq);&lt;br /&gt;
            SetPropertyUint(iPropertyPrimarySeq, 0);&lt;br /&gt;
            SetPropertyUint(iPropertySecondarySeq, 0);&lt;br /&gt;
  &lt;br /&gt;
            Zapp.Core.Action action = new Zapp.Core.Action&lt;br /&gt;
                (&amp;quot;SetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;FireAndForget&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddInputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateSetProperty = new ActionDelegate(DoSetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateSetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateGetProperty = new ActionDelegate(DoGetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetPrimaryProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                 (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;integer&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;boolean&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;string&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;binary&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Type&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;readWrite&amp;quot;);allowedValues.Add&lt;br /&gt;
                (&amp;quot;readOnly&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;writeOnly&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString(&amp;quot;Access&amp;quot;,&lt;br /&gt;
                allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            iDelegateGetPrimaryProperty = new&lt;br /&gt;
            ActionDelegate(DoGetPrimaryProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetPrimaryProperty,&lt;br /&gt;
            GCHandle.ToIntPtr(iGch));&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous&lt;br /&gt;
        /// value&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool SetPropertyOn(bool aValue)&lt;br /&gt;
        {&lt;br /&gt;
            if (iPropertyOn.SetValue(aValue))&lt;br /&gt;
            {&lt;br /&gt;
                lock (iPropertyPrimarySeq)&lt;br /&gt;
                {&lt;br /&gt;
                    SetPropertyUint(iPropertyPrimarySeq,&lt;br /&gt;
                        iPropertyPrimarySeq.Value() + 1);&lt;br /&gt;
                } return true;&lt;br /&gt;
            } return false;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;The value of the property&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool PropertyOn()&lt;br /&gt;
        {&lt;br /&gt;
            return iPropertyOn.Value();&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the On property.&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aVersion&amp;quot;&amp;gt;Version of the service being&lt;br /&gt;
        /// requested (will be &amp;lt;= the version advertised)&amp;lt;/param&amp;gt; &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the On property.&lt;br /&gt;
        /// &amp;lt;/param&amp;gt;&lt;br /&gt;
        protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        private static int DoSetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                byte[] valBin = invocation.ReadBinary(&amp;quot;Value&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                switch (name)&lt;br /&gt;
                {&lt;br /&gt;
                    case &amp;quot;On&amp;quot;:&lt;br /&gt;
                        self.SetOn(aVersion, Converter.&lt;br /&gt;
                            BinaryToBoolean(valBin));&lt;br /&gt;
                        break;&lt;br /&gt;
                    default:&lt;br /&gt;
                        throw new ActionError();&lt;br /&gt;
                }&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
                invocation.WriteEnd();&lt;br /&gt;
            }&lt;br /&gt;
            catch (ActionError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
            catch (PropertyUpdateError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
        return 0;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        private static int DoGetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
            switch (name)&lt;br /&gt;
            {&lt;br /&gt;
                case &amp;quot;On&amp;quot;:&lt;br /&gt;
                invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                    Converter.BooleanToBinary(self.iPropertyOn.&lt;br /&gt;
                        Value()));&lt;br /&gt;
                break;&lt;br /&gt;
                default:&lt;br /&gt;
                throw new ActionError();&lt;br /&gt;
            }&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    private static int DoGetPrimaryProperty(IntPtr aPtr,&lt;br /&gt;
                    IntPtr aInvocation,&lt;br /&gt;
                    uint aVersion)&lt;br /&gt;
    {&lt;br /&gt;
        GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
        DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
            (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
        DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
  &lt;br /&gt;
        try&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReadStart();&lt;br /&gt;
            invocation.ReadEnd();&lt;br /&gt;
            invocation.WriteStart();&lt;br /&gt;
            invocation.WriteString(&amp;quot;Name&amp;quot;, &amp;quot;On&amp;quot;);&lt;br /&gt;
            invocation.WriteString(&amp;quot;Type&amp;quot;, &amp;quot;boolean&amp;quot;);&lt;br /&gt;
            invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                Converter.BooleanToBinary(self.iPropertyOn.Value()));&lt;br /&gt;
            invocation.WriteString(&amp;quot;Access&amp;quot;, &amp;quot;readWrite&amp;quot;);&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt;summary&amp;gt;&lt;br /&gt;
    /// Must be called for each class instance. Must be called before&lt;br /&gt;
    /// Core.Library.Close().&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public void Dispose()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
        GC.SuppressFinalize(this);&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
    ~DvProviderOpenhomeOrgBinaryLight1()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
        private void DoDispose()&lt;br /&gt;
        {&lt;br /&gt;
            lock (this)&lt;br /&gt;
            {&lt;br /&gt;
                if (iHandle == IntPtr.Zero)&lt;br /&gt;
            {&lt;br /&gt;
                    return;&lt;br /&gt;
            }&lt;br /&gt;
            DisposeProvider();&lt;br /&gt;
            iPropertyOn.Dispose();&lt;br /&gt;
            iHandle = IntPtr.Zero;&lt;br /&gt;
            }&lt;br /&gt;
            iGch.Free();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix C. Sample Driver = &lt;br /&gt;
&lt;br /&gt;
== BasicLightDriver.cs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.hWidget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
     class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
     {&lt;br /&gt;
         private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
         public BinaryLightProvider(DvDevice aDevice, &lt;br /&gt;
             ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol = aProtocol;&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
     {&lt;br /&gt;
         private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
         {&lt;br /&gt;
             private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
             private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
             private readonly ISimpleUpnpWidget iProtocol; &lt;br /&gt;
 &lt;br /&gt;
             private readonly BinaryLightProvider iProvider;&lt;br /&gt;
             private readonly DvDevice iDvDevice;&lt;br /&gt;
             private IPublishedWidget iPublishedWidget; &lt;br /&gt;
 &lt;br /&gt;
             public DvDevice DvDevice&lt;br /&gt;
             {&lt;br /&gt;
                 get { return iDvDevice; }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             public string WidgetClass&lt;br /&gt;
             {&lt;br /&gt;
                 get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public DiscoveredWidget(&lt;br /&gt;
                 IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                 string aUdn,&lt;br /&gt;
                 ISimpleUpnpWidget aProxy,&lt;br /&gt;
                 IWidgetPublisher aPublisher)&lt;br /&gt;
             {&lt;br /&gt;
                 iDeviceFactory = aDeviceFactory;&lt;br /&gt;
                 iProtocol = aProtocol;&lt;br /&gt;
 &lt;br /&gt;
                 iPublisher = aPublisher;&lt;br /&gt;
                 iDvDevice = iDeviceFactory.CreateDevice(aUdn);  &lt;br /&gt;
                 iProvider = new BinaryLightProvider(iDvDevice, &lt;br /&gt;
                                                     iProtocol);&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             public void HandleInitialEvent()&lt;br /&gt;
             {&lt;br /&gt;
                 iDvDevice.SetEnabled();&lt;br /&gt;
                 iPublisher.TryPublishWidget(iDvDevice.iUdn(), this,&lt;br /&gt;
                     out iPublishedWidget);&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
             {&lt;br /&gt;
                 if (iPublishedWidget != null)&lt;br /&gt;
                 {&lt;br /&gt;
                     iPublishedWidget.Unpublish();&lt;br /&gt;
                 } &lt;br /&gt;
                 iProvider.Dispose();&lt;br /&gt;
                 iDvDevice.Dispose();&lt;br /&gt;
             }  &lt;br /&gt;
 &lt;br /&gt;
             public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
             {&lt;br /&gt;
                 if (aIndex == 0)&lt;br /&gt;
                 {&lt;br /&gt;
                     iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         private readonly string iName;&lt;br /&gt;
         private readonly IDvDeviceFactory aDeviceFactory;&lt;br /&gt;
         private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
         &lt;br /&gt;
         public BinaryLightDriver(&lt;br /&gt;
             string aName,&lt;br /&gt;
             IWidgetPublisher aPublisher,&lt;br /&gt;
             iDeviceFactory aDeviceFactory)&lt;br /&gt;
         {&lt;br /&gt;
             iWidgetPublisher = aPublisher;&lt;br /&gt;
             iName = aName;&lt;br /&gt;
             iDeviceFactory = aDeviceFactory;&lt;br /&gt;
         } &lt;br /&gt;
 &lt;br /&gt;
         public IEnumerable&amp;amp;lt;uint&amp;amp;gt; WidgetClasses&lt;br /&gt;
         {&lt;br /&gt;
             get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         public void WidgetDiscovered(&lt;br /&gt;
             string aWidgetUdn,&lt;br /&gt;
             uint aWidgetClass,&lt;br /&gt;
             ISimpleUpnpWidget aSimpleUpnpWidget)&lt;br /&gt;
         {&lt;br /&gt;
             string newUdn = aWidgetUdn;&lt;br /&gt;
             DiscoveredWidget discoveredWidget = new DiscoveredWidget&lt;br /&gt;
                 (iDeviceFactory,&lt;br /&gt;
                  newUdn,&lt;br /&gt;
                  aSimpleUpnpWidget,&lt;br /&gt;
                  iWidgetPublisher);&lt;br /&gt;
 &lt;br /&gt;
             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                 discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                 discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                 discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary = &lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in OpenHome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by OpenHome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh - A collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs on ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The OpenHome Operating System. Core software for OpenHome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. &lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. A typical Widget supports only one protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Driver_Development</id>
		<title>OhWidget Driver Development</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Driver_Development"/>
				<updated>2012-03-01T15:16:09Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Related Documents */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for developers using the OpenHome SDK to integrate a Widget into an OpenHome system. Each Widget must have its own driver to allow it to communicate with the OpenHome Nodes. &lt;br /&gt;
&lt;br /&gt;
To help you write your driver, this document provides high level descriptions of the core responsibilities of a Widget driver and gives a detailed walk-through using example code.&lt;br /&gt;
&lt;br /&gt;
Full versions of each file used in the development of the example driver are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin development of your Widget driver you must be in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* your Widget Service XML that describes the properties on your Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document does not contain advice on how to write Widget Service XML. Refer to the OpenHome Widget Service XML definition document for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK&lt;br /&gt;
* your chosen communication protocol's API&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The protocol you choose for your Widgets must be the same protocol used on your choice of Node.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document focuses on the development of the Widget driver. Details about the communications protocol used are beyond the scope of this document. This document assumes you are familiar with your chosen protocol's code libraries and are able to use them in the driver code you write.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Related Documents ==&lt;br /&gt;
&lt;br /&gt;
The following related OpenHome documentation may be of interest to you:&lt;br /&gt;
&lt;br /&gt;
* [[ohWidget Technical Overview|ohWidget Technical Overview]]&lt;br /&gt;
* [[OpenHome Widget Service XML definition|OpenHome Widget Service XML definition]]&lt;br /&gt;
* [http://www.openhome.org/releases/ohNet_DeviceStack.pdf  OpenHome ohNet Device Stack]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
None of the related documents listed above is mandatory reading for Widget driver development.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
== Widget Service XML ==&lt;br /&gt;
OpenHome Widget driver writing relies heavily on the use of code generated from a single source — the Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
The service and actions your Widget provides are represented in code in a file called a Provider. The Provider is automatically generated from the Widget Service XML and produces an abstract class for you to inherit when you write your concrete class driver.&lt;br /&gt;
&lt;br /&gt;
To aid in the explanation of how the Provider is created and put to use we will follow the development of&lt;br /&gt;
a driver for a simple light Widget; taking the defined Widget Service XML and stepping through how it is used to generate the other files. Examples of code are used throughout this document to show you how each one is created and used in an OpenHome system. &lt;br /&gt;
&lt;br /&gt;
It is essential that you start with a well-formed Widget Service XML, conforming to the schema defined&lt;br /&gt;
in the WidgetService.xsd. The following diagram shows the significance of the Widget Service XML in&lt;br /&gt;
relation to the generated files you will use when writing your driver:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarchy, highlighting the areas specifically used in driver development]]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* The grayed-out files are not relevant to Widget driver development but can also be generated from the Widget Service XML.&lt;br /&gt;
* The Provider is generated in C#, meaning your driver must be written in C# as well. The use of managed code is mandatory for driver writing in the OpenHome framework.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Code sample used in this document ==&lt;br /&gt;
&lt;br /&gt;
Our examples in this document use a Widget Service XML definition for a light Widget called&lt;br /&gt;
BasicLight.xml.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Full versions of all the example files used in this document are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We will see how the Provider is generated from this XML and how it is used to aid the driver writing process. The examples also show how your chosen communication protocol should be used in the body of the driver code.&lt;br /&gt;
&lt;br /&gt;
Implementation details of specific protocols you choose to use are beyond the scope of this document. However, the samples used in this document show the use of the SimpleUPnP protocol to aid you in your development process.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol during the early stages of the OpenHome project. It is included in the OpenHome SDK and can be used as a public resource. &lt;br /&gt;
&lt;br /&gt;
The use of SimpleUPnP in the example files and the code snippets within the following sections is highlighted by the [[File:Warning.png]] icon. The lines of code marked by [[File:Warning.png]] must be changed to code from your chosen communication protocol's library. SimpleUPnP is left in to help you understand how a protocol is used in a working example.&lt;br /&gt;
&lt;br /&gt;
The sample code provided attempts to show best-practice coding standards. There are several sections of code that have a mandatory layout or that call specifically named methods and functions. These areas of the code are highlighted where required. &lt;br /&gt;
&lt;br /&gt;
Where the examples do not explicitly state that the code shown is mandatory, you are free to implement it in a different way according to your own coding style and practices.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Driver responsibilities = &lt;br /&gt;
&lt;br /&gt;
== Driver responsibilities ==&lt;br /&gt;
&lt;br /&gt;
An OpenHome Widget driver has several responsibilities which must be met before it can be used on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
These responsibilities are listed R1 to R7 and are defined here, explaining what each one must do. &lt;br /&gt;
&lt;br /&gt;
=== R1 Specifying the type of Widget the driver controls ===&lt;br /&gt;
A driver must know which type of Widget it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
=== R2 Reacting to a discovered Widget on the network ===&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== R3 Setting the initial values for the Widget's properties ===&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
=== R4 Publishing discovered Widgets in the Local Widget Registry on the Node ===&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object.&lt;br /&gt;
&lt;br /&gt;
=== R5 Reacting to an event reported from the Widget ===&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
=== R6 Reacting to actions sent to the Widget ===&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== R7 Reacting to a Widget's departure ===&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no&lt;br /&gt;
longer available.&lt;br /&gt;
&lt;br /&gt;
The sections of example code that follow show you how to write a driver from beginning to end. The accompanying text explaining the example code highlights when a responsibility, or part of a responsibility, has been met.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Driver Architecture = &lt;br /&gt;
&lt;br /&gt;
== Driver Architecture ==&lt;br /&gt;
&lt;br /&gt;
Drivers are installed on the Node and used when the Node needs to communicate with the Widget. Drivers&lt;br /&gt;
use several objects to communicate with Widgets over the Widget's lifetime. Figure 2 shows the objects&lt;br /&gt;
used by the driver and how the responsibilities listed above relate to each one:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture.png|800px|thumb|center|Figure 2: The architecture of a driver, showing the driver's relationship to the objects used to communicate with a Widget. Lines between objects show message flow.]]&lt;br /&gt;
&lt;br /&gt;
The objects contained in the dotted boundary must appear in the code you write to define your driver. The Driver, Provider and IWidgetRegistryEntry objects are all contained in the same driver file. We begin discussing this on page 12. &lt;br /&gt;
&lt;br /&gt;
The other objects are provided by the OpenHome SDK or as installed components on the Node.&lt;br /&gt;
&lt;br /&gt;
The Discovery Module informs the driver of the presence of an available Widget.&lt;br /&gt;
&lt;br /&gt;
Each Node has a Protocol Module which contains the protocol's API. Widgets can communicate with OpenHome Nodes using any one of the set of communications protocols the Node supports. The driver uses your chosen protocol's Protocol Module to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
Both the Protocol Module and the Discovery Module are installed on the Node. When you write your&lt;br /&gt;
driver you will use your Protocol Module to allow the driver to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
IWidgetPublisher, IPublishedWidget and DvDevice are objects provided in the OpenHome&lt;br /&gt;
API. You can read about them in the APIs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Generating the Provider = &lt;br /&gt;
&lt;br /&gt;
== Generating the Provider ==&lt;br /&gt;
&lt;br /&gt;
You must generate your provider before you can begin writing your Widget driver. You use your provider as a guide to implement the functions your Widget needs to set the values of its properties.&lt;br /&gt;
&lt;br /&gt;
The current provider generation process is a manual one involving the use of a text transform tool.&lt;br /&gt;
&lt;br /&gt;
Speak to your OpenHome contact who will help you generate your provider.&lt;br /&gt;
&lt;br /&gt;
Future releases of the OpenHome SDK will include a tool to help you generate the provider.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
You must be in possession of:&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK, unpacked on your computer&lt;br /&gt;
* your Widget Service XML file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Writing a SimpleUPnP driver = &lt;br /&gt;
&lt;br /&gt;
== Introduction to the SimpleUPnP protocol ==&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol used to control emulated Widgets over a custom UPnP service.&lt;br /&gt;
&lt;br /&gt;
This chapter shows how a driver is written using the SimpleUPnP communications protocol. The aim is to show the code using as generic a protocol as possible so that you can see where your own protocol specific code needs to go.&lt;br /&gt;
&lt;br /&gt;
The use of code specific to the SimpleUPnP implementation is highlighted by the use of the [[File:Warning.png]] icon. The lines of code are marked by this icon to make it easier for you to see where the protocol-specific code must go and what parts of the code are generic.&lt;br /&gt;
&lt;br /&gt;
=== Register model ===&lt;br /&gt;
&lt;br /&gt;
SimpleUPnP is modeled on 8 physical registers available on the Widget. Each register is 32-bits wide. They are indexed from 0 to 7 and the last register (register 7) is reserved for storing the Widget's class.&lt;br /&gt;
&lt;br /&gt;
This detail is used by the Protocol Module on the Node to determine which driver is needed to run the new Widget when it has been discovered.&lt;br /&gt;
&lt;br /&gt;
The remaining 7 registers (registers 0 to 6) are free for Widget engineers to assign to the Widget's functions.&lt;br /&gt;
&lt;br /&gt;
Registers 0, 1, 2 and 3 are available as read/write registers. Registers 4, 5 and 6 are readonly registers.&lt;br /&gt;
&lt;br /&gt;
Only the emulated hardware (running on the Node) can change the values held in registers 4, 5 and 6.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Register use in drivers ===&lt;br /&gt;
&lt;br /&gt;
In the example that follows we have a Basic Light Widget with a very simple function: it can be turned on and turned off. The on/off value is stored in register 0, with values 0=OFF and 1=ON. Register 0 is a read/write register. This means we can change the value stored there using messages passed to the Widget from the Node, and by reacting to physical interactions at the Widget (such as someone manually switching the light on or off). &lt;br /&gt;
&lt;br /&gt;
The mapping of registers to properties on the Widget is decided by the engineers who manufacture the device. You must be provided with the mapping before you begin developing your driver.&lt;br /&gt;
&lt;br /&gt;
== Starting the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-BoxHighlight.png|800px|thumb|center|Figure 3 The driver architecture highlighting the Widget driver and its component parts.]]&lt;br /&gt;
&lt;br /&gt;
When you have generated the abstract provider you can put it to use in the Widget driver. A Widget driver&lt;br /&gt;
has three distinct components:&lt;br /&gt;
&lt;br /&gt;
* an implementation of your abstract provider&lt;br /&gt;
* a definition of the Widget driver&lt;br /&gt;
* an implementation of the IWidgetRegistryEntry interface&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must manually write the code for your Widget driver. The differences in implementation of Widget properties and communication protocols means that the driver code cannot be autogenerated.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This section takes you through how to write a Widget driver by implementing the auto-generated provider,&lt;br /&gt;
starting from a new blank file and finishing with a working driver for the Basic Light Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
No assumptions have been made about the type of editor you use to write your code. Shortcuts&lt;br /&gt;
or macros that you use as standard will not appear in the instructions below. A full example&lt;br /&gt;
BinaryLightDriver.cs is available to review in Appendix C.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a new C# file in your IDE. Ensure the following libraries are used:&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 [[File:Warning.png]]using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 namespace OpenHome.Widget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must use the libraries listed above for this specific example.&lt;br /&gt;
&lt;br /&gt;
In general, drivers require the following libraries:&lt;br /&gt;
* System*&lt;br /&gt;
* System.Collections.Generic*&lt;br /&gt;
* OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
&lt;br /&gt;
Your driver will fail to compile if you miss any of these listed libraries. Libraries marked * are typically added by default by most modern IDEs. &lt;br /&gt;
&lt;br /&gt;
The OpenHome.Widget.Protocols.SimpleUpnp library is required only in this SimpleUPnP example. Drivers using a different protocol will use their own protocol library.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Implementing the provider ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-ProviderHighlight.png|800px|thumb|center|Figure 4 The driver architecture highlighting the Provider's place]]&lt;br /&gt;
&lt;br /&gt;
You use your auto-generated abstract provider by writing an implementation of it in the driver file. Responsibilities met by implementing your auto-generated provider are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R6 Reacting to actions sent to the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
Begin by creating a new class. It will subclass the abstract auto-generated provider:&lt;br /&gt;
&lt;br /&gt;
 class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
The Protocol Module will provide an API for the Provider to use to communicate with the Widget. In&lt;br /&gt;
SimpleUPnP we are provided with an interface called ISimpleUpnpWidget. The provider is supplied&lt;br /&gt;
with the required instance of the interface by the Discovery Module on the Node.&lt;br /&gt;
&lt;br /&gt;
The mechanisms for registering providers with specific Protocol Modules, and for the way the module gives each provider its required interface are covered later when writing the discovery method.&lt;br /&gt;
&lt;br /&gt;
For now, we need to give the Provider a place to store the interface that it will later use to communicate&lt;br /&gt;
with the Widget:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]] private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
&lt;br /&gt;
The interface from the Protocol Module is passed in as a parameter in the Provider's constructor and then&lt;br /&gt;
assigned to the variable we just created:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightProvider(DvDevice aDevice,&lt;br /&gt;
 [[File:Warning.png]]         ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
 {&lt;br /&gt;
       iProtocol = aProtocol;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
To satisfy R3 we would normally set the Widget's properties here, giving them an initial value.&lt;br /&gt;
However, in this specific example we cannot set the value of Basic Light's only property because&lt;br /&gt;
we will never know, in advance, what the state of the light will be (either on or off) when we&lt;br /&gt;
create the DiscoveredWidget.&lt;br /&gt;
&lt;br /&gt;
When you cannot set the properties ahead of time, and you are using an eventing protocol like SimpleUPnP, you can instead set them in the HandleRegisterEvent method in the driver class. This also satisfies the requirements for R3. You must set the Widget's properties before you enable it using SetEnabled(). &lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The abstract provider includes an abstract method called SetOn. This method is invoked by the Node when passing a message to the Widget, specifically to set the on property of the Widget to either 0 or 1. The implementation of this method will meet the requirements for R6.&lt;br /&gt;
&lt;br /&gt;
We must override this method and provide the protocol module a way of passing a message on to the Widget to perform the required action, in this case turn the light on or off:&lt;br /&gt;
&lt;br /&gt;
          protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
          {&lt;br /&gt;
     [[File:Warning.png]]        iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
In this example the Basic Light's SetOn property (the boolean property that controls whether the light is&lt;br /&gt;
on or off) is represented in the physical Widget by the register that has an index of 0.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* This method is an example of an action on a Widget. Actions are messages sent from the Node to the Widget. We will see later how to handle events that need to be passed back from the Widget&lt;br /&gt;
to the Node.&lt;br /&gt;
* Your own Widget will likely provide more than a single property. Your auto-generated provider will contain one abstract method to represent each writable property. Read-only properties are not provided an abstract method.&lt;br /&gt;
&lt;br /&gt;
You must implement each abstract method in your driver to ensure the relevant property on&lt;br /&gt;
the Widget can be set.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We have now finished implementing the provider. The next step is to implement the driver.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Implementing the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-DriverHighlight.png|800px|thumb|center|Figure 4: The driver architecture highlighting the implemented driver's place.]]&lt;br /&gt;
&lt;br /&gt;
The code for your Widget driver must provide an implementation of the IWidgetRegistryInterface,&lt;br /&gt;
including the following tasks:&lt;br /&gt;
&lt;br /&gt;
* methods to expose identifying details about the Widget for the Node to access&lt;br /&gt;
* providing methods to handle events reported by the Widget&lt;br /&gt;
&lt;br /&gt;
The driver is implemented as a public class within the same file as the provider code. Each driver must use the interface for the protocol you are using. For the SimpleUPnP protocol the interface is ISimple-UpnpWidgetDriver.&lt;br /&gt;
&lt;br /&gt;
=== Writing code ===&lt;br /&gt;
&lt;br /&gt;
Create your new driver class and subclass the ISimpleUpnpWidgetDriver interface:&lt;br /&gt;
&lt;br /&gt;
 public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Implementing IWidgetRegistryEntry ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry is the interface you use to represent physical Widgets. It is implemented as a subclass of your driver class. We are going to implement this interface in a class called '''DiscoveredWidget'''.&lt;br /&gt;
&lt;br /&gt;
Let's return to our driver architecture diagram for a moment:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-IRegistryEntryHighlight.png|800px|thumb|center|Figure 5 The driver architecture highlighting the IWidgetRegistryEntry object you will now implement]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry uses several other objects to help create it and respond to messages sent to and from it. These objects will be created in our implementation of DiscoveredWidget. &lt;br /&gt;
&lt;br /&gt;
When successfully created and published, the DiscoveredWidget objects are stored in a list on the Node called the Local Widget Registry. The Local Widget Registry is used by Nodes to maintain contact with the Widgets they control.&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry is shown at the top of Figure 5, marked plainly as (Registry). The path to the Local Widget Registry goes through several layers of Node architecture which are not relevant to Widget driver writing, so are not shown in the diagrams.&lt;br /&gt;
&lt;br /&gt;
==== Writing code ====&lt;br /&gt;
&lt;br /&gt;
Start by subclassing the IWidgetRegistryEntry interface in your new class:&lt;br /&gt;
&lt;br /&gt;
      private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
      {&lt;br /&gt;
&lt;br /&gt;
A DiscoveredWidget must provide the driver with the objects required to present the Widget and its&lt;br /&gt;
properties to the Node:&lt;br /&gt;
&lt;br /&gt;
           private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
           private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
           private readonly ISimpleUpnpWidget iProtocol;&lt;br /&gt;
           private readonly BinaryLightProvider iProvider;&lt;br /&gt;
           private readonly DvDevice iDvDevice;&lt;br /&gt;
           private IPublishedWidget iPublishedWidget;&lt;br /&gt;
&lt;br /&gt;
Each of the attributes in the example above are defined as follows:&lt;br /&gt;
&lt;br /&gt;
iDeviceFactory — used by the driver to create a single instance of DvDevice to represent a single Widget&lt;br /&gt;
&lt;br /&gt;
iPublisher — used by the driver to publish the Widget to the Node&lt;br /&gt;
&lt;br /&gt;
iProtocol — the object used by the Widget to communicate with the Protocol Module on the Node&lt;br /&gt;
&lt;br /&gt;
iProvider — an instantiated provider of the type you defined earlier&lt;br /&gt;
&lt;br /&gt;
iDvDevice — a representation of a Widget to which the provider is attached, created using iDevice-Factory above&lt;br /&gt;
&lt;br /&gt;
iPublishedWidget — used to contain the returned object from a successful publishing of the Widget&lt;br /&gt;
If we look again at the driver architecture diagram, we ca highlight the objects we've just defined:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-Highlight.png|800px|thumb|center|Figure 6: The driver architecture highlighting the objects used by the IWidgetRegistryEntry implementation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The DeviceFactory, defined above in the member variable iDeviceFactory, is used to create new DvDevice objects. The DeviceFactory is only ever used to do this once. It is not shown in the driver architecture diagrams due to its minimal role in the operation of a driver, but it would normally appear between the IWidgetRegistryEntry and DvDevice objects.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
A driver requires methods to expose identifying details about the Widget. We must provide access to two of the attributes we just defined above:&lt;br /&gt;
&lt;br /&gt;
 public DvDevice DvDevice&lt;br /&gt;
 {&lt;br /&gt;
     get { return iDvDevice; }&lt;br /&gt;
 }&lt;br /&gt;
 public string WidgetClass&lt;br /&gt;
 {&lt;br /&gt;
     get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The WidgetClass string is formed using a combination of the vendor name and the Widget's name in the&lt;br /&gt;
format:&lt;br /&gt;
&lt;br /&gt;
 [vendor_domain]:[widget_name]&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry can now query both the DvDevice object representing the Widget, and the specific class of Widget this driver represents. The other member variables we defined do not need their own accessor methods.&lt;br /&gt;
&lt;br /&gt;
Now we must write a constructor for DiscoveredWidget and assign the parameters accordingly: &lt;br /&gt;
&lt;br /&gt;
 public DiscoveredWidget(IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                            string aUdn,&lt;br /&gt;
                            ISimpleUpnpWidget aProxy,&lt;br /&gt;
                            IWidgetPublisher aPublisher)&lt;br /&gt;
 {&lt;br /&gt;
      iDeviceFactory = aDeviceFactory;&lt;br /&gt;
      iProtocol = aProtocol;&lt;br /&gt;
      iPublisher = aPublisher;&lt;br /&gt;
      iDvDevice = iDeviceFactory.CreateDevice(aUdn);&lt;br /&gt;
      iProvider = new BinaryLightProvider(iDvDevice,&lt;br /&gt;
      iProtocol);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Event handling ===&lt;br /&gt;
&lt;br /&gt;
A Widget's state can change in one of three significant ways:&lt;br /&gt;
&lt;br /&gt;
* when the Widget needs to be published on the Node&lt;br /&gt;
* when the Widget disappears from the network (by losing power or similar)&lt;br /&gt;
* when a property's state changes and must be updated to a new value&lt;br /&gt;
&lt;br /&gt;
We now need methods to handle these changes.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The methods we define here will be used as callbacks, rather than invoked as method calls. We define the methods here first and then use them later on. We will use the Protocol Module to listen for changes in the Widget's state and register these methods as callbacks there. See Writing the SimpleUPnP Widget discovery method for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this section of the driver are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R4 Publishing discovered Widgets in the Local Widget Registry on the Node'''&lt;br /&gt;
&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object. &lt;br /&gt;
&lt;br /&gt;
'''R5 Reacting to an event reported from the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
'''R7 Reacting to a Widget's departure'''&lt;br /&gt;
&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no longer available.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Enabling and publishing a discovered Widget ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first method initializes the Widget by enabling the device and then using the IWidgetPublisher&lt;br /&gt;
to make it available on the Node:&lt;br /&gt;
&lt;br /&gt;
 public void HandleInitialEvent()&lt;br /&gt;
 {&lt;br /&gt;
      iDvDevice.SetEnabled();&lt;br /&gt;
      iPublisher.TryPublishWidget(iDvDevice.iUdn(),&lt;br /&gt;
                              this,&lt;br /&gt;
                              out iPublishedWidget);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This method meets the requirements for R4.&lt;br /&gt;
&lt;br /&gt;
The call to TryPublishWidget returns an iPublishedWidget object. We use this object later to satisfy the requirements of R7.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The ordering of the calls to SetEnabled and TryPublishWidget is vitally important. You&lt;br /&gt;
must enable the device before you attempt to publish it. Your Widget will not be available to the&lt;br /&gt;
Nodes unless SetEnabled is called first. Nodes will not be able to access a published device&lt;br /&gt;
that has not been enabled.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
R3 requires that you set the Widget's properties before you enable and publish the device. We&lt;br /&gt;
discussed on page 14 how some properties can only be set after the Widget reports what their&lt;br /&gt;
state is. We do this in HandleRegisterEvent.&lt;br /&gt;
&lt;br /&gt;
We rely on the SimpleUPnP Protocol Module guaranteeing a call to HandleRegisterEvent first before HandleInitialEvent. This is informed by guarantees made by the Control Point stack that the calls will be made in that order.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
==== Removing a Widget ====&lt;br /&gt;
&lt;br /&gt;
Removing a Widget involves unpublishing it from the Node. The IPublishedWidget interface provides us with a method we can call to manage that for us:&lt;br /&gt;
&lt;br /&gt;
 public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
 {&lt;br /&gt;
     if (iPublishedWidget != null)&lt;br /&gt;
     { iPublishedWidget.Unpublish(); }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assuming that the Widget was successfully published earlier, it is removed from the Node's Local Widget Registry.&lt;br /&gt;
&lt;br /&gt;
We must also properly handle the resources we used to create and maintain the Widget object while it was published:&lt;br /&gt;
&lt;br /&gt;
      iProvider.Dispose();&lt;br /&gt;
      iDvDevice.Dispose();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The calls to Dispose are made regardless of the Widget's published state, ensuring that any created device and associated provider are properly disposed. This implementation satisfies R7.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Event handling ====&lt;br /&gt;
&lt;br /&gt;
We need a method to handle changes to the state of the Widget's properties.&lt;br /&gt;
&lt;br /&gt;
If the property changes at the Widget, it needs to pass the new state back to the Node so that it is kept up-to-date on the Widget's status. This is called an event. An example in the case of our Basic Light is someone manually switching the light from on to off. This is in contrast to actions, which are passed from the Node to the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Other examples of events involve no human interaction, such as a thermometer Widget updating its current temperature based on environmental changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Our Basic Light Widget has only one property that needs to be handled:&lt;br /&gt;
&lt;br /&gt;
 public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
 {&lt;br /&gt;
     if (aIndex == 0)&lt;br /&gt;
     {&lt;br /&gt;
         iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We use our instance of the provider to update the register on the Widget that is mapped to the On property. This in turn updates the Node with the new state of the Widget.&lt;br /&gt;
&lt;br /&gt;
This method provides implementations to satisfy two driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
* R3 is now completely satisfied, as we can now set the values of all the previously unknown properties here.&lt;br /&gt;
* R5 is also satisfied as this method allows us to update the Widget's status on the Node when a property is changed on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Not all protocols pass messages back to the Node in this manner. The way we have satisfied R3 and R5 here only applies to protocols and Widgets that support this behavior.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Widgets that do not use an eventing protocol need to have their properties set in the provider's constructor to satisfy R3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To satisfy R5, the over-ridden method SetOn in the provider must include the call to SetPropertyOn. Non-eventing protocols do not require a HandleRegisterEvent method.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Constructor ===&lt;br /&gt;
&lt;br /&gt;
The final requirement for the driver is the constructor so that new DiscoveredWidget objects can be created. &lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this area of code are:&lt;br /&gt;
&lt;br /&gt;
'''R1 Specifying the type of Widget the driver controls'''&lt;br /&gt;
&lt;br /&gt;
A driver must know which type of Widget that it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Writing the code ====&lt;br /&gt;
&lt;br /&gt;
We begin by defining the variables we will use to store the objects used by the driver:&lt;br /&gt;
&lt;br /&gt;
 private readonly string iName;&lt;br /&gt;
 private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
 private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now write the constructor for the driver and assign the passed in parameters appropriately:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightDriver(string aName,&lt;br /&gt;
                IWidgetPublisher aPublisher,&lt;br /&gt;
                IDvDeviceFactory aDeviceFactory)&lt;br /&gt;
 {&lt;br /&gt;
     iWidgetPublisher = aPublisher;&lt;br /&gt;
     iName = aName;&lt;br /&gt;
     iDeviceFactory = aDeviceFactory;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally we need to provide the driver a way to publish the class of Widget it controls. This information is requested by the Discovery Module and is used to ensure the Node uses the correct driver when a new Widget appears.&lt;br /&gt;
&lt;br /&gt;
The implementation for this details will be different for each protocol. The SimpleUPnP protocol library provides a file that contains the SimpleUPnP definitions as integers. Each integer represents a particular class of identified Widget.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP implementation of that method is as follows:&lt;br /&gt;
&lt;br /&gt;
 public IEnumerable&amp;lt;uint&amp;gt; WidgetClasses&lt;br /&gt;
 {&lt;br /&gt;
 [[File:Warning.png]]        get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The body of this method is specifically written for the Widget class we are defining (in this case a binary light). This method completes the driver's requirements for R1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Writing the SimpleUPnP Widget discovery method ==&lt;br /&gt;
&lt;br /&gt;
Every driver must contain a method which creates new objects to represent newly discovered Widgets.&lt;br /&gt;
The Discovery Module invokes this method to begin the process of creating the objects required to allow the Node to access the Widget. &lt;br /&gt;
&lt;br /&gt;
The name of this method is dictated by your chosen protocol's API. The SimpleUPnP protocol requires a method called WidgetDiscovered.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The method's name will not always be the same for each protocol. Your protocol's documentation will contain the details of what this method must be called.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This method and its implementation will meet the following driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
'''R2 Reacting to a discovered Widget on the network'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
Our implementation of the WidgetDiscovered method will create a new DiscoveredWidget object and use the Protocol Module to listen for changes to the Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
The method uses the Protocol Module and two ways to identify the Widget. We must pass these in as&lt;br /&gt;
parameters:&lt;br /&gt;
&lt;br /&gt;
 public void WidgetDiscovered(string aWidgetUdn,&lt;br /&gt;
                              uint aWidgetClass,&lt;br /&gt;
                              ISimpleUpnpWidget&lt;br /&gt;
                                  aSimpleUpnpWidget)&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
Every Widget that uses this driver must be uniquely identifiable:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]    string newUdn = aWidgetUdn;&lt;br /&gt;
&lt;br /&gt;
Each new Widget is represented by a DiscoveredWidget object. Create the new DiscoveredWidget and pass in the required parameters we created earlier:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
     DiscoveredWidget discoveredWidget =&lt;br /&gt;
                 new DiscoveredWidget(iDeviceFactory,&lt;br /&gt;
                                      newUdn,&lt;br /&gt;
  &lt;br /&gt;
 [[File:Warning.png]]                                    aSimpleUpnpWidget,&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Registering the callbacks ===&lt;br /&gt;
&lt;br /&gt;
Finally, we ask the Widget's protocol interface to listen for calls to the handler methods we defined earlier in DiscoveredWidget. We do this by registering those methods as callbacks for the Protocol Module&lt;br /&gt;
to listen for:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                        discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                        discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                        discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You have now met 100% of the driver responsibility requirements and have a working driver to use with your SimpleUPnP Widget.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix A. Sample XML =&lt;br /&gt;
&lt;br /&gt;
== Binary Light.xml ==&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
  &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
  &amp;lt;version&amp;gt;&lt;br /&gt;
   &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
   &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/version&amp;gt;&lt;br /&gt;
  &amp;lt;propertylist&amp;gt;&lt;br /&gt;
   &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
       illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
   &amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix B. Sample Provider = &lt;br /&gt;
&lt;br /&gt;
== DvWidgetOpenhomeOrgBasicLight1.cs ==&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Runtime.InteropServices;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Core;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Utils.Binary;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
 {&lt;br /&gt;
    public interface IDvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
        IDisposable&lt;br /&gt;
    {&lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous value&lt;br /&gt;
        /// &amp;lt;/returns&amp;gt;&lt;br /&gt;
        bool SetPropertyOn(bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;Property's value will be copied&lt;br /&gt;
        /// here&amp;lt;/param&amp;gt;&lt;br /&gt;
        bool PropertyOn();&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt; summary&amp;gt;&lt;br /&gt;
    /// Provider for the openhome.org:BinaryLight:1 UPnP service&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public abstract class DvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
               DvProvider,&lt;br /&gt;
               IDisposable,&lt;br /&gt;
               IDvProviderOpenhomeOrgBinaryLight1&lt;br /&gt;
    {&lt;br /&gt;
        private GCHandle iGch;&lt;br /&gt;
        private PropertyBool iPropertyOn;&lt;br /&gt;
        private PropertyUint iPropertyPrimarySeq;&lt;br /&gt;
        private PropertyUint iPropertySecondarySeq;&lt;br /&gt;
        private ActionDelegate iDelegateSetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetPrimaryProperty;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Constructor&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aDevice&amp;quot;&amp;gt;Device which owns this&lt;br /&gt;
        /// provider&amp;lt;/param&amp;gt;&lt;br /&gt;
        protected DvProviderOpenhomeOrgBinaryLight1(DvDevice aDevice)&lt;br /&gt;
            : base(aDevice, &amp;quot;openhome.org&amp;quot;, &amp;quot;GenericWidget&amp;quot;, 1)&lt;br /&gt;
        {&lt;br /&gt;
            iGch = GCHandle.Alloc(this);&lt;br /&gt;
            List&amp;lt;String&amp;gt; allowedValues = new List&amp;lt;String&amp;gt;();&lt;br /&gt;
            iPropertyOn = new PropertyBool(new ParameterBool(&amp;quot;On&amp;quot;));&lt;br /&gt;
            iPropertyPrimarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;PrimarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertyPrimarySeq);&lt;br /&gt;
            iPropertySecondarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;SecondarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertySecondarySeq);&lt;br /&gt;
            SetPropertyUint(iPropertyPrimarySeq, 0);&lt;br /&gt;
            SetPropertyUint(iPropertySecondarySeq, 0);&lt;br /&gt;
  &lt;br /&gt;
            Zapp.Core.Action action = new Zapp.Core.Action&lt;br /&gt;
                (&amp;quot;SetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;FireAndForget&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddInputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateSetProperty = new ActionDelegate(DoSetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateSetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateGetProperty = new ActionDelegate(DoGetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetPrimaryProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                 (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;integer&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;boolean&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;string&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;binary&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Type&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;readWrite&amp;quot;);allowedValues.Add&lt;br /&gt;
                (&amp;quot;readOnly&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;writeOnly&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString(&amp;quot;Access&amp;quot;,&lt;br /&gt;
                allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            iDelegateGetPrimaryProperty = new&lt;br /&gt;
            ActionDelegate(DoGetPrimaryProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetPrimaryProperty,&lt;br /&gt;
            GCHandle.ToIntPtr(iGch));&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous&lt;br /&gt;
        /// value&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool SetPropertyOn(bool aValue)&lt;br /&gt;
        {&lt;br /&gt;
            if (iPropertyOn.SetValue(aValue))&lt;br /&gt;
            {&lt;br /&gt;
                lock (iPropertyPrimarySeq)&lt;br /&gt;
                {&lt;br /&gt;
                    SetPropertyUint(iPropertyPrimarySeq,&lt;br /&gt;
                        iPropertyPrimarySeq.Value() + 1);&lt;br /&gt;
                } return true;&lt;br /&gt;
            } return false;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;The value of the property&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool PropertyOn()&lt;br /&gt;
        {&lt;br /&gt;
            return iPropertyOn.Value();&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the On property.&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aVersion&amp;quot;&amp;gt;Version of the service being&lt;br /&gt;
        /// requested (will be &amp;lt;= the version advertised)&amp;lt;/param&amp;gt; &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the On property.&lt;br /&gt;
        /// &amp;lt;/param&amp;gt;&lt;br /&gt;
        protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        private static int DoSetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                byte[] valBin = invocation.ReadBinary(&amp;quot;Value&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                switch (name)&lt;br /&gt;
                {&lt;br /&gt;
                    case &amp;quot;On&amp;quot;:&lt;br /&gt;
                        self.SetOn(aVersion, Converter.&lt;br /&gt;
                            BinaryToBoolean(valBin));&lt;br /&gt;
                        break;&lt;br /&gt;
                    default:&lt;br /&gt;
                        throw new ActionError();&lt;br /&gt;
                }&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
                invocation.WriteEnd();&lt;br /&gt;
            }&lt;br /&gt;
            catch (ActionError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
            catch (PropertyUpdateError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
        return 0;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        private static int DoGetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
            switch (name)&lt;br /&gt;
            {&lt;br /&gt;
                case &amp;quot;On&amp;quot;:&lt;br /&gt;
                invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                    Converter.BooleanToBinary(self.iPropertyOn.&lt;br /&gt;
                        Value()));&lt;br /&gt;
                break;&lt;br /&gt;
                default:&lt;br /&gt;
                throw new ActionError();&lt;br /&gt;
            }&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    private static int DoGetPrimaryProperty(IntPtr aPtr,&lt;br /&gt;
                    IntPtr aInvocation,&lt;br /&gt;
                    uint aVersion)&lt;br /&gt;
    {&lt;br /&gt;
        GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
        DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
            (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
        DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
  &lt;br /&gt;
        try&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReadStart();&lt;br /&gt;
            invocation.ReadEnd();&lt;br /&gt;
            invocation.WriteStart();&lt;br /&gt;
            invocation.WriteString(&amp;quot;Name&amp;quot;, &amp;quot;On&amp;quot;);&lt;br /&gt;
            invocation.WriteString(&amp;quot;Type&amp;quot;, &amp;quot;boolean&amp;quot;);&lt;br /&gt;
            invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                Converter.BooleanToBinary(self.iPropertyOn.Value()));&lt;br /&gt;
            invocation.WriteString(&amp;quot;Access&amp;quot;, &amp;quot;readWrite&amp;quot;);&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt;summary&amp;gt;&lt;br /&gt;
    /// Must be called for each class instance. Must be called before&lt;br /&gt;
    /// Core.Library.Close().&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public void Dispose()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
        GC.SuppressFinalize(this);&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
    ~DvProviderOpenhomeOrgBinaryLight1()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
        private void DoDispose()&lt;br /&gt;
        {&lt;br /&gt;
            lock (this)&lt;br /&gt;
            {&lt;br /&gt;
                if (iHandle == IntPtr.Zero)&lt;br /&gt;
            {&lt;br /&gt;
                    return;&lt;br /&gt;
            }&lt;br /&gt;
            DisposeProvider();&lt;br /&gt;
            iPropertyOn.Dispose();&lt;br /&gt;
            iHandle = IntPtr.Zero;&lt;br /&gt;
            }&lt;br /&gt;
            iGch.Free();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix C. Sample Driver = &lt;br /&gt;
&lt;br /&gt;
== BasicLightDriver.cs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.hWidget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
     class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
     {&lt;br /&gt;
         private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
         public BinaryLightProvider(DvDevice aDevice, &lt;br /&gt;
             ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol = aProtocol;&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
     {&lt;br /&gt;
         private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
         {&lt;br /&gt;
             private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
             private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
             private readonly ISimpleUpnpWidget iProtocol; &lt;br /&gt;
 &lt;br /&gt;
             private readonly BinaryLightProvider iProvider;&lt;br /&gt;
             private readonly DvDevice iDvDevice;&lt;br /&gt;
             private IPublishedWidget iPublishedWidget; &lt;br /&gt;
 &lt;br /&gt;
             public DvDevice DvDevice&lt;br /&gt;
             {&lt;br /&gt;
                 get { return iDvDevice; }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             public string WidgetClass&lt;br /&gt;
             {&lt;br /&gt;
                 get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public DiscoveredWidget(&lt;br /&gt;
                 IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                 string aUdn,&lt;br /&gt;
                 ISimpleUpnpWidget aProxy,&lt;br /&gt;
                 IWidgetPublisher aPublisher)&lt;br /&gt;
             {&lt;br /&gt;
                 iDeviceFactory = aDeviceFactory;&lt;br /&gt;
                 iProtocol = aProtocol;&lt;br /&gt;
 &lt;br /&gt;
                 iPublisher = aPublisher;&lt;br /&gt;
                 iDvDevice = iDeviceFactory.CreateDevice(aUdn);  &lt;br /&gt;
                 iProvider = new BinaryLightProvider(iDvDevice, &lt;br /&gt;
                                                     iProtocol);&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             public void HandleInitialEvent()&lt;br /&gt;
             {&lt;br /&gt;
                 iDvDevice.SetEnabled();&lt;br /&gt;
                 iPublisher.TryPublishWidget(iDvDevice.iUdn(), this,&lt;br /&gt;
                     out iPublishedWidget);&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
             {&lt;br /&gt;
                 if (iPublishedWidget != null)&lt;br /&gt;
                 {&lt;br /&gt;
                     iPublishedWidget.Unpublish();&lt;br /&gt;
                 } &lt;br /&gt;
                 iProvider.Dispose();&lt;br /&gt;
                 iDvDevice.Dispose();&lt;br /&gt;
             }  &lt;br /&gt;
 &lt;br /&gt;
             public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
             {&lt;br /&gt;
                 if (aIndex == 0)&lt;br /&gt;
                 {&lt;br /&gt;
                     iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         private readonly string iName;&lt;br /&gt;
         private readonly IDvDeviceFactory aDeviceFactory;&lt;br /&gt;
         private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
         &lt;br /&gt;
         public BinaryLightDriver(&lt;br /&gt;
             string aName,&lt;br /&gt;
             IWidgetPublisher aPublisher,&lt;br /&gt;
             iDeviceFactory aDeviceFactory)&lt;br /&gt;
         {&lt;br /&gt;
             iWidgetPublisher = aPublisher;&lt;br /&gt;
             iName = aName;&lt;br /&gt;
             iDeviceFactory = aDeviceFactory;&lt;br /&gt;
         } &lt;br /&gt;
 &lt;br /&gt;
         public IEnumerable&amp;amp;lt;uint&amp;amp;gt; WidgetClasses&lt;br /&gt;
         {&lt;br /&gt;
             get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         public void WidgetDiscovered(&lt;br /&gt;
             string aWidgetUdn,&lt;br /&gt;
             uint aWidgetClass,&lt;br /&gt;
             ISimpleUpnpWidget aSimpleUpnpWidget)&lt;br /&gt;
         {&lt;br /&gt;
             string newUdn = aWidgetUdn;&lt;br /&gt;
             DiscoveredWidget discoveredWidget = new DiscoveredWidget&lt;br /&gt;
                 (iDeviceFactory,&lt;br /&gt;
                  newUdn,&lt;br /&gt;
                  aSimpleUpnpWidget,&lt;br /&gt;
                  iWidgetPublisher);&lt;br /&gt;
 &lt;br /&gt;
             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                 discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                 discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                 discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary = &lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in OpenHome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by OpenHome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh - A collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs on ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The OpenHome Operating System. Core software for OpenHome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. &lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. A typical Widget supports only one protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Driver_Development</id>
		<title>OhWidget Driver Development</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Driver_Development"/>
				<updated>2012-03-01T15:13:48Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Prerequisites */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction = &lt;br /&gt;
&lt;br /&gt;
This document is for developers using the OpenHome SDK to integrate a Widget into an OpenHome system. Each Widget must have its own driver to allow it to communicate with the OpenHome Nodes. &lt;br /&gt;
&lt;br /&gt;
To help you write your driver, this document provides high level descriptions of the core responsibilities of a Widget driver and gives a detailed walk-through using example code.&lt;br /&gt;
&lt;br /&gt;
Full versions of each file used in the development of the example driver are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
To begin development of your Widget driver you must be in possession of the following items:&lt;br /&gt;
&lt;br /&gt;
* your Widget Service XML that describes the properties on your Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document does not contain advice on how to write Widget Service XML. Refer to the OpenHome Widget Service XML definition document for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK&lt;br /&gt;
* your chosen communication protocol's API&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The protocol you choose for your Widgets must be the same protocol used on your choice of Node.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
This document focuses on the development of the Widget driver. Details about the communications protocol used are beyond the scope of this document. This document assumes you are familiar with your chosen protocol's code libraries and are able to use them in the driver code you write.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Related Documents ==&lt;br /&gt;
&lt;br /&gt;
The following related OpenHome documentation may be of interest to you:&lt;br /&gt;
&lt;br /&gt;
* [[ohWidget Technical Overview|ohWidget Technical Overview]]&lt;br /&gt;
* [[OpenHome Widget Service XML definition|OpenHome Widget Service XML definition]]&lt;br /&gt;
* [http://www.openhome.org/releases/ohNet_DeviceStack.pdf  OpenHome ohNet Device Stack]&lt;br /&gt;
* [[OpenHome Node Architecture|OpenHome Node Architecture]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
None of the related documents listed above is mandatory reading for Widget driver development.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
= Widget Service XML = &lt;br /&gt;
&lt;br /&gt;
== Widget Service XML ==&lt;br /&gt;
OpenHome Widget driver writing relies heavily on the use of code generated from a single source — the Widget Service XML.&lt;br /&gt;
&lt;br /&gt;
The service and actions your Widget provides are represented in code in a file called a Provider. The Provider is automatically generated from the Widget Service XML and produces an abstract class for you to inherit when you write your concrete class driver.&lt;br /&gt;
&lt;br /&gt;
To aid in the explanation of how the Provider is created and put to use we will follow the development of&lt;br /&gt;
a driver for a simple light Widget; taking the defined Widget Service XML and stepping through how it is used to generate the other files. Examples of code are used throughout this document to show you how each one is created and used in an OpenHome system. &lt;br /&gt;
&lt;br /&gt;
It is essential that you start with a well-formed Widget Service XML, conforming to the schema defined&lt;br /&gt;
in the WidgetService.xsd. The following diagram shows the significance of the Widget Service XML in&lt;br /&gt;
relation to the generated files you will use when writing your driver:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverDevDocHierarchy.png|800px|thumb|center|Figure 1: The OpenHome document hierarchy, highlighting the areas specifically used in driver development]]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* The grayed-out files are not relevant to Widget driver development but can also be generated from the Widget Service XML.&lt;br /&gt;
* The Provider is generated in C#, meaning your driver must be written in C# as well. The use of managed code is mandatory for driver writing in the OpenHome framework.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Code sample used in this document ==&lt;br /&gt;
&lt;br /&gt;
Our examples in this document use a Widget Service XML definition for a light Widget called&lt;br /&gt;
BasicLight.xml.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Full versions of all the example files used in this document are available in the Appendix.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We will see how the Provider is generated from this XML and how it is used to aid the driver writing process. The examples also show how your chosen communication protocol should be used in the body of the driver code.&lt;br /&gt;
&lt;br /&gt;
Implementation details of specific protocols you choose to use are beyond the scope of this document. However, the samples used in this document show the use of the SimpleUPnP protocol to aid you in your development process.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol during the early stages of the OpenHome project. It is included in the OpenHome SDK and can be used as a public resource. &lt;br /&gt;
&lt;br /&gt;
The use of SimpleUPnP in the example files and the code snippets within the following sections is highlighted by the [[File:Warning.png]] icon. The lines of code marked by [[File:Warning.png]] must be changed to code from your chosen communication protocol's library. SimpleUPnP is left in to help you understand how a protocol is used in a working example.&lt;br /&gt;
&lt;br /&gt;
The sample code provided attempts to show best-practice coding standards. There are several sections of code that have a mandatory layout or that call specifically named methods and functions. These areas of the code are highlighted where required. &lt;br /&gt;
&lt;br /&gt;
Where the examples do not explicitly state that the code shown is mandatory, you are free to implement it in a different way according to your own coding style and practices.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Driver responsibilities = &lt;br /&gt;
&lt;br /&gt;
== Driver responsibilities ==&lt;br /&gt;
&lt;br /&gt;
An OpenHome Widget driver has several responsibilities which must be met before it can be used on an OpenHome Node.&lt;br /&gt;
&lt;br /&gt;
These responsibilities are listed R1 to R7 and are defined here, explaining what each one must do. &lt;br /&gt;
&lt;br /&gt;
=== R1 Specifying the type of Widget the driver controls ===&lt;br /&gt;
A driver must know which type of Widget it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
=== R2 Reacting to a discovered Widget on the network ===&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== R3 Setting the initial values for the Widget's properties ===&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
=== R4 Publishing discovered Widgets in the Local Widget Registry on the Node ===&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object.&lt;br /&gt;
&lt;br /&gt;
=== R5 Reacting to an event reported from the Widget ===&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
=== R6 Reacting to actions sent to the Widget ===&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
=== R7 Reacting to a Widget's departure ===&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no&lt;br /&gt;
longer available.&lt;br /&gt;
&lt;br /&gt;
The sections of example code that follow show you how to write a driver from beginning to end. The accompanying text explaining the example code highlights when a responsibility, or part of a responsibility, has been met.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Driver Architecture = &lt;br /&gt;
&lt;br /&gt;
== Driver Architecture ==&lt;br /&gt;
&lt;br /&gt;
Drivers are installed on the Node and used when the Node needs to communicate with the Widget. Drivers&lt;br /&gt;
use several objects to communicate with Widgets over the Widget's lifetime. Figure 2 shows the objects&lt;br /&gt;
used by the driver and how the responsibilities listed above relate to each one:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture.png|800px|thumb|center|Figure 2: The architecture of a driver, showing the driver's relationship to the objects used to communicate with a Widget. Lines between objects show message flow.]]&lt;br /&gt;
&lt;br /&gt;
The objects contained in the dotted boundary must appear in the code you write to define your driver. The Driver, Provider and IWidgetRegistryEntry objects are all contained in the same driver file. We begin discussing this on page 12. &lt;br /&gt;
&lt;br /&gt;
The other objects are provided by the OpenHome SDK or as installed components on the Node.&lt;br /&gt;
&lt;br /&gt;
The Discovery Module informs the driver of the presence of an available Widget.&lt;br /&gt;
&lt;br /&gt;
Each Node has a Protocol Module which contains the protocol's API. Widgets can communicate with OpenHome Nodes using any one of the set of communications protocols the Node supports. The driver uses your chosen protocol's Protocol Module to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
Both the Protocol Module and the Discovery Module are installed on the Node. When you write your&lt;br /&gt;
driver you will use your Protocol Module to allow the driver to communicate with the Widget.&lt;br /&gt;
&lt;br /&gt;
IWidgetPublisher, IPublishedWidget and DvDevice are objects provided in the OpenHome&lt;br /&gt;
API. You can read about them in the APIs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Generating the Provider = &lt;br /&gt;
&lt;br /&gt;
== Generating the Provider ==&lt;br /&gt;
&lt;br /&gt;
You must generate your provider before you can begin writing your Widget driver. You use your provider as a guide to implement the functions your Widget needs to set the values of its properties.&lt;br /&gt;
&lt;br /&gt;
The current provider generation process is a manual one involving the use of a text transform tool.&lt;br /&gt;
&lt;br /&gt;
Speak to your OpenHome contact who will help you generate your provider.&lt;br /&gt;
&lt;br /&gt;
Future releases of the OpenHome SDK will include a tool to help you generate the provider.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Prerequisites ==&lt;br /&gt;
&lt;br /&gt;
You must be in possession of:&lt;br /&gt;
&lt;br /&gt;
* the OpenHome SDK, unpacked on your computer&lt;br /&gt;
* your Widget Service XML file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Writing a SimpleUPnP driver = &lt;br /&gt;
&lt;br /&gt;
== Introduction to the SimpleUPnP protocol ==&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP protocol was developed as a test protocol used to control emulated Widgets over a custom UPnP service.&lt;br /&gt;
&lt;br /&gt;
This chapter shows how a driver is written using the SimpleUPnP communications protocol. The aim is to show the code using as generic a protocol as possible so that you can see where your own protocol specific code needs to go.&lt;br /&gt;
&lt;br /&gt;
The use of code specific to the SimpleUPnP implementation is highlighted by the use of the [[File:Warning.png]] icon. The lines of code are marked by this icon to make it easier for you to see where the protocol-specific code must go and what parts of the code are generic.&lt;br /&gt;
&lt;br /&gt;
=== Register model ===&lt;br /&gt;
&lt;br /&gt;
SimpleUPnP is modeled on 8 physical registers available on the Widget. Each register is 32-bits wide. They are indexed from 0 to 7 and the last register (register 7) is reserved for storing the Widget's class.&lt;br /&gt;
&lt;br /&gt;
This detail is used by the Protocol Module on the Node to determine which driver is needed to run the new Widget when it has been discovered.&lt;br /&gt;
&lt;br /&gt;
The remaining 7 registers (registers 0 to 6) are free for Widget engineers to assign to the Widget's functions.&lt;br /&gt;
&lt;br /&gt;
Registers 0, 1, 2 and 3 are available as read/write registers. Registers 4, 5 and 6 are readonly registers.&lt;br /&gt;
&lt;br /&gt;
Only the emulated hardware (running on the Node) can change the values held in registers 4, 5 and 6.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Register use in drivers ===&lt;br /&gt;
&lt;br /&gt;
In the example that follows we have a Basic Light Widget with a very simple function: it can be turned on and turned off. The on/off value is stored in register 0, with values 0=OFF and 1=ON. Register 0 is a read/write register. This means we can change the value stored there using messages passed to the Widget from the Node, and by reacting to physical interactions at the Widget (such as someone manually switching the light on or off). &lt;br /&gt;
&lt;br /&gt;
The mapping of registers to properties on the Widget is decided by the engineers who manufacture the device. You must be provided with the mapping before you begin developing your driver.&lt;br /&gt;
&lt;br /&gt;
== Starting the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-BoxHighlight.png|800px|thumb|center|Figure 3 The driver architecture highlighting the Widget driver and its component parts.]]&lt;br /&gt;
&lt;br /&gt;
When you have generated the abstract provider you can put it to use in the Widget driver. A Widget driver&lt;br /&gt;
has three distinct components:&lt;br /&gt;
&lt;br /&gt;
* an implementation of your abstract provider&lt;br /&gt;
* a definition of the Widget driver&lt;br /&gt;
* an implementation of the IWidgetRegistryEntry interface&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must manually write the code for your Widget driver. The differences in implementation of Widget properties and communication protocols means that the driver code cannot be autogenerated.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This section takes you through how to write a Widget driver by implementing the auto-generated provider,&lt;br /&gt;
starting from a new blank file and finishing with a working driver for the Basic Light Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
No assumptions have been made about the type of editor you use to write your code. Shortcuts&lt;br /&gt;
or macros that you use as standard will not appear in the instructions below. A full example&lt;br /&gt;
BinaryLightDriver.cs is available to review in Appendix C.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a new C# file in your IDE. Ensure the following libraries are used:&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 [[File:Warning.png]]using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 namespace OpenHome.Widget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
You must use the libraries listed above for this specific example.&lt;br /&gt;
&lt;br /&gt;
In general, drivers require the following libraries:&lt;br /&gt;
* System*&lt;br /&gt;
* System.Collections.Generic*&lt;br /&gt;
* OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
&lt;br /&gt;
Your driver will fail to compile if you miss any of these listed libraries. Libraries marked * are typically added by default by most modern IDEs. &lt;br /&gt;
&lt;br /&gt;
The OpenHome.Widget.Protocols.SimpleUpnp library is required only in this SimpleUPnP example. Drivers using a different protocol will use their own protocol library.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
== Implementing the provider ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-ProviderHighlight.png|800px|thumb|center|Figure 4 The driver architecture highlighting the Provider's place]]&lt;br /&gt;
&lt;br /&gt;
You use your auto-generated abstract provider by writing an implementation of it in the driver file. Responsibilities met by implementing your auto-generated provider are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R6 Reacting to actions sent to the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update a specified property to a new value when instructed to do so by the Node.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
Begin by creating a new class. It will subclass the abstract auto-generated provider:&lt;br /&gt;
&lt;br /&gt;
 class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
The Protocol Module will provide an API for the Provider to use to communicate with the Widget. In&lt;br /&gt;
SimpleUPnP we are provided with an interface called ISimpleUpnpWidget. The provider is supplied&lt;br /&gt;
with the required instance of the interface by the Discovery Module on the Node.&lt;br /&gt;
&lt;br /&gt;
The mechanisms for registering providers with specific Protocol Modules, and for the way the module gives each provider its required interface are covered later when writing the discovery method.&lt;br /&gt;
&lt;br /&gt;
For now, we need to give the Provider a place to store the interface that it will later use to communicate&lt;br /&gt;
with the Widget:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]] private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
&lt;br /&gt;
The interface from the Protocol Module is passed in as a parameter in the Provider's constructor and then&lt;br /&gt;
assigned to the variable we just created:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightProvider(DvDevice aDevice,&lt;br /&gt;
 [[File:Warning.png]]         ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
 {&lt;br /&gt;
       iProtocol = aProtocol;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
To satisfy R3 we would normally set the Widget's properties here, giving them an initial value.&lt;br /&gt;
However, in this specific example we cannot set the value of Basic Light's only property because&lt;br /&gt;
we will never know, in advance, what the state of the light will be (either on or off) when we&lt;br /&gt;
create the DiscoveredWidget.&lt;br /&gt;
&lt;br /&gt;
When you cannot set the properties ahead of time, and you are using an eventing protocol like SimpleUPnP, you can instead set them in the HandleRegisterEvent method in the driver class. This also satisfies the requirements for R3. You must set the Widget's properties before you enable it using SetEnabled(). &lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The abstract provider includes an abstract method called SetOn. This method is invoked by the Node when passing a message to the Widget, specifically to set the on property of the Widget to either 0 or 1. The implementation of this method will meet the requirements for R6.&lt;br /&gt;
&lt;br /&gt;
We must override this method and provide the protocol module a way of passing a message on to the Widget to perform the required action, in this case turn the light on or off:&lt;br /&gt;
&lt;br /&gt;
          protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
          {&lt;br /&gt;
     [[File:Warning.png]]        iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
          }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
In this example the Basic Light's SetOn property (the boolean property that controls whether the light is&lt;br /&gt;
on or off) is represented in the physical Widget by the register that has an index of 0.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
* This method is an example of an action on a Widget. Actions are messages sent from the Node to the Widget. We will see later how to handle events that need to be passed back from the Widget&lt;br /&gt;
to the Node.&lt;br /&gt;
* Your own Widget will likely provide more than a single property. Your auto-generated provider will contain one abstract method to represent each writable property. Read-only properties are not provided an abstract method.&lt;br /&gt;
&lt;br /&gt;
You must implement each abstract method in your driver to ensure the relevant property on&lt;br /&gt;
the Widget can be set.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
We have now finished implementing the provider. The next step is to implement the driver.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Implementing the driver ==&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-DriverHighlight.png|800px|thumb|center|Figure 4: The driver architecture highlighting the implemented driver's place.]]&lt;br /&gt;
&lt;br /&gt;
The code for your Widget driver must provide an implementation of the IWidgetRegistryInterface,&lt;br /&gt;
including the following tasks:&lt;br /&gt;
&lt;br /&gt;
* methods to expose identifying details about the Widget for the Node to access&lt;br /&gt;
* providing methods to handle events reported by the Widget&lt;br /&gt;
&lt;br /&gt;
The driver is implemented as a public class within the same file as the provider code. Each driver must use the interface for the protocol you are using. For the SimpleUPnP protocol the interface is ISimple-UpnpWidgetDriver.&lt;br /&gt;
&lt;br /&gt;
=== Writing code ===&lt;br /&gt;
&lt;br /&gt;
Create your new driver class and subclass the ISimpleUpnpWidgetDriver interface:&lt;br /&gt;
&lt;br /&gt;
 public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Implementing IWidgetRegistryEntry ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry is the interface you use to represent physical Widgets. It is implemented as a subclass of your driver class. We are going to implement this interface in a class called '''DiscoveredWidget'''.&lt;br /&gt;
&lt;br /&gt;
Let's return to our driver architecture diagram for a moment:&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-IRegistryEntryHighlight.png|800px|thumb|center|Figure 5 The driver architecture highlighting the IWidgetRegistryEntry object you will now implement]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IWidgetRegistryEntry uses several other objects to help create it and respond to messages sent to and from it. These objects will be created in our implementation of DiscoveredWidget. &lt;br /&gt;
&lt;br /&gt;
When successfully created and published, the DiscoveredWidget objects are stored in a list on the Node called the Local Widget Registry. The Local Widget Registry is used by Nodes to maintain contact with the Widgets they control.&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry is shown at the top of Figure 5, marked plainly as (Registry). The path to the Local Widget Registry goes through several layers of Node architecture which are not relevant to Widget driver writing, so are not shown in the diagrams.&lt;br /&gt;
&lt;br /&gt;
==== Writing code ====&lt;br /&gt;
&lt;br /&gt;
Start by subclassing the IWidgetRegistryEntry interface in your new class:&lt;br /&gt;
&lt;br /&gt;
      private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
      {&lt;br /&gt;
&lt;br /&gt;
A DiscoveredWidget must provide the driver with the objects required to present the Widget and its&lt;br /&gt;
properties to the Node:&lt;br /&gt;
&lt;br /&gt;
           private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
           private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
           private readonly ISimpleUpnpWidget iProtocol;&lt;br /&gt;
           private readonly BinaryLightProvider iProvider;&lt;br /&gt;
           private readonly DvDevice iDvDevice;&lt;br /&gt;
           private IPublishedWidget iPublishedWidget;&lt;br /&gt;
&lt;br /&gt;
Each of the attributes in the example above are defined as follows:&lt;br /&gt;
&lt;br /&gt;
iDeviceFactory — used by the driver to create a single instance of DvDevice to represent a single Widget&lt;br /&gt;
&lt;br /&gt;
iPublisher — used by the driver to publish the Widget to the Node&lt;br /&gt;
&lt;br /&gt;
iProtocol — the object used by the Widget to communicate with the Protocol Module on the Node&lt;br /&gt;
&lt;br /&gt;
iProvider — an instantiated provider of the type you defined earlier&lt;br /&gt;
&lt;br /&gt;
iDvDevice — a representation of a Widget to which the provider is attached, created using iDevice-Factory above&lt;br /&gt;
&lt;br /&gt;
iPublishedWidget — used to contain the returned object from a successful publishing of the Widget&lt;br /&gt;
If we look again at the driver architecture diagram, we ca highlight the objects we've just defined:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:DriverNodeArchitecture-Highlight.png|800px|thumb|center|Figure 6: The driver architecture highlighting the objects used by the IWidgetRegistryEntry implementation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The DeviceFactory, defined above in the member variable iDeviceFactory, is used to create new DvDevice objects. The DeviceFactory is only ever used to do this once. It is not shown in the driver architecture diagrams due to its minimal role in the operation of a driver, but it would normally appear between the IWidgetRegistryEntry and DvDevice objects.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
A driver requires methods to expose identifying details about the Widget. We must provide access to two of the attributes we just defined above:&lt;br /&gt;
&lt;br /&gt;
 public DvDevice DvDevice&lt;br /&gt;
 {&lt;br /&gt;
     get { return iDvDevice; }&lt;br /&gt;
 }&lt;br /&gt;
 public string WidgetClass&lt;br /&gt;
 {&lt;br /&gt;
     get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The WidgetClass string is formed using a combination of the vendor name and the Widget's name in the&lt;br /&gt;
format:&lt;br /&gt;
&lt;br /&gt;
 [vendor_domain]:[widget_name]&lt;br /&gt;
&lt;br /&gt;
The Local Widget Registry can now query both the DvDevice object representing the Widget, and the specific class of Widget this driver represents. The other member variables we defined do not need their own accessor methods.&lt;br /&gt;
&lt;br /&gt;
Now we must write a constructor for DiscoveredWidget and assign the parameters accordingly: &lt;br /&gt;
&lt;br /&gt;
 public DiscoveredWidget(IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                            string aUdn,&lt;br /&gt;
                            ISimpleUpnpWidget aProxy,&lt;br /&gt;
                            IWidgetPublisher aPublisher)&lt;br /&gt;
 {&lt;br /&gt;
      iDeviceFactory = aDeviceFactory;&lt;br /&gt;
      iProtocol = aProtocol;&lt;br /&gt;
      iPublisher = aPublisher;&lt;br /&gt;
      iDvDevice = iDeviceFactory.CreateDevice(aUdn);&lt;br /&gt;
      iProvider = new BinaryLightProvider(iDvDevice,&lt;br /&gt;
      iProtocol);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Event handling ===&lt;br /&gt;
&lt;br /&gt;
A Widget's state can change in one of three significant ways:&lt;br /&gt;
&lt;br /&gt;
* when the Widget needs to be published on the Node&lt;br /&gt;
* when the Widget disappears from the network (by losing power or similar)&lt;br /&gt;
* when a property's state changes and must be updated to a new value&lt;br /&gt;
&lt;br /&gt;
We now need methods to handle these changes.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The methods we define here will be used as callbacks, rather than invoked as method calls. We define the methods here first and then use them later on. We will use the Protocol Module to listen for changes in the Widget's state and register these methods as callbacks there. See Writing the SimpleUPnP Widget discovery method for more details.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this section of the driver are:&lt;br /&gt;
&lt;br /&gt;
'''R3 Setting the initial values for the Widget's properties'''&lt;br /&gt;
&lt;br /&gt;
A driver must set the Widget object's initial properties.&lt;br /&gt;
&lt;br /&gt;
'''R4 Publishing discovered Widgets in the Local Widget Registry on the Node'''&lt;br /&gt;
&lt;br /&gt;
Publishing Widgets advertises their presence on the network. This allows Nodes to access the Widgets and present their services for use. A driver must be able to enable and publish a Widget object. &lt;br /&gt;
&lt;br /&gt;
'''R5 Reacting to an event reported from the Widget'''&lt;br /&gt;
&lt;br /&gt;
A driver must update the Node with the state of the Widget's properties when the Widget reports a change.&lt;br /&gt;
&lt;br /&gt;
'''R7 Reacting to a Widget's departure'''&lt;br /&gt;
&lt;br /&gt;
A driver must properly handle the IWidgetRegistryEntry object when the physical Widget is no longer available.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Enabling and publishing a discovered Widget ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The first method initializes the Widget by enabling the device and then using the IWidgetPublisher&lt;br /&gt;
to make it available on the Node:&lt;br /&gt;
&lt;br /&gt;
 public void HandleInitialEvent()&lt;br /&gt;
 {&lt;br /&gt;
      iDvDevice.SetEnabled();&lt;br /&gt;
      iPublisher.TryPublishWidget(iDvDevice.iUdn(),&lt;br /&gt;
                              this,&lt;br /&gt;
                              out iPublishedWidget);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This method meets the requirements for R4.&lt;br /&gt;
&lt;br /&gt;
The call to TryPublishWidget returns an iPublishedWidget object. We use this object later to satisfy the requirements of R7.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
The ordering of the calls to SetEnabled and TryPublishWidget is vitally important. You&lt;br /&gt;
must enable the device before you attempt to publish it. Your Widget will not be available to the&lt;br /&gt;
Nodes unless SetEnabled is called first. Nodes will not be able to access a published device&lt;br /&gt;
that has not been enabled.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
R3 requires that you set the Widget's properties before you enable and publish the device. We&lt;br /&gt;
discussed on page 14 how some properties can only be set after the Widget reports what their&lt;br /&gt;
state is. We do this in HandleRegisterEvent.&lt;br /&gt;
&lt;br /&gt;
We rely on the SimpleUPnP Protocol Module guaranteeing a call to HandleRegisterEvent first before HandleInitialEvent. This is informed by guarantees made by the Control Point stack that the calls will be made in that order.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
==== Removing a Widget ====&lt;br /&gt;
&lt;br /&gt;
Removing a Widget involves unpublishing it from the Node. The IPublishedWidget interface provides us with a method we can call to manage that for us:&lt;br /&gt;
&lt;br /&gt;
 public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
 {&lt;br /&gt;
     if (iPublishedWidget != null)&lt;br /&gt;
     { iPublishedWidget.Unpublish(); }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assuming that the Widget was successfully published earlier, it is removed from the Node's Local Widget Registry.&lt;br /&gt;
&lt;br /&gt;
We must also properly handle the resources we used to create and maintain the Widget object while it was published:&lt;br /&gt;
&lt;br /&gt;
      iProvider.Dispose();&lt;br /&gt;
      iDvDevice.Dispose();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The calls to Dispose are made regardless of the Widget's published state, ensuring that any created device and associated provider are properly disposed. This implementation satisfies R7.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Event handling ====&lt;br /&gt;
&lt;br /&gt;
We need a method to handle changes to the state of the Widget's properties.&lt;br /&gt;
&lt;br /&gt;
If the property changes at the Widget, it needs to pass the new state back to the Node so that it is kept up-to-date on the Widget's status. This is called an event. An example in the case of our Basic Light is someone manually switching the light from on to off. This is in contrast to actions, which are passed from the Node to the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Other examples of events involve no human interaction, such as a thermometer Widget updating its current temperature based on environmental changes.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Our Basic Light Widget has only one property that needs to be handled:&lt;br /&gt;
&lt;br /&gt;
 public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
 {&lt;br /&gt;
     if (aIndex == 0)&lt;br /&gt;
     {&lt;br /&gt;
         iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We use our instance of the provider to update the register on the Widget that is mapped to the On property. This in turn updates the Node with the new state of the Widget.&lt;br /&gt;
&lt;br /&gt;
This method provides implementations to satisfy two driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
* R3 is now completely satisfied, as we can now set the values of all the previously unknown properties here.&lt;br /&gt;
* R5 is also satisfied as this method allows us to update the Widget's status on the Node when a property is changed on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Not all protocols pass messages back to the Node in this manner. The way we have satisfied R3 and R5 here only applies to protocols and Widgets that support this behavior.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Widgets that do not use an eventing protocol need to have their properties set in the provider's constructor to satisfy R3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To satisfy R5, the over-ridden method SetOn in the provider must include the call to SetPropertyOn. Non-eventing protocols do not require a HandleRegisterEvent method.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
=== Constructor ===&lt;br /&gt;
&lt;br /&gt;
The final requirement for the driver is the constructor so that new DiscoveredWidget objects can be created. &lt;br /&gt;
&lt;br /&gt;
Responsibilities met in this area of code are:&lt;br /&gt;
&lt;br /&gt;
'''R1 Specifying the type of Widget the driver controls'''&lt;br /&gt;
&lt;br /&gt;
A driver must know which type of Widget that it can communicate with and be able to provide that information to the Discovery Module. A driver will normally communicate with one specific type of Widget and will only ever use one communications protocol.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Writing the code ====&lt;br /&gt;
&lt;br /&gt;
We begin by defining the variables we will use to store the objects used by the driver:&lt;br /&gt;
&lt;br /&gt;
 private readonly string iName;&lt;br /&gt;
 private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
 private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now write the constructor for the driver and assign the passed in parameters appropriately:&lt;br /&gt;
&lt;br /&gt;
 public BinaryLightDriver(string aName,&lt;br /&gt;
                IWidgetPublisher aPublisher,&lt;br /&gt;
                IDvDeviceFactory aDeviceFactory)&lt;br /&gt;
 {&lt;br /&gt;
     iWidgetPublisher = aPublisher;&lt;br /&gt;
     iName = aName;&lt;br /&gt;
     iDeviceFactory = aDeviceFactory;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally we need to provide the driver a way to publish the class of Widget it controls. This information is requested by the Discovery Module and is used to ensure the Node uses the correct driver when a new Widget appears.&lt;br /&gt;
&lt;br /&gt;
The implementation for this details will be different for each protocol. The SimpleUPnP protocol library provides a file that contains the SimpleUPnP definitions as integers. Each integer represents a particular class of identified Widget.&lt;br /&gt;
&lt;br /&gt;
The SimpleUPnP implementation of that method is as follows:&lt;br /&gt;
&lt;br /&gt;
 public IEnumerable&amp;lt;uint&amp;gt; WidgetClasses&lt;br /&gt;
 {&lt;br /&gt;
 [[File:Warning.png]]        get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The body of this method is specifically written for the Widget class we are defining (in this case a binary light). This method completes the driver's requirements for R1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Writing the SimpleUPnP Widget discovery method ==&lt;br /&gt;
&lt;br /&gt;
Every driver must contain a method which creates new objects to represent newly discovered Widgets.&lt;br /&gt;
The Discovery Module invokes this method to begin the process of creating the objects required to allow the Node to access the Widget. &lt;br /&gt;
&lt;br /&gt;
The name of this method is dictated by your chosen protocol's API. The SimpleUPnP protocol requires a method called WidgetDiscovered.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The method's name will not always be the same for each protocol. Your protocol's documentation will contain the details of what this method must be called.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This method and its implementation will meet the following driver responsibilities:&lt;br /&gt;
&lt;br /&gt;
'''R2 Reacting to a discovered Widget on the network'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A driver must create a new IWidgetRegistryEntry object to represent the Widget and use it to listen to changes in the physical Widget's state.&lt;br /&gt;
&lt;br /&gt;
Our implementation of the WidgetDiscovered method will create a new DiscoveredWidget object and use the Protocol Module to listen for changes to the Widget's state.&lt;br /&gt;
&lt;br /&gt;
=== Writing the code ===&lt;br /&gt;
&lt;br /&gt;
The method uses the Protocol Module and two ways to identify the Widget. We must pass these in as&lt;br /&gt;
parameters:&lt;br /&gt;
&lt;br /&gt;
 public void WidgetDiscovered(string aWidgetUdn,&lt;br /&gt;
                              uint aWidgetClass,&lt;br /&gt;
                              ISimpleUpnpWidget&lt;br /&gt;
                                  aSimpleUpnpWidget)&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
Every Widget that uses this driver must be uniquely identifiable:&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]    string newUdn = aWidgetUdn;&lt;br /&gt;
&lt;br /&gt;
Each new Widget is represented by a DiscoveredWidget object. Create the new DiscoveredWidget and pass in the required parameters we created earlier:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
     DiscoveredWidget discoveredWidget =&lt;br /&gt;
                 new DiscoveredWidget(iDeviceFactory,&lt;br /&gt;
                                      newUdn,&lt;br /&gt;
  &lt;br /&gt;
 [[File:Warning.png]]                                    aSimpleUpnpWidget,&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Registering the callbacks ===&lt;br /&gt;
&lt;br /&gt;
Finally, we ask the Widget's protocol interface to listen for calls to the handler methods we defined earlier in DiscoveredWidget. We do this by registering those methods as callbacks for the Protocol Module&lt;br /&gt;
to listen for:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [[File:Warning.png]]             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                        discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                        discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                        discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You have now met 100% of the driver responsibility requirements and have a working driver to use with your SimpleUPnP Widget.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix A. Sample XML =&lt;br /&gt;
&lt;br /&gt;
== Binary Light.xml ==&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;widgetService&amp;gt;&lt;br /&gt;
  &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;&lt;br /&gt;
  &amp;lt;version&amp;gt;&lt;br /&gt;
   &amp;lt;major&amp;gt;1&amp;lt;/major&amp;gt;&lt;br /&gt;
   &amp;lt;minor&amp;gt;0&amp;lt;/minor&amp;gt;&lt;br /&gt;
  &amp;lt;/version&amp;gt;&lt;br /&gt;
  &amp;lt;propertylist&amp;gt;&lt;br /&gt;
   &amp;lt;property primary=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;Indicates whether the light is currently&lt;br /&gt;
       illuminated&amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;name&amp;gt;On&amp;lt;/name&amp;gt;&lt;br /&gt;
    &amp;lt;dataType&amp;gt;boolean&amp;lt;/dataType&amp;gt;&lt;br /&gt;
    &amp;lt;access&amp;gt;readWrite&amp;lt;/access&amp;gt;&lt;br /&gt;
   &amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;/propertylist&amp;gt;&lt;br /&gt;
 &amp;lt;/widgetService&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Appendix B. Sample Provider = &lt;br /&gt;
&lt;br /&gt;
== DvWidgetOpenhomeOrgBasicLight1.cs ==&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Runtime.InteropServices;&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Core;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Utils.Binary;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.Widget.Nodes.Local.Providers&lt;br /&gt;
 {&lt;br /&gt;
    public interface IDvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
        IDisposable&lt;br /&gt;
    {&lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous value&lt;br /&gt;
        /// &amp;lt;/returns&amp;gt;&lt;br /&gt;
        bool SetPropertyOn(bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;Property's value will be copied&lt;br /&gt;
        /// here&amp;lt;/param&amp;gt;&lt;br /&gt;
        bool PropertyOn();&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt; summary&amp;gt;&lt;br /&gt;
    /// Provider for the openhome.org:BinaryLight:1 UPnP service&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public abstract class DvProviderOpenhomeOrgBinaryLight1 :&lt;br /&gt;
               DvProvider,&lt;br /&gt;
               IDisposable,&lt;br /&gt;
               IDvProviderOpenhomeOrgBinaryLight1&lt;br /&gt;
    {&lt;br /&gt;
        private GCHandle iGch;&lt;br /&gt;
        private PropertyBool iPropertyOn;&lt;br /&gt;
        private PropertyUint iPropertyPrimarySeq;&lt;br /&gt;
        private PropertyUint iPropertySecondarySeq;&lt;br /&gt;
        private ActionDelegate iDelegateSetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetProperty;&lt;br /&gt;
        private ActionDelegate iDelegateGetPrimaryProperty;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Constructor&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aDevice&amp;quot;&amp;gt;Device which owns this&lt;br /&gt;
        /// provider&amp;lt;/param&amp;gt;&lt;br /&gt;
        protected DvProviderOpenhomeOrgBinaryLight1(DvDevice aDevice)&lt;br /&gt;
            : base(aDevice, &amp;quot;openhome.org&amp;quot;, &amp;quot;GenericWidget&amp;quot;, 1)&lt;br /&gt;
        {&lt;br /&gt;
            iGch = GCHandle.Alloc(this);&lt;br /&gt;
            List&amp;lt;String&amp;gt; allowedValues = new List&amp;lt;String&amp;gt;();&lt;br /&gt;
            iPropertyOn = new PropertyBool(new ParameterBool(&amp;quot;On&amp;quot;));&lt;br /&gt;
            iPropertyPrimarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;PrimarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertyPrimarySeq);&lt;br /&gt;
            iPropertySecondarySeq = new PropertyUint&lt;br /&gt;
                (new ParameterUint(&amp;quot;SecondarySeq&amp;quot;));&lt;br /&gt;
            AddProperty(iPropertySecondarySeq);&lt;br /&gt;
            SetPropertyUint(iPropertyPrimarySeq, 0);&lt;br /&gt;
            SetPropertyUint(iPropertySecondarySeq, 0);&lt;br /&gt;
  &lt;br /&gt;
            Zapp.Core.Action action = new Zapp.Core.Action&lt;br /&gt;
                (&amp;quot;SetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;FireAndForget&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddInputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateSetProperty = new ActionDelegate(DoSetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateSetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddInputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            iDelegateGetProperty = new ActionDelegate(DoGetProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetProperty,&lt;br /&gt;
                GCHandle.ToIntPtr(iGch));&lt;br /&gt;
  &lt;br /&gt;
            action = new Zapp.Core.Action(&amp;quot;GetPrimaryProperty&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropInt&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBool&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropStr&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;PropBin&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;UpdateCount&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                 (&amp;quot;Name&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;integer&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;boolean&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;string&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;binary&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString&lt;br /&gt;
                (&amp;quot;Type&amp;quot;, allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            action.AddOutputParameter(new ParameterBinary(&amp;quot;Value&amp;quot;));&lt;br /&gt;
            allowedValues.Add(&amp;quot;&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;readWrite&amp;quot;);allowedValues.Add&lt;br /&gt;
                (&amp;quot;readOnly&amp;quot;);&lt;br /&gt;
            allowedValues.Add(&amp;quot;writeOnly&amp;quot;);&lt;br /&gt;
            action.AddOutputParameter(new ParameterString(&amp;quot;Access&amp;quot;,&lt;br /&gt;
                allowedValues));&lt;br /&gt;
            allowedValues.Clear();&lt;br /&gt;
            iDelegateGetPrimaryProperty = new&lt;br /&gt;
            ActionDelegate(DoGetPrimaryProperty);&lt;br /&gt;
            EnableAction(action, iDelegateGetPrimaryProperty,&lt;br /&gt;
            GCHandle.ToIntPtr(iGch));&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the property&amp;lt;/param&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;true if the value has been updated;&lt;br /&gt;
        /// false if aValue was the same as the previous&lt;br /&gt;
        /// value&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool SetPropertyOn(bool aValue)&lt;br /&gt;
        {&lt;br /&gt;
            if (iPropertyOn.SetValue(aValue))&lt;br /&gt;
            {&lt;br /&gt;
                lock (iPropertyPrimarySeq)&lt;br /&gt;
                {&lt;br /&gt;
                    SetPropertyUint(iPropertyPrimarySeq,&lt;br /&gt;
                        iPropertyPrimarySeq.Value() + 1);&lt;br /&gt;
                } return true;&lt;br /&gt;
            } return false;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Get a copy of the value of the On property&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;returns&amp;gt;The value of the property&amp;lt;/returns&amp;gt;&lt;br /&gt;
        public bool PropertyOn()&lt;br /&gt;
        {&lt;br /&gt;
            return iPropertyOn.Value();&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        /// &amp;lt;summary&amp;gt;&lt;br /&gt;
        /// Set the On property.&lt;br /&gt;
        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aVersion&amp;quot;&amp;gt;Version of the service being&lt;br /&gt;
        /// requested (will be &amp;lt;= the version advertised)&amp;lt;/param&amp;gt; &lt;br /&gt;
        /// &amp;lt;param name=&amp;quot;aValue&amp;quot;&amp;gt;New value for the On property.&lt;br /&gt;
        /// &amp;lt;/param&amp;gt;&lt;br /&gt;
        protected abstract void SetOn(uint aVersion, bool aValue);&lt;br /&gt;
  &lt;br /&gt;
        private static int DoSetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                byte[] valBin = invocation.ReadBinary(&amp;quot;Value&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                switch (name)&lt;br /&gt;
                {&lt;br /&gt;
                    case &amp;quot;On&amp;quot;:&lt;br /&gt;
                        self.SetOn(aVersion, Converter.&lt;br /&gt;
                            BinaryToBoolean(valBin));&lt;br /&gt;
                        break;&lt;br /&gt;
                    default:&lt;br /&gt;
                        throw new ActionError();&lt;br /&gt;
                }&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
                invocation.WriteEnd();&lt;br /&gt;
            }&lt;br /&gt;
            catch (ActionError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
            catch (PropertyUpdateError)&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
                return -1;&lt;br /&gt;
            }&lt;br /&gt;
        return 0;&lt;br /&gt;
        }&lt;br /&gt;
  &lt;br /&gt;
        private static int DoGetProperty(IntPtr aPtr,&lt;br /&gt;
                        IntPtr aInvocation,&lt;br /&gt;
                        uint aVersion)&lt;br /&gt;
        {&lt;br /&gt;
            GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
            DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
                (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
            DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
            try&lt;br /&gt;
            {&lt;br /&gt;
                invocation.ReadStart();&lt;br /&gt;
                string name = invocation.ReadString(&amp;quot;Name&amp;quot;);&lt;br /&gt;
                invocation.ReadEnd();&lt;br /&gt;
                invocation.WriteStart();&lt;br /&gt;
            switch (name)&lt;br /&gt;
            {&lt;br /&gt;
                case &amp;quot;On&amp;quot;:&lt;br /&gt;
                invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                    Converter.BooleanToBinary(self.iPropertyOn.&lt;br /&gt;
                        Value()));&lt;br /&gt;
                break;&lt;br /&gt;
                default:&lt;br /&gt;
                throw new ActionError();&lt;br /&gt;
            }&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    private static int DoGetPrimaryProperty(IntPtr aPtr,&lt;br /&gt;
                    IntPtr aInvocation,&lt;br /&gt;
                    uint aVersion)&lt;br /&gt;
    {&lt;br /&gt;
        GCHandle gch = GCHandle.FromIntPtr(aPtr);&lt;br /&gt;
        DvProviderOpenhomeOrgBinaryLight1 self =&lt;br /&gt;
            (DvProviderOpenhomeOrgBinaryLight1)gch.Target;&lt;br /&gt;
        DvInvocation invocation = new DvInvocation(aInvocation);&lt;br /&gt;
  &lt;br /&gt;
        try&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReadStart();&lt;br /&gt;
            invocation.ReadEnd();&lt;br /&gt;
            invocation.WriteStart();&lt;br /&gt;
            invocation.WriteString(&amp;quot;Name&amp;quot;, &amp;quot;On&amp;quot;);&lt;br /&gt;
            invocation.WriteString(&amp;quot;Type&amp;quot;, &amp;quot;boolean&amp;quot;);&lt;br /&gt;
            invocation.WriteBinary(&amp;quot;Value&amp;quot;,&lt;br /&gt;
                Converter.BooleanToBinary(self.iPropertyOn.Value()));&lt;br /&gt;
            invocation.WriteString(&amp;quot;Access&amp;quot;, &amp;quot;readWrite&amp;quot;);&lt;br /&gt;
            invocation.WriteEnd();&lt;br /&gt;
        }&lt;br /&gt;
        catch (ActionError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        catch (PropertyUpdateError)&lt;br /&gt;
        {&lt;br /&gt;
            invocation.ReportError(501, &amp;quot;Invalid XML&amp;quot;); ;&lt;br /&gt;
            return -1;&lt;br /&gt;
        }&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    /// &amp;lt;summary&amp;gt;&lt;br /&gt;
    /// Must be called for each class instance. Must be called before&lt;br /&gt;
    /// Core.Library.Close().&lt;br /&gt;
    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;
    public void Dispose()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
        GC.SuppressFinalize(this);&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
    ~DvProviderOpenhomeOrgBinaryLight1()&lt;br /&gt;
    {&lt;br /&gt;
        DoDispose();&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
        private void DoDispose()&lt;br /&gt;
        {&lt;br /&gt;
            lock (this)&lt;br /&gt;
            {&lt;br /&gt;
                if (iHandle == IntPtr.Zero)&lt;br /&gt;
            {&lt;br /&gt;
                    return;&lt;br /&gt;
            }&lt;br /&gt;
            DisposeProvider();&lt;br /&gt;
            iPropertyOn.Dispose();&lt;br /&gt;
            iHandle = IntPtr.Zero;&lt;br /&gt;
            }&lt;br /&gt;
            iGch.Free();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
= Appendix C. Sample Driver = &lt;br /&gt;
&lt;br /&gt;
== BasicLightDriver.cs ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 using System.Collections.Generic;&lt;br /&gt;
 using OpenHome.Net.Device;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local;&lt;br /&gt;
 using OpenHome.Widget.Nodes.Local.Providers;&lt;br /&gt;
 using OpenHome.Widget.Protocols.SimpleUpnp;&lt;br /&gt;
 &lt;br /&gt;
 namespace OpenHome.hWidget.Drivers.SimpleUpnp&lt;br /&gt;
 {&lt;br /&gt;
     class BinaryLightProvider : DvProviderOpenhomeOrgTestBinaryLight1&lt;br /&gt;
     {&lt;br /&gt;
         private ISimpleUpnpWidget iProtocol;&lt;br /&gt;
         public BinaryLightProvider(DvDevice aDevice, &lt;br /&gt;
             ISimpleUpnpWidget aProtocol) : base(aDevice)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol = aProtocol;&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         protected override void SetOn(uint aVersion, bool aValue)&lt;br /&gt;
         {&lt;br /&gt;
             iProtocol.Registers[0] = aValue ? (uint)1 : 0;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     public class BinaryLightDriver : ISimpleUpnpWidgetDriver&lt;br /&gt;
     {&lt;br /&gt;
         private class DiscoveredWidget : IWidgetRegistryEntry&lt;br /&gt;
         {&lt;br /&gt;
             private readonly IDvDeviceFactory iDeviceFactory;&lt;br /&gt;
             private readonly IWidgetPublisher iPublisher;&lt;br /&gt;
             private readonly ISimpleUpnpWidget iProtocol; &lt;br /&gt;
 &lt;br /&gt;
             private readonly BinaryLightProvider iProvider;&lt;br /&gt;
             private readonly DvDevice iDvDevice;&lt;br /&gt;
             private IPublishedWidget iPublishedWidget; &lt;br /&gt;
 &lt;br /&gt;
             public DvDevice DvDevice&lt;br /&gt;
             {&lt;br /&gt;
                 get { return iDvDevice; }&lt;br /&gt;
             }&lt;br /&gt;
             &lt;br /&gt;
             public string WidgetClass&lt;br /&gt;
             {&lt;br /&gt;
                 get { return &amp;quot;openhome.org:BinaryLight&amp;quot;; }&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public DiscoveredWidget(&lt;br /&gt;
                 IDvDeviceFactory aDeviceFactory,&lt;br /&gt;
                 string aUdn,&lt;br /&gt;
                 ISimpleUpnpWidget aProxy,&lt;br /&gt;
                 IWidgetPublisher aPublisher)&lt;br /&gt;
             {&lt;br /&gt;
                 iDeviceFactory = aDeviceFactory;&lt;br /&gt;
                 iProtocol = aProtocol;&lt;br /&gt;
 &lt;br /&gt;
                 iPublisher = aPublisher;&lt;br /&gt;
                 iDvDevice = iDeviceFactory.CreateDevice(aUdn);  &lt;br /&gt;
                 iProvider = new BinaryLightProvider(iDvDevice, &lt;br /&gt;
                                                     iProtocol);&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             public void HandleInitialEvent()&lt;br /&gt;
             {&lt;br /&gt;
                 iDvDevice.SetEnabled();&lt;br /&gt;
                 iPublisher.TryPublishWidget(iDvDevice.iUdn(), this,&lt;br /&gt;
                     out iPublishedWidget);&lt;br /&gt;
             } &lt;br /&gt;
 &lt;br /&gt;
             public void HandleDisappearance(bool aGoneFromNetwork)&lt;br /&gt;
             {&lt;br /&gt;
                 if (iPublishedWidget != null)&lt;br /&gt;
                 {&lt;br /&gt;
                     iPublishedWidget.Unpublish();&lt;br /&gt;
                 } &lt;br /&gt;
                 iProvider.Dispose();&lt;br /&gt;
                 iDvDevice.Dispose();&lt;br /&gt;
             }  &lt;br /&gt;
 &lt;br /&gt;
             public void HandleRegisterEvent(uint aIndex, uint aValue)&lt;br /&gt;
             {&lt;br /&gt;
                 if (aIndex == 0)&lt;br /&gt;
                 {&lt;br /&gt;
                     iProvider.SetPropertyOn(aValue != 0);&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         private readonly string iName;&lt;br /&gt;
         private readonly IDvDeviceFactory aDeviceFactory;&lt;br /&gt;
         private readonly IWidgetPublisher iWidgetPublisher;&lt;br /&gt;
         &lt;br /&gt;
         public BinaryLightDriver(&lt;br /&gt;
             string aName,&lt;br /&gt;
             IWidgetPublisher aPublisher,&lt;br /&gt;
             iDeviceFactory aDeviceFactory)&lt;br /&gt;
         {&lt;br /&gt;
             iWidgetPublisher = aPublisher;&lt;br /&gt;
             iName = aName;&lt;br /&gt;
             iDeviceFactory = aDeviceFactory;&lt;br /&gt;
         } &lt;br /&gt;
 &lt;br /&gt;
         public IEnumerable&amp;amp;lt;uint&amp;amp;gt; WidgetClasses&lt;br /&gt;
         {&lt;br /&gt;
             get { yield return (uint)WidgetKind.BinaryLight; }&lt;br /&gt;
         }  &lt;br /&gt;
 &lt;br /&gt;
         public void WidgetDiscovered(&lt;br /&gt;
             string aWidgetUdn,&lt;br /&gt;
             uint aWidgetClass,&lt;br /&gt;
             ISimpleUpnpWidget aSimpleUpnpWidget)&lt;br /&gt;
         {&lt;br /&gt;
             string newUdn = aWidgetUdn;&lt;br /&gt;
             DiscoveredWidget discoveredWidget = new DiscoveredWidget&lt;br /&gt;
                 (iDeviceFactory,&lt;br /&gt;
                  newUdn,&lt;br /&gt;
                  aSimpleUpnpWidget,&lt;br /&gt;
                  iWidgetPublisher);&lt;br /&gt;
 &lt;br /&gt;
             aSimpleUpnpWidget.Listen(&lt;br /&gt;
                 discoveredWidget.HandleInitialEvent,&lt;br /&gt;
                 discoveredWidget.HandleRegisterEvent,&lt;br /&gt;
                 discoveredWidget.HandleDisappearance);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 } //End of file&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Glossary = &lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
CPNW - Control Point, Node, Widget. The model of devices used in OpenHome environments.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by OpenHome to allow Nodes to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh - A collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs on ohOS.&lt;br /&gt;
&lt;br /&gt;
ohNet - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
ohOS - The OpenHome Operating System. Core software for OpenHome systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
UPnP - Universal Plug and Play. The network protocols set out by the UPnP Forum to allow networked devices to seamlessly establish connections and services.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. &lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. A typical Widget supports only one protocol.&lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	<entry>
		<id>http://wiki.openhome.org/wiki/OhWidget_Technical_Overview</id>
		<title>OhWidget Technical Overview</title>
		<link rel="alternate" type="text/html" href="http://wiki.openhome.org/wiki/OhWidget_Technical_Overview"/>
				<updated>2012-03-01T15:08:18Z</updated>
		
		<summary type="html">&lt;p&gt;Openhome: /* Glossary */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
This document provides a technical overview of the [[ohWidget|ohWidget]] home automation system and details about the physical architecture it uses. It introduces the concepts, terminology and interactions of each component of an ohWidget system.&lt;br /&gt;
&lt;br /&gt;
This document does not provide low-level technical information such as hardware specifications of the&lt;br /&gt;
Nodes nor code examples from the ohWidget API.&lt;br /&gt;
&lt;br /&gt;
== [[ohWidget|ohWidget]] ==&lt;br /&gt;
&lt;br /&gt;
[[ohWidget|ohWidget]] makes use of three distinct components: Widgets, Control Points and Nodes.&lt;br /&gt;
This document uses these three terms heavily throughout and are defined simply as follows:&lt;br /&gt;
&lt;br /&gt;
=== Widget ===&lt;br /&gt;
&lt;br /&gt;
Any device in an end-user's home that can be remotely controlled. Widgets can range in complexity from&lt;br /&gt;
simple single-service lights to multi-service audio/visual devices.&lt;br /&gt;
&lt;br /&gt;
=== Control Point ===&lt;br /&gt;
&lt;br /&gt;
A device used by the end-user to access the services provided by each Widget.&lt;br /&gt;
&lt;br /&gt;
=== Node ===&lt;br /&gt;
&lt;br /&gt;
The device used to aggregate devices and services published by Widgets, for quick and easy access by&lt;br /&gt;
Control Points.&lt;br /&gt;
&lt;br /&gt;
Together these three classes of device can be used in any number to create an [[ohWidget|ohWidget]] home automation system.&lt;br /&gt;
&lt;br /&gt;
== Node manufacturer benefits ==&lt;br /&gt;
&lt;br /&gt;
[[ohWidget|ohWidget]] supports Node manufacturers by:&lt;br /&gt;
&lt;br /&gt;
* providing a protocol-independent framework from which to build the communications hardware most suited to each manufacturer&lt;br /&gt;
* removing the tightly coupled nature of Control Points and devices that appears in other home automation systems&lt;br /&gt;
* allowing Widget vendors to specify the Widget requirements&lt;br /&gt;
* not tying Nodes directly to Widgets, and vice-versa&lt;br /&gt;
* providing a customizable user interface design to allow for smart and intuitive user experiences&lt;br /&gt;
&lt;br /&gt;
== Widget vendor benefits ==&lt;br /&gt;
&lt;br /&gt;
Widget vendors using [[ohWidget|ohWidget]] benefit from how little the need to do to make their Widgets [[ohWidget|ohWidget]] compatible.&lt;br /&gt;
&lt;br /&gt;
[[ohWidget|ohWidget]] supports Widget vendors by:&lt;br /&gt;
&lt;br /&gt;
* allowing the easy integration of Widgets to a connected home with the addition of a tiny amount of intelligence on the Widget itself, without the necessity for a large-scale redesign of the products&lt;br /&gt;
* supporting managed code for driver writing in C# allowing for faster development across multiple hardware implementations&lt;br /&gt;
* auto-generating several essential files from one central configuration file&lt;br /&gt;
* defining the configuration details of the device in simple XML which is easily created and maintained&lt;br /&gt;
&lt;br /&gt;
== User benefits ==&lt;br /&gt;
&lt;br /&gt;
The goal of [[ohWidget|ohWidget]] is to place the user at the center of their own home services by providing them an aggregated view of all the devices in their home, irrespective of the vendor.&lt;br /&gt;
&lt;br /&gt;
[[ohWidget|ohWidget]] puts the focus on the user in their home by:&lt;br /&gt;
&lt;br /&gt;
* giving users complete freedom of choice of which devices are used in their own home&lt;br /&gt;
* allowing existing, familiar devices to be used as the Control Point, including a choice from among smartphones and tablet PCs&lt;br /&gt;
* providing a system backbone that persists when in the home (removing the Control Point doesn't remove the system)&lt;br /&gt;
* providing a minimum set up system for home users by applying the benefits of Universal Plug and Play to all devices, independently of the communications protocol used by each device&lt;br /&gt;
* aggregating all Widgets in the home, regardless of vendor or protocol&lt;br /&gt;
* providing a truly scalable solution allowing the user to build their own smart home network as they wish&lt;br /&gt;
&lt;br /&gt;
= Technical Overview =&lt;br /&gt;
&lt;br /&gt;
A very simple view of an ohWidget connected home is shown in Figure 1 below. One Control Point&lt;br /&gt;
accesses a single Widget by interacting with the Node:&lt;br /&gt;
&lt;br /&gt;
[[File:CPNW.jpg|800px|thumb|center|Figure 1: An abstract view of a Control Point, Node and Widget using a home network to communicate.]]&lt;br /&gt;
&lt;br /&gt;
Key:&lt;br /&gt;
&lt;br /&gt;
* WAP: Wireless Access Point. A network point allowing the Control Point and Nodes to access the 802.11a/b/g/n protocol.&lt;br /&gt;
* PLC: Power Line Communications. Can be used to help extend ethernet connections around the home.&lt;br /&gt;
* LEC: Low Energy Communications. The module installed on the Node used to communicate with compatible Widgets. Examples are [http://www.6lowpan.org/ 6LowPan], [http://www.zigbee.org/ ZigBee], [http://www.sigmadesigns.com/solutions_subcat.php?id=24 Z-wave] or [http://www.bluetooth.com Bluetooth LE].&lt;br /&gt;
* Home network: A representation of any number of routers, switches and wireless access points in the home. This also includes wired Ethernet connections, indicated in the diagram by the thick lines between the Control Point, Home network and Node.&lt;br /&gt;
* Wireless comms: The protocol used by the Node and Widget to communicate with each other.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The Node is shown with a broken line through it to represent the possibility of a second Node being contacted to pass the message on to the Widget. At most a message will travel from Control Point &amp;gt; Node &amp;gt; Node &amp;gt; Widget (this is discussed in more detail in the Node chapter). In this case, the first Node will continue to use ethernet comms (potentially augmented by [http://en.wikipedia.org/wiki/Power_line_communication PLC]) to contact the second Node, and the second Node will use the LEC protocol to contact the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
An ohWidget network grows with no maintenance burden on the user when new Widgets are introduced. Communication between the Control Point and the Widget is key to ensuring a smart home functions efficiently as possible for users. &lt;br /&gt;
&lt;br /&gt;
The view shown in the diagram above places the emphasis for this scalability and openness on the Node.&lt;br /&gt;
Nodes treat both Widget and Control Point as abstract concepts and operate, for the most part, independently of the requirements of both. This is what stands ohWidget apart from other smart home systems.&lt;br /&gt;
&lt;br /&gt;
= Widgets = &lt;br /&gt;
&lt;br /&gt;
Widgets are any device that offer a service that can be interacted with from a Control Point. The Widget can be as complicated as an integrated audio streaming center or as simple as a light. &lt;br /&gt;
&lt;br /&gt;
To be an ohWidget compatible device, a Widget needs to have the following knowledge about itself:&lt;br /&gt;
* State — the current status of the Widget, such as On or Off&lt;br /&gt;
* Service — the list of actions and options the Widget offers over the network&lt;br /&gt;
* Unique identifier (UID) — the value used to identify the Widget from all others&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
These details must be present on the Widget. This small requirement means that almost any device can&lt;br /&gt;
be compatible with ohWidget.&lt;br /&gt;
&lt;br /&gt;
The intelligence and mechanisms required to access and use these details is not stored on the Widget.&lt;br /&gt;
ohWidget loads the intelligence on the Nodes rather than demand Widget vendors make their Widgets&lt;br /&gt;
more complicated than they have to be.&lt;br /&gt;
&lt;br /&gt;
== Classifying Widgets ==&lt;br /&gt;
&lt;br /&gt;
Some devices will already be complex in the range of function that they offer, whilst others will remain&lt;br /&gt;
simple devices offering one or two functions at most. The simpler devices, Widgets, are supported by&lt;br /&gt;
ohWidget's property list. These devices can have their functionality easily defined within the ohWidget&lt;br /&gt;
framework, producing both auto-generated code for developers and intuitive user interfaces to present the&lt;br /&gt;
Widget to the user.&lt;br /&gt;
&lt;br /&gt;
== Widgets in more detail ==&lt;br /&gt;
&lt;br /&gt;
A Widget is a simple hardware device such as a light or thermometer. Widgets communicate with the&lt;br /&gt;
Node using a low-energy communications protocol, such as [http://www.zigbee.org Zigbee] or [http://www.z-wave.com/modules/ZwaveStart/ Z-Wave]. They are controlled using&lt;br /&gt;
a device- and protocol-specific driver. Widget drivers are installed on the Node and used as required.&lt;br /&gt;
&lt;br /&gt;
For example, two Widgets providing an identical service over the same communications protocol will both&lt;br /&gt;
use the same copy of the device driver. A new Widget providing the same service as the first two but over&lt;br /&gt;
a different communications protocol will need a new device driver. A fourth Widget offering a different&lt;br /&gt;
service, but using the same protocol as the first two, will also need its own device driver.&lt;br /&gt;
&lt;br /&gt;
A more advanced device might not have its full range of functionality supported in the set of ohWidget&lt;br /&gt;
properties alone. These devices are called External Widgets. Their more complicated functions must be&lt;br /&gt;
defined externally of the ohWidget properties. However, ohWidget will fully integrate an External Widget&lt;br /&gt;
definition so that it can be presented seamlessly alongside other Widgets.&lt;br /&gt;
&lt;br /&gt;
[[File:MultipleDriverExplanation.png|800px|thumb|center|Figure 2: Four Widgets shown using three drivers installed on the Node]]&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
For more information on writing a Widget driver, see the [[ohWidget Driver Development|ohWidget Driver Development]] document&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
If we examine the list of compatibility requirements again, we see that Widgets automatically meet each&lt;br /&gt;
one:&lt;br /&gt;
&lt;br /&gt;
* State — Widgets will typically offer one state variable that can be changed (such as a light being able to turn on or off), so their state is readily and easily available.&lt;br /&gt;
* Service — As above, most Widgets will offer a single service that can be controlled which Widget vendors will write and publish in an XML description file.&lt;br /&gt;
* Unique Identifier (UID) — By providing the Widget with a communications protocol (such as a light that communicates over the [http://www.zigbee.org Zigbee] protocol) you also give it a MAC address. The Widget's MAC address can easily be used as the UID.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Widgets can be provided with a communications protocol either internally by including the protocol hardware in the body of the device itself, or externally by converting the device using a commercially available adapter. Either way, the Widget becomes network accessible and is assigned a MAC address.&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
Widget vendors are responsible for providing sufficient information about their Widgets in a Widget class driver. The information provided in the driver is written by the Widget vendor and released at the same time as the Widget. This does not mean, however, that it is necessarily packaged with the Widget. Some drivers will be deployed via an automatic download to the Node, or manually installed using a USB stick. This allows any Widget from any vendor to be added to the network (assuming that the Widget and the Node share a compatible communications protocol) and provides instant access to the Widget's services. No IP address or other complex TCP/IP stack requirements are placed on the Widget, keeping it simple and focused on its primary function. &lt;br /&gt;
&lt;br /&gt;
ohWidget allows Widgets to remain:&lt;br /&gt;
&lt;br /&gt;
* low in power consumption&lt;br /&gt;
* unhindered by the extra hardware and software expense that would have been required to maintain multiple communications protocols on a single device&lt;br /&gt;
* dedicated to providing the service it was designed for&lt;br /&gt;
&lt;br /&gt;
== External Widgets in more detail ==&lt;br /&gt;
&lt;br /&gt;
An External Widget is a complex hardware or software device that cannot have its controls and interface easily presented as a Widget. An External Widget will typically communicate over a network using TCP/IP, but can also use the same protocols as a Simple Widget (such as [http://www.zigbee.org Zigbee] or [http://www.z-wave.com/modules/ZwaveStart/ Z-Wave]). External widgets are hosted in separate apps. These apps have the ability of being displayed and controlled through the ohwidget user interface. For more details refer to the [[External Widget Application Development|External Widget Application Development]] document.&lt;br /&gt;
&lt;br /&gt;
== User Interface ==&lt;br /&gt;
&lt;br /&gt;
The responsibility for hosting the user interface (UI) to control Widgets is given to the Node. This ensures the Widget remains dedicated to providing the service it was originally designed for. By default, ohWidget will provide a full UI to allow users to control each function available on the Widget.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
For more details of UI hosting and Node UI design, see the User interface section in the Nodes chapter.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The Widget vendor must provide the details of how to control each device they manufacture for use in the smart home. This information is provided in the Widget Service XML file which is used to generate the UI.&lt;br /&gt;
&lt;br /&gt;
Each Widget UI provides both a summary and a details view. The summary view allows users quick access to a Widget's single basic function, such as a simple on/off command. The details view provides users access to the full range of functionality that the Widget offers. This allows vendors to be as specific as they like for each Widget they produce.&lt;br /&gt;
&lt;br /&gt;
The summary view is automatically displayed when the Widget has been detected on the network. The UI aggregates all of the available Widgets' summary views into a single list for the user.&lt;br /&gt;
&lt;br /&gt;
The details view can be auto-generated from the information provided in the service XML. Vendors can then customize the look of the details view UI with custom CSS and JavaScript.&lt;br /&gt;
&lt;br /&gt;
ohWidget does not restrict vendors in how they present their Widgets to the end-user. To assist Widget vendors in getting their product integrated into an ohWidget system as quickly and easily as possible, the details view can be generated automatically from the service XML Widget vendors write when releasing a new Widget.&lt;br /&gt;
&lt;br /&gt;
There is a list of supported controls that the auto-generation process generates from the XML into HTML, complete with CSS and associated JavaScript. Any other controls the vendor needs to have displayed can be provided in custom-written HTML alongside the auto-generated content.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The CSS is hosted on the Node and the auto-generated HTML will default to using this. If Widget vendors want to customize the look and feel of their UI they must provide their own custom CSS and ship it along with their HTML.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
This operation is carried out at compile time, before the Widget is shipped. &lt;br /&gt;
&lt;br /&gt;
See the [[External Widget Application Development|External Widget Application Development]] document for more information on writing custom details view UIs for External Widgets.&lt;br /&gt;
&lt;br /&gt;
= Control Points = &lt;br /&gt;
&lt;br /&gt;
== Control Points ==&lt;br /&gt;
&lt;br /&gt;
A Control Point is used by the end-user to control each of the Widgets in their smart home. A Control Point is itself a device, but isn't considered a Widget in the ohWidget system. &lt;br /&gt;
&lt;br /&gt;
The UI provided by ohWidget for Control Points to use is web-based. It is hosted on the Node and developed in two parts by Node manufacturers and Widget vendors, with auto-generation tools and support provided in the ohWidget software to assist this process. ohWidget provides support for the development of native Control Point applications to be developed, but the development of native applications is a manual process. ohWidget provides no auto-generation tools for native Control Point applications.&lt;br /&gt;
&lt;br /&gt;
== Familiar Devices ==&lt;br /&gt;
&lt;br /&gt;
A typical Control Point already exists in the modern-day home in the form of:&lt;br /&gt;
* tablet PC&lt;br /&gt;
* smart phone&lt;br /&gt;
* personal computer&lt;br /&gt;
* laptop&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A typical modern home has at least one of these devices (and in a lot of cases often more than one of each type) readily available to perform the function of Control Point in a smart home.&lt;br /&gt;
&lt;br /&gt;
Users are already comfortable using these devices and ohWidget is designed to leverage that comfort zone&lt;br /&gt;
and minimize further costs to the user.&lt;br /&gt;
&lt;br /&gt;
This leaves the user free to focus on choosing which Widgets they want to install in their home.&lt;br /&gt;
&lt;br /&gt;
== Flexible network architecture ==&lt;br /&gt;
&lt;br /&gt;
ohWidget provides a network architecture that allows the relationship between the Control Point and the&lt;br /&gt;
user's smart home to remain flexible at the hardware level, yet tightly bound at the software level. &lt;br /&gt;
&lt;br /&gt;
Other attempts at home automation use proprietary hardware for the Control Point, loading it with the intelligence needed to run the devices in your home meaning that it must remain in the home as a part of the network solution. In a way, it could be said that in those solutions the Control Point is the smart home network. &lt;br /&gt;
&lt;br /&gt;
ohWidget actively encourages users to use devices they already familiar with as their Control Point. Furthermore, the intelligence of the network is not placed on those devices, but on the Nodes connected to the Widgets. This reduces the learning curve for users, ensures their Widgets are always accessible and opens up the possibility to give users remote access to their home.&lt;br /&gt;
&lt;br /&gt;
Removing the Control Point from the home does not remove the ohWidget network. It persists as long as&lt;br /&gt;
the Nodes and Widgets remain connected. Devices such as tablet PCs, smart phones and laptop computers&lt;br /&gt;
are all readily usable as Control Points — both inside and out of the user's home.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
Control Point hardware is not delivered as part of the ohWidget home automation system, though the ability to present the services that Widgets provide is. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The model provides a simple Web server to run on the Node which is given the responsibility of serving the user interface to the Control Point. &lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Nodes =&lt;br /&gt;
&lt;br /&gt;
== Nodes ==&lt;br /&gt;
&lt;br /&gt;
A Node is a device used to bridge communications between a Control Point and the Widgets connected to the network.&lt;br /&gt;
&lt;br /&gt;
The ohWidget software for Nodes is designed to be hardware independent and isn't tied to any particular protocol when communicating with Widgets. The choice of hardware configuration used by Node manufacturers is not defined by OpenHome, and is not constrained by the ohWidget software.&lt;br /&gt;
&lt;br /&gt;
However, the use of the Universal Plug and Play (UPnP) protocol is mandatory for communications between the Nodes. This is built in to the ohWidget software.&lt;br /&gt;
&lt;br /&gt;
OpenHome recommend and support a small form-factor to easily introduce Nodes into the home of the end-user who might not have the technical ability of a modern smart home hobbyist, enthusiast or custom installer. Depending on the manufacturer's choice a Node may take the form of a plugcomputer or something more ubiquitous such as a light wall switch.&lt;br /&gt;
&lt;br /&gt;
== Self management ==&lt;br /&gt;
&lt;br /&gt;
When several Nodes are introduced to the same network they will negotiate with each other to arrange themselves into a robust network backbone within the home. The network enables Control Points to be able to connect to, and access the services on the Widgets connected to the network.&lt;br /&gt;
&lt;br /&gt;
Each Node maintains a list of the Widgets it controls, called the Widget registry. The Node publishes its Widget registry across the Node network. Every Node on the network aggregates the published Widget registries from other Nodes into one list. This means that every Node knows which is the controlling Node for each Widget on the network.&lt;br /&gt;
&lt;br /&gt;
Interconnected Nodes pass messages from one Node to another ensuring that the Control Point contacts the destination Widget via the correct controlling Node. At maximum the communication path will be no more than Control Point &amp;gt; presentation Node &amp;gt; controlling Node &amp;gt; Widget, with allowances for network routing in between.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
The Node contacted after the presentation Node will always be the Node that controls the destination&lt;br /&gt;
Widget. If the presentation Node is also the controlling Node, the communication path is&lt;br /&gt;
reduced by one step.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A presentation Node is the Node the Control Point is connected to when accessing the user interface. A Node can only be regarded as a presentation Node when a Control Point is connected to it. Otherwise it is equal in status among the other Nodes.&lt;br /&gt;
&lt;br /&gt;
Nodes are equal in their responsibilities when presenting the UI to a Control Point. Any Node is capable of presenting the UI to a Control Point. A Node may present the UI to any number of Control Points currently connected to it. There is no 1-to-1 mapping of Control Points to presentation Nodes.&lt;br /&gt;
&lt;br /&gt;
=== Widget aggregator ===&lt;br /&gt;
&lt;br /&gt;
When a Control Point connects to any Node, the full list of available Widgets is immediately available in&lt;br /&gt;
the UI. Any further filtering or arranging of the Widgets must be handled by the Control Point.&lt;br /&gt;
&lt;br /&gt;
Widgets are registered with the Nodes when they are added to the network. This occurs either automatically using automatic discovery or manually using the pairing mechanism provided by the specific communication protocol. No matter the method, all Widgets are maintained in the same list on the Node so that the Nodes have a single aggregation point to manage the entire list of available Widgets. Giving this function over to the Nodes removes the extra complexity from both the Control Point and the Widgets&lt;br /&gt;
that would otherwise be required to ensure services are kept available to the end-user.&lt;br /&gt;
&lt;br /&gt;
== Protocol independent Nodes ==&lt;br /&gt;
&lt;br /&gt;
=== Node to Node communication ===&lt;br /&gt;
&lt;br /&gt;
Nodes communicate with each other over Ethernet.&lt;br /&gt;
&lt;br /&gt;
=== Node to Widget communication ===&lt;br /&gt;
&lt;br /&gt;
It is not expected that Widgets should be stacked with the complex UPnP software and necessary extra hardware to support UPnP communications. Node to Widget communication is expected to use a lighter protocol.&lt;br /&gt;
&lt;br /&gt;
However, OpenHome recognizes the requirement for Widget vendors to select their own protocols for their Widgets, and provides an independent framework to allow the freedom of protocol choice.&lt;br /&gt;
&lt;br /&gt;
====Protocol independent communication ====&lt;br /&gt;
&lt;br /&gt;
The hardware limitations implicit in a small form factor Node mean that not every wireless communications protocol can be supported. Attempting to support several standards on a single Node has several consequences, including:&lt;br /&gt;
&lt;br /&gt;
* increasing the manufacturing costs of the Nodes&lt;br /&gt;
* power consumption increases with each new piece of hardware added to the Node&lt;br /&gt;
* practical issues such as shielding one protocol from another in a single Node&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
However, minimizing the list of supported protocols by preventing communications by one or more of the available methods is against the goal of OpenHome. Rather than attempt to support some at the risk of alienating others, OpenHome provides Node software that is completely protocol independent with software to support whatever hardware is implemented in the Nodes.&lt;br /&gt;
&lt;br /&gt;
The manufacturing choices will, ultimately, make that choice explicit. For example, a Node built with Bluetooth LE transceiver hardware will only be able to communicate with Widgets that are also Bluetooth LE enabled.&lt;br /&gt;
&lt;br /&gt;
Nodes built to support multiple protocols will likewise be constrained to communicate with only those Widgets that use those same protocols.&lt;br /&gt;
&lt;br /&gt;
OpenHome support both of these scenarios by not limiting the choices for manufacturers.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
Practically speaking it is not expected that Widget vendors will stack their devices with a range of communications protocols to ensure many types of Node can communicate with them. Rather, it is expected that Widget vendors will choose a Node manufacturer with whom they want to interoperate and design their Widgets to support the chosen Node manufacturer's implemented protocol.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Cooperation between Node manufacturers and Widget vendors will ensure each vendor's devices can communicate with each other.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
==== Widget service access ====&lt;br /&gt;
&lt;br /&gt;
ohOS places no constraint on the classes of Widgets that Nodes can communicate with. In fact, ohWidget Nodes will never need to ship with specific details about Widgets and the services or actions they provide.&lt;br /&gt;
&lt;br /&gt;
Instead, the Widget manufacturers are given the responsibility of providing the details required for the Node to communicate with their Widgets. &lt;br /&gt;
&lt;br /&gt;
This keeps the Nodes open and able to communicate with any Widget it can see on the home network, and also means that Node manufacturers are not spending their time concerned with a large amount of Widget implementation detail.&lt;br /&gt;
&lt;br /&gt;
The details that Nodes do require are stored in separate Widget drivers. The Node operates independently of the content of each Widget driver and, therefore, independently of the function of each Widget. See Widget class driver below for more details of drivers. &lt;br /&gt;
&lt;br /&gt;
Widget vendors have direct control over how much functionality each Widget exposes entirely independently of any conventions, consortium or forum. See the [[ohWidget Driver Development|ohWidget Driver Development]] document for more details about writing Widget drivers.&lt;br /&gt;
&lt;br /&gt;
This clear separation of responsibility allows Node manufacturers to be concerned only with the communications protocol they want to use, and the hardware implications of that choice. Widget vendors are solely responsible for providing the required details to allow Nodes access to the Widget.&lt;br /&gt;
&lt;br /&gt;
== Widget independent Nodes ==&lt;br /&gt;
&lt;br /&gt;
A Node is never fully aware of the services each Widget it has access to provides. The complexity of the Widget is an unimportant detail for Nodes. Instead each Node is provided with the necessary drivers it needs to communicate with the Widget. The driver is used when a message is passed between the Node and the Control Point.&lt;br /&gt;
&lt;br /&gt;
When the Node does not have access to the necessary driver, it will attempt to automatically retrieve it from an online resource. This can be either directly from the Widget vendor or from a database of drivers hosted elsewhere.&lt;br /&gt;
&lt;br /&gt;
Alternatively the driver can be loaded manually by the user, using whatever means are made available by the hardware in the Node (such as USB stick or SD card). Both automatic and manual resolutions involve low levels of interaction by the user. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Widget class driver ===&lt;br /&gt;
&lt;br /&gt;
Each class of Widget, and each Widget using a different communications protocol within that class (i.e. two Widgets, both in the binary light class, one of which communicates with [http://www.bluetooth.com Bluetooth LE] and the other with [http://www.zigbee.org Zigbee]), has its own driver. Widget drivers are installed on the Node. Each driver contains code to allow the Widget to accept actions and report events. &lt;br /&gt;
&lt;br /&gt;
An action is a message sent from the Control Point to the Widget, instructing the Widget to change its state in a particular way. Actions are initiated by the user from the UI, such as someone pressing the on button. An event is a message sent to the Control Point from the Widget, updating the Control Point about a change in the Widget's state. Events are initiated at the Widget, such as someone physically turning a light off.&lt;br /&gt;
&lt;br /&gt;
Many previous attempts at home automation solutions relied on the Widget coming stacked with the necessary protocols and other networking interface information, such as a TCP/IP stack. ohWidget moves this responsibility away from the vendors by placing the information on the Nodes, leaving them fully capable of communicating with any Widget that needs to connect to the network.&lt;br /&gt;
&lt;br /&gt;
To allow for the inclusion of more Widgets at any time the Nodes are designed to have no immediate knowledge of the Widgets in their vicinity. Beyond discovering the class of the Widget the Node remains functionally ignorant of each Widget, whether it be a light, a sprinkler or a thermostat. &lt;br /&gt;
&lt;br /&gt;
It is left to Widget vendors as the experts of their own device to provide the specific details in Widget class drivers about each service a Widget provides. Widget drivers are written using the API provided by ohWidget and augmented by the vendor as required to suit a specific Widget's needs (such as specific communication protocol requirements).&lt;br /&gt;
&lt;br /&gt;
Drivers must be written using managed code but can otherwise contain as much or as little code as the Widget vendors decide. ohWidget does not prescribe which services or actions Widget vendors can expose in their Widgets, leaving the Widget vendors free to implement their drivers with no compromise to any specific standard.&lt;br /&gt;
&lt;br /&gt;
== User interface ==&lt;br /&gt;
&lt;br /&gt;
=== UI host ===&lt;br /&gt;
&lt;br /&gt;
The Nodes are provided with a simple Web server. It hosts the user interface and gives the user access to the Widget's services. &lt;br /&gt;
&lt;br /&gt;
OpenHome recommends the use of plug computers for Nodes due to both their small form factor and their&lt;br /&gt;
processing power. The processing power of a plug computer is more than enough to serve the UI to the end-user.&lt;br /&gt;
&lt;br /&gt;
Using the Node as the UI host means that Widgets do not have extra responsibility added to them. It also allows Node manufacturers to customize the look and feel of the UI.&lt;br /&gt;
&lt;br /&gt;
Widget vendors can instead focus on the two most important aspects:&lt;br /&gt;
&lt;br /&gt;
* ensuring the Widget provides the best possible service it was designed for&lt;br /&gt;
* focusing the vendor's own developers on building clean, usable interfaces that are specific to a particular Widget&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== UI design ===&lt;br /&gt;
&lt;br /&gt;
The Node manufacturer has complete control over how the user interface looks and feels.&lt;br /&gt;
&lt;br /&gt;
{{Notebox}}&lt;br /&gt;
'''Important'''&lt;br /&gt;
&lt;br /&gt;
A reference UI is provided with the ohWidget software to display a list of aggregated services. Node manufacturers are entirely responsible for the design of the user interface beyond that.&lt;br /&gt;
&lt;br /&gt;
{{Noteboxend}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The HTML, JavaScript and CSS files provided with the UI SDK can be customized to suit the design&lt;br /&gt;
specifications of the Node manufacturer.&lt;br /&gt;
&lt;br /&gt;
ohWidget provides an API for manufacturers to develop UIs for their own Nodes. Presented as a Web-based API, it offers the simplest and easiest method to access the Widget's functionality. Using a Web-based presentation means that most end-users will be able to access the Widget's UI with no extra hardware costs. Most modern homes already have one or more Web-enabled devices already installed, whether it be a personal computer or a smartphone.&lt;br /&gt;
&lt;br /&gt;
The Web UI is capable of running on both types of device and the range of devices in between.&lt;br /&gt;
&lt;br /&gt;
= Glossary = &lt;br /&gt;
&lt;br /&gt;
Control Point - The device that displays the user interface which makes use of services on the&lt;br /&gt;
network to control a UPnP device.&lt;br /&gt;
&lt;br /&gt;
Node - The communications bridge between the Control Point and the Widget. Also the target for deployment of ohApps.&lt;br /&gt;
&lt;br /&gt;
Node communication protocol - The custom UPnP protocol provided by Openhome to allow Nodes to communicate&lt;br /&gt;
with each other.&lt;br /&gt;
&lt;br /&gt;
Node mesh - A collection of Nodes that intercommunicate.&lt;br /&gt;
&lt;br /&gt;
ohApp - An application that runs inside ohOS.&lt;br /&gt;
&lt;br /&gt;
[[ohNet|ohNet]] - Library for discovering, eventing and controlling services on a network. Includes a full implementation of the UPnP stack.&lt;br /&gt;
&lt;br /&gt;
[[ohOs|ohOs]] - The Openhome Operating System. Core software for ohWidget systems that runs on Nodes.&lt;br /&gt;
&lt;br /&gt;
Widget - The physical device installed in the user's home to provide them with a service. Typical Widgets are lights, speakers, temperature controls.&lt;br /&gt;
&lt;br /&gt;
Widget communication protocol - The protocol used by the Widget to advertise its availability and services to the Nodes. Widget manufacturers are responsible for choosing which protocols each Widget supports. A typical Widget supports only one Widget communication protocol. &lt;br /&gt;
&lt;br /&gt;
Widget driver - The software used by the Node to communicate with the Widget.&lt;/div&gt;</summary>
		<author><name>Openhome</name></author>	</entry>

	</feed>