Add some different xPL implementations done by Telldus
This commit is contained in:
parent
deebf2045e
commit
d4b46c71ec
21 changed files with 2285 additions and 0 deletions
371
xpl/data/uml.xmi
Normal file
371
xpl/data/uml.xmi
Normal file
|
@ -0,0 +1,371 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<XMI verified="false" xmi.version="1.2" timestamp="2009-08-20T21:13:04" xmlns:UML="http://schema.omg.org/spec/UML/1.3" >
|
||||
<XMI.header>
|
||||
<XMI.documentation>
|
||||
<XMI.exporter>umbrello uml modeller http://uml.sf.net</XMI.exporter>
|
||||
<XMI.exporterVersion>1.5.8</XMI.exporterVersion>
|
||||
<XMI.exporterEncoding>UnicodeUTF8</XMI.exporterEncoding>
|
||||
</XMI.documentation>
|
||||
<XMI.metamodel xmi.version="1.3" href="UML.xml" xmi.name="UML" />
|
||||
</XMI.header>
|
||||
<XMI.content>
|
||||
<UML:Model isSpecification="false" isAbstract="false" isLeaf="false" xmi.id="m1" isRoot="false" name="UML Model" >
|
||||
<UML:Namespace.ownedElement>
|
||||
<UML:Stereotype visibility="public" isSpecification="false" namespace="m1" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="folder" name="folder" />
|
||||
<UML:Stereotype visibility="public" isSpecification="false" namespace="m1" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="datatype" name="datatype" />
|
||||
<UML:Stereotype visibility="public" isSpecification="false" namespace="m1" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="enum" name="enum" />
|
||||
<UML:Model stereotype="folder" visibility="public" isSpecification="false" namespace="m1" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="Logical View" name="Logical View" >
|
||||
<UML:Namespace.ownedElement>
|
||||
<UML:Package stereotype="folder" visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="Datatypes" name="Datatypes" >
|
||||
<UML:Namespace.ownedElement>
|
||||
<UML:DataType stereotype="datatype" visibility="public" isSpecification="false" namespace="Datatypes" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="IGSdGv66Dl0t" name="int" />
|
||||
<UML:DataType stereotype="datatype" visibility="public" isSpecification="false" namespace="Datatypes" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="U4XSIE3QJ6hx" name="char" />
|
||||
<UML:DataType stereotype="datatype" visibility="public" isSpecification="false" namespace="Datatypes" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="wqDoP5wfLOIc" name="bool" />
|
||||
<UML:DataType stereotype="datatype" visibility="public" isSpecification="false" namespace="Datatypes" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="HMiS7gMcit21" name="float" />
|
||||
<UML:DataType stereotype="datatype" visibility="public" isSpecification="false" namespace="Datatypes" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="63PN95L5vWtI" name="double" />
|
||||
<UML:DataType stereotype="datatype" visibility="public" isSpecification="false" namespace="Datatypes" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="bnxw9DWQZCtg" name="short" />
|
||||
<UML:DataType stereotype="datatype" visibility="public" isSpecification="false" namespace="Datatypes" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="sDGZ4IaALxYS" name="long" />
|
||||
<UML:DataType stereotype="datatype" visibility="public" isSpecification="false" namespace="Datatypes" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="2rVxNPDwAAqK" name="unsigned int" />
|
||||
<UML:DataType stereotype="datatype" visibility="public" isSpecification="false" namespace="Datatypes" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="NNkuXbbOmpxp" name="unsigned short" />
|
||||
<UML:DataType stereotype="datatype" visibility="public" isSpecification="false" namespace="Datatypes" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="8XzRUVsXMNSh" name="unsigned long" />
|
||||
<UML:DataType stereotype="datatype" visibility="public" isSpecification="false" namespace="Datatypes" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="kedvoSFAnx4K" name="string" />
|
||||
<UML:DataType stereotype="datatype" visibility="public" isSpecification="false" namespace="Datatypes" isAbstract="false" isLeaf="false" elementReference="dvT79RUD0eZq" isRoot="false" xmi.id="blfxn9Uuu2yR" name="Map<string, string>" />
|
||||
</UML:Namespace.ownedElement>
|
||||
</UML:Package>
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="XdiJTf8ZA6yd" name="xPLMessage" >
|
||||
<UML:Classifier.feature>
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="Oy4sMfnqmwFE" type="blfxn9Uuu2yR" name="body" />
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="7Dsh3RQhMBqr" type="IGSdGv66Dl0t" name="hop" />
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="o7d2CrsruJHZ" type="kedvoSFAnx4K" name="source" />
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="fRQUU8LUIdpp" type="kedvoSFAnx4K" name="target" />
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="tCGUEQs0VW0i" type="ZqAwEabwEDr1" name="identifier" />
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="HHoVQbGDrTVa" type="kedvoSFAnx4K" name="messageSchemeIdentifier" />
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="IvRClCZ1LX9n" name="xPLMessage" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter visibility="private" isSpecification="false" xmi.id="fqxUu37A4RS3" type="ZqAwEabwEDr1" value="" name="identifier" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="uUirWhfMjnAf" name="addBodyItem" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter visibility="private" isSpecification="false" xmi.id="5UmJmRq4exRu" type="kedvoSFAnx4K" value="" name="key" />
|
||||
<UML:Parameter visibility="private" isSpecification="false" xmi.id="gUweefMhDcVo" type="kedvoSFAnx4K" value="" name="value" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="Ujr3jkVCgowi" name="addHeadItem" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter visibility="private" isSpecification="false" xmi.id="M6EhfsocNMwl" type="kedvoSFAnx4K" value="" name="key" />
|
||||
<UML:Parameter visibility="private" isSpecification="false" xmi.id="vB79kv7SfBkB" type="kedvoSFAnx4K" value="" name="value" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="true" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="Zvm4WIb2Z2yx" name="bodyItem" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter kind="return" xmi.id="rqKcz5n6oSXF" type="kedvoSFAnx4K" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="0U12xzu7s4bX" name="setMessageSchemeIdentifier" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter visibility="private" isSpecification="false" xmi.id="0baZghhFr2Gt" type="ZqAwEabwEDr1" value="" name="msi" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="IjmpHLdfT2KV" name="setSource" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter visibility="private" isSpecification="false" xmi.id="rmmDgsIsGvAe" type="kedvoSFAnx4K" value="" name="value" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="5F2P6cAAbBHb" name="setTarget" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter visibility="private" isSpecification="false" xmi.id="SpoO35A5dPta" type="kedvoSFAnx4K" value="" name="value" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="rfXl2OnJiltE" name="source" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter kind="return" xmi.id="WAMYNo0vYq2M" type="kedvoSFAnx4K" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="qZIqOH4DSRXm" name="target" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter kind="return" xmi.id="w1rngMZgkKzR" type="kedvoSFAnx4K" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="true" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="tM3YAlRVdQgs" name="toString" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter kind="return" xmi.id="5XkHvMEmhb5n" type="kedvoSFAnx4K" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" ownerScope="classifier" isRoot="false" xmi.id="MKlnQwQyMUPk" name="createMessageFromString" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter kind="return" xmi.id="dHW4EsYbaZuh" type="XdiJTf8ZA6yd" />
|
||||
<UML:Parameter visibility="private" isSpecification="false" xmi.id="ZN62oiIzXjU7" type="kedvoSFAnx4K" value="" name="message" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
</UML:Classifier.feature>
|
||||
</UML:Class>
|
||||
<UML:Enumeration stereotype="enum" visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="ZqAwEabwEDr1" name="Identifier" >
|
||||
<UML:EnumerationLiteral visibility="public" isSpecification="false" namespace="ZqAwEabwEDr1" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="a2Smc4ipHYou" name="xpl-cmnd" />
|
||||
<UML:EnumerationLiteral visibility="public" isSpecification="false" namespace="ZqAwEabwEDr1" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="gnMEpp0PriC6" name="xpl-stat" />
|
||||
<UML:EnumerationLiteral visibility="public" isSpecification="false" namespace="ZqAwEabwEDr1" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="R3WGxP4bAOpz" name="xpl-trig" />
|
||||
</UML:Enumeration>
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="dvT79RUD0eZq" name="Map" />
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="4xTqfjoBSIIy" name="xPLInstance" >
|
||||
<UML:Classifier.feature>
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="gzfxVRaEH2yu" type="EhAjKT6PpPv2" name="thisDevice" />
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="6hYNhUIrbCdr" type="EhAjKT6PpPv2" name="devices[]" />
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="ijPzFRB6xmeW" name="xPLInstance" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter visibility="private" isSpecification="false" xmi.id="CHVlflsSjf9B" type="EhAjKT6PpPv2" value="" name="device" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="QBcO7FmfSSb5" name="xPLInstance" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter visibility="private" isSpecification="false" xmi.id="RTrVOEMT27QK" type="kedvoSFAnx4K" value="" name="vendor" />
|
||||
<UML:Parameter visibility="private" isSpecification="false" xmi.id="pZAPjjbo64Jc" type="kedvoSFAnx4K" value="" name="device" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="wveG7Ynvnhnk" name="attatched" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter kind="return" xmi.id="luTzkEVhEVCS" type="wqDoP5wfLOIc" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="6ZLoecJsWISz" name="detach" />
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="G2jy7qV2pA4v" name="devices" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter kind="return" xmi.id="3jSGxUztZpPb" type="EhAjKT6PpPv2" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="true" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="lFdgofbt1M6S" name="sendMessage" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter visibility="private" isSpecification="false" xmi.id="hnmruig0iw66" type="XdiJTf8ZA6yd" value="" name="message" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="protected" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="bCE0DS6qC5QW" name="attatchedToNetwork" />
|
||||
<UML:Operation visibility="protected" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="moaxEeoRjCxr" name="handleMessage" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter kind="return" xmi.id="LD8G4G2pzErD" type="wqDoP5wfLOIc" />
|
||||
<UML:Parameter visibility="private" isSpecification="false" xmi.id="9V85HisHjStJ" type="XdiJTf8ZA6yd" value="" name="message" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
</UML:Classifier.feature>
|
||||
</UML:Class>
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="EhAjKT6PpPv2" name="xPLDevice" >
|
||||
<UML:Classifier.feature>
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="5LzeZ6f1a24e" type="kedvoSFAnx4K" name="vendor" />
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="r7p70tyF8bH0" type="kedvoSFAnx4K" name="device" />
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="gvkX0lhPYP5H" type="kedvoSFAnx4K" name="instance" />
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="sawPoTW1GCXN" type="kedvoSFAnx4K" name="address" />
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="st4NSOrILO1a" type="IGSdGv66Dl0t" name="heartbeatInterval" />
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="1PNIBOyUoUUx" type="IGSdGv66Dl0t" name="port" />
|
||||
<UML:Attribute visibility="private" isSpecification="false" xmi.id="jU2f3VMLHg33" type="P9JIMGtNBq3k" name="lastHeartBeat" />
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="uHpYNKyBWovy" name="xPLDevice" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter visibility="private" isSpecification="false" xmi.id="qRHXZ0q35DqS" type="kedvoSFAnx4K" value="" name="vendor" />
|
||||
<UML:Parameter visibility="private" isSpecification="false" xmi.id="8soItGDA5jYO" type="kedvoSFAnx4K" value="" name="device" />
|
||||
<UML:Parameter visibility="private" isSpecification="false" xmi.id="ihuWcqZSIoyr" type="kedvoSFAnx4K" value="" name="instance" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="pmsszjK7Z9NS" name="xPLDevice" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter visibility="private" isSpecification="false" xmi.id="NYbQI7oymhSN" type="kedvoSFAnx4K" value="" name="vendor" />
|
||||
<UML:Parameter visibility="private" isSpecification="false" xmi.id="X1nnnldaVVSU" type="kedvoSFAnx4K" value="" name="device" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="true" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="rxv2JOVkHT5S" name="address" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter kind="return" xmi.id="6sTypq4ddy6C" type="kedvoSFAnx4K" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="true" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="gowBqombL9ae" name="heartBeatInterval" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter kind="return" xmi.id="gim7k4LmGj6g" type="IGSdGv66Dl0t" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="true" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="1HoixgmuU10N" name="deviceName" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter kind="return" xmi.id="PL0k7PSvf2Gm" type="kedvoSFAnx4K" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="true" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="BIvEFJyCZGpO" name="lastHeartBeat" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter kind="return" xmi.id="56bP90wqKGUp" type="P9JIMGtNBq3k" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="true" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="CUdVuyok5Btg" name="port" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter kind="return" xmi.id="lWuymn7SufRD" type="IGSdGv66Dl0t" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="4RXtnfpZOlly" name="setAddress" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter visibility="private" isSpecification="false" xmi.id="1MJSZetHX46j" type="kedvoSFAnx4K" value="" name="address" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="jDamtEfHNoSK" name="setHeartBeatInterval" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter visibility="private" isSpecification="false" xmi.id="MSTbJJwgWBKp" type="IGSdGv66Dl0t" value="" name="minutes" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="la9uc1o3SziP" name="setLastHeartbeat" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter visibility="private" isSpecification="false" xmi.id="PEdHSGRODs9y" type="P9JIMGtNBq3k" value="" name="timestamp" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
<UML:Operation visibility="public" isSpecification="false" isQuery="false" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="nQWXNeQsFSEb" name="setPort" >
|
||||
<UML:BehavioralFeature.parameter>
|
||||
<UML:Parameter visibility="private" isSpecification="false" xmi.id="z1XnDSALsQqX" type="IGSdGv66Dl0t" value="" name="port" />
|
||||
</UML:BehavioralFeature.parameter>
|
||||
</UML:Operation>
|
||||
</UML:Classifier.feature>
|
||||
</UML:Class>
|
||||
<UML:Enumeration stereotype="enum" visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="ioL5YhpoYAWd" name="OperationMode" >
|
||||
<UML:EnumerationLiteral visibility="public" isSpecification="false" namespace="ioL5YhpoYAWd" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="7C7bDTwbQv2H" name="Client" />
|
||||
<UML:EnumerationLiteral visibility="public" isSpecification="false" namespace="ioL5YhpoYAWd" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="DQHpEraw64eW" name="Disconnected" />
|
||||
<UML:EnumerationLiteral visibility="public" isSpecification="false" namespace="ioL5YhpoYAWd" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="MsihEUMf7fjn" name="Hub" />
|
||||
</UML:Enumeration>
|
||||
<UML:Class visibility="public" isSpecification="false" namespace="Logical View" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="P9JIMGtNBq3k" name="datetime" />
|
||||
</UML:Namespace.ownedElement>
|
||||
<XMI.extension xmi.extender="umbrello" >
|
||||
<diagrams>
|
||||
<diagram showopsig="1" linecolor="#ff0000" snapx="10" showattribassocs="1" snapy="10" linewidth="0" showattsig="1" showpubliconly="0" showpackage="1" showstereotype="1" name="class diagram" font="Sans Serif,10,-1,0,50,0,0,0,0,0" canvasheight="801" canvaswidth="1075" localid="" snapcsgrid="0" showgrid="0" showops="1" usefillcolor="1" fillcolor="#ffff00" zoom="100" xmi.id="hb855HgsAFsZ" documentation="" showscope="1" snapgrid="0" showatts="1" type="1" >
|
||||
<widgets>
|
||||
<classwidget linecolor="#ff0000" usesdiagramfillcolor="0" linewidth="none" showoperations="1" usesdiagramusefillcolor="0" showpubliconly="0" showpackage="1" x="86" showattsigs="601" showstereotype="1" y="55" showattributes="1" font="Sans Serif,10,-1,5,75,0,0,0,0,0" width="401" isinstance="0" usefillcolor="1" fillcolor="#ffff00" xmi.id="XdiJTf8ZA6yd" showscope="1" height="288" showopsigs="601" />
|
||||
<enumwidget width="79" showstereotype="1" x="546" y="54" usesdiagramusefillcolor="1" usesdiagramfillcolor="1" isinstance="0" fillcolor="none" height="80" linecolor="none" xmi.id="ZqAwEabwEDr1" showpackage="1" usefillcolor="1" linewidth="none" font="Sans Serif,10,-1,0,50,0,0,0,0,0" />
|
||||
<classwidget linecolor="#ff0000" usesdiagramfillcolor="0" linewidth="none" showoperations="1" usesdiagramusefillcolor="0" showpubliconly="0" showpackage="1" x="106" showattsigs="601" showstereotype="1" y="380" showattributes="1" font="Sans Serif,10,-1,5,75,0,0,0,0,0" width="324" isinstance="0" usefillcolor="1" fillcolor="#ffff00" xmi.id="4xTqfjoBSIIy" showscope="1" height="176" showopsigs="601" />
|
||||
<classwidget linecolor="#ff0000" usesdiagramfillcolor="0" linewidth="none" showoperations="1" usesdiagramusefillcolor="0" showpubliconly="0" showpackage="1" x="529" showattsigs="601" showstereotype="1" y="180" showattributes="1" font="Sans Serif,10,-1,5,50,0,0,0,0,0" width="399" isinstance="0" usefillcolor="1" fillcolor="#ffff00" xmi.id="EhAjKT6PpPv2" showscope="1" height="304" showopsigs="601" />
|
||||
</widgets>
|
||||
<messages/>
|
||||
<associations>
|
||||
<assocwidget indexa="1" indexb="1" visibilityA="0" widgetaid="XdiJTf8ZA6yd" visibilityB="0" linecolor="none" changeabilityA="900" totalcounta="2" xmi.id="tCGUEQs0VW0i" changeabilityB="900" widgetbid="ZqAwEabwEDr1" totalcountb="2" type="510" linewidth="none" >
|
||||
<linepath>
|
||||
<startpoint startx="487" starty="115" />
|
||||
<endpoint endx="546" endy="115" />
|
||||
</linepath>
|
||||
<floatingtext linecolor="none" usesdiagramfillcolor="1" linewidth="none" usesdiagramusefillcolor="1" x="482" showstereotype="1" y="117" text="identifier" font="Sans Serif,10,-1,0,50,0,0,0,0,0" pretext="-" role="710" width="66" isinstance="0" posttext="" usefillcolor="1" fillcolor="none" xmi.id="NcywuLejcB4E" height="22" />
|
||||
</assocwidget>
|
||||
<assocwidget indexa="1" indexb="1" visibilityA="0" widgetaid="4xTqfjoBSIIy" visibilityB="0" linecolor="none" changeabilityA="900" totalcounta="3" xmi.id="gzfxVRaEH2yu" changeabilityB="900" widgetbid="EhAjKT6PpPv2" totalcountb="3" type="510" linewidth="none" >
|
||||
<linepath>
|
||||
<startpoint startx="430" starty="432" />
|
||||
<endpoint endx="529" endy="432" />
|
||||
</linepath>
|
||||
<floatingtext linecolor="none" usesdiagramfillcolor="1" linewidth="none" usesdiagramusefillcolor="1" x="452" showstereotype="1" y="400" text="thisDevice" font="Sans Serif,10,-1,0,50,0,0,0,0,0" pretext="-" role="710" width="77" isinstance="0" posttext="" usefillcolor="1" fillcolor="none" xmi.id="dUkwuSZTB6bL" height="22" />
|
||||
</assocwidget>
|
||||
<assocwidget indexa="2" indexb="2" visibilityA="0" widgetaid="4xTqfjoBSIIy" visibilityB="0" linecolor="none" changeabilityA="900" totalcounta="3" xmi.id="6hYNhUIrbCdr" changeabilityB="900" widgetbid="EhAjKT6PpPv2" totalcountb="3" type="510" linewidth="none" >
|
||||
<linepath>
|
||||
<startpoint startx="430" starty="432" />
|
||||
<endpoint endx="529" endy="432" />
|
||||
</linepath>
|
||||
<floatingtext linecolor="none" usesdiagramfillcolor="1" linewidth="none" usesdiagramusefillcolor="1" x="459" showstereotype="1" y="434" text="devices[]" font="Sans Serif,10,-1,0,50,0,0,0,0,0" pretext="-" role="710" width="68" isinstance="0" posttext="" usefillcolor="1" fillcolor="none" xmi.id="QBvCzLeKycFq" height="22" />
|
||||
</assocwidget>
|
||||
</associations>
|
||||
</diagram>
|
||||
</diagrams>
|
||||
</XMI.extension>
|
||||
</UML:Model>
|
||||
<UML:Model stereotype="folder" visibility="public" isSpecification="false" namespace="m1" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="Use Case View" name="Use Case View" >
|
||||
<UML:Namespace.ownedElement/>
|
||||
</UML:Model>
|
||||
<UML:Model stereotype="folder" visibility="public" isSpecification="false" namespace="m1" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="Component View" name="Component View" >
|
||||
<UML:Namespace.ownedElement/>
|
||||
</UML:Model>
|
||||
<UML:Model stereotype="folder" visibility="public" isSpecification="false" namespace="m1" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="Deployment View" name="Deployment View" >
|
||||
<UML:Namespace.ownedElement/>
|
||||
</UML:Model>
|
||||
<UML:Model stereotype="folder" visibility="public" isSpecification="false" namespace="m1" isAbstract="false" isLeaf="false" isRoot="false" xmi.id="Entity Relationship Model" name="Entity Relationship Model" >
|
||||
<UML:Namespace.ownedElement/>
|
||||
</UML:Model>
|
||||
</UML:Namespace.ownedElement>
|
||||
</UML:Model>
|
||||
</XMI.content>
|
||||
<XMI.extensions xmi.extender="umbrello" >
|
||||
<docsettings viewid="hb855HgsAFsZ" uniqueid="w1rngMZgkKzR" documentation="" />
|
||||
<listview>
|
||||
<listitem open="1" type="800" label="Views" >
|
||||
<listitem open="1" type="801" id="Logical View" >
|
||||
<listitem open="0" type="807" id="hb855HgsAFsZ" label="class diagram" />
|
||||
<listitem open="1" type="813" id="dvT79RUD0eZq" />
|
||||
<listitem open="1" type="813" id="P9JIMGtNBq3k" />
|
||||
<listitem open="1" type="813" id="EhAjKT6PpPv2" >
|
||||
<listitem open="0" type="814" id="5LzeZ6f1a24e" />
|
||||
<listitem open="0" type="814" id="r7p70tyF8bH0" />
|
||||
<listitem open="0" type="814" id="gvkX0lhPYP5H" />
|
||||
<listitem open="0" type="814" id="sawPoTW1GCXN" />
|
||||
<listitem open="0" type="814" id="st4NSOrILO1a" />
|
||||
<listitem open="0" type="814" id="1PNIBOyUoUUx" />
|
||||
<listitem open="0" type="814" id="jU2f3VMLHg33" />
|
||||
<listitem open="0" type="815" id="uHpYNKyBWovy" />
|
||||
<listitem open="0" type="815" id="pmsszjK7Z9NS" />
|
||||
<listitem open="0" type="815" id="rxv2JOVkHT5S" />
|
||||
<listitem open="0" type="815" id="gowBqombL9ae" />
|
||||
<listitem open="0" type="815" id="1HoixgmuU10N" />
|
||||
<listitem open="0" type="815" id="BIvEFJyCZGpO" />
|
||||
<listitem open="0" type="815" id="CUdVuyok5Btg" />
|
||||
<listitem open="0" type="815" id="4RXtnfpZOlly" />
|
||||
<listitem open="0" type="815" id="jDamtEfHNoSK" />
|
||||
<listitem open="0" type="815" id="la9uc1o3SziP" />
|
||||
<listitem open="0" type="815" id="nQWXNeQsFSEb" />
|
||||
</listitem>
|
||||
<listitem open="1" type="813" id="4xTqfjoBSIIy" >
|
||||
<listitem open="0" type="814" id="gzfxVRaEH2yu" />
|
||||
<listitem open="0" type="814" id="6hYNhUIrbCdr" />
|
||||
<listitem open="0" type="815" id="ijPzFRB6xmeW" />
|
||||
<listitem open="0" type="815" id="QBcO7FmfSSb5" />
|
||||
<listitem open="0" type="815" id="wveG7Ynvnhnk" />
|
||||
<listitem open="0" type="815" id="6ZLoecJsWISz" />
|
||||
<listitem open="0" type="815" id="G2jy7qV2pA4v" />
|
||||
<listitem open="0" type="815" id="lFdgofbt1M6S" />
|
||||
<listitem open="0" type="815" id="bCE0DS6qC5QW" />
|
||||
<listitem open="0" type="815" id="moaxEeoRjCxr" />
|
||||
</listitem>
|
||||
<listitem open="1" type="813" id="XdiJTf8ZA6yd" >
|
||||
<listitem open="0" type="814" id="Oy4sMfnqmwFE" />
|
||||
<listitem open="0" type="814" id="7Dsh3RQhMBqr" />
|
||||
<listitem open="0" type="814" id="o7d2CrsruJHZ" />
|
||||
<listitem open="0" type="814" id="fRQUU8LUIdpp" />
|
||||
<listitem open="0" type="814" id="tCGUEQs0VW0i" />
|
||||
<listitem open="0" type="814" id="HHoVQbGDrTVa" />
|
||||
<listitem open="0" type="815" id="IvRClCZ1LX9n" />
|
||||
<listitem open="0" type="815" id="uUirWhfMjnAf" />
|
||||
<listitem open="0" type="815" id="Ujr3jkVCgowi" />
|
||||
<listitem open="0" type="815" id="Zvm4WIb2Z2yx" />
|
||||
<listitem open="0" type="815" id="0U12xzu7s4bX" />
|
||||
<listitem open="0" type="815" id="IjmpHLdfT2KV" />
|
||||
<listitem open="0" type="815" id="5F2P6cAAbBHb" />
|
||||
<listitem open="0" type="815" id="rfXl2OnJiltE" />
|
||||
<listitem open="0" type="815" id="qZIqOH4DSRXm" />
|
||||
<listitem open="0" type="815" id="tM3YAlRVdQgs" />
|
||||
<listitem open="0" type="815" id="MKlnQwQyMUPk" />
|
||||
</listitem>
|
||||
<listitem open="0" type="830" id="Datatypes" >
|
||||
<listitem open="1" type="829" id="blfxn9Uuu2yR" />
|
||||
<listitem open="1" type="829" id="wqDoP5wfLOIc" />
|
||||
<listitem open="1" type="829" id="U4XSIE3QJ6hx" />
|
||||
<listitem open="1" type="829" id="63PN95L5vWtI" />
|
||||
<listitem open="1" type="829" id="HMiS7gMcit21" />
|
||||
<listitem open="1" type="829" id="IGSdGv66Dl0t" />
|
||||
<listitem open="1" type="829" id="sDGZ4IaALxYS" />
|
||||
<listitem open="1" type="829" id="bnxw9DWQZCtg" />
|
||||
<listitem open="1" type="829" id="kedvoSFAnx4K" />
|
||||
<listitem open="1" type="829" id="2rVxNPDwAAqK" />
|
||||
<listitem open="1" type="829" id="8XzRUVsXMNSh" />
|
||||
<listitem open="1" type="829" id="NNkuXbbOmpxp" />
|
||||
</listitem>
|
||||
<listitem open="1" type="831" id="ZqAwEabwEDr1" >
|
||||
<listitem open="0" type="839" id="a2Smc4ipHYou" />
|
||||
<listitem open="0" type="839" id="gnMEpp0PriC6" />
|
||||
<listitem open="0" type="839" id="R3WGxP4bAOpz" />
|
||||
</listitem>
|
||||
<listitem open="1" type="831" id="ioL5YhpoYAWd" >
|
||||
<listitem open="0" type="839" id="7C7bDTwbQv2H" />
|
||||
<listitem open="0" type="839" id="DQHpEraw64eW" />
|
||||
<listitem open="0" type="839" id="MsihEUMf7fjn" />
|
||||
</listitem>
|
||||
</listitem>
|
||||
<listitem open="1" type="802" id="Use Case View" />
|
||||
<listitem open="1" type="821" id="Component View" />
|
||||
<listitem open="1" type="827" id="Deployment View" />
|
||||
<listitem open="1" type="836" id="Entity Relationship Model" />
|
||||
</listitem>
|
||||
</listview>
|
||||
<codegeneration>
|
||||
<codegenerator language="C++" />
|
||||
</codegeneration>
|
||||
</XMI.extensions>
|
||||
</XMI>
|
21
xpl/phpxpl/example.php
Normal file
21
xpl/phpxpl/example.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
require_once 'xpllighting.class.php';
|
||||
|
||||
$xplinstance = new XPLLighting('192.168.0.50');
|
||||
|
||||
$running = true;
|
||||
declare(ticks = 1) {
|
||||
pcntl_signal( SIGINT, 'signalHandler' );
|
||||
while($running) {
|
||||
if ($xplinstance->doEvents()) {
|
||||
usleep(100);
|
||||
}
|
||||
}
|
||||
$xplinstance->detach();
|
||||
}
|
||||
|
||||
function signalHandler() {
|
||||
global $running;
|
||||
$running = false;
|
||||
}
|
66
xpl/phpxpl/xpldevice.class.php
Normal file
66
xpl/phpxpl/xpldevice.class.php
Normal file
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
define('DEFAULT_HBEAT_INTERVAL', 5);
|
||||
|
||||
class xPLDevice {
|
||||
|
||||
private $_heartBeatInterval = DEFAULT_HBEAT_INTERVAL;
|
||||
private $_port = 0;
|
||||
private $_vendor = '';
|
||||
private $_device = '';
|
||||
private $_instance = '';
|
||||
private $_address = '';
|
||||
private $_lastHeartBeat = 0;
|
||||
|
||||
public function __construct( $vendor, $device = null ) {
|
||||
if (is_null($device)) {
|
||||
$dash = strpos($vendor, '-');
|
||||
$dot = strpos($vendor, '.');
|
||||
$this->_vendor = substr($vendor, 0, $dash);
|
||||
$this->_device = substr($vendor, $dash+1, $dot-$dash-1);
|
||||
$this->_instance = substr($vendor, $dot+1);
|
||||
} else {
|
||||
$this->_vendor = $vendor;
|
||||
$this->_device = $device;
|
||||
|
||||
//Generate an instance
|
||||
$randomNumber = mt_rand(1, 9999); //Generate ranom number between 1-9999
|
||||
$this->_instance = sprintf('default%s', $randomNumber);
|
||||
}
|
||||
}
|
||||
|
||||
public function address() {
|
||||
return $this->_address;
|
||||
}
|
||||
|
||||
public function heartBeatInterval() {
|
||||
return $this->_heartBeatInterval;
|
||||
}
|
||||
|
||||
public function deviceName() {
|
||||
return sprintf('%s-%s.%s', $this->_vendor, $this->_device, $this->_instance);
|
||||
}
|
||||
|
||||
public function lastHeartBeat() {
|
||||
return $this->_lastHeartBeat;
|
||||
}
|
||||
|
||||
public function port() {
|
||||
return $this->_port;
|
||||
}
|
||||
|
||||
public function setAddress( $address ) {
|
||||
$this->_address = $address;
|
||||
}
|
||||
|
||||
public function setHeartBeatInterval( $minutes ) {
|
||||
$this->_heartBeatInterval = $minutes;
|
||||
}
|
||||
|
||||
public function setPort( $p ) {
|
||||
$this->_port = $p;
|
||||
}
|
||||
|
||||
public function setLastHeartBeat( $timestamp ) {
|
||||
$this->_lastHeartBeat = $timestamp;
|
||||
}
|
||||
}
|
210
xpl/phpxpl/xplinstance.class.php
Normal file
210
xpl/phpxpl/xplinstance.class.php
Normal file
|
@ -0,0 +1,210 @@
|
|||
<?php
|
||||
|
||||
require_once 'xplmessage.class.php';
|
||||
require_once 'xpldevice.class.php';
|
||||
|
||||
define( XPL_PORT, 3865 );
|
||||
|
||||
class XPLInstance {
|
||||
protected $_thisDevice = null;
|
||||
protected $_devices = array();
|
||||
|
||||
private $_socket;
|
||||
private $_isAttached = false;
|
||||
private $_ip;
|
||||
|
||||
public function __construct($vendor, $device, $ip) {
|
||||
$this->_ip = $ip;
|
||||
$this->_thisDevice = new XPLDevice($vendor, $device);
|
||||
|
||||
$this->init();
|
||||
}
|
||||
|
||||
public function attatched() {
|
||||
return $this->_isAttatched;
|
||||
}
|
||||
|
||||
public function detach() {
|
||||
$message = new xPLMessage( xPLMessage::xplstat );
|
||||
$message->setMessageSchemeIdentifier( 'hbeat.end' );
|
||||
$message->setTarget('*');
|
||||
$message->setSource( $this->_thisDevice->deviceName() );
|
||||
$this->sendMessage( $message );
|
||||
socket_close($this->_socket);
|
||||
$this->_socket = null;
|
||||
}
|
||||
|
||||
public function doEvents() {
|
||||
$string = socket_read( $this->_socket, 1500);
|
||||
if ($string != '') {
|
||||
$message = XPLMessage::createMessageFromString($string);
|
||||
if ($message) {
|
||||
$this->processMessage( $message );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
$this->poll();
|
||||
return true;
|
||||
}
|
||||
|
||||
public function sendMessage( $message, $device = null ) {
|
||||
//echo "Sending heartbeat\n";
|
||||
$msg = (string)$message;
|
||||
socket_sendto( $this->_socket, $msg, strlen($msg), 0, '255.255.255.255', XPL_PORT );
|
||||
}
|
||||
|
||||
protected function attatchedToNetwork() {
|
||||
}
|
||||
|
||||
protected function handleMessage( $message ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private function bindToPort() {
|
||||
$port = 49152;
|
||||
//$port = XPL_PORT;
|
||||
$error = 98;
|
||||
while ($error == 98 && $port < 65535) {
|
||||
if (@socket_bind($this->_socket, $this->_ip, $port) === false) {
|
||||
++$port;
|
||||
} else {
|
||||
echo "Bind succeded as client on: " . $port . "\n";
|
||||
return $port;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function init() {
|
||||
if (($this->_socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP)) === false) {
|
||||
echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
socket_set_option( $this->_socket, SOL_SOCKET, SO_BROADCAST, 1);
|
||||
socket_set_nonblock( $this->_socket );
|
||||
|
||||
$this->_thisDevice->setPort( $this->bindToPort() );
|
||||
if ($this->_thisDevice->port() == 0) {
|
||||
echo "socket_bind() failed: reason: " . socket_strerror(socket_last_error($this->_socket)) . "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
printf("xPL server started (bound to port %s)\n", $this->_thisDevice->port());
|
||||
$this->sendHeartbeat();
|
||||
}
|
||||
|
||||
private function poll() {
|
||||
if (!$this->attatched()) {
|
||||
$this->sendHeartbeat();
|
||||
return;
|
||||
}
|
||||
|
||||
if (time()-$this->_thisDevice->lastHeartBeat() >= $this->_thisDevice->heartBeatInterval() * 60) {
|
||||
$this->sendHeartbeat();
|
||||
}
|
||||
//Loop all devices to see if they have timed out
|
||||
foreach( $this->_devices as $key => $device ) {
|
||||
if ( time()-$device->lastHeartBeat() >= $device->heartBeatInterval() * 60 * 2) {
|
||||
printf("Device removed (timeout): %s\n", $device->deviceName());
|
||||
|
||||
//This is not a prefeered way of removing the item from an array
|
||||
//Since we are iterating the loop will miss to check the new item.
|
||||
//Here, it will be checked next time poll is called
|
||||
unset($this->_devices[$key]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function processHeartBeat( $message ) {
|
||||
if ($message->messageSchemeIdentifier() == 'hbeat.request') {
|
||||
$this->sendHeartbeat();
|
||||
return true;
|
||||
}
|
||||
foreach( $this->_devices as $key => $device ) {
|
||||
if ( $device->deviceName() == $message->source() ) {
|
||||
if (substr($message->messageSchemeIdentifier(), -3) == 'end') {
|
||||
echo "Device removed: " . $message->source() . "\n";
|
||||
unset($this->_devices[$key]);
|
||||
return true;
|
||||
} else {
|
||||
$device->setLastHeartBeat( time() );
|
||||
$device->setHeartBeatInterval( $message->bodyItem( 'interval' ) );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if ( (substr($message->messageSchemeIdentifier(), -3) != 'app') && (substr($message->messageSchemeIdentifier(), -5) != 'basic') ) { //Not a heartbeat
|
||||
return false;
|
||||
}
|
||||
|
||||
printf( "New device: %s\n", $message->source() );
|
||||
$device = new xPLDevice( $message->source() );
|
||||
$device->setHeartBeatInterval( $message->bodyItem('interval') );
|
||||
$device->setLastHeartBeat( time() );
|
||||
if ($message->messageSchemeIdentifier() == 'hbeat.app') {
|
||||
$device->setAddress( $message->bodyItem('remote-ip'));
|
||||
$device->setPort( $message->bodyItem('port') );
|
||||
}
|
||||
$this->_devices[] = $device;
|
||||
return true;
|
||||
}
|
||||
|
||||
private function processMessage( $message ) {
|
||||
if (!$this->attatched() && $message->messageSchemeIdentifier() == 'hbeat.app' && $message->source() == $this->_thisDevice->deviceName()) {
|
||||
//Our own echo
|
||||
$this->setAttatched( true );
|
||||
return;
|
||||
}
|
||||
if ($message->source() == $this->_thisDevice->deviceName()) {
|
||||
//Ignore messages from ourselves
|
||||
return;
|
||||
}
|
||||
if ( (substr($message->messageSchemeIdentifier(), 0, 5) == 'hbeat') || (substr($message->messageSchemeIdentifier(), 0, 6) == 'config') ) {
|
||||
if ($this->processHeartBeat( $message )) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ($message->target() != $this->_thisDevice->deviceName() && $message->target() != '*') {
|
||||
//Message not for us
|
||||
return;
|
||||
}
|
||||
if (!$this->handleMessage($message)) {
|
||||
printf("Got message:\n%s", $message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function sendHeartbeat() {
|
||||
// echo "Sending heartbeat\n";
|
||||
$message = new xPLMessage( xPLMessage::xplstat );
|
||||
$message->setMessageSchemeIdentifier( 'hbeat.app' );
|
||||
$message->setTarget('*');
|
||||
$message->setSource( $this->_thisDevice->deviceName() );
|
||||
$message->addBodyItem( 'interval', $this->_thisDevice->heartBeatInterval() );
|
||||
$message->addBodyItem( 'port', $this->_thisDevice->port() );
|
||||
$message->addBodyItem( 'remote-ip', $this->_ip );
|
||||
$this->sendMessage( $message );
|
||||
$this->_thisDevice->setLastHeartBeat( time() );
|
||||
}
|
||||
|
||||
private function setAttatched( $attatched ) {
|
||||
$this->_isAttatched = $attatched;
|
||||
if ($this->_isAttatched) {
|
||||
echo "Attatched to xPL-network\n";
|
||||
// timer->setInterval( 60000 ); //Once a minute
|
||||
|
||||
$message = new xPLMessage( xPLMessage::xplcmnd );
|
||||
$message->setTarget( "*" );
|
||||
$message->setSource( $this->_thisDevice->deviceName() );
|
||||
$message->setMessageSchemeIdentifier( 'hbeat.request' );
|
||||
$message->addBodyItem('command', 'request');
|
||||
$this->sendMessage( $message );
|
||||
|
||||
$this->attatchedToNetwork();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
172
xpl/phpxpl/xpllighting.class.php
Normal file
172
xpl/phpxpl/xpllighting.class.php
Normal file
|
@ -0,0 +1,172 @@
|
|||
<?php
|
||||
|
||||
require_once 'xplinstance.class.php';
|
||||
|
||||
class xPLLighting extends XPLInstance {
|
||||
|
||||
public function __construct($ip) {
|
||||
parent::__construct('telldus', 'core', $ip);
|
||||
}
|
||||
|
||||
protected function attatchedToNetwork() {
|
||||
$message = new xPLMessage( xPLMessage::xpltrig );
|
||||
$message->setMessageSchemeIdentifier( 'lighting.gateway' );
|
||||
$message->setTarget('*');
|
||||
$message->setSource( $this->_thisDevice->deviceName() );
|
||||
$message->addBodyItem( 'report', 'gateway-ready' );
|
||||
$this->sendMessage( $message );
|
||||
}
|
||||
|
||||
protected function handleMessage( $message ) {
|
||||
if ($message->messageSchemeIdentifier() == 'lighting.request') {
|
||||
return $this->lightingRequest($message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function lightingRequest( $message ) {
|
||||
switch( $message->bodyItem('request') ) {
|
||||
case 'gateinfo':
|
||||
return $this->gateInfo( );
|
||||
case 'netlist':
|
||||
return $this->netList( );
|
||||
case 'netinfo':
|
||||
return $this->netInfo( $message );
|
||||
case 'devlist':
|
||||
return $this->devList( $message );
|
||||
case 'devinfo':
|
||||
return $this->devInfo( $message );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function gateInfo( ) {
|
||||
$message = new xPLMessage( xPLMessage::xplstat );
|
||||
$message->setMessageSchemeIdentifier( 'lighting.gateinfo' );
|
||||
$message->setTarget('*');
|
||||
$message->setSource( $this->_thisDevice->deviceName() );
|
||||
$message->addBodyItem( 'status', 'ok' );
|
||||
$message->addBodyItem( 'protocol', 'TELLDUS' );
|
||||
$message->addBodyItem( 'description', 'xPL to Telldus TellStick gateway' );
|
||||
$message->addBodyItem( 'version', '1.0' );
|
||||
$message->addBodyItem( 'author', 'Telldus Technologies AB' );
|
||||
$message->addBodyItem( 'info-url', 'http://www.telldus.se' );
|
||||
$message->addBodyItem( 'net-count', '1' );
|
||||
$message->addBodyItem( 'preferred-net', '1' );
|
||||
$message->addBodyItem( 'scenes-ok', 'false' );
|
||||
$message->addBodyItem( 'channels-ok', 'false' );
|
||||
$message->addBodyItem( 'fade-rate-ok', 'false' );
|
||||
$this->sendMessage( $message );
|
||||
return true;
|
||||
}
|
||||
|
||||
private function netList( ) {
|
||||
$message = new xPLMessage( xPLMessage::xplstat );
|
||||
$message->setMessageSchemeIdentifier( 'lighting.netlist' );
|
||||
$message->setTarget('*');
|
||||
$message->setSource( $this->_thisDevice->deviceName() );
|
||||
$message->addBodyItem( 'status', 'ok' );
|
||||
$message->addBodyItem( 'network', '1' );
|
||||
$this->sendMessage( $message );
|
||||
return true;
|
||||
}
|
||||
|
||||
private function netInfo( $message ) {
|
||||
$msg = new xPLMessage( xPLMessage::xplstat );
|
||||
$msg->setMessageSchemeIdentifier( 'lighting.netinfo' );
|
||||
$msg->setTarget('*');
|
||||
$msg->setSource( $this->_thisDevice->deviceName() );
|
||||
// print_r($message);
|
||||
$msg->addBodyItem( 'network', $message->bodyItem('network') );
|
||||
if ($msg->bodyItem('network') == '1') {
|
||||
$msg->addBodyItem( 'status', 'ok' );
|
||||
$msg->addBodyItem( 'name', exec('hostname') );
|
||||
$msg->addBodyItem( 'device-count', tdGetNumberOfDevices() );
|
||||
$msg->addBodyItem( 'scene-count', 0 );
|
||||
} else {
|
||||
$msg->addBodyItem( 'status', 'not-found' );
|
||||
}
|
||||
$this->sendMessage( $msg );
|
||||
return true;
|
||||
}
|
||||
|
||||
private function devList( $message ) {
|
||||
$msg = new xPLMessage( xPLMessage::xplstat );
|
||||
$msg->setMessageSchemeIdentifier( 'lighting.devlist' );
|
||||
$msg->setTarget('*');
|
||||
$msg->setSource( $this->_thisDevice->deviceName() );
|
||||
$msg->addBodyItem( 'network', $message->bodyItem('network') );
|
||||
if ($msg->bodyItem('network') == '1') {
|
||||
$msg->addBodyItem( 'status', 'ok' );
|
||||
$count = tdGetNumberOfDevices();
|
||||
$deviceList = array();
|
||||
for( $i = 0; $i < $count; ++$i ) {
|
||||
$deviceList[] = tdGetDeviceId($i);
|
||||
}
|
||||
$msg->addBodyItem( 'device-count', $count );
|
||||
$msg->addBodyItem( 'device', implode(',', $deviceList) );
|
||||
} else {
|
||||
$msg->addBodyItem( 'status', 'not-found' );
|
||||
}
|
||||
$this->sendMessage( $msg );
|
||||
return true;
|
||||
}
|
||||
|
||||
private function devInfo( $message ) {
|
||||
$found = false;
|
||||
$count = tdGetNumberOfDevices();
|
||||
$deviceId = $message->bodyItem('device');
|
||||
for( $i = 0; $i < $count; ++$i ) {
|
||||
if (tdGetDeviceId($i) == $deviceId) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$msg = new xPLMessage( xPLMessage::xplstat );
|
||||
$msg->setMessageSchemeIdentifier( 'lighting.devinfo' );
|
||||
$msg->addBodyItem( 'network', $message->bodyItem('network') );
|
||||
$msg->addBodyItem( 'device', $deviceId );
|
||||
$msg->setTarget('*');
|
||||
$msg->setSource( $this->_thisDevice->deviceName() );
|
||||
|
||||
if ($msg->bodyItem('network') == '1' && $found) {
|
||||
$methods = tdMethods($deviceId, TELLDUS_TURNON | TELLDUS_TURNOFF | TELLDUS_DIM );
|
||||
$msg->addBodyItem( 'status', 'ok' );
|
||||
$msg->addBodyItem( 'name', tdGetName($deviceId) );
|
||||
$msg->addBodyItem( 'report-on-manual', 'false' );
|
||||
$msg->addBodyItem( 'channel-count', '1');
|
||||
$msg->addBodyItem( 'primary-channel', '1');
|
||||
$msg->addBodyItem( 'channel', sprintf('1,%s,0,0', ($methods & TELLDUS_DIM ? 'true' : 'false')) );
|
||||
$msg->addBodyItem( 'scene-count', '0');
|
||||
} else {
|
||||
$msg->addBodyItem( 'status', 'not-found' );
|
||||
}
|
||||
$this->sendMessage( $msg );
|
||||
return true;
|
||||
}
|
||||
|
||||
private function scnList( $message ) {
|
||||
$msg = new xPLMessage( xPLMessage::xplstat );
|
||||
$msg->setMessageSchemeIdentifier( 'lighting.scnlist' );
|
||||
$msg->setTarget('*');
|
||||
$msg->setSource( $this->_thisDevice->deviceName() );
|
||||
$msg->addBodyItem( 'network', $message->bodyItem('network') );
|
||||
$msg->addBodyItem( 'status', 'not-found' );
|
||||
$this->sendMessage( $msg );
|
||||
return true;
|
||||
}
|
||||
|
||||
private function scnInfo( $message ) {
|
||||
$msg = new xPLMessage( xPLMessage::xplstat );
|
||||
$msg->setMessageSchemeIdentifier( 'lighting.scninfo' );
|
||||
$msg->addBodyItem( 'network', $message->bodyItem('network') );
|
||||
$msg->addBodyItem( 'scene', $message->bodyItem('scene') );
|
||||
$msg->setTarget('*');
|
||||
$msg->setSource( $this->_thisDevice->deviceName() );
|
||||
$msg->addBodyItem( 'status', 'not-found' );
|
||||
$this->sendMessage( $msg );
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
144
xpl/phpxpl/xplmessage.class.php
Normal file
144
xpl/phpxpl/xplmessage.class.php
Normal file
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
|
||||
class xPLMessage {
|
||||
|
||||
private $_hop = 1;
|
||||
private $_identifier = null;
|
||||
private $_body = array();
|
||||
private $_msi = '';
|
||||
private $_source = '';
|
||||
private $_target = '';
|
||||
|
||||
const xplcmnd = 1;
|
||||
const xplstat = 2;
|
||||
const xpltrig = 3;
|
||||
|
||||
public function __construct($identifier) {
|
||||
$this->_identifier = $identifier;
|
||||
}
|
||||
|
||||
public function addBodyItem( $key, $value ) {
|
||||
$this->_body[$key] = $value;
|
||||
}
|
||||
|
||||
public function addHeadItem( $key, $value ) {
|
||||
if ($key == 'hop') {
|
||||
$hop = (int)$value;
|
||||
} else if ($key == 'source') {
|
||||
$this->setSource($value);
|
||||
} else if ($key == 'target') {
|
||||
$this->setTarget($value);
|
||||
}
|
||||
}
|
||||
|
||||
public function bodyItem( $key ) {
|
||||
if (array_key_exists($key, $this->_body)) {
|
||||
return $this->_body[$key];
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
public function messageSchemeIdentifier() {
|
||||
return $this->_msi;
|
||||
}
|
||||
|
||||
public function source() {
|
||||
return $this->_source;
|
||||
}
|
||||
|
||||
public function target() {
|
||||
return $this->_target;
|
||||
}
|
||||
|
||||
public function setMessageSchemeIdentifier( $messageSchemeIdentifier ) {
|
||||
$this->_msi = $messageSchemeIdentifier;
|
||||
}
|
||||
|
||||
public function setSource( $value ) {
|
||||
$this->_source = $value;
|
||||
}
|
||||
|
||||
public function setTarget( $value ) {
|
||||
$this->_target = $value;
|
||||
}
|
||||
|
||||
public function __tostring() {
|
||||
$message = '';
|
||||
|
||||
switch( $this->_identifier ) {
|
||||
case self::xplcmnd:
|
||||
$message .= "xpl-cmnd\n";
|
||||
break;
|
||||
case self::xplstat:
|
||||
$message .= "xpl-stat\n";
|
||||
break;
|
||||
case self::xpltrig:
|
||||
$message .= "xpl-trig\n";
|
||||
break;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
||||
$message .= "{\n";
|
||||
$message .= sprintf("hop=%s\n", $this->_hop);
|
||||
$message .= sprintf("source=%s\n", $this->_source);
|
||||
$message .= sprintf("target=%s\n", $this->_target);
|
||||
$message .= "}\n";
|
||||
$message .= $this->_msi . "\n";
|
||||
$message .= "{\n";
|
||||
foreach( $this->_body as $key => $value ) {
|
||||
$message .= sprintf("%s=%s\n", $key, $value);
|
||||
}
|
||||
$message .= "}\n";
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
public static function createMessageFromString( $message ) {
|
||||
$lines = explode("\n", $message);
|
||||
$row = 0;
|
||||
|
||||
$i = 0;
|
||||
|
||||
if ($lines[$row] == 'xpl-cmnd') {
|
||||
$i = self::xplcmnd;
|
||||
} else if ($lines[$row] == 'xpl-stat') {
|
||||
$i = self::xplstat;
|
||||
} else if ($lines[$row] == 'xpl-trig') {
|
||||
$i = self::xpltrig;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
++$row;
|
||||
|
||||
if ($lines[$row] != '{') {
|
||||
return 0;
|
||||
}
|
||||
++$row;
|
||||
|
||||
$msg = new xPLMessage($i);
|
||||
for(; $row < count($lines) && $lines[$row] != '}'; ++$row) {
|
||||
list($name, $value) = explode( '=', $lines[$row] );
|
||||
$msg->addHeadItem( $name, $value );
|
||||
}
|
||||
if ($row >= count($lines)) {
|
||||
return 0;
|
||||
}
|
||||
++$row;
|
||||
|
||||
$msg->setMessageSchemeIdentifier( $lines[$row] );
|
||||
++$row;
|
||||
|
||||
if ($lines[$row] != '{') {
|
||||
return 0;
|
||||
}
|
||||
++$row;
|
||||
|
||||
for(; $row < count($lines) && $lines[$row] != '}'; ++$row) {
|
||||
list($name, $value) = explode( '=', $lines[$row] );
|
||||
$msg->addBodyItem( $name, $value );
|
||||
}
|
||||
|
||||
return $msg;
|
||||
}
|
||||
}
|
1
xpl/pyxpl/__init__.py
Normal file
1
xpl/pyxpl/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
__all__ = ["xplmessage", "xpldevice", "xplinstance"]
|
22
xpl/pyxpl/xpldevice.py
Normal file
22
xpl/pyxpl/xpldevice.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
###########################################################################
|
||||
# Copyright (C) 2009 by Magnus Ahlberg
|
||||
# <magnus.ahlberg@svart-katt.se>
|
||||
#
|
||||
# Copyright: See COPYING file that comes with this distribution
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
class XPLDevice:
|
||||
"""A class to manage and xPL device"""
|
||||
vendor = ""
|
||||
device = ""
|
||||
instance = ""
|
||||
|
||||
def __init__(devicename):
|
||||
pass
|
||||
|
||||
def __init__(vendor, device):
|
||||
pass
|
||||
|
||||
def __init__(vendor, device, instance):
|
||||
pass
|
47
xpl/pyxpl/xplinstance.py
Normal file
47
xpl/pyxpl/xplinstance.py
Normal file
|
@ -0,0 +1,47 @@
|
|||
###########################################################################
|
||||
# Copyright (C) 2009 by Magnus Ahlberg
|
||||
# <magnus.ahlberg@svart-katt.se>
|
||||
#
|
||||
# Copyright: See COPYING file that comes with this distribution
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
from xpldevice import *
|
||||
|
||||
from socket import *
|
||||
|
||||
class XPLInstance:
|
||||
"""Class to handle an xPL session"""
|
||||
MODE_UNDEFINED, MODE_CLIENT, MODE_DISCONNECTED, MODE_HUB = range(4)
|
||||
|
||||
__thisDevice = XPLDevice()
|
||||
__devices = ()
|
||||
__mode = MODE_UNDEFINED
|
||||
|
||||
def __init__(self, device):
|
||||
self.__thisDevice = device
|
||||
|
||||
def __init__(self, vendor, deviceName):
|
||||
device = XPLDevice(vendor, deviceName)
|
||||
self.__init__(device)
|
||||
|
||||
def attached(self):
|
||||
pass
|
||||
|
||||
def devices(self):
|
||||
return devices
|
||||
|
||||
def operationMode(self):
|
||||
return operationMode
|
||||
|
||||
def sendMessage(self, message):
|
||||
pass
|
||||
|
||||
def sendMessage(self, message, device):
|
||||
pass
|
||||
|
||||
def shutdown(self):
|
||||
pass
|
||||
|
||||
def bindToPort(self):
|
||||
pass
|
56
xpl/pyxpl/xplmessage.py
Normal file
56
xpl/pyxpl/xplmessage.py
Normal file
|
@ -0,0 +1,56 @@
|
|||
###########################################################################
|
||||
# Copyright (C) 2009 by Magnus Ahlberg
|
||||
# <magnus.ahlberg@svart-katt.se>
|
||||
#
|
||||
# Copyright: See COPYING file that comes with this distribution
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
class XPLMessage:
|
||||
"""A class for managing xPL messages"""
|
||||
ID_UNDEFINED, ID_XPLCMND, ID_XPLSTAT, ID_XPLTRIG = range(4)
|
||||
__body = {}
|
||||
__hop = 0
|
||||
__source = ""
|
||||
__target = ""
|
||||
__identifier = ID_UNDEFINED
|
||||
__identifierString = ("-", "xpl-cmnd", "xpl-stat", "xpl-trig")
|
||||
__messageSchemaIdentifier = ""
|
||||
|
||||
def __init__(self, identifier, messageSchemaIdentifier):
|
||||
self.__identifier = identifier
|
||||
self.__messageSchemaIdentifier = messageSchemaIdentifier
|
||||
|
||||
def addBodyItem(self, key, value):
|
||||
self.__body[key] = value
|
||||
|
||||
def bodyItem(self, key):
|
||||
return self.__body[key]
|
||||
|
||||
def createMessageFromString(message):
|
||||
pass
|
||||
|
||||
def setSource(self, value):
|
||||
self.__source = value
|
||||
|
||||
def setTarget(self, value):
|
||||
self.__target = value
|
||||
|
||||
def toString(self):
|
||||
if self.__identifier == self.ID_UNDEFINED:
|
||||
return ""
|
||||
|
||||
messageStringList = []
|
||||
messageStringList.append(self.__identifierString[self.__identifier] + "\n")
|
||||
messageStringList.append("{\n")
|
||||
messageStringList.append("hop=" + str(self.__hop) + "\n")
|
||||
messageStringList.append("source=" + self.__source + "\n")
|
||||
messageStringList.append("target=" + self.__target + "\n")
|
||||
messageStringList.append("}\n")
|
||||
messageStringList.append(self.__messageSchemaIdentifier + "\n")
|
||||
messageStringList.append("{\n")
|
||||
for key, value in self.__body.iteritems():
|
||||
messageStringList.append(key + "=" + value + "\n")
|
||||
messageStringList.append("}\n")
|
||||
|
||||
return "".join(messageStringList)
|
43
xpl/qtxpl/CMakeLists.txt
Normal file
43
xpl/qtxpl/CMakeLists.txt
Normal file
|
@ -0,0 +1,43 @@
|
|||
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
|
||||
PROJECT(qtxpl)
|
||||
|
||||
FIND_PACKAGE( Qt4 REQUIRED )
|
||||
SET(QT_USE_QTNETWORK TRUE)
|
||||
INCLUDE( ${QT_USE_FILE} )
|
||||
|
||||
SET( QTXPL_SRCS
|
||||
xpldevice.cpp
|
||||
xplinstance.cpp
|
||||
xplmessage.cpp
|
||||
)
|
||||
|
||||
SET( QTXPL_HDRS
|
||||
xpldevice.h
|
||||
)
|
||||
|
||||
SET( QTXPL_MOC_HDRS
|
||||
xplinstance.h
|
||||
xplmessage.h
|
||||
)
|
||||
|
||||
|
||||
QT4_WRAP_CPP( QTXPL_MOC_SRCS ${QTXPL_MOC_HDRS} )
|
||||
QT4_AUTOMOC ( ${QTXPL_SRCS} )
|
||||
|
||||
|
||||
SET( QTXPL_LIBRARIES
|
||||
${QT_LIBRARIES}
|
||||
)
|
||||
|
||||
ADD_DEFINITIONS(${QT_DEFINITIONS})
|
||||
ADD_DEFINITIONS(-DQT_NO_DEBUG)
|
||||
|
||||
ADD_LIBRARY("qtxpl" SHARED
|
||||
${QTXPL_SRCS}
|
||||
${QTXPL_HDRS}
|
||||
${QTXPL_MOC_HDRS}
|
||||
${QTXPL_MOC_SRCS}
|
||||
)
|
||||
|
||||
TARGET_LINK_LIBRARIES( "qtxpl" ${QTXPL_LIBRARIES} )
|
||||
|
12
xpl/qtxpl/main.cpp
Normal file
12
xpl/qtxpl/main.cpp
Normal file
|
@ -0,0 +1,12 @@
|
|||
#include <QtCore/QCoreApplication>
|
||||
|
||||
#include "xplinstance.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication a(argc, argv);
|
||||
|
||||
/*xPLInstance *instance = */new xPLInstance("telldus", "center");
|
||||
|
||||
return a.exec();
|
||||
}
|
15
xpl/qtxpl/qtxpl.pro
Normal file
15
xpl/qtxpl/qtxpl.pro
Normal file
|
@ -0,0 +1,15 @@
|
|||
# -------------------------------------------------
|
||||
# Project created by QtCreator 2009-03-05T16:12:24
|
||||
# -------------------------------------------------
|
||||
QT += network
|
||||
QT -= gui
|
||||
TARGET = qtxpl
|
||||
CONFIG += console
|
||||
CONFIG -= app_bundle
|
||||
TEMPLATE = lib
|
||||
SOURCES += xpldevice.cpp \
|
||||
xplinstance.cpp \
|
||||
xplmessage.cpp
|
||||
HEADERS += xpldevice.h \
|
||||
xplinstance.h \
|
||||
xplmessage.h
|
105
xpl/qtxpl/xpldevice.cpp
Normal file
105
xpl/qtxpl/xpldevice.cpp
Normal file
|
@ -0,0 +1,105 @@
|
|||
#include "xpldevice.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
const int DEFAULT_HBEAT_INTERVAL = 5;
|
||||
|
||||
class xPLDevicePrivate {
|
||||
public:
|
||||
QString vendor, device, instance;
|
||||
QDateTime lastHeartBeat;
|
||||
int port, heartBeatInterval;
|
||||
QHostAddress address;
|
||||
};
|
||||
|
||||
xPLDevice::xPLDevice( const xPLDevice &other )
|
||||
: d( new xPLDevicePrivate( *other.d ))
|
||||
{
|
||||
//do nothing
|
||||
}
|
||||
|
||||
xPLDevice& xPLDevice::operator=( xPLDevice other ) {
|
||||
std::swap( this->d, other.d );
|
||||
return *this;
|
||||
}
|
||||
|
||||
xPLDevice::xPLDevice( const QString &deviceName )
|
||||
:d(new xPLDevicePrivate)
|
||||
{
|
||||
d->port = 0;
|
||||
d->heartBeatInterval = DEFAULT_HBEAT_INTERVAL;
|
||||
QString name = deviceName.section('.', 0, 0);
|
||||
d->vendor = name.section('-', 0, 0);
|
||||
d->device = name.section('-', 1, 1);
|
||||
d->instance = deviceName.section('.', 1);
|
||||
}
|
||||
|
||||
xPLDevice::xPLDevice( const QString &vendor, const QString &device )
|
||||
:d(new xPLDevicePrivate)
|
||||
{
|
||||
d->vendor = vendor;
|
||||
d->device = device;
|
||||
d->instance = "";
|
||||
d->port = 0;
|
||||
d->heartBeatInterval = DEFAULT_HBEAT_INTERVAL;
|
||||
|
||||
//Seed the random number generator
|
||||
srand( (unsigned int)time( NULL ) );
|
||||
|
||||
//Generate an instance
|
||||
int randomNumber = rand() % 9999 + 1; //Generate ranom number between 1-9999
|
||||
d->instance = QString("default%1").arg(randomNumber);
|
||||
}
|
||||
|
||||
xPLDevice::xPLDevice( const QString &vendor, const QString &device, const QString &instance )
|
||||
:d(new xPLDevicePrivate)
|
||||
{
|
||||
d->vendor = vendor;
|
||||
d->device = device;
|
||||
d->instance = instance;
|
||||
d->port = 0;
|
||||
d->heartBeatInterval = DEFAULT_HBEAT_INTERVAL;
|
||||
|
||||
}
|
||||
|
||||
xPLDevice::~xPLDevice() {
|
||||
delete d;
|
||||
}
|
||||
|
||||
QHostAddress xPLDevice::address() const {
|
||||
return d->address;
|
||||
}
|
||||
|
||||
int xPLDevice::heartBeatInterval() const {
|
||||
return d->heartBeatInterval;
|
||||
}
|
||||
|
||||
QString xPLDevice::deviceName() const {
|
||||
return QString("%1-%2.%3").arg(d->vendor).arg(d->device).arg(d->instance);
|
||||
}
|
||||
|
||||
QDateTime xPLDevice::lastHeartBeat() const {
|
||||
return d->lastHeartBeat;
|
||||
}
|
||||
|
||||
int xPLDevice::port() const {
|
||||
return d->port;
|
||||
}
|
||||
|
||||
void xPLDevice::setAddress( const QHostAddress &address ) {
|
||||
d->address = address;
|
||||
}
|
||||
|
||||
void xPLDevice::setHeartBeatInterval( int minutes ) {
|
||||
d->heartBeatInterval = minutes;
|
||||
}
|
||||
|
||||
void xPLDevice::setPort( int p ) {
|
||||
d->port = p;
|
||||
}
|
||||
|
||||
void xPLDevice::setLastHeartBeat( const QDateTime ×tamp ) {
|
||||
d->lastHeartBeat = timestamp;
|
||||
}
|
38
xpl/qtxpl/xpldevice.h
Normal file
38
xpl/qtxpl/xpldevice.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
#ifndef XPLDEVICE_H
|
||||
#define XPLDEVICE_H
|
||||
|
||||
#include "xplmessage.h"
|
||||
#include <QDateTime>
|
||||
#include <QHostAddress>
|
||||
|
||||
class xPLDevicePrivate;
|
||||
|
||||
class QTXPL_EXPORT xPLDevice
|
||||
{
|
||||
public:
|
||||
xPLDevice( const xPLDevice & ); //Copy constructor
|
||||
xPLDevice& operator=( xPLDevice ); //Copy assignment operator
|
||||
|
||||
xPLDevice( const QString &deviceName );
|
||||
xPLDevice( const QString &vendor, const QString &device );
|
||||
xPLDevice( const QString &vendor, const QString &device, const QString &instance );
|
||||
|
||||
~xPLDevice();
|
||||
|
||||
QString deviceName() const;
|
||||
|
||||
QDateTime lastHeartBeat() const;
|
||||
|
||||
QHostAddress address() const;
|
||||
int heartBeatInterval() const;
|
||||
int port() const;
|
||||
void setAddress( const QHostAddress &address );
|
||||
void setHeartBeatInterval( int minutes );
|
||||
void setPort( int port );
|
||||
void setLastHeartBeat( const QDateTime ×tamp );
|
||||
|
||||
private:
|
||||
xPLDevicePrivate *d;
|
||||
};
|
||||
|
||||
#endif // XPLDEVICE_H
|
226
xpl/qtxpl/xplinstance.cpp
Normal file
226
xpl/qtxpl/xplinstance.cpp
Normal file
|
@ -0,0 +1,226 @@
|
|||
#include "xplinstance.h"
|
||||
#include "xplmessage.h"
|
||||
|
||||
#include <QUdpSocket>
|
||||
#include <QLinkedList>
|
||||
#include <QNetworkInterface>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
|
||||
class xPLInstancePrivate {
|
||||
public:
|
||||
xPLDevice *thisDevice;
|
||||
QLinkedList<xPLDevice> devices;
|
||||
QUdpSocket *socket;
|
||||
xPLInstance::OperationMode mode;
|
||||
QHostAddress address;
|
||||
bool isAttatched;
|
||||
QTimer *timer;
|
||||
};
|
||||
|
||||
xPLInstance::xPLInstance( const xPLDevice &device, QObject *parent )
|
||||
:QObject(parent)
|
||||
{
|
||||
d = new xPLInstancePrivate;
|
||||
d->thisDevice = new xPLDevice(device);
|
||||
d->mode = Disconnected;
|
||||
d->timer = new QTimer(this);
|
||||
this->init();
|
||||
}
|
||||
|
||||
xPLInstance::xPLInstance( const QString &vendor, const QString &device, QObject *parent )
|
||||
:QObject(parent)
|
||||
{
|
||||
d = new xPLInstancePrivate;
|
||||
d->thisDevice = new xPLDevice(vendor, device);
|
||||
d->mode = Disconnected;
|
||||
d->timer = new QTimer(this);
|
||||
this->init();
|
||||
}
|
||||
|
||||
xPLInstance::~xPLInstance() {
|
||||
delete d->thisDevice;
|
||||
delete d;
|
||||
}
|
||||
|
||||
void xPLInstance::init() {
|
||||
foreach(QHostAddress address, QNetworkInterface::allAddresses()) {
|
||||
if (address.protocol() == QAbstractSocket::IPv4Protocol && address != QHostAddress::LocalHost) {
|
||||
d->address = address;
|
||||
break;
|
||||
}
|
||||
}
|
||||
d->isAttatched = false;
|
||||
d->socket = new QUdpSocket(this);
|
||||
d->thisDevice->setPort(this->bindToPort());
|
||||
if (d->thisDevice->port() == 0) {
|
||||
return;
|
||||
}
|
||||
d->timer->setInterval( 3000 );
|
||||
connect(d->socket, SIGNAL(readyRead()), this, SLOT(processPendingDatagrams()));
|
||||
connect(d->timer, SIGNAL(timeout()), this, SLOT(poll()));
|
||||
this->sendHeartbeat();
|
||||
d->timer->start();
|
||||
}
|
||||
|
||||
bool xPLInstance::attatched() const {
|
||||
return this->d->isAttatched;
|
||||
}
|
||||
|
||||
int xPLInstance::bindToPort() {
|
||||
//Hub-mode not supported
|
||||
/*if (d->socket->bind( XPL_PORT )) {
|
||||
d->mode = Hub;
|
||||
qDebug("Bind succeded as hub");
|
||||
return XPL_PORT;
|
||||
}*/
|
||||
for (int port = 49152; port <= 65535; ++port) {
|
||||
if (d->socket->bind( port, QUdpSocket::DontShareAddress )) {
|
||||
d->mode = Client;
|
||||
qDebug() << "Bind succeded as client on" << port;
|
||||
return port;
|
||||
}
|
||||
}
|
||||
qDebug("Bind failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
xPLInstance::OperationMode xPLInstance::operationMode() const {
|
||||
return d->mode;
|
||||
}
|
||||
|
||||
void xPLInstance::processPendingDatagrams() {
|
||||
while (d->socket->hasPendingDatagrams()) {
|
||||
QByteArray datagram;
|
||||
datagram.resize(d->socket->pendingDatagramSize());
|
||||
d->socket->readDatagram(datagram.data(), datagram.size());
|
||||
xPLMessage *message = xPLMessage::createMessageFromString( datagram.data() );
|
||||
if (message) {
|
||||
processMessage( *message );
|
||||
delete message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void xPLInstance::poll() {
|
||||
if (!attatched()) {
|
||||
sendHeartbeat();
|
||||
return;
|
||||
}
|
||||
if (d->thisDevice->lastHeartBeat().secsTo( QDateTime::currentDateTime() ) >= d->thisDevice->heartBeatInterval() * 60) {
|
||||
sendHeartbeat();
|
||||
}
|
||||
//Loop all devices to see if they have timed out
|
||||
for( QLinkedList<xPLDevice>::iterator it = d->devices.begin(); it != d->devices.end(); ) {
|
||||
if ((*it).lastHeartBeat().secsTo( QDateTime::currentDateTime() ) >= (*it).heartBeatInterval() * 60 * 2) {
|
||||
qDebug() << "Device removed (timeout):" << (*it).deviceName();
|
||||
it = d->devices.erase( it );
|
||||
continue;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void xPLInstance::sendMessage( const xPLMessage &msg ) const {
|
||||
xPLMessage message(msg); //Copy so we don't have const
|
||||
message.setSource(d->thisDevice->deviceName());
|
||||
QByteArray datagram = message.toString().toAscii();
|
||||
d->socket->writeDatagram(datagram.data(), datagram.size(), QHostAddress::Broadcast, XPL_PORT);
|
||||
}
|
||||
|
||||
void xPLInstance::sendMessage( xPLMessage * message ) const {
|
||||
this->sendMessage(*message);
|
||||
}
|
||||
|
||||
void xPLInstance::sendMessage( const xPLMessage &message, const xPLDevice &device ) const {
|
||||
QByteArray datagram = message.toString().toAscii();
|
||||
d->socket->writeDatagram(datagram.data(), datagram.size(), device.address(), device.port());
|
||||
}
|
||||
|
||||
void xPLInstance::processHeartBeat( const xPLMessage &message ) {
|
||||
if (message.messageSchemeIdentifier() == "hbeat.request") {
|
||||
sendHeartbeat();
|
||||
return;
|
||||
}
|
||||
for( QLinkedList<xPLDevice>::iterator it = d->devices.begin(); it != d->devices.end(); ++it ) {
|
||||
if ( (*it).deviceName() == message.source() ) {
|
||||
if (message.messageSchemeIdentifier() == "hbeat.end") {
|
||||
qDebug() << "Device removed:" << message.source();
|
||||
d->devices.erase( it );
|
||||
return;
|
||||
} else {
|
||||
(*it).setLastHeartBeat( QDateTime::currentDateTime() );
|
||||
(*it).setHeartBeatInterval( message.bodyItem( "interval" ).toInt() );
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!message.messageSchemeIdentifier().endsWith("app") && !message.messageSchemeIdentifier().endsWith("basic")) {
|
||||
return;
|
||||
}
|
||||
qDebug() << "New device:" << message.source();
|
||||
xPLDevice device( message.source() );
|
||||
device.setHeartBeatInterval( message.bodyItem("interval").toInt() );
|
||||
device.setLastHeartBeat( QDateTime::currentDateTime() );
|
||||
if (message.messageSchemeIdentifier() == "hbeat.app") {
|
||||
device.setAddress( QHostAddress(message.bodyItem("remote-ip")) );
|
||||
device.setPort( message.bodyItem("port").toInt() );
|
||||
}
|
||||
d->devices.append( device );
|
||||
}
|
||||
|
||||
void xPLInstance::processMessage( const xPLMessage &message ) {
|
||||
if (!attatched() && message.messageSchemeIdentifier() == "hbeat.app" && message.source() == d->thisDevice->deviceName()) {
|
||||
//Our own echo
|
||||
setAttatched( true );
|
||||
return;
|
||||
}
|
||||
if (message.source() == d->thisDevice->deviceName()) {
|
||||
//Ignore messages from ourselves
|
||||
return;
|
||||
}
|
||||
if (message.messageSchemeIdentifier().startsWith("hbeat") || message.messageSchemeIdentifier().startsWith("config")) {
|
||||
processHeartBeat( message );
|
||||
}
|
||||
if (d->mode == xPLInstance::Hub) {
|
||||
//Reply the message to all clients
|
||||
for( QLinkedList<xPLDevice>::iterator it = d->devices.begin(); it != d->devices.end(); ++it ) {
|
||||
sendMessage(message, *it);
|
||||
}
|
||||
}
|
||||
if (message.target() != d->thisDevice->deviceName() && message.target() != "*") {
|
||||
//Message not for us
|
||||
return;
|
||||
}
|
||||
xPLMessage newMsg(message);
|
||||
emit messageReceived(&newMsg);
|
||||
}
|
||||
|
||||
void xPLInstance::sendHeartbeat() {
|
||||
xPLMessage message( xPLMessage::xplstat );
|
||||
message.setMessageSchemeIdentifier( "hbeat.app" );
|
||||
message.setTarget("*");
|
||||
message.setSource( d->thisDevice->deviceName() );
|
||||
message.addBodyItem( "interval", QString::number(d->thisDevice->heartBeatInterval()) );
|
||||
message.addBodyItem( "port", QString::number(d->thisDevice->port()) );
|
||||
message.addBodyItem( "remote-ip", d->address.toString() );
|
||||
sendMessage( message );
|
||||
d->thisDevice->setLastHeartBeat( QDateTime::currentDateTime() );
|
||||
}
|
||||
|
||||
void xPLInstance::setAttatched( bool attatched ) {
|
||||
d->isAttatched = attatched;
|
||||
if (d->isAttatched) {
|
||||
qDebug() << "Attached to network!";
|
||||
d->timer->setInterval( 60000 ); //Once a minute
|
||||
|
||||
xPLMessage message( xPLMessage::xplcmnd );
|
||||
message.setTarget( "*" );
|
||||
message.setSource( d->thisDevice->deviceName() );
|
||||
message.setMessageSchemeIdentifier( "hbeat.request" );
|
||||
message.addBodyItem("command", "request");
|
||||
sendMessage( message );
|
||||
emit attachedToNetwork();
|
||||
}
|
||||
}
|
55
xpl/qtxpl/xplinstance.h
Normal file
55
xpl/qtxpl/xplinstance.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
#ifndef XPLINSTANCE_H
|
||||
#define XPLINSTANCE_H
|
||||
|
||||
#include <QObject>
|
||||
#include "xpldevice.h"
|
||||
#include "xplmessage.h"
|
||||
|
||||
const int XPL_PORT = 3865;
|
||||
|
||||
class QTimer;
|
||||
class xPLInstancePrivate;
|
||||
|
||||
class QTXPL_EXPORT xPLInstance : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_ENUMS( OperationMode );
|
||||
|
||||
Q_PROPERTY( OperationMode operationMode READ operationMode );
|
||||
public:
|
||||
enum OperationMode { Client, Disconnected, Hub };
|
||||
|
||||
xPLInstance( const xPLDevice &device, QObject *parent = 0 );
|
||||
xPLInstance( const QString &vendor, const QString &device, QObject *parent = 0 );
|
||||
~xPLInstance();
|
||||
|
||||
public slots:
|
||||
bool attatched() const;
|
||||
|
||||
OperationMode operationMode() const;
|
||||
|
||||
void sendMessage( const xPLMessage &message ) const;
|
||||
void sendMessage( xPLMessage * message ) const;
|
||||
void sendMessage( const xPLMessage &message, const xPLDevice &device ) const;
|
||||
|
||||
signals:
|
||||
void messageReceived(xPLMessage *message);
|
||||
void attachedToNetwork();
|
||||
|
||||
private slots:
|
||||
void processPendingDatagrams();
|
||||
void sendHeartbeat();
|
||||
void poll();
|
||||
|
||||
private:
|
||||
void processHeartBeat( const xPLMessage &message );
|
||||
void processMessage( const xPLMessage &message );
|
||||
void init();
|
||||
int bindToPort();
|
||||
void setAttatched( bool attatched );
|
||||
|
||||
xPLInstancePrivate *d;
|
||||
};
|
||||
|
||||
#endif // XPLINSTANCE_H
|
188
xpl/qtxpl/xplmessage.cpp
Normal file
188
xpl/qtxpl/xplmessage.cpp
Normal file
|
@ -0,0 +1,188 @@
|
|||
#include "xplmessage.h"
|
||||
|
||||
#include <QStringList>
|
||||
#include <QMap>
|
||||
#include <QDebug>
|
||||
|
||||
class xPLMessage::xPLMessagePrivate {
|
||||
public:
|
||||
xPLMessage::Identifier identifier;
|
||||
int hop;
|
||||
QString source, target, msi;
|
||||
QMap<QString, QString> headExtra, body;
|
||||
};
|
||||
|
||||
xPLMessage::xPLMessage( const xPLMessage &other )
|
||||
: QObject(),
|
||||
d( new xPLMessagePrivate( *other.d ))
|
||||
{
|
||||
//do nothing
|
||||
}
|
||||
|
||||
xPLMessage& xPLMessage::operator=( xPLMessage other ) {
|
||||
std::swap( this->d, other.d );
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
xPLMessage::xPLMessage(Identifier i)
|
||||
:QObject(),
|
||||
d(new xPLMessagePrivate)
|
||||
{
|
||||
d->hop = 1;
|
||||
d->identifier = i;
|
||||
d->target = "*";
|
||||
}
|
||||
|
||||
xPLMessage::xPLMessage()
|
||||
:QObject(),
|
||||
d(new xPLMessagePrivate)
|
||||
{
|
||||
|
||||
d->hop = 1;
|
||||
d->identifier = xplcmnd;
|
||||
d->target = "*";
|
||||
}
|
||||
|
||||
xPLMessage::~xPLMessage() {
|
||||
delete d;
|
||||
}
|
||||
|
||||
|
||||
void xPLMessage::addBodyItem( const QString &key, const QString &value ) {
|
||||
d->body[key] = value;
|
||||
}
|
||||
|
||||
void xPLMessage::addHeadItem( const QString &key, const QString &value ) {
|
||||
if (key == "hop") {
|
||||
d->hop = value.toInt();
|
||||
} else if (key == "source") {
|
||||
setSource(value);
|
||||
} else if (key == "target") {
|
||||
setTarget(value);
|
||||
} else {
|
||||
d->headExtra[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
QString xPLMessage::bodyItem( const QString &key ) const {
|
||||
if (d->body.contains(key)) {
|
||||
return d->body[key];
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
QString xPLMessage::headItem( const QString &key ) const {
|
||||
if (d->headExtra.contains(key)) {
|
||||
return d->headExtra[key];
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
QString xPLMessage::messageSchemeIdentifier() const {
|
||||
return d->msi;
|
||||
}
|
||||
|
||||
QString xPLMessage::source() const {
|
||||
return d->source;
|
||||
}
|
||||
|
||||
QString xPLMessage::target() const {
|
||||
return d->target;
|
||||
}
|
||||
|
||||
void xPLMessage::setMessageSchemeIdentifier( const QString &messageSchemeIdentifier ) {
|
||||
d->msi = messageSchemeIdentifier;
|
||||
}
|
||||
|
||||
void xPLMessage::setSource( const QString &value ) {
|
||||
d->source = value;
|
||||
}
|
||||
|
||||
void xPLMessage::setTarget( const QString &value ) {
|
||||
d->target = value;
|
||||
}
|
||||
|
||||
QString xPLMessage::toString() const {
|
||||
QString message;
|
||||
|
||||
switch( d->identifier ) {
|
||||
case xplcmnd:
|
||||
message += "xpl-cmnd\n";
|
||||
break;
|
||||
case xplstat:
|
||||
message += "xpl-stat\n";
|
||||
break;
|
||||
case xpltrig:
|
||||
message += "xpl-trig\n";
|
||||
break;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
||||
message += "{\n";
|
||||
message += QString("hop=%1\n").arg(d->hop);
|
||||
message += QString("source=%1\n").arg(d->source);
|
||||
message += QString("target=%1\n").arg(d->target);
|
||||
for( QMap<QString, QString>::const_iterator it = d->headExtra.begin(); it != d->headExtra.end(); ++it ) {
|
||||
message += QString("%1=%2\n").arg(it.key()).arg(it.value());
|
||||
}
|
||||
message += "}\n";
|
||||
message += d->msi + "\n";
|
||||
message += "{\n";
|
||||
for( QMap<QString, QString>::const_iterator it = d->body.begin(); it != d->body.end(); ++it ) {
|
||||
message += QString("%1=%2\n").arg(it.key()).arg(it.value());
|
||||
}
|
||||
message += "}\n";
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
xPLMessage *xPLMessage::createMessageFromString( const QString &message ) {
|
||||
QStringList lines = message.split('\n', QString::SkipEmptyParts);
|
||||
QStringList::const_iterator it = lines.begin();
|
||||
|
||||
Identifier i;
|
||||
|
||||
if (*it == "xpl-cmnd") {
|
||||
i = xplcmnd;
|
||||
} else if (*it == "xpl-stat") {
|
||||
i = xplstat;
|
||||
} else if (*it == "xpl-trig") {
|
||||
i = xpltrig;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
++it;
|
||||
|
||||
if (*it != "{") {
|
||||
return 0;
|
||||
}
|
||||
++it;
|
||||
|
||||
xPLMessage *msg = new xPLMessage(i);
|
||||
for(; it != lines.end() && *it != "}"; ++it) {
|
||||
msg->addHeadItem( (*it).section('=', 0, 0), (*it).section('=', 1) );
|
||||
}
|
||||
if (it == lines.end()) {
|
||||
delete msg;
|
||||
return 0;
|
||||
}
|
||||
++it;
|
||||
|
||||
msg->setMessageSchemeIdentifier( *it );
|
||||
++it;
|
||||
|
||||
if (*it != "{") {
|
||||
delete msg;
|
||||
return 0;
|
||||
}
|
||||
++it;
|
||||
|
||||
for(; it != lines.end() && *it != "}"; ++it) {
|
||||
msg->addBodyItem( (*it).section('=', 0, 0), (*it).section('=', 1) );
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
57
xpl/qtxpl/xplmessage.h
Normal file
57
xpl/qtxpl/xplmessage.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
#ifndef XPLMESSAGE_H
|
||||
#define XPLMESSAGE_H
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#ifdef qtxpl_EXPORTS
|
||||
#define QTXPL_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define QTXPL_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define QTXPL_EXPORT
|
||||
#endif
|
||||
|
||||
#include <QObject>
|
||||
#include <QMetaType>
|
||||
|
||||
class QTXPL_EXPORT xPLMessage : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_ENUMS( Identifier );
|
||||
public:
|
||||
enum Identifier { xplcmnd, xplstat, xpltrig };
|
||||
|
||||
xPLMessage( const xPLMessage & ); //Copy constructor
|
||||
xPLMessage& operator=( xPLMessage ); //Copy assignment operator
|
||||
|
||||
xPLMessage(Identifier identifier);
|
||||
xPLMessage();
|
||||
virtual ~xPLMessage();
|
||||
|
||||
static xPLMessage *createMessageFromString( const QString &message );
|
||||
|
||||
public slots:
|
||||
void addBodyItem( const QString &key, const QString &value );
|
||||
void addHeadItem( const QString &key, const QString &value );
|
||||
|
||||
QString bodyItem( const QString &key ) const;
|
||||
QString headItem( const QString &key ) const;
|
||||
QString messageSchemeIdentifier() const;
|
||||
QString source() const;
|
||||
QString target() const;
|
||||
|
||||
void setMessageSchemeIdentifier( const QString &msi );
|
||||
void setSource( const QString &value );
|
||||
void setTarget( const QString &value );
|
||||
|
||||
QString toString() const;
|
||||
|
||||
private:
|
||||
class xPLMessagePrivate;
|
||||
xPLMessagePrivate *d;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(xPLMessage*)
|
||||
|
||||
#endif // XPLMESSAGE_H
|
37
xpl/telldus-core-xpl/Makefile
Normal file
37
xpl/telldus-core-xpl/Makefile
Normal file
|
@ -0,0 +1,37 @@
|
|||
#
|
||||
# Makefile for xPLLib
|
||||
#
|
||||
|
||||
#
|
||||
# For LINUX, use the following
|
||||
CCOPTS = -g -DLINUX -pedantic -Wall
|
||||
LIBS = -g -lm -lxPL -ltelldus-core
|
||||
|
||||
LDOPTS = -O
|
||||
CC = cc $(CCOPTS)
|
||||
LD = cc $(LDOPTS)
|
||||
|
||||
CMD_LIST = xPL_TelldusCore
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $<
|
||||
|
||||
.o:
|
||||
$(LD) -o $@ $< $(LIBS)
|
||||
|
||||
.c:
|
||||
$(CC) -c $<
|
||||
$(LD) -o $@ $< $(LIBS)
|
||||
|
||||
|
||||
all: ${CMD_LIST}
|
||||
|
||||
clean:
|
||||
rm -f *.o *.a core ${CMD_LIST}
|
||||
|
||||
rebuild: clean all
|
||||
|
||||
|
||||
|
||||
|
||||
|
399
xpl/telldus-core-xpl/xPL_TelldusCore.c
Normal file
399
xpl/telldus-core-xpl/xPL_TelldusCore.c
Normal file
|
@ -0,0 +1,399 @@
|
|||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <xPL.h>
|
||||
#include <telldus-core.h>
|
||||
|
||||
#define TELLDUS_VERSION "1.0"
|
||||
#define INSTANCE_MAX 16
|
||||
|
||||
static xPL_ServicePtr telldusService = NULL;
|
||||
static Bool daemonMode = TRUE;
|
||||
char hostname[INSTANCE_MAX];
|
||||
|
||||
void sendDevInfo(xPL_MessagePtr msg);
|
||||
void sendDevList(xPL_MessagePtr msg);
|
||||
void sendGatewayInfo();
|
||||
void sendNetInfo(xPL_MessagePtr msg);
|
||||
void sendNetList();
|
||||
|
||||
void lightingCommandHandler(xPL_ServicePtr theService, xPL_MessagePtr theMessage, xPL_ObjectPtr userValue) {
|
||||
Bool found = FALSE;
|
||||
int deviceCount = 0, deviceId = 0, i, level = 0;
|
||||
|
||||
if (!xPL_doesMessageNamedValueExist(theMessage, "command")) {
|
||||
return;
|
||||
} else if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(theMessage, "command"), "goto") != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!xPL_doesMessageNamedValueExist(theMessage, "network")) {
|
||||
return;
|
||||
} else if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(theMessage, "network"), "1") != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!xPL_doesMessageNamedValueExist(theMessage, "device")) {
|
||||
return;
|
||||
} else {
|
||||
/* Loop the devices to see it realy exists */
|
||||
deviceCount = tdGetNumberOfDevices();
|
||||
|
||||
xPL_strToInt(xPL_getMessageNamedValue(theMessage, "device"), &deviceId);
|
||||
for( i = 0; i < deviceCount; ++i ) {
|
||||
if (tdGetDeviceId(i) == deviceId) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found == FALSE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!xPL_doesMessageNamedValueExist(theMessage, "level")) {
|
||||
return;
|
||||
} else {
|
||||
xPL_strToInt(xPL_getMessageNamedValue(theMessage, "level"), &level);
|
||||
if (level < 0 || level > 100) {
|
||||
return;
|
||||
}
|
||||
level = (float)level * 255.0 / 100.0;
|
||||
}
|
||||
|
||||
if (level > 0 && level < 255) {
|
||||
/* See if the device supports dim */
|
||||
if (!(tdMethods(deviceId, TELLSTICK_DIM) & TELLSTICK_DIM)) {
|
||||
/* Non dimmable device was dimmed */
|
||||
return;
|
||||
}
|
||||
tdDim(deviceId, (unsigned char)level);
|
||||
} else if (level == 255) {
|
||||
/* See if the device supports dim */
|
||||
if (!(tdMethods(deviceId, TELLSTICK_TURNON) & TELLSTICK_TURNON)) {
|
||||
/* Non dimmable device was dimmed */
|
||||
return;
|
||||
}
|
||||
tdTurnOn(deviceId);
|
||||
} else if (level == 0) {
|
||||
/* See if the device supports dim */
|
||||
if (!(tdMethods(deviceId, TELLSTICK_TURNOFF) & TELLSTICK_TURNOFF)) {
|
||||
/* Non dimmable device was dimmed */
|
||||
return;
|
||||
}
|
||||
tdTurnOff(deviceId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void lightingRequestHandler(xPL_ServicePtr theService, xPL_MessagePtr theMessage, xPL_ObjectPtr userValue) {
|
||||
|
||||
if (!xPL_doesMessageNamedValueExist(theMessage, "request")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(theMessage, "request"), "devinfo") == 0) {
|
||||
sendDevInfo(theMessage);
|
||||
} else if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(theMessage, "request"), "devlist") == 0) {
|
||||
sendDevList(theMessage);
|
||||
} else if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(theMessage, "request"), "gateinfo") == 0) {
|
||||
sendGatewayInfo();
|
||||
} else if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(theMessage, "request"), "netinfo") == 0) {
|
||||
sendNetInfo(theMessage);
|
||||
} else if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(theMessage, "request"), "netlist") == 0) {
|
||||
sendNetList();
|
||||
} else {
|
||||
/* fprintf(stdout, "Request: %s\n", xPL_getMessageNamedValue(theMessage, "request")); */
|
||||
}
|
||||
}
|
||||
|
||||
void shutdownHandler(int onSignal) {
|
||||
xPL_setServiceEnabled(telldusService, FALSE);
|
||||
xPL_releaseService(telldusService);
|
||||
xPL_shutdown();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void sendDevInfo(xPL_MessagePtr msg) {
|
||||
xPL_MessagePtr message = NULL;
|
||||
Bool found = FALSE, deviceCount = tdGetNumberOfDevices();
|
||||
int deviceId = 0, methods = 0, i = 0, lastSentCommand, level = 0;
|
||||
char *name, buffer[12], *value;
|
||||
|
||||
xPL_strToInt(xPL_getMessageNamedValue(msg, "device"), &deviceId);
|
||||
for( i = 0; i < deviceCount; ++i ) {
|
||||
if (tdGetDeviceId(i) == deviceId) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
message = xPL_createBroadcastMessage(telldusService, xPL_MESSAGE_STATUS);
|
||||
xPL_setSchema(message, "lighting", "devinfo");
|
||||
|
||||
xPL_setMessageNamedValue(message, "network", xPL_getMessageNamedValue(msg, "network"));
|
||||
xPL_setMessageNamedValue(message, "device", xPL_getMessageNamedValue(msg, "device"));
|
||||
|
||||
if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(msg, "network"), "1") == 0 && found == TRUE) {
|
||||
lastSentCommand = tdLastSentCommand(deviceId, TELLSTICK_TURNON | TELLSTICK_TURNOFF | TELLSTICK_DIM);
|
||||
if (lastSentCommand == TELLSTICK_TURNON) {
|
||||
level = 100;
|
||||
} else if (lastSentCommand == TELLSTICK_DIM) {
|
||||
value = tdLastSentValue(deviceId);
|
||||
level = atoi(value);
|
||||
free(value);
|
||||
level = round((float)level / 255.0 * 100.0);
|
||||
if (level > 100) {
|
||||
level = 100;
|
||||
} else if (level < 0) {
|
||||
level = 0;
|
||||
}
|
||||
} else {
|
||||
level = 0;
|
||||
}
|
||||
methods = tdMethods(deviceId, TELLSTICK_TURNON | TELLSTICK_TURNOFF | TELLSTICK_DIM);
|
||||
name = tdGetName(deviceId);
|
||||
sprintf(buffer, "1,%s,0,%i", (methods & TELLSTICK_DIM ? "true" : "false"), level);
|
||||
xPL_setMessageNamedValue(message, "status", "ok");
|
||||
xPL_setMessageNamedValue(message, "name", name );
|
||||
xPL_setMessageNamedValue(message, "report-on-manual", "false" );
|
||||
xPL_setMessageNamedValue(message, "channel-count", "1" );
|
||||
xPL_setMessageNamedValue(message, "primary-channel", "1" );
|
||||
xPL_setMessageNamedValue(message, "channel", buffer );
|
||||
xPL_setMessageNamedValue(message, "scene-count", "0" );
|
||||
|
||||
free(name);
|
||||
} else {
|
||||
xPL_setMessageNamedValue(message, "status", "not-found");
|
||||
}
|
||||
|
||||
xPL_sendMessage(message);
|
||||
|
||||
xPL_releaseMessage(message);
|
||||
}
|
||||
|
||||
void sendDevList(xPL_MessagePtr msg) {
|
||||
int deviceCount = 0, i;
|
||||
char deviceList[128];
|
||||
xPL_MessagePtr message = NULL;
|
||||
|
||||
message = xPL_createBroadcastMessage(telldusService, xPL_MESSAGE_STATUS);
|
||||
xPL_setSchema(message, "lighting", "devlist");
|
||||
|
||||
xPL_setMessageNamedValue(message, "network", xPL_getMessageNamedValue(msg, "network"));
|
||||
|
||||
if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(msg, "network"), "1") == 0) {
|
||||
xPL_setMessageNamedValue(message, "status", "ok");
|
||||
deviceCount = tdGetNumberOfDevices();
|
||||
for( i = 0; i < deviceCount; ++i ) {
|
||||
if (i == 0) { /* First */
|
||||
strcpy(deviceList, xPL_intToStr(tdGetDeviceId(i)));
|
||||
} else {
|
||||
strcat(deviceList, ",");
|
||||
strcat(deviceList, xPL_intToStr(tdGetDeviceId(i)));
|
||||
}
|
||||
}
|
||||
|
||||
xPL_setMessageNamedValue(message, "device-count", xPL_intToStr(deviceCount) );
|
||||
xPL_setMessageNamedValue(message, "device", deviceList );
|
||||
} else {
|
||||
xPL_setMessageNamedValue(message, "status", "not-found");
|
||||
}
|
||||
|
||||
xPL_sendMessage(message);
|
||||
|
||||
xPL_releaseMessage(message);
|
||||
}
|
||||
|
||||
void sendGatewayInfo() {
|
||||
xPL_MessagePtr message = NULL;
|
||||
|
||||
message = xPL_createBroadcastMessage(telldusService, xPL_MESSAGE_STATUS);
|
||||
xPL_setSchema(message, "lighting", "gateinfo");
|
||||
|
||||
xPL_setMessageNamedValue(message, "status", "ok");
|
||||
xPL_setMessageNamedValue(message, "protocol", "TELLDUS");
|
||||
xPL_setMessageNamedValue(message, "description", "xPL to Telldus TellStick gateway");
|
||||
xPL_setMessageNamedValue(message, "version", TELLDUS_VERSION);
|
||||
xPL_setMessageNamedValue(message, "author", "Telldus Technologies AB");
|
||||
xPL_setMessageNamedValue(message, "info-url", "http://www.telldus.se");
|
||||
xPL_setMessageNamedValue(message, "net-count", "1");
|
||||
xPL_setMessageNamedValue(message, "preferred-net", "1");
|
||||
xPL_setMessageNamedValue(message, "scenes-ok", "false");
|
||||
xPL_setMessageNamedValue(message, "channels-ok", "false");
|
||||
xPL_setMessageNamedValue(message, "fade-rate-ok", "false");
|
||||
|
||||
/* Broadcast the message */
|
||||
xPL_sendMessage(message);
|
||||
|
||||
xPL_releaseMessage(message);
|
||||
}
|
||||
|
||||
void sendNetInfo(xPL_MessagePtr msg) {
|
||||
xPL_MessagePtr message = NULL;
|
||||
|
||||
message = xPL_createBroadcastMessage(telldusService, xPL_MESSAGE_STATUS);
|
||||
xPL_setSchema(message, "lighting", "netinfo");
|
||||
|
||||
xPL_setMessageNamedValue(message, "network", xPL_getMessageNamedValue(msg, "network"));
|
||||
|
||||
if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(msg, "network"), "1") == 0) {
|
||||
xPL_setMessageNamedValue(message, "status", "ok");
|
||||
xPL_setMessageNamedValue(message, "name", hostname );
|
||||
xPL_setMessageNamedValue(message, "device-count", xPL_intToStr(tdGetNumberOfDevices()) );
|
||||
xPL_setMessageNamedValue(message, "scene-count", "0" );
|
||||
} else {
|
||||
xPL_setMessageNamedValue(message, "status", "not-found");
|
||||
}
|
||||
|
||||
xPL_sendMessage(message);
|
||||
|
||||
xPL_releaseMessage(message);
|
||||
}
|
||||
|
||||
void sendNetList() {
|
||||
xPL_MessagePtr message = NULL;
|
||||
|
||||
message = xPL_createBroadcastMessage(telldusService, xPL_MESSAGE_STATUS);
|
||||
xPL_setSchema(message, "lighting", "netlist");
|
||||
|
||||
xPL_setMessageNamedValue(message, "status", "ok");
|
||||
xPL_setMessageNamedValue(message, "network", "1");
|
||||
|
||||
/* Broadcast the message */
|
||||
xPL_sendMessage(message);
|
||||
|
||||
xPL_releaseMessage(message);
|
||||
}
|
||||
|
||||
void sendGatewayReadyMessage() {
|
||||
xPL_MessagePtr gatewayReadyMessage = NULL;
|
||||
/* Create a message to send */
|
||||
gatewayReadyMessage = xPL_createBroadcastMessage(telldusService, xPL_MESSAGE_TRIGGER);
|
||||
xPL_setSchema(gatewayReadyMessage, "lighting", "gateway");
|
||||
|
||||
/* Install the value and send the message */
|
||||
xPL_setMessageNamedValue(gatewayReadyMessage, "report", "gateway-ready");
|
||||
|
||||
/* Broadcast the message */
|
||||
xPL_sendMessage(gatewayReadyMessage);
|
||||
|
||||
xPL_releaseMessage(gatewayReadyMessage);
|
||||
}
|
||||
|
||||
/* parseCmdLine will handles command line switches. Valid switches are: */
|
||||
/* -interface x - set interface to use */
|
||||
/* -xpldebug - set debugging and enable xPL debugging */
|
||||
/* -nodaemon - Dosn't disconnect from the console */
|
||||
static Bool parseCmdLine( int *argc, char *argv[]) {
|
||||
int swptr;
|
||||
int newcnt = 0;
|
||||
|
||||
/* Handle each item of the command line. If it starts with a '-', then */
|
||||
/* process it as a switch. If not, then copy it to a new position in */
|
||||
/* the argv list and up the new parm counter. */
|
||||
for(swptr = 0; swptr < *argc; swptr++) {
|
||||
/* If it doesn't begin with a '-', it's not a switch. */
|
||||
if (argv[swptr][0] != '-') {
|
||||
if (swptr != newcnt) argv[++newcnt] = argv[swptr];
|
||||
} else {
|
||||
/* Check for daemon mode */
|
||||
if (!strcmp(argv[swptr],"-nodaemon")) {
|
||||
daemonMode = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Anything left is unknown */
|
||||
fprintf(stderr, "Unknown switch `%s'", argv[swptr] );
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set in place the new argument count and exit */
|
||||
*argc = newcnt + 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Print command usage info out */
|
||||
void printUsage(String ourName) {
|
||||
fprintf(stderr, "%s - Telldus TellStick xPL interface\n", ourName);
|
||||
fprintf(stderr, "Copyright (c) 2009, Telldus Technologies AB\n\n");
|
||||
fprintf(stderr, "Usage: %s [-xpldebug] [-nodaemon] [-ip x] [-interface x]\n", ourName);
|
||||
fprintf(stderr, " -xpldebug -- enable xPLLib debugging messagaes\n");
|
||||
fprintf(stderr, " -nodaemon -- don't detach -- run from the console\n");
|
||||
fprintf(stderr, " -interface x -- Use interface named x (i.e. eth0) as network interface\n");
|
||||
fprintf(stderr, " -ip x -- Bind to specified IP address for xPL\n");
|
||||
}
|
||||
|
||||
void startServer() {
|
||||
/* Initialze lighting service */
|
||||
|
||||
/* Create a service for us */
|
||||
if (gethostname(hostname, INSTANCE_MAX) != 0) {
|
||||
fprintf(stderr, "Unable to retrieve the hostname");
|
||||
exit(1);
|
||||
}
|
||||
telldusService = xPL_createService("telldus", "core", hostname);
|
||||
xPL_setServiceVersion(telldusService, TELLDUS_VERSION);
|
||||
|
||||
/* Add a responder */
|
||||
xPL_addServiceListener(telldusService, lightingRequestHandler, xPL_MESSAGE_COMMAND, "lighting", "request", NULL);
|
||||
xPL_addServiceListener(telldusService, lightingCommandHandler, xPL_MESSAGE_COMMAND, "lighting", "basic", NULL);
|
||||
|
||||
/* Install signal traps for proper shutdown */
|
||||
signal(SIGTERM, shutdownHandler);
|
||||
signal(SIGINT, shutdownHandler);
|
||||
|
||||
/* Enable the service */
|
||||
xPL_setServiceEnabled(telldusService, TRUE);
|
||||
sendGatewayReadyMessage();
|
||||
|
||||
for (;;) {
|
||||
/* Let XPL run */
|
||||
xPL_processMessages(-1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, String argv[]) {
|
||||
|
||||
/* Parse command line parms */
|
||||
if (!xPL_parseCommonArgs(&argc, argv, FALSE)) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Start xPL up */
|
||||
if (!xPL_initialize(xPL_getParsedConnectionType())) {
|
||||
fprintf(stderr, "Unable to start xPL");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Parse Hub command arguments */
|
||||
if (!parseCmdLine(&argc, argv)) {
|
||||
printUsage(argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (daemonMode) {
|
||||
switch (fork()) {
|
||||
case 0: /* child */
|
||||
/* No io in child mode */
|
||||
close(fileno(stdin));
|
||||
close(fileno(stdout));
|
||||
close(fileno(stderr));
|
||||
setpgrp();
|
||||
|
||||
startServer();
|
||||
break;
|
||||
case -1: /* error */
|
||||
fprintf(stderr, "Unable to spawn daemon, %s (%d)\n", strerror(errno), errno);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
startServer();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue