1 //-----------------------------------------------------------------------------
2 //
3 // Node.cpp
4 //
5 // A node in the Z-Wave network.
6 //
7 // Copyright (c) 2009 Mal Lansell <xpl@lansell.org>
8 //
9 // SOFTWARE NOTICE AND LICENSE
10 //
11 // This file is part of OpenZWave.
12 //
13 // OpenZWave is free software: you can redistribute it and/or modify
14 // it under the terms of the GNU Lesser General Public License as published by
15 // the Free Software Foundation, either version 3 of the License, or
16 // (at your option) any later version.
17 //
18 // OpenZWave is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 // GNU Lesser General Public License for more details.
22 //
23 // You should have received a copy of the GNU Lesser General Public License
24 // along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
25 //
26 //-----------------------------------------------------------------------------
27
28 #include <iomanip>
29
30
31 #include "Node.h"
32 #include "Defs.h"
33 #include "Group.h"
34 #include "Options.h"
35 #include "Manager.h"
36 #include "Driver.h"
37 #include "Notification.h"
38 #include "Msg.h"
39 #include "ZWSecurity.h"
40 #include "platform/Log.h"
41 #include "platform/Mutex.h"
42 #include "Utils.h"
43
44 #include "tinyxml.h"
45
46 #include "command_classes/CommandClasses.h"
47 #include "command_classes/CommandClass.h"
48 #include "command_classes/Association.h"
49 #include "command_classes/Basic.h"
50 #include "command_classes/Configuration.h"
51 #include "command_classes/ControllerReplication.h"
52 #include "command_classes/ManufacturerSpecific.h"
53 #include "command_classes/MultiInstance.h"
54 #include "command_classes/MultiChannelAssociation.h"
55 #include "command_classes/Security.h"
56 #include "command_classes/WakeUp.h"
57 #include "command_classes/NodeNaming.h"
58 #include "command_classes/NoOperation.h"
59 #include "command_classes/Version.h"
60 #include "command_classes/SwitchAll.h"
61 #include "command_classes/ZWavePlusInfo.h"
62 #include "command_classes/DeviceResetLocally.h"
63
64 #include "Scene.h"
65
66 #include "value_classes/ValueID.h"
67 #include "value_classes/Value.h"
68 #include "value_classes/ValueBool.h"
69 #include "value_classes/ValueButton.h"
70 #include "value_classes/ValueByte.h"
71 #include "value_classes/ValueDecimal.h"
72 #include "value_classes/ValueInt.h"
73 #include "value_classes/ValueRaw.h"
74 #include "value_classes/ValueList.h"
75 #include "value_classes/ValueSchedule.h"
76 #include "value_classes/ValueShort.h"
77 #include "value_classes/ValueString.h"
78 #include "value_classes/ValueStore.h"
79
80 using namespace OpenZWave;
81
82 //-----------------------------------------------------------------------------
83 // Statics
84 //-----------------------------------------------------------------------------
85 bool Node::s_deviceClassesLoaded = false;
86 map<uint8,string> Node::s_basicDeviceClasses;
87 map<uint8,Node::GenericDeviceClass*> Node::s_genericDeviceClasses;
88 map<uint8,Node::DeviceClass*> Node::s_roleDeviceClasses;
89 map<uint16,Node::DeviceClass*> Node::s_deviceTypeClasses;
90 map<uint8,Node::DeviceClass*> Node::s_nodeTypes;
91
92 static char const* c_queryStageNames[] =
93 {
94 "None",
95 "ProtocolInfo",
96 "Probe",
97 "WakeUp",
98 "ManufacturerSpecific1",
99 "NodeInfo",
100 "NodePlusInfo",
101 "SecurityReport",
102 "ManufacturerSpecific2",
103 "Versions",
104 "Instances",
105 "Static",
106 "CacheLoad",
107 "Associations",
108 "Neighbors",
109 "Session",
110 "Dynamic",
111 "Configuration",
112 "Complete"
113 };
114
115 //-----------------------------------------------------------------------------
116 // <Node::Node>
117 // Constructor
118 //-----------------------------------------------------------------------------
Node(uint32 const _homeId,uint8 const _nodeId)119 Node::Node
120 (
121 uint32 const _homeId,
122 uint8 const _nodeId
123 ):
124 m_queryStage( QueryStage_None ),
125 m_queryPending( false ),
126 m_queryConfiguration( false ),
127 m_queryRetries( 0 ),
128 m_protocolInfoReceived( false ),
129 m_basicprotocolInfoReceived( false ),
130 m_nodeInfoReceived( false ),
131 m_nodePlusInfoReceived( false ),
132 m_manufacturerSpecificClassReceived( false ),
133 m_nodeInfoSupported( true ),
134 m_refreshonNodeInfoFrame ( true ),
135 m_nodeAlive( true ), // assome live node
136 m_listening( true ), // assume we start out listening
137 m_frequentListening( false ),
138 m_beaming( false ),
139 m_routing( false ),
140 m_maxBaudRate( 0 ),
141 m_version( 0 ),
142 m_security( false ),
143 m_homeId( _homeId ),
144 m_nodeId( _nodeId ),
145 m_basic( 0 ),
146 m_generic( 0 ),
147 m_specific( 0 ),
148 m_type( "" ),
149 m_numRouteNodes( 0 ),
150 m_addingNode( false ),
151 m_manufacturerName( "" ),
152 m_productName( "" ),
153 m_nodeName( "" ),
154 m_location( "" ),
155 m_manufacturerId( 0 ),
156 m_productType( 0 ),
157 m_productId( 0 ),
158 m_deviceType( 0 ),
159 m_role( 0 ),
160 m_nodeType ( 0 ),
161 m_secured ( false ),
162 m_values( new ValueStore() ),
163 m_sentCnt( 0 ),
164 m_sentFailed( 0 ),
165 m_retries( 0 ),
166 m_receivedCnt( 0 ),
167 m_receivedDups( 0 ),
168 m_receivedUnsolicited( 0 ),
169 m_lastRequestRTT( 0 ),
170 m_lastResponseRTT( 0 ),
171 m_averageRequestRTT( 0 ),
172 m_averageResponseRTT( 0 ),
173 m_quality( 0 ),
174 m_lastReceivedMessage(),
175 m_errors( 0 ),
176 m_lastnonce ( 0 )
177 {
178 memset( m_neighbors, 0, sizeof(m_neighbors) );
179 memset( m_routeNodes, 0, sizeof(m_routeNodes) );
180 memset( m_nonces, 0, sizeof(m_nonces) );
181 AddCommandClass( 0 );
182 }
183
184 //-----------------------------------------------------------------------------
185 // <Node::~Node>
186 // Destructor
187 //-----------------------------------------------------------------------------
~Node()188 Node::~Node
189 (
190 )
191 {
192 // Remove any messages from queues
193 GetDriver()->RemoveQueues( m_nodeId );
194
195 // Remove the values from the poll list
196 for( ValueStore::Iterator it = m_values->Begin(); it != m_values->End(); ++it )
197 {
198 ValueID const& valueId = it->second->GetID();
199 if( GetDriver()->isPolled( valueId ) )
200 {
201 GetDriver()->DisablePoll( valueId );
202 }
203 }
204
205 Scene::RemoveValues( m_homeId, m_nodeId );
206
207 // Delete the values
208 delete m_values;
209
210 // Delete the command classes
211 while( !m_commandClassMap.empty() )
212 {
213 map<uint8,CommandClass*>::iterator it = m_commandClassMap.begin();
214 delete it->second;
215 m_commandClassMap.erase( it );
216 }
217
218 // Delete the groups
219 while( !m_groups.empty() )
220 {
221 map<uint8,Group*>::iterator it = m_groups.begin();
222 delete it->second;
223 m_groups.erase( it );
224 }
225
226 // Delete the button map
227 while( !m_buttonMap.empty() )
228 {
229 map<uint8,uint8>::iterator it = m_buttonMap.begin();
230 m_buttonMap.erase( it );
231 }
232 }
233
234 //-----------------------------------------------------------------------------
235 // <Node::AdvanceQueries>
236 // Proceed through the initialisation process
237 //-----------------------------------------------------------------------------
AdvanceQueries()238 void Node::AdvanceQueries
239 (
240 )
241 {
242 // For OpenZWave to discover everything about a node, we have to follow a certain
243 // order of queries, because the results of one stage may affect what is requested
244 // in the next stage. The stage is saved with the node data, so that any incomplete
245 // queries can be restarted the next time the application runs.
246 // The individual command classes also store some state as to whether they have
247 // had a response to certain queries. This state is initilized by the SetStaticRequests
248 // call in QueryStage_None. It is also saved, so we do not need to request state
249 // from every command class if some have previously responded.
250 //
251 // Each stage must generate all the messages for its particular stage as
252 // assumptions are made in later code (RemoveMsg) that this is the case. This means
253 // each stage is only visited once.
254
255 Log::Write( LogLevel_Detail, m_nodeId, "AdvanceQueries queryPending=%d queryRetries=%d queryStage=%s live=%d", m_queryPending, m_queryRetries, c_queryStageNames[m_queryStage], m_nodeAlive );
256 bool addQSC = false; // We only want to add a query stage complete if we did some work.
257 while( !m_queryPending && m_nodeAlive )
258 {
259 switch( m_queryStage )
260 {
261 case QueryStage_None:
262 {
263 // Init the node query process
264 m_queryStage = QueryStage_ProtocolInfo;
265 m_queryRetries = 0;
266 break;
267 }
268 case QueryStage_ProtocolInfo:
269 {
270 // determines, among other things, whether this node is a listener, its maximum baud rate and its device classes
271 if( !ProtocolInfoReceived() )
272 {
273 Log::Write( LogLevel_Detail, m_nodeId, "QueryStage_ProtocolInfo" );
274 Msg* msg = new Msg( "Get Node Protocol Info", m_nodeId, REQUEST, FUNC_ID_ZW_GET_NODE_PROTOCOL_INFO, false );
275 msg->Append( m_nodeId );
276 GetDriver()->SendMsg( msg, Driver::MsgQueue_Query );
277 m_queryPending = true;
278 addQSC = true;
279 }
280 else
281 {
282 // This stage has been done already, so move to the Neighbours stage
283 m_queryStage = QueryStage_Probe;
284 m_queryRetries = 0;
285 }
286 break;
287 }
288 case QueryStage_Probe:
289 {
290 Log::Write( LogLevel_Detail, m_nodeId, "QueryStage_Probe" );
291 //
292 // Send a NoOperation message to see if the node is awake
293 // and alive. Based on the response or lack of response
294 // will determine next step.
295 //
296 NoOperation* noop = static_cast<NoOperation*>( GetCommandClass( NoOperation::StaticGetCommandClassId() ) );
297 /* don't Probe the Controller */
298 if( GetDriver()->GetControllerNodeId() != m_nodeId )
299 {
300 noop->Set( true );
301 m_queryPending = true;
302 addQSC = true;
303 }
304 else
305 {
306 m_queryStage = QueryStage_WakeUp;
307 m_queryRetries = 0;
308 }
309 break;
310 }
311 case QueryStage_WakeUp:
312 {
313 // For sleeping devices other than controllers, we need to defer the usual requests until
314 // we have told the device to send it's wake-up notifications to the PC controller.
315 Log::Write( LogLevel_Detail, m_nodeId, "QueryStage_WakeUp" );
316
317 WakeUp* wakeUp = static_cast<WakeUp*>( GetCommandClass( WakeUp::StaticGetCommandClassId() ) );
318
319 // if this device is a "sleeping device" and not a controller and not a
320 // FLiRS device. FLiRS will wake up when you send them something and they
321 // don't seem to support Wakeup
322 if( wakeUp && !IsController() && !IsFrequentListeningDevice() )
323 {
324 // start the process of requesting node state from this sleeping device
325 wakeUp->Init();
326 m_queryPending = true;
327 addQSC = true;
328 }
329 else
330 {
331 // this is not a sleeping device, so move to the ManufacturerSpecific1 stage
332 m_queryStage = QueryStage_ManufacturerSpecific1;
333 m_queryRetries = 0;
334 }
335 break;
336 }
337 case QueryStage_ManufacturerSpecific1:
338 {
339 // Obtain manufacturer, product type and product ID code from the node device
340 // Manufacturer Specific data is requested before the other command class data so
341 // that we can modify the supported command classes list through the product XML files.
342 Log::Write( LogLevel_Detail, m_nodeId, "QueryStage_ManufacturerSpecific1" );
343
344 /* if its the Controller, then we can just load up the XML straight away */
345 if( GetDriver()->GetControllerNodeId() == m_nodeId )
346 {
347 Log::Write( LogLevel_Detail, m_nodeId, "Load Controller Manufacturer Specific Config");
348 string configPath = ManufacturerSpecific::SetProductDetails( this, GetDriver()->GetManufacturerId(), GetDriver()->GetProductType(), GetDriver()->GetProductId() );
349 if( configPath.length() > 0 )
350 {
351 ManufacturerSpecific::LoadConfigXML( this, configPath );
352 }
353 m_queryStage = QueryStage_NodeInfo;
354 m_queryRetries = 0;
355 }
356 else
357 {
358 Log::Write( LogLevel_Detail, m_nodeId, "Checking for ManufacturerSpecific CC and Requesting values if present on this node");
359 /* if the ManufacturerSpecific CC was not specified in the ProtocolInfo packet for the Generic/Specific Device type (as part a Mandatory Command Class)
360 * then this will fail, but we will retry in ManufacturerSpecific2
361 *
362 * XXX TODO: This could probably be reworked a bit to make this a Mandatory CC for all devices regardless
363 * of Generic/Specific Type. Then we can drop the Second ManufacturerSpecific QueryStage later.
364 */
365 ManufacturerSpecific* cc = static_cast<ManufacturerSpecific*>( GetCommandClass( ManufacturerSpecific::StaticGetCommandClassId() ) );
366 if( cc )
367 {
368 m_queryPending = cc->RequestState( CommandClass::RequestFlag_Static, 1, Driver::MsgQueue_Query );
369 addQSC = m_queryPending;
370 }
371 if( !m_queryPending )
372 {
373 m_queryStage = QueryStage_NodeInfo;
374 m_queryRetries = 0;
375 }
376 }
377 break;
378 }
379 case QueryStage_NodeInfo:
380 {
381 if( !NodeInfoReceived() && m_nodeInfoSupported && (GetDriver()->GetControllerNodeId() != m_nodeId))
382 {
383 // obtain from the node a list of command classes that it 1) supports and 2) controls (separated by a mark in the buffer)
384 Log::Write( LogLevel_Detail, m_nodeId, "QueryStage_NodeInfo" );
385 Msg* msg = new Msg( "Request Node Info", m_nodeId, REQUEST, FUNC_ID_ZW_REQUEST_NODE_INFO, false, true, FUNC_ID_ZW_APPLICATION_UPDATE );
386 msg->Append( m_nodeId );
387 GetDriver()->SendMsg( msg, Driver::MsgQueue_Query );
388 m_queryPending = true;
389 addQSC = true;
390 }
391 else
392 {
393 // This stage has been done already, so move to the Manufacturer Specific stage
394 m_queryStage = QueryStage_NodePlusInfo;
395 m_queryRetries = 0;
396 }
397 break;
398 }
399 case QueryStage_NodePlusInfo:
400 {
401 Log::Write( LogLevel_Detail, m_nodeId, "QueryStage_NodePlusInfo" );
402 ZWavePlusInfo* pluscc = static_cast<ZWavePlusInfo*>( GetCommandClass( ZWavePlusInfo::StaticGetCommandClassId() ) );
403
404 if ( pluscc )
405 {
406 m_queryPending = pluscc->RequestState( CommandClass::RequestFlag_Static, 1, Driver::MsgQueue_Query );
407 }
408 if (m_queryPending)
409 {
410 addQSC = m_queryPending;
411 }
412 else
413 {
414 // this is not a Zwave+ node, so move onto the next querystage
415 m_queryStage = QueryStage_SecurityReport;
416 m_queryRetries = 0;
417 }
418
419 break;
420 }
421 case QueryStage_SecurityReport:
422 {
423 /* For Devices that Support the Security Class, we have to request a list of
424 * Command Classes that Require Security.
425 */
426 Log::Write( LogLevel_Detail, m_nodeId, "QueryStage_SecurityReport" );
427
428 Security* seccc = static_cast<Security*>( GetCommandClass( Security::StaticGetCommandClassId() ) );
429
430 if( seccc )
431 {
432 // start the process setting up the Security CommandClass
433 m_queryPending = seccc->Init();
434 /* Dont add a QueryStageComplete flag here, as this is a multipacket exchange.
435 * the Security Command Class will automatically advance the Query Stage
436 * when we recieve a SecurityCmd_SupportedReport
437 */
438 addQSC = true;
439 }
440 else
441 {
442 // this is not a Security Device, so move onto the next querystage
443 m_queryStage = QueryStage_ManufacturerSpecific2;
444 m_queryRetries = 0;
445 }
446
447 break;
448 }
449 case QueryStage_ManufacturerSpecific2:
450 {
451 if( !m_manufacturerSpecificClassReceived )
452 {
453 // Obtain manufacturer, product type and product ID code from the node device
454 // Manufacturer Specific data is requested before the other command class data so
455 // that we can modify the supported command classes list through the product XML files.
456 Log::Write( LogLevel_Detail, m_nodeId, "QueryStage_ManufacturerSpecific2" );
457 ManufacturerSpecific* cc = static_cast<ManufacturerSpecific*>( GetCommandClass( ManufacturerSpecific::StaticGetCommandClassId() ) );
458 if( cc )
459 {
460 m_queryPending = cc->RequestState( CommandClass::RequestFlag_Static, 1, Driver::MsgQueue_Query );
461 addQSC = m_queryPending;
462 }
463 if( !m_queryPending )
464 {
465 m_queryStage = QueryStage_Versions;
466 m_queryRetries = 0;
467 }
468 }
469 else
470 {
471 ManufacturerSpecific* cc = static_cast<ManufacturerSpecific*>( GetCommandClass( ManufacturerSpecific::StaticGetCommandClassId() ) );
472 if( cc )
473 {
474 cc->ReLoadConfigXML();
475 }
476 m_queryStage = QueryStage_Versions;
477 m_queryRetries = 0;
478 }
479 break;
480 }
481 case QueryStage_Versions:
482 {
483 // Get the version information (if the device supports COMMAND_CLASS_VERSION
484 Log::Write( LogLevel_Detail, m_nodeId, "QueryStage_Versions" );
485 Version* vcc = static_cast<Version*>( GetCommandClass( Version::StaticGetCommandClassId() ) );
486 if( vcc )
487 {
488 Log::Write(LogLevel_Info, m_nodeId, "Requesting Versions");
489 for( map<uint8,CommandClass*>::const_iterator it = m_commandClassMap.begin(); it != m_commandClassMap.end(); ++it )
490 {
491 CommandClass* cc = it->second;
492 Log::Write(LogLevel_Info, m_nodeId, "Requesting Versions for %s", cc->GetCommandClassName().c_str());
493
494 if( cc->GetMaxVersion() > 1 )
495 {
496 Log::Write(LogLevel_Info, m_nodeId, " ok");
497 // Get the version for each supported command class that
498 // we have implemented at greater than version one.
499 m_queryPending |= vcc->RequestCommandClassVersion( it->second );
500 }
501 }
502 addQSC = m_queryPending;
503 }
504 // advance to Instances stage when finished
505 if( !m_queryPending )
506 {
507 m_queryStage = QueryStage_Instances;
508 m_queryRetries = 0;
509 }
510 break;
511 }
512 case QueryStage_Instances:
513 {
514 // if the device at this node supports multiple instances, obtain a list of these instances
515 Log::Write( LogLevel_Detail, m_nodeId, "QueryStage_Instances" );
516 MultiInstance* micc = static_cast<MultiInstance*>( GetCommandClass( MultiInstance::StaticGetCommandClassId() ) );
517 if( micc )
518 {
519 m_queryPending = micc->RequestInstances();
520 addQSC = m_queryPending;
521 }
522
523 // when done, advance to the Static stage
524 if( !m_queryPending )
525 {
526 m_queryStage = QueryStage_Static;
527 m_queryRetries = 0;
528
529 Log::Write( LogLevel_Info, m_nodeId, "Essential node queries are complete" );
530 Notification* notification = new Notification( Notification::Type_EssentialNodeQueriesComplete );
531 notification->SetHomeAndNodeIds( m_homeId, m_nodeId );
532 GetDriver()->QueueNotification( notification );
533 }
534 break;
535 }
536 case QueryStage_Static:
537 {
538 // Request any other static values associated with each command class supported by this node
539 // examples are supported thermostat operating modes, setpoints and fan modes
540 Log::Write( LogLevel_Detail, m_nodeId, "QueryStage_Static" );
541 for( map<uint8,CommandClass*>::const_iterator it = m_commandClassMap.begin(); it != m_commandClassMap.end(); ++it )
542 {
543 if( !it->second->IsAfterMark() )
544 {
545 m_queryPending |= it->second->RequestStateForAllInstances( CommandClass::RequestFlag_Static, Driver::MsgQueue_Query );
546 } else {
547 /* Controlling CC's might still need to retrieve some info */
548 m_queryPending |= it->second->RequestStateForAllInstances( CommandClass::RequestFlag_AfterMark, Driver::MsgQueue_Query );
549 }
550 }
551 addQSC = m_queryPending;
552
553 if( !m_queryPending )
554 {
555 // when all (if any) static information has been retrieved, advance to the Associations stage
556 // CacheLoad stage is for Nodes that are read in via the zw state file, as is skipped as we would
557 // have already queried it at the discovery phase in Probe.
558 m_queryStage = QueryStage_Associations;
559 m_queryRetries = 0;
560 }
561 break;
562 }
563 /* CacheLoad is where we start if we are loading a device from our zwcfg_*.xml file rather than
564 * a brand new device.
565 */
566 case QueryStage_CacheLoad:
567 {
568 Log::Write( LogLevel_Detail, m_nodeId, "QueryStage_CacheLoad" );
569 Log::Write( LogLevel_Info, GetNodeId(), "Node Identity Codes: %.4x:%.4x:%.4x", GetManufacturerId(), GetProductType(), GetProductId() );
570 //
571 // Send a NoOperation message to see if the node is awake
572 // and alive. Based on the response or lack of response
573 // will determine next step. Called here when configuration exists.
574 //
575 NoOperation* noop = static_cast<NoOperation*>( GetCommandClass( NoOperation::StaticGetCommandClassId() ) );
576 /* Don't do this if its to the Controller */
577 if( GetDriver()->GetControllerNodeId() != m_nodeId )
578 {
579 noop->Set( true );
580 m_queryPending = true;
581 addQSC = true;
582 }
583 else
584 {
585 m_queryStage = QueryStage_Associations;
586 m_queryRetries = 0;
587 }
588 break;
589 }
590 case QueryStage_Associations:
591 {
592 // if this device supports COMMAND_CLASS_ASSOCIATION, determine to which groups this node belong
593 Log::Write( LogLevel_Detail, m_nodeId, "QueryStage_Associations" );
594 MultiChannelAssociation* macc = static_cast<MultiChannelAssociation*>( GetCommandClass( MultiChannelAssociation::StaticGetCommandClassId() ) );
595 if( macc )
596 {
597 macc->RequestAllGroups( 0 );
598 m_queryPending = true;
599 addQSC = true;
600 }
601 else
602 {
603 Association* acc = static_cast<Association*>( GetCommandClass( Association::StaticGetCommandClassId() ) );
604 if( acc )
605 {
606 acc->RequestAllGroups( 0 );
607 m_queryPending = true;
608 addQSC = true;
609 }
610 else
611 {
612 // if this device doesn't support Associations, move to retrieve Session information
613 m_queryStage = QueryStage_Neighbors;
614 m_queryRetries = 0;
615 }
616 }
617 break;
618 }
619 case QueryStage_Neighbors:
620 {
621 // retrieves this node's neighbors and stores the neighbor bitmap in the node object
622 Log::Write( LogLevel_Detail, m_nodeId, "QueryStage_Neighbors" );
623 GetDriver()->RequestNodeNeighbors( m_nodeId, 0 );
624 m_queryPending = true;
625 addQSC = true;
626 break;
627 }
628 case QueryStage_Session:
629 {
630 // Request the session values from the command classes in turn
631 // examples of Session information are: current thermostat setpoints, node names and climate control schedules
632 Log::Write( LogLevel_Detail, m_nodeId, "QueryStage_Session" );
633 for( map<uint8,CommandClass*>::const_iterator it = m_commandClassMap.begin(); it != m_commandClassMap.end(); ++it )
634 {
635 if( !it->second->IsAfterMark() )
636 {
637 m_queryPending |= it->second->RequestStateForAllInstances( CommandClass::RequestFlag_Session, Driver::MsgQueue_Query );
638 }
639 }
640 addQSC = m_queryPending;
641 if( !m_queryPending )
642 {
643 m_queryStage = QueryStage_Dynamic;
644 m_queryRetries = 0;
645 }
646 break;
647 }
648 case QueryStage_Dynamic:
649 {
650 // Request the dynamic values from the node, that can change at any time
651 // Examples include on/off state, heating mode, temperature, etc.
652 Log::Write( LogLevel_Detail, m_nodeId, "QueryStage_Dynamic" );
653 m_queryPending = RequestDynamicValues();
654 addQSC = m_queryPending;
655
656 if( !m_queryPending )
657 {
658 m_queryStage = QueryStage_Configuration;
659 m_queryRetries = 0;
660 }
661 break;
662 }
663 case QueryStage_Configuration:
664 {
665 // Request the configurable parameter values from the node.
666 Log::Write( LogLevel_Detail, m_nodeId, "QueryStage_Configuration" );
667 if( m_queryConfiguration )
668 {
669 if( RequestAllConfigParams( 0 ) )
670 {
671 m_queryPending = true;
672 addQSC = true;
673 }
674 m_queryConfiguration = false;
675 }
676 if( !m_queryPending )
677 {
678 m_queryStage = QueryStage_Complete;
679 m_queryRetries = 0;
680 }
681 break;
682 }
683 case QueryStage_Complete:
684 {
685 ClearAddingNode();
686 // Notify the watchers that the queries are complete for this node
687 Log::Write( LogLevel_Detail, m_nodeId, "QueryStage_Complete" );
688 Notification* notification = new Notification( Notification::Type_NodeQueriesComplete );
689 notification->SetHomeAndNodeIds( m_homeId, m_nodeId );
690 GetDriver()->QueueNotification( notification );
691
692 /* if its a sleeping node, this will send a NoMoreInformation Packet to the device */
693 WakeUp* cc = static_cast<WakeUp*>( GetCommandClass( WakeUp::StaticGetCommandClassId() ) );
694 if( cc )
695 {
696 cc->SendPending();
697 }
698 // Check whether all nodes are now complete
699 GetDriver()->CheckCompletedNodeQueries();
700 return;
701 }
702 default:
703 {
704 break;
705 }
706 }
707 }
708
709 if( addQSC && m_nodeAlive )
710 {
711 // Add a marker to the query queue so this advance method
712 // gets called again once this stage has completed.
713 GetDriver()->SendQueryStageComplete( m_nodeId, m_queryStage );
714 }
715 }
716
717 //-----------------------------------------------------------------------------
718 // <Node::QueryStageComplete>
719 // We are done with a stage in the query process
720 //-----------------------------------------------------------------------------
QueryStageComplete(QueryStage const _stage)721 void Node::QueryStageComplete
722 (
723 QueryStage const _stage
724 )
725 {
726 // Check that we are actually on the specified stage
727 if( _stage != m_queryStage )
728 {
729 return;
730 }
731
732 if( m_queryStage != QueryStage_Complete )
733 {
734 // Move to the next stage
735 m_queryPending = false;
736 m_queryStage = (QueryStage)( (uint32)m_queryStage + 1 );
737 if( m_queryStage == QueryStage_CacheLoad )
738 {
739 m_queryStage = (QueryStage)( (uint32)m_queryStage + 1 );
740 }
741 m_queryRetries = 0;
742 }
743 }
744
745 //-----------------------------------------------------------------------------
746 // <Node::QueryStageRetry>
747 // Retry a stage up to the specified maximum
748 //-----------------------------------------------------------------------------
QueryStageRetry(QueryStage const _stage,uint8 const _maxAttempts)749 void Node::QueryStageRetry
750 (
751 QueryStage const _stage,
752 uint8 const _maxAttempts // = 0
753 )
754 {
755 Log::Write( LogLevel_Info, m_nodeId, "QueryStageRetry stage %s requested stage %s max %d retries %d pending %d", c_queryStageNames[_stage], c_queryStageNames[m_queryStage], _maxAttempts, m_queryRetries, m_queryPending);
756
757 // Check that we are actually on the specified stage
758 if( _stage != m_queryStage )
759 {
760 return;
761 }
762
763 m_queryPending = false;
764 if( _maxAttempts && ( ++m_queryRetries >= _maxAttempts ) )
765 {
766 m_queryRetries = 0;
767 // We've retried too many times. Move to the next stage but only if
768 // we aren't in any of the probe stages.
769 if( m_queryStage != QueryStage_Probe && m_queryStage != QueryStage_CacheLoad )
770 {
771 m_queryStage = (Node::QueryStage)( (uint32)(m_queryStage + 1) );
772 }
773 }
774 // Repeat the current query stage
775 GetDriver()->RetryQueryStageComplete( m_nodeId, m_queryStage );
776 }
777
778 //-----------------------------------------------------------------------------
779 // <Node::SetQueryStage>
780 // Set the query stage (but only to an earlier stage)
781 //-----------------------------------------------------------------------------
SetQueryStage(QueryStage const _stage,bool const _advance)782 void Node::SetQueryStage
783 (
784 QueryStage const _stage,
785 bool const _advance // = true
786 )
787 {
788 if( (int)_stage < (int)m_queryStage )
789 {
790 m_queryStage = _stage;
791 m_queryPending = false;
792
793 if( QueryStage_Configuration == _stage )
794 {
795 m_queryConfiguration = true;
796 }
797 }
798 if( _advance )
799 {
800 AdvanceQueries();
801 }
802 }
803
804 //-----------------------------------------------------------------------------
805 // <Node::GetQueryStageName>
806 // Gets the query stage name
807 //-----------------------------------------------------------------------------
GetQueryStageName(QueryStage const _stage)808 string Node::GetQueryStageName
809 (
810 QueryStage const _stage
811 )
812 {
813 return c_queryStageNames[_stage];
814 }
815
816 //-----------------------------------------------------------------------------
817 // <Node::GetNeighbors>
818 // Gets the neighbors of a node
819 //-----------------------------------------------------------------------------
GetNeighbors(uint8 ** o_neighbors)820 uint32 Node::GetNeighbors
821 (
822 uint8** o_neighbors
823 )
824 {
825 // determine how many neighbors there are
826 int i;
827 uint32 numNeighbors = 0;
828 if( m_queryStage < QueryStage_Session )
829 {
830 *o_neighbors = NULL;
831 return 0;
832 }
833 for( i = 0; i < 29; i++ )
834 {
835 for( unsigned char mask = 0x80; mask != 0; mask >>= 1 )
836 if( ( m_neighbors[i] & mask ) != 0 )
837 numNeighbors++;
838 }
839
840 // handle the possibility that no neighbors are reported
841 if( !numNeighbors )
842 {
843 *o_neighbors = NULL;
844 return 0;
845 }
846
847 // create and populate an array with neighbor node ids
848 uint8* neighbors = new uint8[numNeighbors];
849 uint32 index = 0;
850 for( int by=0; by<29; by++ )
851 {
852 for( int bi=0; bi<8; bi++ )
853 {
854 if( (m_neighbors[by] & ( 0x01<<bi ) ) )
855 neighbors[index++] = ( ( by<<3 ) + bi + 1 );
856 }
857 }
858
859 *o_neighbors = neighbors;
860 return numNeighbors;
861 }
862
863 //-----------------------------------------------------------------------------
864 // <Node::ReadXML>
865 // Read the node config from XML
866 //-----------------------------------------------------------------------------
ReadXML(TiXmlElement const * _node)867 void Node::ReadXML
868 (
869 TiXmlElement const* _node
870 )
871 {
872 char const* str;
873 int intVal;
874
875 str = _node->Attribute( "query_stage" );
876 if( str )
877 {
878 // After restoring state from a file, we need to at least refresh the association, session and dynamic values.
879 QueryStage queryStage = QueryStage_Associations;
880 for( uint32 i=0; i<(uint32)QueryStage_Associations; ++i )
881 {
882 if( !strcmp( str, c_queryStageNames[i] ) )
883 {
884 queryStage = (QueryStage)i;
885 break;
886 }
887 }
888
889 /* we cant use the SetQueryStage method here, as it only allows us to
890 * go to a lower QueryStage, and not a higher QueryStage. As QueryStage_Complete is higher than
891 * QueryStage_None (the default) we manually set it here. Note - in Driver::HandleSerialAPIGetInitDataResponse the
892 * QueryStage is set to CacheLoad (which is less than QueryStage_Associations) if this is a existing node read in via the zw state file.
893 *
894 */
895 m_queryStage = queryStage;
896 m_queryPending = false;
897
898 if( QueryStage_Configuration == queryStage )
899 {
900 m_queryConfiguration = true;
901 }
902 }
903
904 if( m_queryStage != QueryStage_None )
905 {
906 if( m_queryStage > QueryStage_ProtocolInfo )
907 {
908 // Notify the watchers of the protocol info.
909 // We do the notification here so that it gets into the queue ahead of
910 // any other notifications generated by adding command classes etc.
911 m_protocolInfoReceived = true;
912 Notification* notification = new Notification( Notification::Type_NodeProtocolInfo );
913 notification->SetHomeAndNodeIds( m_homeId, m_nodeId );
914 GetDriver()->QueueNotification( notification );
915 }
916
917 if( m_queryStage > QueryStage_NodeInfo )
918 {
919 m_nodeInfoReceived = true;
920 }
921
922 if( m_queryStage > QueryStage_Instances )
923 {
924 Notification* notification = new Notification( Notification::Type_EssentialNodeQueriesComplete );
925 notification->SetHomeAndNodeIds( m_homeId, m_nodeId );
926 GetDriver()->QueueNotification( notification );
927 }
928 }
929
930 str = _node->Attribute( "name" );
931 if( str )
932 {
933 m_nodeName = str;
934 }
935
936 str = _node->Attribute( "location" );
937 if( str )
938 {
939 m_location = str;
940 }
941
942 if( TIXML_SUCCESS == _node->QueryIntAttribute( "basic", &intVal ) )
943 {
944 m_basic = (uint8)intVal;
945 }
946
947 if( TIXML_SUCCESS == _node->QueryIntAttribute( "generic", &intVal ) )
948 {
949 m_generic = (uint8)intVal;
950 }
951
952 if( TIXML_SUCCESS == _node->QueryIntAttribute( "specific", &intVal ) )
953 {
954 m_specific = (uint8)intVal;
955 }
956
957 if( TIXML_SUCCESS == _node->QueryIntAttribute( "roletype", &intVal ) )
958 {
959 m_role = (uint8)intVal;
960 m_nodePlusInfoReceived = true;
961 }
962
963 if( TIXML_SUCCESS == _node->QueryIntAttribute( "devicetype", &intVal ) )
964 {
965 m_deviceType = (uint16)intVal;
966 m_nodePlusInfoReceived = true;
967 }
968
969 if (TIXML_SUCCESS == _node->QueryIntAttribute ( "nodetype", &intVal ) )
970 {
971 m_nodeType = (uint8)intVal;
972 m_nodePlusInfoReceived = true;
973 }
974
975 str = _node->Attribute( "type" );
976 if( str )
977 {
978 m_type = str;
979 }
980
981 m_listening = true;
982 str = _node->Attribute( "listening" );
983 if( str )
984 {
985 m_listening = !strcmp( str, "true" );
986 }
987
988 m_frequentListening = false;
989 str = _node->Attribute( "frequentListening" );
990 if( str )
991 {
992 m_frequentListening = !strcmp( str, "true" );
993 }
994
995 m_beaming = false;
996 str = _node->Attribute( "beaming" );
997 if( str )
998 {
999 m_beaming = !strcmp( str, "true" );
1000 }
1001
1002 m_routing = true;
1003 str = _node->Attribute( "routing" );
1004 if( str )
1005 {
1006 m_routing = !strcmp( str, "true" );
1007 }
1008
1009 m_maxBaudRate = 0;
1010 if( TIXML_SUCCESS == _node->QueryIntAttribute( "max_baud_rate", &intVal ) )
1011 {
1012 m_maxBaudRate = (uint32)intVal;
1013 }
1014
1015 m_version = 0;
1016 if( TIXML_SUCCESS == _node->QueryIntAttribute( "version", &intVal ) )
1017 {
1018 m_version = (uint8)intVal;
1019 }
1020
1021 m_security = false;
1022 str = _node->Attribute( "security" );
1023 if( str )
1024 {
1025 m_security = !strcmp( str, "true" );
1026 }
1027
1028 m_secured = false;
1029 str = _node->Attribute( "secured" );
1030 if( str )
1031 {
1032 m_secured = !strcmp( str, "true" );
1033 }
1034
1035 m_nodeInfoSupported = true;
1036 str = _node->Attribute( "nodeinfosupported" );
1037 if( str )
1038 {
1039 m_nodeInfoSupported = !strcmp( str, "true" );
1040 }
1041
1042 m_refreshonNodeInfoFrame = true;
1043 str = _node->Attribute( "refreshonnodeinfoframe" );
1044 if ( str )
1045 m_refreshonNodeInfoFrame = !strcmp (str, "true" );
1046
1047 // Read the manufacturer info and create the command classes
1048 TiXmlElement const* child = _node->FirstChildElement();
1049 while( child )
1050 {
1051 str = child->Value();
1052 if( str )
1053 {
1054 if( !strcmp( str, "CommandClasses" ) )
1055 {
1056 ReadCommandClassesXML( child );
1057 }
1058 else if( !strcmp( str, "Manufacturer" ) )
1059 {
1060 str = child->Attribute( "id" );
1061 if( str )
1062 {
1063 m_manufacturerId = strtol(str, NULL, 16);
1064 }
1065
1066 str = child->Attribute( "name" );
1067 if( str )
1068 {
1069 m_manufacturerName = str;
1070 }
1071
1072 TiXmlElement const* product = child->FirstChildElement();
1073 if( !strcmp( product->Value(), "Product" ) )
1074 {
1075 str = product->Attribute( "type" );
1076 if( str )
1077 {
1078 m_productType = strtol(str, NULL, 16);
1079 }
1080
1081 str = product->Attribute( "id" );
1082 if( str )
1083 {
1084 m_productId = strtol(str, NULL, 16);
1085 }
1086
1087 str = product->Attribute( "name" );
1088 if( str )
1089 {
1090 m_productName = str;
1091 }
1092 }
1093 }
1094 }
1095
1096 // Move to the next child node
1097 child = child->NextSiblingElement();
1098 }
1099
1100 if( m_nodeName.length() > 0 || m_location.length() > 0 || m_manufacturerId > 0 )
1101 {
1102 // Notify the watchers of the name changes
1103 Notification* notification = new Notification( Notification::Type_NodeNaming );
1104 notification->SetHomeAndNodeIds( m_homeId, m_nodeId );
1105 GetDriver()->QueueNotification( notification );
1106 }
1107 }
1108
1109 //-----------------------------------------------------------------------------
1110 // <Node::ReadDeviceProtocolXML>
1111 // Read the device's protocol configuration from XML
1112 //-----------------------------------------------------------------------------
ReadDeviceProtocolXML(TiXmlElement const * _ccsElement)1113 void Node::ReadDeviceProtocolXML
1114 (
1115 TiXmlElement const* _ccsElement
1116 )
1117 {
1118 TiXmlElement const* ccElement = _ccsElement->FirstChildElement();
1119 while( ccElement )
1120 {
1121 char const* str = ccElement->Value();
1122 if( str && !strcmp( str, "Protocol" ) )
1123 {
1124 str = ccElement->Attribute( "nodeinfosupported" );
1125 if( str )
1126 {
1127 m_nodeInfoSupported = !strcmp( str, "true" );
1128 }
1129
1130 str = ccElement->Attribute( "refreshonnodeinfoframe" );
1131 if ( str )
1132 {
1133 m_refreshonNodeInfoFrame = !strcmp( str, "true" );
1134 }
1135
1136 // Some controllers support API calls that aren't advertised in their returned data.
1137 // So provide a way to manipulate the returned data to reflect reality.
1138 TiXmlElement const* childElement = _ccsElement->FirstChildElement();
1139 while( childElement )
1140 {
1141 str = childElement->Value();
1142 if( str && !strcmp( str, "APIcall" ) )
1143 {
1144 char const* funcStr = childElement->Attribute( "function" );
1145 char *p;
1146 uint8 func = (uint8)strtol( funcStr, &p, 16 );
1147 if( p != funcStr )
1148 {
1149 char const* presStr = ccElement->Attribute( "present" );
1150 GetDriver()->SetAPICall( func, !strcmp( presStr, "true" ) );
1151 }
1152 }
1153 childElement = childElement->NextSiblingElement();
1154 }
1155 return;
1156 }
1157 ccElement = ccElement->NextSiblingElement();
1158 }
1159 }
1160
1161 //-----------------------------------------------------------------------------
1162 // <Node::ReadCommandClassesXML>
1163 // Read the command classes from XML
1164 //-----------------------------------------------------------------------------
ReadCommandClassesXML(TiXmlElement const * _ccsElement)1165 void Node::ReadCommandClassesXML
1166 (
1167 TiXmlElement const* _ccsElement
1168 )
1169 {
1170 char const* str;
1171 int32 intVal;
1172
1173 TiXmlElement const* ccElement = _ccsElement->FirstChildElement();
1174 while( ccElement )
1175 {
1176 str = ccElement->Value();
1177 if( str && !strcmp( str, "CommandClass" ) )
1178 {
1179 if( TIXML_SUCCESS == ccElement->QueryIntAttribute( "id", &intVal ) )
1180 {
1181 uint8 id = (uint8)intVal;
1182
1183 // Check whether this command class is to be removed (product XMLs might
1184 // request this if a class is not implemented properly by the device)
1185 bool remove = false;
1186 char const* action = ccElement->Attribute( "action" );
1187 if( action && !strcasecmp( action, "remove" ) )
1188 {
1189 remove = true;
1190 }
1191
1192 CommandClass* cc = GetCommandClass( id );
1193 if( remove )
1194 {
1195 // Remove support for the command class
1196 RemoveCommandClass( id );
1197 }
1198 else
1199 {
1200 if( NULL == cc )
1201 {
1202 if (Security::StaticGetCommandClassId() == id && !GetDriver()->isNetworkKeySet()) {
1203 Log::Write(LogLevel_Warning, "Security Command Class cannot be Loaded. NetworkKey is not set");
1204 ccElement = ccElement->NextSiblingElement();
1205 continue;
1206 }
1207
1208 // Command class support does not exist yet, so we create it
1209 cc = AddCommandClass( id );
1210 }
1211
1212 if( NULL != cc )
1213 {
1214 cc->ReadXML( ccElement );
1215 }
1216 }
1217 }
1218 }
1219
1220 ccElement = ccElement->NextSiblingElement();
1221 }
1222 }
1223
1224 //-----------------------------------------------------------------------------
1225 // <Node::WriteXML>
1226 // Save the static node configuration data
1227 //-----------------------------------------------------------------------------
WriteXML(TiXmlElement * _driverElement)1228 void Node::WriteXML
1229 (
1230 TiXmlElement* _driverElement
1231 )
1232 {
1233 char str[32];
1234
1235 TiXmlElement* nodeElement = new TiXmlElement( "Node" );
1236 _driverElement->LinkEndChild( nodeElement );
1237
1238 snprintf( str, 32, "%d", m_nodeId );
1239 nodeElement->SetAttribute( "id", str );
1240
1241 nodeElement->SetAttribute( "name", m_nodeName.c_str() );
1242 nodeElement->SetAttribute( "location", m_location.c_str() );
1243
1244 snprintf( str, 32, "%d", m_basic );
1245 nodeElement->SetAttribute( "basic", str );
1246
1247 snprintf( str, 32, "%d", m_generic );
1248 nodeElement->SetAttribute( "generic", str );
1249
1250 snprintf( str, 32, "%d", m_specific );
1251 nodeElement->SetAttribute( "specific", str );
1252
1253 if( m_nodePlusInfoReceived )
1254 {
1255 snprintf( str, 32, "%d", m_role );
1256 nodeElement->SetAttribute( "roletype", str );
1257
1258 snprintf( str, 32, "%d", m_deviceType );
1259 nodeElement->SetAttribute( "devicetype", str );
1260
1261 snprintf( str, 32, "%d", m_nodeType );
1262 nodeElement->SetAttribute ( "nodetype", str );
1263 }
1264
1265 nodeElement->SetAttribute( "type", m_type.c_str() );
1266
1267 nodeElement->SetAttribute( "listening", m_listening ? "true" : "false" );
1268 nodeElement->SetAttribute( "frequentListening", m_frequentListening ? "true" : "false" );
1269 nodeElement->SetAttribute( "beaming", m_beaming ? "true" : "false" );
1270 nodeElement->SetAttribute( "routing", m_routing ? "true" : "false" );
1271
1272 snprintf( str, 32, "%d", m_maxBaudRate );
1273 nodeElement->SetAttribute( "max_baud_rate", str );
1274
1275 snprintf( str, 32, "%d", m_version );
1276 nodeElement->SetAttribute( "version", str );
1277
1278 if( m_security )
1279 {
1280 nodeElement->SetAttribute( "security", "true" );
1281 }
1282
1283 if( m_secured )
1284 {
1285 nodeElement->SetAttribute( "secured", "true" );
1286 }
1287
1288
1289 if( !m_nodeInfoSupported )
1290 {
1291 nodeElement->SetAttribute( "nodeinfosupported", "false" );
1292 }
1293
1294 if (!m_refreshonNodeInfoFrame)
1295 {
1296 nodeElement->SetAttribute( "refreshonnodeinfoframe", "false" );
1297 }
1298
1299 nodeElement->SetAttribute( "query_stage", c_queryStageNames[m_queryStage] );
1300
1301 // Write the manufacturer and product data in the same format
1302 // as used in the ManyfacturerSpecfic.xml file. This will
1303 // allow new devices to be added via a simple cut and paste.
1304 TiXmlElement* manufacturerElement = new TiXmlElement( "Manufacturer" );
1305 nodeElement->LinkEndChild( manufacturerElement );
1306
1307 /* this should be written in hex to avoid confusion... */
1308 {
1309 std::stringstream ss;
1310 ss << std::hex << m_manufacturerId;
1311 manufacturerElement->SetAttribute( "id", ss.str().c_str() );
1312 }
1313 manufacturerElement->SetAttribute( "name", m_manufacturerName.c_str() );
1314
1315 TiXmlElement* productElement = new TiXmlElement( "Product" );
1316 manufacturerElement->LinkEndChild( productElement );
1317
1318 /* this should be written in hex to avoid confusion... */
1319 {
1320 std::stringstream ss;
1321 ss << std::hex << m_productType;
1322 productElement->SetAttribute( "type", ss.str().c_str() );
1323 }
1324
1325 /* this should be written in hex to avoid confusion... */
1326 {
1327 std::stringstream ss;
1328 ss << std::hex << m_productId;
1329 productElement->SetAttribute( "id", ss.str().c_str() );
1330 }
1331 productElement->SetAttribute( "name", m_productName.c_str() );
1332
1333 // Write the command classes
1334 TiXmlElement* ccsElement = new TiXmlElement( "CommandClasses" );
1335 nodeElement->LinkEndChild( ccsElement );
1336
1337 for( map<uint8,CommandClass*>::const_iterator it = m_commandClassMap.begin(); it != m_commandClassMap.end(); ++it )
1338 {
1339 if( it->second->GetCommandClassId() == NoOperation::StaticGetCommandClassId() ) // don't output NoOperation
1340 {
1341 continue;
1342 }
1343 TiXmlElement* ccElement = new TiXmlElement( "CommandClass" );
1344 ccsElement->LinkEndChild( ccElement );
1345 it->second->WriteXML( ccElement );
1346 }
1347 }
1348
1349 //-----------------------------------------------------------------------------
1350 // <Node::UpdateProtocolInfo>
1351 // Handle the FUNC_ID_ZW_GET_NODE_PROTOCOL_INFO response
1352 //-----------------------------------------------------------------------------
UpdateProtocolInfo(uint8 const * _data)1353 void Node::UpdateProtocolInfo
1354 (
1355 uint8 const* _data
1356 )
1357 {
1358 if( ProtocolInfoReceived() )
1359 {
1360 // We already have this info
1361 return;
1362 }
1363
1364 if( _data[4] == 0 )
1365 {
1366 // Node doesn't exist if Generic class is zero.
1367 Log::Write( LogLevel_Info, m_nodeId, " Protocol Info for Node %d reports node nonexistent", m_nodeId );
1368 SetNodeAlive( false );
1369 return;
1370 }
1371
1372 // Capabilities
1373 m_listening = ( ( _data[0] & 0x80 ) != 0 );
1374 m_routing = ( ( _data[0] & 0x40 ) != 0 );
1375
1376 m_maxBaudRate = 9600;
1377 if( ( _data[0] & 0x38 ) == 0x10 )
1378 {
1379 m_maxBaudRate = 40000;
1380 }
1381
1382 m_version = ( _data[0] & 0x07 ) + 1;
1383
1384 m_frequentListening = ( ( _data[1] & ( SecurityFlag_Sensor250ms | SecurityFlag_Sensor1000ms ) ) != 0 );
1385 m_beaming = ( ( _data[1] & SecurityFlag_BeamCapability ) != 0 );
1386
1387 // Security
1388 m_security = ( ( _data[1] & SecurityFlag_Security ) != 0 );
1389
1390 // Optional flag is true if the device reports optional command classes.
1391 // NOTE: We stopped using this because not all devices report it properly,
1392 // and now just request the optional classes regardless.
1393 // bool optional = (( _data[1] & 0x80 ) != 0 );
1394 /* dont do any further processing if we have already recieved our Protocol Info, or basicprotocolInfo */
1395 if( ProtocolInfoReceived())
1396 {
1397 // We already have this info
1398 return;
1399 }
1400
1401 Log::Write( LogLevel_Info, m_nodeId, " Protocol Info for Node %d:", m_nodeId );
1402 if( m_listening )
1403 Log::Write( LogLevel_Info, m_nodeId, " Listening = true" );
1404 else
1405 {
1406 Log::Write( LogLevel_Info, m_nodeId, " Listening = false" );
1407 Log::Write( LogLevel_Info, m_nodeId, " Frequent = %s", m_frequentListening ? "true" : "false" );
1408 }
1409 Log::Write( LogLevel_Info, m_nodeId, " Beaming = %s", m_beaming ? "true" : "false" );
1410 Log::Write( LogLevel_Info, m_nodeId, " Routing = %s", m_routing ? "true" : "false" );
1411 Log::Write( LogLevel_Info, m_nodeId, " Max Baud Rate = %d", m_maxBaudRate );
1412 Log::Write( LogLevel_Info, m_nodeId, " Version = %d", m_version );
1413 Log::Write( LogLevel_Info, m_nodeId, " Security = %s", m_security ? "true" : "false" );
1414
1415 if (m_basicprotocolInfoReceived == false) {
1416
1417 // Notify the watchers of the protocol info.
1418 // We do the notification here so that it gets into the queue ahead of
1419 // any other notifications generated by adding command classes etc.
1420 Notification* notification = new Notification( Notification::Type_NodeProtocolInfo );
1421 notification->SetHomeAndNodeIds( m_homeId, m_nodeId );
1422 GetDriver()->QueueNotification( notification );
1423
1424 // Set up the device class based data for the node, including mandatory command classes
1425 SetDeviceClasses( _data[3], _data[4], _data[5] );
1426 // Do this for every controller. A little extra work but it won't be a large file.
1427 if( IsController() )
1428 {
1429 GetDriver()->ReadButtons( m_nodeId );
1430 }
1431 m_basicprotocolInfoReceived = true;
1432 } else {
1433 /* we have to setup the Wakeup CC if needed here, because
1434 * it wouldn't have been created in the SetProtocolInfo function, as we didn't
1435 * have the Device Flags then
1436 */
1437 if( !m_listening && !IsFrequentListeningDevice())
1438 {
1439 // Device does not always listen, so we need the WakeUp handler. We can't
1440 // wait for the command class list because the request for the command
1441 // classes may need to go in the wakeup queue itself!
1442 if( CommandClass* pCommandClass = AddCommandClass( WakeUp::StaticGetCommandClassId() ) )
1443 {
1444 pCommandClass->SetInstance( 1 );
1445 }
1446 }
1447
1448 }
1449 m_protocolInfoReceived = true;
1450 }
1451
SetProtocolInfo(uint8 const * _protocolInfo,uint8 const _length)1452 void Node::SetProtocolInfo
1453 (
1454 uint8 const* _protocolInfo,
1455 uint8 const _length
1456 )
1457 {
1458
1459 if( ProtocolInfoReceived() || m_basicprotocolInfoReceived == true )
1460 {
1461 // We already have this info
1462 return;
1463 }
1464
1465 if( _protocolInfo[1] == 0 )
1466 {
1467 // Node doesn't exist if Generic class is zero.
1468 Log::Write( LogLevel_Info, m_nodeId, " Protocol Info for Node %d reports node nonexistent", m_nodeId );
1469 SetNodeAlive( false );
1470 return;
1471 }
1472
1473 // Notify the watchers of the protocol info.
1474 // We do the notification here so that it gets into the queue ahead of
1475 // any other notifications generated by adding command classes etc.
1476 Notification* notification = new Notification( Notification::Type_NodeProtocolInfo );
1477 notification->SetHomeAndNodeIds( m_homeId, m_nodeId );
1478 GetDriver()->QueueNotification( notification );
1479
1480
1481 // Set up the device class based data for the node, including mandatory command classes
1482 SetDeviceClasses( _protocolInfo[0], _protocolInfo[1], _protocolInfo[2] );
1483
1484 /* Remaining Bytes in _protocolInfo are the CommandClasses this device supports */
1485 /* first iterate over them and check for the Security CC, as we want to quickly start exchanging the Network Keys
1486 * first (before other CC's start sending stuff and slowing down our exchange
1487 */
1488 if (m_secured) {
1489 if (Security *pCommandClass = static_cast<Security *>(GetCommandClass(Security::StaticGetCommandClassId()))) {
1490 /* Security CC has already been loaded, most likely via the SetDeviceClasses Function above */
1491 if (!GetDriver()->isNetworkKeySet()) {
1492 Log::Write(LogLevel_Warning, m_nodeId, "Security Command Class Disabled. NetworkKey is not Set");
1493 } else {
1494 pCommandClass->ExchangeNetworkKeys();
1495 }
1496 } else {
1497 /* Security CC is not loaded, see if its in our NIF frame and load if necessary */
1498 for (int i = 3; i < _length; i++) {
1499 if (_protocolInfo[i] == Security::StaticGetCommandClassId()) {
1500 pCommandClass = static_cast<Security *>(AddCommandClass(_protocolInfo[i]));
1501 if (!GetDriver()->isNetworkKeySet()) {
1502 Log::Write(LogLevel_Warning, m_nodeId, "Security Command Class Disabled. NetworkKey is not Set");
1503 } else {
1504 pCommandClass->ExchangeNetworkKeys();
1505 }
1506 }
1507 }
1508 }
1509 }
1510 UpdateNodeInfo(&_protocolInfo[3], _length-3);
1511
1512
1513 m_basicprotocolInfoReceived = true;
1514 }
1515
SetSecured(bool secure)1516 void Node::SetSecured(bool secure) {
1517 m_secured = secure;
1518 }
1519
1520
1521
SetSecuredClasses(uint8 const * _data,uint8 const _length)1522 void Node::SetSecuredClasses
1523 (
1524 uint8 const* _data,
1525 uint8 const _length
1526 )
1527 {
1528 uint32 i;
1529 m_secured = true;
1530 Log::Write( LogLevel_Info, m_nodeId, " Secured command classes for node %d:", m_nodeId );
1531
1532 if (!GetDriver()->isNetworkKeySet()) {
1533 Log::Write (LogLevel_Warning, m_nodeId, " Secured Command Classes cannot be enabled as Network Key is not set");
1534 return;
1535 }
1536
1537
1538 bool afterMark = false;
1539 for( i=0; i<_length; ++i )
1540 {
1541 if( _data[i] == 0xef )
1542 {
1543 // COMMAND_CLASS_MARK.
1544 // Marks the end of the list of supported command classes. The remaining classes
1545 // are those that can be controlled by the device. These classes are created
1546 // without values. Messages received cause notification events instead.
1547 afterMark = true;
1548 continue;
1549 }
1550 /* Check if this is a CC that is already registered with the node */
1551 if (CommandClass *pCommandClass = GetCommandClass(_data[i]))
1552 {
1553 /* if it was specified int he NIF frame, and came in as part of the Security SupportedReport message
1554 * then it can support both Clear Text and Secured Comms. So do a check first
1555 */
1556 if (pCommandClass->IsInNIF()) {
1557 /* if the CC Supports Security and our SecurityStrategy says we should encrypt it, then mark it as encrypted */
1558 if (pCommandClass->IsSecureSupported() && (ShouldSecureCommandClass(_data[i]) == SecurityStrategy_Supported )) {
1559 pCommandClass->SetSecured();
1560 Log::Write( LogLevel_Info, m_nodeId, " %s (Secured) - %s", pCommandClass->GetCommandClassName().c_str(), pCommandClass->IsInNIF() ? "InNIF": "NotInNIF");
1561 }
1562 /* if it wasn't in the NIF frame, then it will only support Secured Comms. */
1563 } else {
1564 if (pCommandClass->IsSecureSupported()) {
1565 pCommandClass->SetSecured();
1566 Log::Write( LogLevel_Info, m_nodeId, " %s (Secured) - %s", pCommandClass->GetCommandClassName().c_str(), pCommandClass->IsInNIF() ? "InNIF": "NotInNIF");
1567 }
1568 }
1569 }
1570 /* it might be a new CC we havn't seen as part of the NIF. In that case
1571 * its only supported via the Security CC, so no need to check our SecurityStrategy, just
1572 * encrypt it regardless */
1573 else if( CommandClasses::IsSupported( _data[i] ) )
1574 {
1575 if( CommandClass* pCommandClass = AddCommandClass( _data[i] ) )
1576 {
1577 // If this class came after the COMMAND_CLASS_MARK, then we do not create values.
1578 if( afterMark )
1579 {
1580 pCommandClass->SetAfterMark();
1581 }
1582 if (pCommandClass->IsSecureSupported()) {
1583 pCommandClass->SetSecured();
1584 Log::Write( LogLevel_Info, m_nodeId, " %s (Secured) - %s", pCommandClass->GetCommandClassName().c_str(), pCommandClass->IsInNIF() ? "InNIF" : "NotInNIF" );
1585 }
1586 // Start with an instance count of one. If the device supports COMMMAND_CLASS_MULTI_INSTANCE
1587 // then some command class instance counts will increase once the responses to the RequestState
1588 // call at the end of this method have been processed.
1589 pCommandClass->SetInstance( 1 );
1590
1591 /* set our Static Request Flags */
1592 uint8 request = 0;
1593
1594 if( GetCommandClass( MultiInstance::StaticGetCommandClassId() ) )
1595 {
1596 // Request instances
1597 request |= (uint8)CommandClass::StaticRequest_Instances;
1598 }
1599
1600 if( GetCommandClass( Version::StaticGetCommandClassId() ) )
1601 {
1602 // Request versions
1603 request |= (uint8)CommandClass::StaticRequest_Version;
1604 }
1605
1606 if( request )
1607 {
1608 pCommandClass->SetStaticRequest( request );
1609 }
1610 }
1611 }
1612 else
1613 {
1614 Log::Write( LogLevel_Info, m_nodeId, " Secure CommandClass 0x%.2x - NOT SUPPORTED", _data[i] );
1615 }
1616 }
1617 Log::Write( LogLevel_Info, m_nodeId, " UnSecured command classes for node %d:", m_nodeId );
1618 for( map<uint8,CommandClass*>::const_iterator it = m_commandClassMap.begin(); it != m_commandClassMap.end(); ++it )
1619 {
1620 if (!it->second->IsSecured())
1621 Log::Write( LogLevel_Info, m_nodeId, " %s (Unsecured) - %s", it->second->GetCommandClassName().c_str(), it->second->IsInNIF() ? "InNIF" : "NotInNIF" );
1622 }
1623
1624
1625 }
1626 //-----------------------------------------------------------------------------
1627 // <Node::UpdateNodeInfo>
1628 // Set up the command classes from the node info frame
1629 //-----------------------------------------------------------------------------
UpdateNodeInfo(uint8 const * _data,uint8 const _length)1630 void Node::UpdateNodeInfo
1631 (
1632 uint8 const* _data,
1633 uint8 const _length
1634 )
1635 {
1636 if( !NodeInfoReceived() )
1637 {
1638 // Add the command classes specified by the device
1639 Log::Write( LogLevel_Info, m_nodeId, " Optional command classes for node %d:", m_nodeId );
1640
1641 bool newCommandClasses = false;
1642 uint32 i;
1643
1644 bool afterMark = false;
1645 for( i=0; i<_length; ++i )
1646 {
1647 if( _data[i] == 0xef )
1648 {
1649 // COMMAND_CLASS_MARK.
1650 // Marks the end of the list of supported command classes. The remaining classes
1651 // are those that can be controlled by the device. These classes are created
1652 // without values. Messages received cause notification events instead.
1653 afterMark = true;
1654
1655 if( !newCommandClasses )
1656 {
1657 Log::Write( LogLevel_Info, m_nodeId, " None" );
1658 }
1659 Log::Write( LogLevel_Info, m_nodeId, " Optional command classes controlled by node %d:", m_nodeId );
1660 newCommandClasses = false;
1661 continue;
1662 }
1663
1664 if( CommandClasses::IsSupported( _data[i] ) )
1665 {
1666 if (Security::StaticGetCommandClassId() == _data[i] && !GetDriver()->isNetworkKeySet()) {
1667 Log::Write (LogLevel_Info, m_nodeId, " %s (Disabled - Network Key Not Set)", Security::StaticGetCommandClassName().c_str());
1668 continue;
1669 }
1670 if( CommandClass* pCommandClass = AddCommandClass( _data[i] ) )
1671 {
1672 /* this CC was in the NIF frame */
1673 pCommandClass->SetInNIF();
1674 // If this class came after the COMMAND_CLASS_MARK, then we do not create values.
1675 if( afterMark )
1676 {
1677 pCommandClass->SetAfterMark();
1678 }
1679
1680 // Start with an instance count of one. If the device supports COMMMAND_CLASS_MULTI_INSTANCE
1681 // then some command class instance counts will increase once the responses to the RequestState
1682 // call at the end of this method have been processed.
1683 pCommandClass->SetInstance( 1 );
1684 newCommandClasses = true;
1685 Log::Write( LogLevel_Info, m_nodeId, " %s", pCommandClass->GetCommandClassName().c_str() );
1686 } else if (CommandClass *pCommandClass = GetCommandClass( _data[i] ) ) {
1687 /* this CC was in the NIF frame */
1688 pCommandClass->SetInNIF();
1689 Log::Write( LogLevel_Info, m_nodeId, " %s (Existing)", pCommandClass->GetCommandClassName().c_str() );
1690 }
1691 }
1692 else
1693 {
1694 Log::Write( LogLevel_Info, m_nodeId, " CommandClass 0x%.2x - NOT REQUIRED", _data[i] );
1695 }
1696 }
1697
1698 if( !newCommandClasses )
1699 {
1700 // No additional command classes over the mandatory ones.
1701 Log::Write( LogLevel_Info, m_nodeId, " None" );
1702 }
1703
1704 SetStaticRequests();
1705 m_nodeInfoReceived = true;
1706 }
1707 else
1708 {
1709 /* Only Refresh if the Device Config Specifies it - Only the dynamic stuff */
1710 if (m_refreshonNodeInfoFrame)
1711 SetQueryStage( QueryStage_Dynamic );
1712 }
1713
1714 // Treat the node info frame as a sign that the node is awake
1715 if( WakeUp* wakeUp = static_cast<WakeUp*>( GetCommandClass( WakeUp::StaticGetCommandClassId() ) ) )
1716 {
1717 wakeUp->SetAwake( true );
1718 }
1719 }
1720
1721 //-----------------------------------------------------------------------------
1722 // <Node::SetNodeAlive>
1723 // Track alive state of a node for dead node detection.
1724 //-----------------------------------------------------------------------------
SetNodeAlive(bool const _isAlive)1725 void Node::SetNodeAlive
1726 (
1727 bool const _isAlive
1728 )
1729 {
1730 Notification* notification;
1731
1732 if( _isAlive )
1733 {
1734 Log::Write( LogLevel_Error, m_nodeId, "WARNING: node revived" );
1735 m_nodeAlive = true;
1736 m_errors = 0;
1737 if( m_queryStage != Node::QueryStage_Complete )
1738 {
1739 m_queryRetries = 0; // restart at last stage
1740 AdvanceQueries();
1741 }
1742 notification = new Notification( Notification::Type_Notification );
1743 notification->SetHomeAndNodeIds( m_homeId, m_nodeId );
1744 notification->SetNotification( Notification::Code_Alive );
1745 }
1746 else
1747 {
1748 Log::Write( LogLevel_Error, m_nodeId, "ERROR: node presumed dead" );
1749 m_nodeAlive = false;
1750 if( m_queryStage != Node::QueryStage_Complete )
1751 {
1752 // Check whether all nodes are now complete
1753 GetDriver()->CheckCompletedNodeQueries();
1754 }
1755 notification = new Notification( Notification::Type_Notification );
1756 notification->SetHomeAndNodeIds( m_homeId, m_nodeId );
1757 notification->SetNotification( Notification::Code_Dead );
1758 }
1759 GetDriver()->QueueNotification( notification );
1760 }
1761
1762 //-----------------------------------------------------------------------------
1763 // <Node::SetStaticRequests>
1764 // The first time we hear from a node, we set flags to indicate the
1765 // need to request certain static data from the device. This is so that
1766 // we can track which data has been received, and which has not.
1767 //-----------------------------------------------------------------------------
SetStaticRequests()1768 void Node::SetStaticRequests
1769 (
1770 )
1771 {
1772 uint8 request = 0;
1773
1774 if( GetCommandClass( MultiInstance::StaticGetCommandClassId() ) )
1775 {
1776 // Request instances
1777 request |= (uint8)CommandClass::StaticRequest_Instances;
1778 }
1779
1780 if( GetCommandClass( Version::StaticGetCommandClassId() ) )
1781 {
1782 // Request versions
1783 request |= (uint8)CommandClass::StaticRequest_Version;
1784 }
1785
1786 if( request )
1787 {
1788 for( map<uint8,CommandClass*>::const_iterator it = m_commandClassMap.begin(); it != m_commandClassMap.end(); ++it )
1789 {
1790 it->second->SetStaticRequest( request );
1791 }
1792 SetQueryStage( QueryStage_ManufacturerSpecific2 );
1793 }
1794 }
1795
1796 //-----------------------------------------------------------------------------
1797 // <Node::SetNodeName>
1798 // Set the name of the node
1799 //-----------------------------------------------------------------------------
SetNodeName(string const & _nodeName)1800 void Node::SetNodeName
1801 (
1802 string const& _nodeName
1803 )
1804 {
1805 m_nodeName = _nodeName;
1806 // Notify the watchers of the name changes
1807 Notification* notification = new Notification( Notification::Type_NodeNaming );
1808 notification->SetHomeAndNodeIds( m_homeId, m_nodeId );
1809 GetDriver()->QueueNotification( notification );
1810 if( NodeNaming* cc = static_cast<NodeNaming*>( GetCommandClass( NodeNaming::StaticGetCommandClassId() ) ) )
1811 {
1812 // The node supports naming, so we try to write the name into the device
1813 cc->SetName( _nodeName );
1814 }
1815 }
1816
1817 //-----------------------------------------------------------------------------
1818 // <Node::SetLocation>
1819 // Set the location of the node
1820 //-----------------------------------------------------------------------------
SetLocation(string const & _location)1821 void Node::SetLocation
1822 (
1823 string const& _location
1824 )
1825 {
1826 m_location = _location;
1827 // Notify the watchers of the name changes
1828 Notification* notification = new Notification( Notification::Type_NodeNaming );
1829 notification->SetHomeAndNodeIds( m_homeId, m_nodeId );
1830 GetDriver()->QueueNotification( notification );
1831 if( NodeNaming* cc = static_cast<NodeNaming*>( GetCommandClass( NodeNaming::StaticGetCommandClassId() ) ) )
1832 {
1833 // The node supports naming, so we try to write the location into the device
1834 cc->SetLocation( _location );
1835 }
1836 }
1837
1838 //-----------------------------------------------------------------------------
1839 // <Node::ApplicationCommandHandler>
1840 // Handle a command class message
1841 //-----------------------------------------------------------------------------
ApplicationCommandHandler(uint8 const * _data,bool encrypted)1842 void Node::ApplicationCommandHandler
1843 (
1844 uint8 const* _data,
1845 bool encrypted
1846
1847 )
1848 {
1849 if( CommandClass* pCommandClass = GetCommandClass( _data[5] ) )
1850 {
1851 if (pCommandClass->IsSecured() && !encrypted) {
1852 Log::Write( LogLevel_Warning, m_nodeId, "Received a Clear Text Message for the CommandClass %s which is Secured", pCommandClass->GetCommandClassName().c_str());
1853 bool drop = true;
1854 Options::Get()->GetOptionAsBool("EnforceSecureReception", &drop);
1855 if (drop) {
1856 Log::Write( LogLevel_Warning, m_nodeId, " Dropping Message");
1857 return;
1858 } else {
1859 Log::Write( LogLevel_Warning, m_nodeId, " Allowing Message (EnforceSecureReception is not set)");
1860 }
1861 }
1862
1863 pCommandClass->ReceivedCntIncr();
1864 pCommandClass->HandleMsg( &_data[6], _data[4] );
1865 }
1866 else
1867 {
1868 if( _data[5] == ControllerReplication::StaticGetCommandClassId() )
1869 {
1870 // This is a controller replication message, and we do not support it.
1871 // We have to at least acknowledge the message to avoid locking the sending device.
1872 Log::Write( LogLevel_Info, m_nodeId, "ApplicationCommandHandler - Default acknowledgement of controller replication data" );
1873
1874 Msg* msg = new Msg( "Replication Command Complete", m_nodeId, REQUEST, FUNC_ID_ZW_REPLICATION_COMMAND_COMPLETE, false );
1875 GetDriver()->SendMsg( msg, Driver::MsgQueue_Command );
1876 }
1877 else
1878 {
1879 Log::Write( LogLevel_Info, m_nodeId, "ApplicationCommandHandler - Unhandled Command Class 0x%.2x", _data[5] );
1880 }
1881 }
1882 }
1883
1884 //-----------------------------------------------------------------------------
1885 // <Node::GetCommandClass>
1886 // Get the specified command class object if supported, otherwise NULL
1887 //-----------------------------------------------------------------------------
GetCommandClass(uint8 const _commandClassId) const1888 CommandClass* Node::GetCommandClass
1889 (
1890 uint8 const _commandClassId
1891 )const
1892 {
1893 map<uint8,CommandClass*>::const_iterator it = m_commandClassMap.find( _commandClassId );
1894 if( it != m_commandClassMap.end() )
1895 {
1896 return it->second;
1897 }
1898
1899 // Not found
1900 return NULL;
1901 }
1902
1903 //-----------------------------------------------------------------------------
1904 // <Node::AddCommandClass>
1905 // Add a command class to the node
1906 //-----------------------------------------------------------------------------
AddCommandClass(uint8 const _commandClassId)1907 CommandClass* Node::AddCommandClass
1908 (
1909 uint8 const _commandClassId
1910 )
1911 {
1912 if( GetCommandClass( _commandClassId ) )
1913 {
1914 // Class and instance have already been added
1915 return NULL;
1916 }
1917
1918 // Create the command class object and add it to our map
1919 if( CommandClass* pCommandClass = CommandClasses::CreateCommandClass( _commandClassId, m_homeId, m_nodeId ) )
1920 {
1921 m_commandClassMap[_commandClassId] = pCommandClass;
1922 return pCommandClass;
1923 }
1924 else
1925 {
1926 Log::Write( LogLevel_Info, m_nodeId, "AddCommandClass - Unsupported Command Class 0x%.2x", _commandClassId );
1927 }
1928
1929 return NULL;
1930 }
1931
1932 //-----------------------------------------------------------------------------
1933 // <Node::RemoveCommandClass>
1934 // Remove a command class from the node
1935 //-----------------------------------------------------------------------------
RemoveCommandClass(uint8 const _commandClassId)1936 void Node::RemoveCommandClass
1937 (
1938 uint8 const _commandClassId
1939 )
1940 {
1941 map<uint8,CommandClass*>::iterator it = m_commandClassMap.find( _commandClassId );
1942 if( it == m_commandClassMap.end() )
1943 {
1944 // Class is not found
1945 return;
1946 }
1947
1948 // Remove all the values associated with this class
1949 if( ValueStore* store = GetValueStore() )
1950 {
1951 store->RemoveCommandClassValues( _commandClassId );
1952 }
1953
1954 // Destroy the command class object and remove it from our map
1955 Log::Write( LogLevel_Info, m_nodeId, "RemoveCommandClass - Removed support for %s", it->second->GetCommandClassName().c_str() );
1956
1957 delete it->second;
1958 m_commandClassMap.erase( it );
1959 }
1960
1961 //-----------------------------------------------------------------------------
1962 // <Node::SetConfigParam>
1963 // Set a configuration parameter in a device
1964 //-----------------------------------------------------------------------------
SetConfigParam(uint8 const _param,int32 _value,uint8 const _size)1965 bool Node::SetConfigParam
1966 (
1967 uint8 const _param,
1968 int32 _value,
1969 uint8 const _size
1970 )
1971 {
1972 if( Configuration* cc = static_cast<Configuration*>( GetCommandClass( Configuration::StaticGetCommandClassId() ) ) )
1973 {
1974 // First try to find an existing value representing the parameter, and set that.
1975 if( Value* value = cc->GetValue( 1, _param ) )
1976 {
1977 switch( value->GetID().GetType() )
1978 {
1979 case ValueID::ValueType_Bool:
1980 {
1981 ValueBool* valueBool = static_cast<ValueBool*>( value );
1982 valueBool->Set( _value != 0 );
1983 break;
1984 }
1985 case ValueID::ValueType_Byte:
1986 {
1987 ValueByte* valueByte = static_cast<ValueByte*>( value );
1988 valueByte->Set( (uint8)_value );
1989 break;
1990 }
1991 case ValueID::ValueType_Short:
1992 {
1993 ValueShort* valueShort = static_cast<ValueShort*>( value );
1994 valueShort->Set( (uint16)_value );
1995 break;
1996 }
1997 case ValueID::ValueType_Int:
1998 {
1999 ValueInt* valueInt = static_cast<ValueInt*>( value );
2000 valueInt->Set( _value );
2001 break;
2002 }
2003 case ValueID::ValueType_List:
2004 {
2005 ValueList* valueList = static_cast<ValueList*>( value );
2006 valueList->SetByValue( _value );
2007 break;
2008 }
2009 default:
2010 {
2011 }
2012 }
2013
2014 return true;
2015 }
2016
2017 // Failed to find an existing value object representing this
2018 // configuration parameter, so we try using the default or
2019 // included size through the Configuration command class.
2020 cc->Set( _param, _value, _size );
2021 return true;
2022 }
2023
2024 return false;
2025 }
2026
2027 //-----------------------------------------------------------------------------
2028 // <Node::RequestConfigParam>
2029 // Request the value of a configuration parameter from the device
2030 //-----------------------------------------------------------------------------
RequestConfigParam(uint8 const _param)2031 void Node::RequestConfigParam
2032 (
2033 uint8 const _param
2034 )
2035 {
2036 if( Configuration* cc = static_cast<Configuration*>( GetCommandClass( Configuration::StaticGetCommandClassId() ) ) )
2037 {
2038 cc->RequestValue( 0, _param, 1, Driver::MsgQueue_Send );
2039 }
2040 }
2041
2042 //-----------------------------------------------------------------------------
2043 // <Node::RequestAllConfigParams>
2044 // Request the values of all known configuration parameters from the device
2045 //-----------------------------------------------------------------------------
RequestAllConfigParams(uint32 const _requestFlags)2046 bool Node::RequestAllConfigParams
2047 (
2048 uint32 const _requestFlags
2049 )
2050 {
2051 bool res = false;
2052 if( Configuration* cc = static_cast<Configuration*>( GetCommandClass( Configuration::StaticGetCommandClassId() ) ) )
2053 {
2054 // Go through all the values in the value store, and request all those which are in the Configuration command class
2055 for( ValueStore::Iterator it = m_values->Begin(); it != m_values->End(); ++it )
2056 {
2057 Value* value = it->second;
2058 if( value->GetID().GetCommandClassId() == Configuration::StaticGetCommandClassId() && !value->IsWriteOnly() )
2059 {
2060 /* put the ConfigParams Request into the MsgQueue_Query queue. This is so MsgQueue_Send doesn't get backlogged with a
2061 * lot of ConfigParams requests, and should help speed up any user generated messages being sent out (as the MsgQueue_Send has a higher
2062 * priority than MsgQueue_Query
2063 */
2064 res |= cc->RequestValue( _requestFlags, value->GetID().GetIndex(), 1, Driver::MsgQueue_Query );
2065 }
2066 }
2067 }
2068
2069 return res;
2070 }
2071
2072 //-----------------------------------------------------------------------------
2073 // <Node::RequestDynamicValues>
2074 // Request an update of all known dynamic values from the device
2075 //-----------------------------------------------------------------------------
RequestDynamicValues()2076 bool Node::RequestDynamicValues
2077 (
2078 )
2079 {
2080 bool res = false;
2081 for( map<uint8,CommandClass*>::const_iterator it = m_commandClassMap.begin(); it != m_commandClassMap.end(); ++it )
2082 {
2083 if( !it->second->IsAfterMark() )
2084 {
2085 res |= it->second->RequestStateForAllInstances( CommandClass::RequestFlag_Dynamic, Driver::MsgQueue_Send );
2086 }
2087 }
2088
2089 return res;
2090 }
2091
2092 //-----------------------------------------------------------------------------
2093 // <Node::SetLevel>
2094 // Helper method to set a device's basic level
2095 //-----------------------------------------------------------------------------
SetLevel(uint8 const _level)2096 void Node::SetLevel
2097 (
2098 uint8 const _level
2099 )
2100 {
2101 // Level is 0-99, with 0 = off and 99 = fully on. 255 = turn on at last level.
2102 uint8 adjustedLevel = _level;
2103 if( ( _level > 99 ) && ( _level < 255 ) )
2104 {
2105 adjustedLevel = 99;
2106 }
2107
2108 if( Basic* cc = static_cast<Basic*>( GetCommandClass( Basic::StaticGetCommandClassId() ) ) )
2109 {
2110 cc->Set( adjustedLevel );
2111 }
2112 }
2113
2114 //-----------------------------------------------------------------------------
2115 // <Node::SetNodeOn>
2116 // Helper method to set a device to be on
2117 //-----------------------------------------------------------------------------
SetNodeOn()2118 void Node::SetNodeOn
2119 (
2120 )
2121 {
2122 // Level is 0-99, with 0 = off and 99 = fully on. 255 = turn on at last level.
2123 if( Basic* cc = static_cast<Basic*>( GetCommandClass( Basic::StaticGetCommandClassId() ) ) )
2124 {
2125 cc->Set( 255 );
2126 }
2127 }
2128
2129 //-----------------------------------------------------------------------------
2130 // <Node::SetNodeOff>
2131 // Helper method to set a device to be off
2132 //-----------------------------------------------------------------------------
SetNodeOff()2133 void Node::SetNodeOff
2134 (
2135 )
2136 {
2137 // Level is 0-99, with 0 = off and 99 = fully on. 255 = turn on at last level.
2138 if( Basic* cc = static_cast<Basic*>( GetCommandClass( Basic::StaticGetCommandClassId() ) ) )
2139 {
2140 cc->Set( 0 );
2141 }
2142 }
2143
2144 //-----------------------------------------------------------------------------
2145 // <Node::CreateValueID>
2146 // Helper to create a ValueID
2147 //-----------------------------------------------------------------------------
CreateValueID(ValueID::ValueGenre const _genre,uint8 const _commandClassId,uint8 const _instance,uint8 const _valueIndex,ValueID::ValueType const _type)2148 ValueID Node::CreateValueID
2149 (
2150 ValueID::ValueGenre const _genre,
2151 uint8 const _commandClassId,
2152 uint8 const _instance,
2153 uint8 const _valueIndex,
2154 ValueID::ValueType const _type
2155 )
2156 {
2157 return ValueID( m_homeId, m_nodeId, _genre, _commandClassId, _instance, _valueIndex, _type );
2158 }
2159
2160 //-----------------------------------------------------------------------------
2161 // <Node::CreateValueBool>
2162 // Helper to create a new bool value and add it to the value store
2163 //-----------------------------------------------------------------------------
CreateValueBool(ValueID::ValueGenre const _genre,uint8 const _commandClassId,uint8 const _instance,uint8 const _valueIndex,string const & _label,string const & _units,bool const _readOnly,bool const _writeOnly,bool const _default,uint8 const _pollIntensity)2164 bool Node::CreateValueBool
2165 (
2166 ValueID::ValueGenre const _genre,
2167 uint8 const _commandClassId,
2168 uint8 const _instance,
2169 uint8 const _valueIndex,
2170 string const& _label,
2171 string const& _units,
2172 bool const _readOnly,
2173 bool const _writeOnly,
2174 bool const _default,
2175 uint8 const _pollIntensity
2176 )
2177 {
2178 ValueBool* value = new ValueBool( m_homeId, m_nodeId, _genre, _commandClassId, _instance, _valueIndex, _label, _units, _readOnly, _writeOnly, _default, _pollIntensity );
2179 ValueStore* store = GetValueStore();
2180 if( store->AddValue( value ) )
2181 {
2182 value->Release();
2183 return true;
2184 }
2185
2186 value->Release();
2187 return false;
2188 }
2189
2190 //-----------------------------------------------------------------------------
2191 // <Node::CreateValueButton>
2192 // Helper to create a new trigger value and add it to the value store
2193 //-----------------------------------------------------------------------------
CreateValueButton(ValueID::ValueGenre const _genre,uint8 const _commandClassId,uint8 const _instance,uint8 const _valueIndex,string const & _label,uint8 const _pollIntensity)2194 bool Node::CreateValueButton
2195 (
2196 ValueID::ValueGenre const _genre,
2197 uint8 const _commandClassId,
2198 uint8 const _instance,
2199 uint8 const _valueIndex,
2200 string const& _label,
2201 uint8 const _pollIntensity
2202 )
2203 {
2204 ValueButton* value = new ValueButton( m_homeId, m_nodeId, _genre, _commandClassId, _instance, _valueIndex, _label, _pollIntensity );
2205 ValueStore* store = GetValueStore();
2206 if( store->AddValue( value ) )
2207 {
2208 value->Release();
2209 return true;
2210 }
2211
2212 value->Release();
2213 return false;
2214 }
2215
2216 //-----------------------------------------------------------------------------
2217 // <Node::CreateValueByte>
2218 // Helper to create a new byte value and add it to the value store
2219 //-----------------------------------------------------------------------------
CreateValueByte(ValueID::ValueGenre const _genre,uint8 const _commandClassId,uint8 const _instance,uint8 const _valueIndex,string const & _label,string const & _units,bool const _readOnly,bool const _writeOnly,uint8 const _default,uint8 const _pollIntensity)2220 bool Node::CreateValueByte
2221 (
2222 ValueID::ValueGenre const _genre,
2223 uint8 const _commandClassId,
2224 uint8 const _instance,
2225 uint8 const _valueIndex,
2226 string const& _label,
2227 string const& _units,
2228 bool const _readOnly,
2229 bool const _writeOnly,
2230 uint8 const _default,
2231 uint8 const _pollIntensity
2232 )
2233 {
2234 ValueByte* value = new ValueByte( m_homeId, m_nodeId, _genre, _commandClassId, _instance, _valueIndex, _label, _units, _readOnly, _writeOnly, _default, _pollIntensity );
2235 ValueStore* store = GetValueStore();
2236 if( store->AddValue( value ) )
2237 {
2238 value->Release();
2239 return true;
2240 }
2241
2242 value->Release();
2243 return false;
2244 }
2245
2246 //-----------------------------------------------------------------------------
2247 // <Node::CreateValueDecimal>
2248 // Helper to create a new decimal value and add it to the value store
2249 //-----------------------------------------------------------------------------
CreateValueDecimal(ValueID::ValueGenre const _genre,uint8 const _commandClassId,uint8 const _instance,uint8 const _valueIndex,string const & _label,string const & _units,bool const _readOnly,bool const _writeOnly,string const & _default,uint8 const _pollIntensity)2250 bool Node::CreateValueDecimal
2251 (
2252 ValueID::ValueGenre const _genre,
2253 uint8 const _commandClassId,
2254 uint8 const _instance,
2255 uint8 const _valueIndex,
2256 string const& _label,
2257 string const& _units,
2258 bool const _readOnly,
2259 bool const _writeOnly,
2260 string const& _default,
2261 uint8 const _pollIntensity
2262 )
2263 {
2264 ValueDecimal* value = new ValueDecimal( m_homeId, m_nodeId, _genre, _commandClassId, _instance, _valueIndex, _label, _units, _readOnly, _writeOnly, _default, _pollIntensity );
2265 ValueStore* store = GetValueStore();
2266 if( store->AddValue( value ) )
2267 {
2268 value->Release();
2269 return true;
2270 }
2271
2272 value->Release();
2273 return false;
2274 }
2275
2276 //-----------------------------------------------------------------------------
2277 // <Node::CreateValueInt>
2278 // Helper to create a new int value and add it to the value store
2279 //-----------------------------------------------------------------------------
CreateValueInt(ValueID::ValueGenre const _genre,uint8 const _commandClassId,uint8 const _instance,uint8 const _valueIndex,string const & _label,string const & _units,bool const _readOnly,bool const _writeOnly,int32 const _default,uint8 const _pollIntensity)2280 bool Node::CreateValueInt
2281 (
2282 ValueID::ValueGenre const _genre,
2283 uint8 const _commandClassId,
2284 uint8 const _instance,
2285 uint8 const _valueIndex,
2286 string const& _label,
2287 string const& _units,
2288 bool const _readOnly,
2289 bool const _writeOnly,
2290 int32 const _default,
2291 uint8 const _pollIntensity
2292 )
2293 {
2294 ValueInt* value = new ValueInt( m_homeId, m_nodeId, _genre, _commandClassId, _instance, _valueIndex, _label, _units, _readOnly, _writeOnly, _default, _pollIntensity );
2295 ValueStore* store = GetValueStore();
2296 if( store->AddValue( value ) )
2297 {
2298 value->Release();
2299 return true;
2300 }
2301
2302 value->Release();
2303 return false;
2304 }
2305
2306 //-----------------------------------------------------------------------------
2307 // <Node::CreateValueList>
2308 // Helper to create a new list value and add it to the value store
2309 //-----------------------------------------------------------------------------
CreateValueList(ValueID::ValueGenre const _genre,uint8 const _commandClassId,uint8 const _instance,uint8 const _valueIndex,string const & _label,string const & _units,bool const _readOnly,bool const _writeOnly,uint8 const _size,vector<ValueList::Item> const & _items,int32 const _default,uint8 const _pollIntensity)2310 bool Node::CreateValueList
2311 (
2312 ValueID::ValueGenre const _genre,
2313 uint8 const _commandClassId,
2314 uint8 const _instance,
2315 uint8 const _valueIndex,
2316 string const& _label,
2317 string const& _units,
2318 bool const _readOnly,
2319 bool const _writeOnly,
2320 uint8 const _size,
2321 vector<ValueList::Item> const& _items,
2322 int32 const _default,
2323 uint8 const _pollIntensity
2324 )
2325 {
2326 ValueList* value = new ValueList( m_homeId, m_nodeId, _genre, _commandClassId, _instance, _valueIndex, _label, _units, _readOnly, _writeOnly, _items, _default, _pollIntensity, _size );
2327 ValueStore* store = GetValueStore();
2328 if( store->AddValue( value ) )
2329 {
2330 value->Release();
2331 return true;
2332 }
2333
2334 value->Release();
2335 return false;
2336 }
2337
2338 //-----------------------------------------------------------------------------
2339 // <Node::CreateValueRaw>
2340 // Helper to create a new raw value and add it to the value store
2341 //-----------------------------------------------------------------------------
CreateValueRaw(ValueID::ValueGenre const _genre,uint8 const _commandClassId,uint8 const _instance,uint8 const _valueIndex,string const & _label,string const & _units,bool const _readOnly,bool const _writeOnly,uint8 const * _default,uint8 const _length,uint8 const _pollIntensity)2342 bool Node::CreateValueRaw
2343 (
2344 ValueID::ValueGenre const _genre,
2345 uint8 const _commandClassId,
2346 uint8 const _instance,
2347 uint8 const _valueIndex,
2348 string const& _label,
2349 string const& _units,
2350 bool const _readOnly,
2351 bool const _writeOnly,
2352 uint8 const* _default,
2353 uint8 const _length,
2354 uint8 const _pollIntensity
2355 )
2356 {
2357 ValueRaw* value = new ValueRaw( m_homeId, m_nodeId, _genre, _commandClassId, _instance, _valueIndex, _label, _units, _readOnly, _writeOnly, _default, _length, _pollIntensity );
2358 ValueStore* store = GetValueStore();
2359 if( store->AddValue( value ) )
2360 {
2361 value->Release();
2362 return true;
2363 }
2364
2365 value->Release();
2366 return false;
2367 }
2368
2369 //-----------------------------------------------------------------------------
2370 // <Node::CreateValueSchedule>
2371 // Helper to create a new schedule value and add it to the value store
2372 //-----------------------------------------------------------------------------
CreateValueSchedule(ValueID::ValueGenre const _genre,uint8 const _commandClassId,uint8 const _instance,uint8 const _valueIndex,string const & _label,string const & _units,bool const _readOnly,bool const _writeOnly,uint8 const _pollIntensity)2373 bool Node::CreateValueSchedule
2374 (
2375 ValueID::ValueGenre const _genre,
2376 uint8 const _commandClassId,
2377 uint8 const _instance,
2378 uint8 const _valueIndex,
2379 string const& _label,
2380 string const& _units,
2381 bool const _readOnly,
2382 bool const _writeOnly,
2383 uint8 const _pollIntensity
2384 )
2385 {
2386 ValueSchedule* value = new ValueSchedule( m_homeId, m_nodeId, _genre, _commandClassId, _instance, _valueIndex, _label, _units, _readOnly, _writeOnly, _pollIntensity );
2387 ValueStore* store = GetValueStore();
2388 if( store->AddValue( value ) )
2389 {
2390 value->Release();
2391 return true;
2392 }
2393
2394 value->Release();
2395 return false;
2396 }
2397
2398 //-----------------------------------------------------------------------------
2399 // <Node::CreateValueShort>
2400 // Helper to create a new short value and add it to the value store
2401 //-----------------------------------------------------------------------------
CreateValueShort(ValueID::ValueGenre const _genre,uint8 const _commandClassId,uint8 const _instance,uint8 const _valueIndex,string const & _label,string const & _units,bool const _readOnly,bool const _writeOnly,int16 const _default,uint8 const _pollIntensity)2402 bool Node::CreateValueShort
2403 (
2404 ValueID::ValueGenre const _genre,
2405 uint8 const _commandClassId,
2406 uint8 const _instance,
2407 uint8 const _valueIndex,
2408 string const& _label,
2409 string const& _units,
2410 bool const _readOnly,
2411 bool const _writeOnly,
2412 int16 const _default,
2413 uint8 const _pollIntensity
2414 )
2415 {
2416 ValueShort* value = new ValueShort( m_homeId, m_nodeId, _genre, _commandClassId, _instance, _valueIndex, _label, _units, _readOnly, _writeOnly, _default, _pollIntensity );
2417 ValueStore* store = GetValueStore();
2418 if( store->AddValue( value ) )
2419 {
2420 value->Release();
2421 return true;
2422 }
2423
2424 value->Release();
2425 return false;
2426 }
2427
2428 //-----------------------------------------------------------------------------
2429 // <Node::CreateValueString>
2430 // Helper to create a new string value and add it to the value store
2431 //-----------------------------------------------------------------------------
CreateValueString(ValueID::ValueGenre const _genre,uint8 const _commandClassId,uint8 const _instance,uint8 const _valueIndex,string const & _label,string const & _units,bool const _readOnly,bool const _writeOnly,string const & _default,uint8 const _pollIntensity)2432 bool Node::CreateValueString
2433 (
2434 ValueID::ValueGenre const _genre,
2435 uint8 const _commandClassId,
2436 uint8 const _instance,
2437 uint8 const _valueIndex,
2438 string const& _label,
2439 string const& _units,
2440 bool const _readOnly,
2441 bool const _writeOnly,
2442 string const& _default,
2443 uint8 const _pollIntensity
2444 )
2445 {
2446 ValueString* value = new ValueString( m_homeId, m_nodeId, _genre, _commandClassId, _instance, _valueIndex, _label, _units, _readOnly, _writeOnly, _default, _pollIntensity );
2447 ValueStore* store = GetValueStore();
2448 if( store->AddValue( value ) )
2449 {
2450 value->Release();
2451 return true;
2452 }
2453
2454 value->Release();
2455 return false;
2456 }
2457
2458 //-----------------------------------------------------------------------------
2459 // <Node::RemoveValueList>
2460 // Helper to remove an existing list value from the value store
2461 //-----------------------------------------------------------------------------
RemoveValueList(ValueList * _value)2462 void Node::RemoveValueList
2463 (
2464 ValueList* _value
2465 )
2466 {
2467 ValueStore* store = GetValueStore();
2468 store->RemoveValue( _value->GetID().GetValueStoreKey() );
2469 }
2470
2471 //-----------------------------------------------------------------------------
2472 // <Node::CreateValueFromXML>
2473 // Get the value object with the specified ID
2474 //-----------------------------------------------------------------------------
CreateValueFromXML(uint8 const _commandClassId,TiXmlElement const * _valueElement)2475 bool Node::CreateValueFromXML
2476 (
2477 uint8 const _commandClassId,
2478 TiXmlElement const* _valueElement
2479 )
2480 {
2481 Value* value = NULL;
2482
2483 // Create the value
2484 ValueID::ValueType type = Value::GetTypeEnumFromName( _valueElement->Attribute( "type" ) );
2485
2486 switch( type )
2487 {
2488 case ValueID::ValueType_Bool: { value = new ValueBool(); break; }
2489 case ValueID::ValueType_Byte: { value = new ValueByte(); break; }
2490 case ValueID::ValueType_Decimal: { value = new ValueDecimal(); break; }
2491 case ValueID::ValueType_Int: { value = new ValueInt(); break; }
2492 case ValueID::ValueType_List: { value = new ValueList(); break; }
2493 case ValueID::ValueType_Schedule: { value = new ValueSchedule(); break; }
2494 case ValueID::ValueType_Short: { value = new ValueShort(); break; }
2495 case ValueID::ValueType_String: { value = new ValueString(); break; }
2496 case ValueID::ValueType_Button: { value = new ValueButton(); break; }
2497 case ValueID::ValueType_Raw: { value = new ValueRaw(); break; }
2498 default: { Log::Write( LogLevel_Info, m_nodeId, "Unknown ValueType in XML: %s", _valueElement->Attribute( "type" ) ); break; }
2499 }
2500
2501 if( value )
2502 {
2503 value->ReadXML( m_homeId, m_nodeId, _commandClassId, _valueElement );
2504
2505 ValueStore* store = GetValueStore();
2506 if( store->AddValue( value ) )
2507 {
2508 value->Release();
2509 return true;
2510 }
2511
2512 value->Release();
2513 }
2514
2515 return false;
2516 }
2517
2518 //-----------------------------------------------------------------------------
2519 // <Node::ReadValueFromXML>
2520 // Apply XML differences to a value
2521 //-----------------------------------------------------------------------------
ReadValueFromXML(uint8 const _commandClassId,TiXmlElement const * _valueElement)2522 void Node::ReadValueFromXML
2523 (
2524 uint8 const _commandClassId,
2525 TiXmlElement const* _valueElement
2526 )
2527 {
2528 int32 intVal;
2529
2530 ValueID::ValueGenre genre = Value::GetGenreEnumFromName( _valueElement->Attribute( "genre" ) );
2531 ValueID::ValueType type = Value::GetTypeEnumFromName( _valueElement->Attribute( "type" ) );
2532
2533 uint8 instance = 0;
2534 if( TIXML_SUCCESS == _valueElement->QueryIntAttribute( "instance", &intVal ) )
2535 {
2536 instance = (uint8)intVal;
2537 }
2538
2539 uint8 index = 0;
2540 if( TIXML_SUCCESS == _valueElement->QueryIntAttribute( "index", &intVal ) )
2541 {
2542 index = (uint8)intVal;
2543 }
2544
2545 ValueID id = ValueID( m_homeId, m_nodeId, genre, _commandClassId, instance, index, type );
2546
2547 // Try to get the value from the ValueStore (everything except configuration parameters
2548 // should already have been created when the command class instance count was read in).
2549 // Create it if it doesn't already exist.
2550 if( ValueStore* store = GetValueStore() )
2551 {
2552 if( Value* value = store->GetValue( id.GetValueStoreKey() ) )
2553 {
2554 value->ReadXML( m_homeId, m_nodeId, _commandClassId, _valueElement );
2555 value->Release();
2556 }
2557 else
2558 {
2559 CreateValueFromXML( _commandClassId, _valueElement );
2560 }
2561 }
2562 }
2563
2564 //-----------------------------------------------------------------------------
2565 // <Node::GetValue>
2566 // Get the value object with the specified ID
2567 //-----------------------------------------------------------------------------
GetValue(ValueID const & _id)2568 Value* Node::GetValue
2569 (
2570 ValueID const& _id
2571 )
2572 {
2573 // This increments the value's reference count
2574 return GetValueStore()->GetValue( _id.GetValueStoreKey() );
2575 }
2576
2577 //-----------------------------------------------------------------------------
2578 // <Node::GetValue>
2579 // Get the value object with the specified settings
2580 //-----------------------------------------------------------------------------
GetValue(uint8 const _commandClassId,uint8 const _instance,uint8 const _valueIndex)2581 Value* Node::GetValue
2582 (
2583 uint8 const _commandClassId,
2584 uint8 const _instance,
2585 uint8 const _valueIndex
2586 )
2587 {
2588 Value* value = NULL;
2589 ValueStore* store = GetValueStore();
2590 // This increments the value's reference count
2591 value = store->GetValue( ValueID::GetValueStoreKey( _commandClassId, _instance, _valueIndex ) );
2592 return value;
2593 }
2594
2595 //-----------------------------------------------------------------------------
2596 // <Node::RemoveValue>
2597 // Remove the value object with the specified settings
2598 //-----------------------------------------------------------------------------
RemoveValue(uint8 const _commandClassId,uint8 const _instance,uint8 const _valueIndex)2599 bool Node::RemoveValue
2600 (
2601 uint8 const _commandClassId,
2602 uint8 const _instance,
2603 uint8 const _valueIndex
2604 )
2605 {
2606 ValueStore* store = GetValueStore();
2607 return store->RemoveValue( ValueID::GetValueStoreKey( _commandClassId, _instance, _valueIndex ) );
2608 }
2609
2610 //-----------------------------------------------------------------------------
2611 // <Node::GetGroup>
2612 // Get a Group from the node's map
2613 //-----------------------------------------------------------------------------
GetGroup(uint8 const _groupIdx)2614 Group* Node::GetGroup
2615 (
2616 uint8 const _groupIdx
2617 )
2618 {
2619 map<uint8,Group*>::iterator it = m_groups.find( _groupIdx );
2620 if( it == m_groups.end() )
2621 {
2622 return NULL;
2623 }
2624
2625 return it->second;
2626 }
2627
2628 //-----------------------------------------------------------------------------
2629 // <Node::AddGroup>
2630 // Add a group into the node's map
2631 //-----------------------------------------------------------------------------
AddGroup(Group * _group)2632 void Node::AddGroup
2633 (
2634 Group* _group
2635 )
2636 {
2637 map<uint8,Group*>::iterator it = m_groups.find( _group->GetIdx() );
2638 if( it != m_groups.end() )
2639 {
2640 // There is already a group with this id. We will replace it.
2641 delete it->second;
2642 m_groups.erase( it );
2643 }
2644
2645 m_groups[_group->GetIdx()] = _group;
2646 }
2647
2648 //-----------------------------------------------------------------------------
2649 // <Node::WriteGroups>
2650 // Save the group data
2651 //-----------------------------------------------------------------------------
WriteGroups(TiXmlElement * _associationsElement)2652 void Node::WriteGroups
2653 (
2654 TiXmlElement* _associationsElement
2655 )
2656 {
2657 for( map<uint8,Group*>::iterator it = m_groups.begin(); it != m_groups.end(); ++it )
2658 {
2659 Group* group = it->second;
2660
2661 TiXmlElement* groupElement = new TiXmlElement( "Group" );
2662 _associationsElement->LinkEndChild( groupElement );
2663 group->WriteXML( groupElement );
2664 }
2665 }
2666
2667 //-----------------------------------------------------------------------------
2668 // <Node::GetNumGroups>
2669 // Gets the number of association groups reported by this node
2670 //-----------------------------------------------------------------------------
GetNumGroups()2671 uint8 Node::GetNumGroups
2672 (
2673 )
2674 {
2675 return (uint8) m_groups.size();
2676 }
2677
2678 //-----------------------------------------------------------------------------
2679 // <Node::GetAssociations>
2680 // Gets the associations for a group
2681 //-----------------------------------------------------------------------------
GetAssociations(uint8 const _groupIdx,uint8 ** o_associations)2682 uint32 Node::GetAssociations
2683 (
2684 uint8 const _groupIdx,
2685 uint8** o_associations
2686 )
2687 {
2688 uint32 numAssociations = 0;
2689 if( Group* group = GetGroup( _groupIdx ) )
2690 {
2691 numAssociations = group->GetAssociations( o_associations );
2692 }
2693
2694 return numAssociations;
2695 }
2696
2697 //-----------------------------------------------------------------------------
2698 // <Node::GetAssociations>
2699 // Gets the associations for a group
2700 //-----------------------------------------------------------------------------
GetAssociations(uint8 const _groupIdx,InstanceAssociation ** o_associations)2701 uint32 Node::GetAssociations
2702 (
2703 uint8 const _groupIdx,
2704 InstanceAssociation** o_associations
2705 )
2706 {
2707 uint32 numAssociations = 0;
2708 if( Group* group = GetGroup( _groupIdx ) )
2709 {
2710 numAssociations = group->GetAssociations( o_associations );
2711 }
2712
2713 return numAssociations;
2714 }
2715
2716 //-----------------------------------------------------------------------------
2717 // <Node::GetMaxAssociations>
2718 // Gets the maximum number of associations for a group
2719 //-----------------------------------------------------------------------------
GetMaxAssociations(uint8 const _groupIdx)2720 uint8 Node::GetMaxAssociations
2721 (
2722 uint8 const _groupIdx
2723 )
2724 {
2725 uint8 maxAssociations = 0;
2726 if( Group* group = GetGroup( _groupIdx ) )
2727 {
2728 maxAssociations = group->GetMaxAssociations();
2729 }
2730
2731 return maxAssociations;
2732 }
2733
2734 //-----------------------------------------------------------------------------
2735 // <Node::GetGroupLabel>
2736 // Gets the label for a particular group
2737 //-----------------------------------------------------------------------------
GetGroupLabel(uint8 const _groupIdx)2738 string Node::GetGroupLabel
2739 (
2740 uint8 const _groupIdx
2741 )
2742 {
2743 string label = "";
2744 if( Group* group = GetGroup( _groupIdx ) )
2745 {
2746 label = group->GetLabel();
2747 }
2748
2749 return label;
2750 }
2751
2752 //-----------------------------------------------------------------------------
2753 // <Node::AddAssociation>
2754 // Adds a node to an association group
2755 //-----------------------------------------------------------------------------
AddAssociation(uint8 const _groupIdx,uint8 const _targetNodeId,uint8 const _instance)2756 void Node::AddAssociation
2757 (
2758 uint8 const _groupIdx,
2759 uint8 const _targetNodeId,
2760 uint8 const _instance
2761 )
2762 {
2763 if( Group* group = GetGroup( _groupIdx ) )
2764 {
2765 group->AddAssociation( _targetNodeId, _instance );
2766 }
2767 }
2768
2769 //-----------------------------------------------------------------------------
2770 // <Node::RemoveAssociation>
2771 // Removes a node from an association group
2772 //-----------------------------------------------------------------------------
RemoveAssociation(uint8 const _groupIdx,uint8 const _targetNodeId,uint8 const _instance)2773 void Node::RemoveAssociation
2774 (
2775 uint8 const _groupIdx,
2776 uint8 const _targetNodeId,
2777 uint8 const _instance
2778 )
2779 {
2780 if( Group* group = GetGroup( _groupIdx ) )
2781 {
2782 group->RemoveAssociation( _targetNodeId, _instance );
2783 }
2784 }
2785
2786 //-----------------------------------------------------------------------------
2787 // <Node::AutoAssociate>
2788 // Automatically associate the controller with certain groups
2789 //-----------------------------------------------------------------------------
AutoAssociate()2790 void Node::AutoAssociate
2791 (
2792 )
2793 {
2794 bool autoAssociate = false;
2795 Options::Get()->GetOptionAsBool( "Associate", &autoAssociate );
2796 if( autoAssociate )
2797 {
2798 // Try to automatically associate with any groups that have been flagged.
2799 uint8 controllerNodeId = GetDriver()->GetControllerNodeId();
2800
2801 for( map<uint8,Group*>::iterator it = m_groups.begin(); it != m_groups.end(); ++it )
2802 {
2803 Group* group = it->second;
2804 if( group->IsAuto() && !group->Contains( controllerNodeId ) )
2805 {
2806 // Associate the controller into the group
2807 Log::Write( LogLevel_Info, m_nodeId, "Adding the controller to group %d (%s) of node %d", group->GetIdx(), group->GetLabel().c_str(), GetNodeId() );
2808 group->AddAssociation( controllerNodeId );
2809 }
2810 }
2811 }
2812 }
2813
2814 //-----------------------------------------------------------------------------
2815 // <Node::GetDriver>
2816 // Get a pointer to our driver
2817 //-----------------------------------------------------------------------------
GetDriver() const2818 Driver* Node::GetDriver
2819 (
2820 )const
2821 {
2822 return( Manager::Get()->GetDriver( m_homeId ) );
2823 }
2824
2825 //-----------------------------------------------------------------------------
2826 // Device Classes
2827 //-----------------------------------------------------------------------------
2828
2829 //-----------------------------------------------------------------------------
2830 // <Node::GetEndPointDeviceClassLabel>
2831 // Use the device class data to get a label for a MultiChannel EndPoint.
2832 //-----------------------------------------------------------------------------
GetEndPointDeviceClassLabel(uint8 const _generic,uint8 const _specific)2833 string Node::GetEndPointDeviceClassLabel
2834 (
2835 uint8 const _generic,
2836 uint8 const _specific
2837 )
2838 {
2839 char str[32];
2840 string label;
2841
2842 snprintf( str, sizeof(str), "Generic 0x%.2x Specific 0x%.2x", _generic, _specific );
2843 label = str;
2844
2845 // Read in the device class data if it has not been read already.
2846 if( !s_deviceClassesLoaded )
2847 {
2848 ReadDeviceClasses();
2849 }
2850
2851 // Get the Generic device class label
2852 map<uint8,GenericDeviceClass*>::iterator git = s_genericDeviceClasses.find( _generic );
2853 if( git != s_genericDeviceClasses.end() )
2854 {
2855 GenericDeviceClass* genericDeviceClass = git->second;
2856 label = genericDeviceClass->GetLabel();
2857
2858 // Override with any specific device class label
2859 if( DeviceClass* specificDeviceClass = genericDeviceClass->GetSpecificDeviceClass( _specific ) )
2860 {
2861 label = specificDeviceClass->GetLabel();
2862 }
2863 }
2864
2865 return label;
2866 }
2867
2868 //-----------------------------------------------------------------------------
2869 // <Node::SetDeviceClasses>
2870 // Set the device class data for the node
2871 //-----------------------------------------------------------------------------
SetDeviceClasses(uint8 const _basic,uint8 const _generic,uint8 const _specific)2872 bool Node::SetDeviceClasses
2873 (
2874 uint8 const _basic,
2875 uint8 const _generic,
2876 uint8 const _specific
2877 )
2878 {
2879 m_basic = _basic;
2880 m_generic = _generic;
2881 m_specific = _specific;
2882
2883 // Read in the device class data if it has not been read already.
2884 if( !s_deviceClassesLoaded )
2885 {
2886 ReadDeviceClasses();
2887 }
2888
2889 // Get the basic device class label
2890 map<uint8,string>::iterator bit = s_basicDeviceClasses.find( _basic );
2891 if( bit != s_basicDeviceClasses.end() )
2892 {
2893 m_type = bit->second;
2894 Log::Write( LogLevel_Info, m_nodeId, " Basic device class (0x%.2x) - %s", m_basic, m_type.c_str() );
2895 }
2896 else
2897 {
2898 Log::Write( LogLevel_Info, m_nodeId, " Basic device class unknown" );
2899 }
2900
2901 // Apply any Generic device class data
2902 uint8 basicMapping = 0;
2903 map<uint8,GenericDeviceClass*>::iterator git = s_genericDeviceClasses.find( _generic );
2904 if( git != s_genericDeviceClasses.end() )
2905 {
2906 GenericDeviceClass* genericDeviceClass = git->second;
2907 m_type = genericDeviceClass->GetLabel();
2908
2909 Log::Write( LogLevel_Info, m_nodeId, " Generic device Class (0x%.2x) - %s", m_generic, m_type.c_str() );
2910
2911 // Add the mandatory command classes for this generic class type
2912 AddMandatoryCommandClasses( genericDeviceClass->GetMandatoryCommandClasses() );
2913
2914 // Get the command class that COMMAND_CLASS_BASIC maps to.
2915 basicMapping = genericDeviceClass->GetBasicMapping();
2916
2917 // Apply any Specific device class data
2918 if( DeviceClass* specificDeviceClass = genericDeviceClass->GetSpecificDeviceClass( _specific ) )
2919 {
2920 m_type = specificDeviceClass->GetLabel();
2921
2922 Log::Write( LogLevel_Info, m_nodeId, " Specific device class (0x%.2x) - %s", m_specific, m_type.c_str() );
2923
2924 // Add the mandatory command classes for this specific class type
2925 AddMandatoryCommandClasses( specificDeviceClass->GetMandatoryCommandClasses() );
2926
2927 if( specificDeviceClass->GetBasicMapping() )
2928 {
2929 // Override the generic device class basic mapping with the specific device class one.
2930 basicMapping = specificDeviceClass->GetBasicMapping();
2931 }
2932 }
2933 else
2934 {
2935 Log::Write( LogLevel_Info, m_nodeId, " No specific device class defined" );
2936 }
2937 }
2938 else
2939 {
2940 Log::Write( LogLevel_Info, m_nodeId, " No generic or specific device classes defined" );
2941 }
2942
2943 // Deal with sleeping devices
2944 if( !m_listening && !IsFrequentListeningDevice())
2945 {
2946 // Device does not always listen, so we need the WakeUp handler. We can't
2947 // wait for the command class list because the request for the command
2948 // classes may need to go in the wakeup queue itself!
2949 if( CommandClass* pCommandClass = AddCommandClass( WakeUp::StaticGetCommandClassId() ) )
2950 {
2951 pCommandClass->SetInstance( 1 );
2952 }
2953 }
2954
2955 // Apply any COMMAND_CLASS_BASIC remapping
2956 if( Basic* cc = static_cast<Basic*>( GetCommandClass( Basic::StaticGetCommandClassId() ) ) )
2957 {
2958 cc->SetMapping( basicMapping );
2959 }
2960
2961 // Write the mandatory command classes to the log
2962 if( !m_commandClassMap.empty() )
2963 {
2964 map<uint8,CommandClass*>::const_iterator cit;
2965
2966 Log::Write( LogLevel_Info, m_nodeId, " Mandatory Command Classes for Node %d:", m_nodeId );
2967 bool reportedClasses = false;
2968 for( cit = m_commandClassMap.begin(); cit != m_commandClassMap.end(); ++cit )
2969 {
2970 if( !cit->second->IsAfterMark() && cit->second->GetCommandClassId() != NoOperation::StaticGetCommandClassId() )
2971 {
2972 Log::Write( LogLevel_Info, m_nodeId, " %s", cit->second->GetCommandClassName().c_str() );
2973 reportedClasses = true;
2974 }
2975 }
2976 if( !reportedClasses )
2977 {
2978 Log::Write( LogLevel_Info, m_nodeId, " None" );
2979 }
2980
2981 Log::Write( LogLevel_Info, m_nodeId, " Mandatory Command Classes controlled by Node %d:", m_nodeId );
2982 reportedClasses = false;
2983 for( cit = m_commandClassMap.begin(); cit != m_commandClassMap.end(); ++cit )
2984 {
2985 if( cit->second->IsAfterMark() )
2986 {
2987 Log::Write( LogLevel_Info, m_nodeId, " %s", cit->second->GetCommandClassName().c_str() );
2988 reportedClasses = true;
2989 }
2990 }
2991 if( !reportedClasses )
2992 {
2993 Log::Write( LogLevel_Info, m_nodeId, " None" );
2994 }
2995 }
2996
2997 return true;
2998 }
2999
3000 //-----------------------------------------------------------------------------
3001 // <Node::SetPlusDeviceClasses>
3002 // Set the device class data for the node based on the Zwave+ info report
3003 //-----------------------------------------------------------------------------
SetPlusDeviceClasses(uint8 const _role,uint8 const _nodeType,uint16 const _deviceType)3004 bool Node::SetPlusDeviceClasses
3005 (
3006 uint8 const _role,
3007 uint8 const _nodeType,
3008 uint16 const _deviceType
3009 )
3010 {
3011 if ( m_nodePlusInfoReceived )
3012 {
3013 return false; // already set
3014 }
3015
3016 if( !s_deviceClassesLoaded )
3017 {
3018 ReadDeviceClasses();
3019 }
3020
3021 m_nodePlusInfoReceived = true;
3022 m_role = _role;
3023 m_deviceType = _deviceType;
3024 m_nodeType = _nodeType;
3025
3026 Log::Write (LogLevel_Info, m_nodeId, "ZWave+ Info Received from Node %d", m_nodeId);
3027 map<uint8,DeviceClass*>::iterator nit = s_nodeTypes.find( m_nodeType );
3028 if (nit != s_nodeTypes.end())
3029 {
3030 DeviceClass* deviceClass = nit->second;
3031
3032 Log::Write( LogLevel_Info, m_nodeId, " Zwave+ Node Type (0x%.2x) - %s. Mandatory Command Classes:", m_nodeType, deviceClass->GetLabel().c_str() );
3033 uint8 const *_commandClasses = deviceClass->GetMandatoryCommandClasses();
3034
3035 /* no CommandClasses to add */
3036 if (_commandClasses != NULL)
3037 {
3038 int i = 0;
3039 while (uint8 ccid = _commandClasses[i++])
3040 {
3041 if( CommandClasses::IsSupported( ccid ) )
3042 {
3043 Log::Write( LogLevel_Info, m_nodeId, " %s", CommandClasses::GetName(ccid).c_str());
3044 }
3045 else
3046 {
3047 Log::Write( LogLevel_Info, m_nodeId, " 0x%.2x (Not Supported)", ccid);
3048 }
3049 }
3050
3051
3052 // Add the mandatory command classes for this Roletype
3053 AddMandatoryCommandClasses( deviceClass->GetMandatoryCommandClasses() );
3054 }
3055 else
3056 {
3057 Log::Write( LogLevel_Info, m_nodeId, " NONE");
3058 }
3059 }
3060 else
3061 {
3062 Log::Write (LogLevel_Warning, m_nodeId, " Zwave+ Node Type (0x%.2x) - NOT FOUND. No Mandatory Command Classes Loaded:", m_nodeType);
3063 }
3064
3065
3066 // Apply any Zwave+ device class data
3067 map<uint16,DeviceClass*>::iterator dit = s_deviceTypeClasses.find( _deviceType );
3068 if( dit != s_deviceTypeClasses.end() )
3069 {
3070 DeviceClass* deviceClass = dit->second;
3071 // m_type = deviceClass->GetLabel(); // do we what to update the type with the zwave+ info??
3072
3073 Log::Write( LogLevel_Info, m_nodeId, " Zwave+ Device Type (0x%.2x) - %s. Mandatory Command Classes:", _deviceType, deviceClass->GetLabel().c_str() );
3074 uint8 const *_commandClasses = deviceClass->GetMandatoryCommandClasses();
3075
3076 /* no CommandClasses to add */
3077 if (_commandClasses != NULL)
3078 {
3079 int i = 0;
3080 while (uint8 ccid = _commandClasses[i++])
3081 {
3082 if( CommandClasses::IsSupported( ccid ) )
3083 {
3084 Log::Write( LogLevel_Info, m_nodeId, " %s", CommandClasses::GetName(ccid).c_str());
3085 }
3086 else
3087 {
3088 Log::Write( LogLevel_Info, m_nodeId, " 0x%.2x (Not Supported)", ccid);
3089 }
3090 }
3091
3092
3093 // Add the mandatory command classes for this device class type
3094 AddMandatoryCommandClasses( deviceClass->GetMandatoryCommandClasses() );
3095 }
3096 else
3097 {
3098 Log::Write( LogLevel_Info, m_nodeId, " NONE");
3099 }
3100 }
3101 else
3102 {
3103 Log::Write (LogLevel_Warning, m_nodeId, " Zwave+ Device Type (0x%.2x) - NOT FOUND. No Mandatory Command Classes Loaded:", m_nodeType);
3104 }
3105
3106 // Apply any Role device class data
3107 map<uint8,DeviceClass*>::iterator rit = s_roleDeviceClasses.find( _role );
3108 if( rit != s_roleDeviceClasses.end() )
3109 {
3110 DeviceClass* roleDeviceClass = rit->second;
3111
3112 Log::Write( LogLevel_Info, m_nodeId, " ZWave+ Role Type (0x%.2x) - %s", m_generic, roleDeviceClass->GetLabel().c_str() );
3113
3114 uint8 const *_commandClasses = roleDeviceClass->GetMandatoryCommandClasses();
3115
3116 /* no CommandClasses to add */
3117 if (_commandClasses != NULL)
3118 {
3119 int i = 0;
3120 while (uint8 ccid = _commandClasses[i++])
3121 {
3122 if( CommandClasses::IsSupported( ccid ) )
3123 {
3124 Log::Write( LogLevel_Info, m_nodeId, " %s", CommandClasses::GetName(ccid).c_str());
3125 }
3126 else
3127 {
3128 Log::Write( LogLevel_Info, m_nodeId, " 0x%.2x (Not Supported)", ccid);
3129 }
3130 }
3131
3132
3133 // Add the mandatory command classes for this role class type
3134 AddMandatoryCommandClasses( roleDeviceClass->GetMandatoryCommandClasses() );
3135 }
3136 else
3137 {
3138 Log::Write( LogLevel_Info, m_nodeId, " NONE");
3139 }
3140
3141 }
3142 else
3143 {
3144 Log::Write (LogLevel_Warning, m_nodeId, " ZWave+ Role Type (0x%.2x) - NOT FOUND. No Mandatory Command Classes Loaded:", m_nodeType);
3145 }
3146
3147
3148 return true;
3149 }
3150
3151 //-----------------------------------------------------------------------------
3152 // <Node::AddMandatoryCommandClasses>
3153 // Add mandatory command classes to the node
3154 //-----------------------------------------------------------------------------
AddMandatoryCommandClasses(uint8 const * _commandClasses)3155 bool Node::AddMandatoryCommandClasses
3156 (
3157 uint8 const* _commandClasses
3158 )
3159 {
3160 if( NULL == _commandClasses )
3161 {
3162 // No command classes to add
3163 return false;
3164 }
3165
3166 int i=0;
3167 bool afterMark = false;
3168 while( uint8 cc = _commandClasses[i++] )
3169 {
3170 if( cc == 0xef )
3171 {
3172 // COMMAND_CLASS_MARK.
3173 // Marks the end of the list of supported command classes. The remaining classes
3174 // are those that can be controlled by this device, which we can ignore.
3175 afterMark = true;
3176 continue;
3177 }
3178
3179 if( CommandClasses::IsSupported( cc ) )
3180 {
3181 if (Security::StaticGetCommandClassId() == cc && !GetDriver()->isNetworkKeySet()) {
3182 Log::Write(LogLevel_Warning, m_nodeId, "Security Command Class Cannot be Enabled - NetworkKey is not set");
3183 continue;
3184 }
3185
3186 if( CommandClass* commandClass = AddCommandClass( cc ) )
3187 {
3188 // If this class came after the COMMAND_CLASS_MARK, then we do not create values.
3189 if( afterMark )
3190 {
3191 commandClass->SetAfterMark();
3192 }
3193
3194 // Start with an instance count of one. If the device supports COMMMAND_CLASS_MULTI_INSTANCE
3195 // then some command class instance counts will increase.
3196 commandClass->SetInstance( 1 );
3197 }
3198 }
3199 }
3200
3201 return true;
3202 }
3203
3204 //-----------------------------------------------------------------------------
3205 // <Node::ReadDeviceClasses>
3206 // Read the static device class data from the device_classes.xml file
3207 //-----------------------------------------------------------------------------
ReadDeviceClasses()3208 void Node::ReadDeviceClasses
3209 (
3210 )
3211 {
3212 // Load the XML document that contains the device class information
3213 string configPath;
3214 Options::Get()->GetOptionAsString( "ConfigPath", &configPath );
3215
3216 string filename = configPath + string("device_classes.xml");
3217
3218 TiXmlDocument doc;
3219 if( !doc.LoadFile( filename.c_str(), TIXML_ENCODING_UTF8 ) )
3220 {
3221 Log::Write( LogLevel_Info, "Failed to load device_classes.xml" );
3222 Log::Write( LogLevel_Info, "Check that the config path provided when creating the Manager points to the correct location." );
3223 return;
3224 }
3225
3226 TiXmlElement const* deviceClassesElement = doc.RootElement();
3227
3228 // Read the basic and generic device classes
3229 TiXmlElement const* child = deviceClassesElement->FirstChildElement();
3230 while( child )
3231 {
3232 char const* str = child->Value();
3233 if( str )
3234 {
3235 char const* keyStr = child->Attribute( "key" );
3236 if( keyStr )
3237 {
3238 char* pStop;
3239 uint16 key = (uint16)strtol( keyStr, &pStop, 16 );
3240
3241 if( !strcmp( str, "Generic" ) )
3242 {
3243 s_genericDeviceClasses[key] = new GenericDeviceClass( child );
3244 }
3245 else if( !strcmp( str, "Basic" ) )
3246 {
3247 char const* label = child->Attribute( "label" );
3248 if( label )
3249 {
3250 s_basicDeviceClasses[key] = label;
3251 }
3252 }
3253 else if( !strcmp( str, "Role" ) )
3254 {
3255 s_roleDeviceClasses[key] = new DeviceClass( child );
3256 }
3257 else if( !strcmp( str, "DeviceType" ) )
3258 {
3259 s_deviceTypeClasses[key] = new DeviceClass( child );
3260 }
3261 else if (!strcmp( str, "NodeType" ) )
3262 {
3263 s_nodeTypes[key] = new DeviceClass( child );
3264 }
3265 }
3266 }
3267
3268 child = child->NextSiblingElement();
3269 }
3270
3271 s_deviceClassesLoaded = true;
3272 }
3273
3274 //-----------------------------------------------------------------------------
3275 // <Node::GetNoderStatistics>
3276 // Return driver statistics
3277 //-----------------------------------------------------------------------------
GetNodeStatistics(NodeData * _data)3278 void Node::GetNodeStatistics
3279 (
3280 NodeData* _data
3281 )
3282 {
3283 _data->m_sentCnt = m_sentCnt;
3284 _data->m_sentFailed = m_sentFailed;
3285 _data->m_retries = m_retries;
3286 _data->m_receivedCnt = m_receivedCnt;
3287 _data->m_receivedDups = m_receivedDups;
3288 _data->m_receivedUnsolicited = m_receivedUnsolicited;
3289 _data->m_lastRequestRTT = m_lastRequestRTT;
3290 _data->m_lastResponseRTT = m_lastResponseRTT;
3291 _data->m_sentTS = m_sentTS.GetAsString();
3292 _data->m_receivedTS = m_receivedTS.GetAsString();
3293 _data->m_averageRequestRTT = m_averageRequestRTT;
3294 _data->m_averageResponseRTT = m_averageResponseRTT;
3295 _data->m_quality = m_quality;
3296 memcpy( _data->m_lastReceivedMessage, m_lastReceivedMessage, sizeof(m_lastReceivedMessage) );
3297 for( map<uint8,CommandClass*>::const_iterator it = m_commandClassMap.begin(); it != m_commandClassMap.end(); ++it )
3298 {
3299 CommandClassData ccData;
3300 ccData.m_commandClassId = it->second->GetCommandClassId();
3301 ccData.m_sentCnt = it->second->GetSentCnt();
3302 ccData.m_receivedCnt = it->second->GetReceivedCnt();
3303 _data->m_ccData.push_back( ccData );
3304 }
3305 }
3306
3307 //-----------------------------------------------------------------------------
3308 // <DeviceClass::DeviceClass>
3309 // Constructor
3310 //-----------------------------------------------------------------------------
DeviceClass(TiXmlElement const * _el)3311 Node::DeviceClass::DeviceClass
3312 (
3313 TiXmlElement const* _el
3314 ):
3315 m_mandatoryCommandClasses(NULL),
3316 m_basicMapping(0)
3317 {
3318 char const* str = _el->Attribute( "label" );
3319 if( str )
3320 {
3321 m_label = str;
3322 }
3323
3324 str = _el->Attribute( "command_classes" );
3325 if( str )
3326 {
3327 // Parse the comma delimted command class
3328 // list into a temporary vector.
3329 vector<uint8> ccs;
3330 char* pos = const_cast<char*>(str);
3331 while( *pos )
3332 {
3333 ccs.push_back( (uint8)strtol( pos, &pos, 16 ) );
3334 if( (*pos) == ',' )
3335 {
3336 ++pos;
3337 }
3338 }
3339
3340 // Copy the vector contents into an array.
3341 size_t numCCs = ccs.size();
3342 m_mandatoryCommandClasses = new uint8[numCCs+1];
3343 m_mandatoryCommandClasses[numCCs] = 0; // Zero terminator
3344
3345 for( uint32 i=0; i<numCCs; ++i )
3346 {
3347 m_mandatoryCommandClasses[i] = ccs[i];
3348 }
3349 }
3350
3351 str = _el->Attribute( "basic" );
3352 if( str )
3353 {
3354 char* pStop;
3355 m_basicMapping = (uint8)strtol( str, &pStop, 16 );
3356 }
3357 }
3358
3359 //-----------------------------------------------------------------------------
3360 // <Node::GenericDeviceClass::GenericDeviceClass>
3361 // Constructor
3362 //-----------------------------------------------------------------------------
GenericDeviceClass(TiXmlElement const * _el)3363 Node::GenericDeviceClass::GenericDeviceClass
3364 (
3365 TiXmlElement const* _el
3366 ):
3367 DeviceClass( _el )
3368 {
3369 // Add any specific device classes
3370 TiXmlElement const* child = _el->FirstChildElement();
3371 while( child )
3372 {
3373 char const* str = child->Value();
3374 if( str && !strcmp( str, "Specific" ) )
3375 {
3376 char const* keyStr = child->Attribute( "key" );
3377 if( keyStr )
3378 {
3379 char* pStop;
3380 uint8 key = (uint8)strtol( keyStr, &pStop, 16 );
3381
3382 m_specificDeviceClasses[key] = new DeviceClass( child );
3383 }
3384 }
3385
3386 child = child->NextSiblingElement();
3387 }
3388 }
3389
3390 //-----------------------------------------------------------------------------
3391 // <Node::GenericDeviceClass::~GenericDeviceClass>
3392 // Destructor
3393 //-----------------------------------------------------------------------------
~GenericDeviceClass()3394 Node::GenericDeviceClass::~GenericDeviceClass
3395 (
3396 )
3397 {
3398 while( !m_specificDeviceClasses.empty() )
3399 {
3400 map<uint8,DeviceClass*>::iterator it = m_specificDeviceClasses.begin();
3401 delete it->second;
3402 m_specificDeviceClasses.erase( it );
3403 }
3404 }
3405
3406 //-----------------------------------------------------------------------------
3407 // <Node::GenericDeviceClass::GetSpecificDeviceClass>
3408 // Get a specific device class object
3409 //-----------------------------------------------------------------------------
GetSpecificDeviceClass(uint8 const & _specific)3410 Node::DeviceClass* Node::GenericDeviceClass::GetSpecificDeviceClass
3411 (
3412 uint8 const& _specific
3413 )
3414 {
3415 map<uint8,DeviceClass*>::iterator it = m_specificDeviceClasses.find( _specific );
3416 if( it != m_specificDeviceClasses.end() )
3417 {
3418 return it->second;
3419 }
3420
3421 return NULL;
3422 }
3423
3424 //-----------------------------------------------------------------------------
3425 // <Node::GenerateNonceKey>
3426 // Generate a NONCE key for this node
3427 //-----------------------------------------------------------------------------
GenerateNonceKey()3428 uint8 *Node::GenerateNonceKey() {
3429 uint8 idx = this->m_lastnonce;
3430
3431 /* The first byte must be unique and non-zero. The others are random.
3432 Per Numerical Recipes in C its best to use the high-order byte. The
3433 floating point calculation here doesn't assume the size of the random
3434 integer, otherwise we could just shift the high byte over.
3435 */
3436 uint8 match = 0;
3437 do {
3438 this->m_nonces[idx][0] = 1 + (uint8) (255.0 * rand() / (RAND_MAX + 1.0));
3439 match = 0;
3440 for (int i = 0; i < 8; i++) {
3441 if (i == idx) {
3442 continue;
3443 }
3444 if (this->m_nonces[idx][0] == this->m_nonces[i][0]) {
3445 match = 1;
3446 }
3447 }
3448 } while (match);
3449
3450 /* The other bytes have no restrictions. */
3451 for (int i = 1; i < 8; i++) {
3452 this->m_nonces[idx][i] = (int) (256.0 * rand() / (RAND_MAX + 1.0));
3453 }
3454
3455 this->m_lastnonce++;
3456 if (this->m_lastnonce >= 8)
3457 this->m_lastnonce = 0;
3458 for (uint8 i = 0; i < 8; i++) {
3459 PrintHex("NONCES", (const uint8_t*)this->m_nonces[i], 8);
3460 }
3461 return &this->m_nonces[idx][0];
3462 }
3463 //-----------------------------------------------------------------------------
3464 // <Node::GetNonceKey>
3465 // Get a NONCE key for this node that matches the nonceid.
3466 //-----------------------------------------------------------------------------
3467
GetNonceKey(uint32 nonceid)3468 uint8 *Node::GetNonceKey(uint32 nonceid) {
3469 for (uint8 i = 0; i < 8; i++) {
3470 /* make sure the nonceid matches the first byte of our stored Nonce */
3471 if (nonceid == this->m_nonces[i][0]) {
3472 return &this->m_nonces[i][0];
3473 }
3474 }
3475 Log::Write(LogLevel_Warning, m_nodeId, "A Nonce with id %x does not exist", nonceid);
3476 for (uint8 i = 0; i < 8; i++) {
3477 PrintHex("NONCES", (const uint8_t*)this->m_nonces[i], 8);
3478 }
3479 return NULL;
3480 }
3481
3482 //-----------------------------------------------------------------------------
3483 // <Node::GetDeviceTypeString>
3484 // Get the ZWave+ DeviceType as a String
3485 //-----------------------------------------------------------------------------
GetDeviceTypeString()3486 string Node::GetDeviceTypeString() {
3487
3488 if( !s_deviceClassesLoaded )
3489 {
3490 ReadDeviceClasses();
3491 }
3492 map<uint16,DeviceClass*>::iterator nit = s_deviceTypeClasses.find( m_deviceType );
3493 if (nit != s_deviceTypeClasses.end())
3494 {
3495 DeviceClass* deviceClass = nit->second;
3496 return deviceClass->GetLabel();
3497 }
3498 return "";
3499 }
3500 //-----------------------------------------------------------------------------
3501 // <Node::GetRoleTypeString>
3502 // Get the ZWave+ RoleType as a String
3503 //-----------------------------------------------------------------------------
GetRoleTypeString()3504 string Node::GetRoleTypeString() {
3505 if( !s_deviceClassesLoaded )
3506 {
3507 ReadDeviceClasses();
3508 }
3509 map<uint8,DeviceClass*>::iterator nit = s_roleDeviceClasses.find( m_role );
3510 if (nit != s_roleDeviceClasses.end())
3511 {
3512 DeviceClass* deviceClass = nit->second;
3513 return deviceClass->GetLabel();
3514 }
3515 return "";
3516 }
3517 //-----------------------------------------------------------------------------
3518 // <Node::GetRoleTypeString>
3519 // Get the ZWave+ NodeType as a String
3520 //-----------------------------------------------------------------------------
GetNodeTypeString()3521 string Node::GetNodeTypeString() {
3522 if( !s_deviceClassesLoaded )
3523 {
3524 ReadDeviceClasses();
3525 }
3526 map<uint8,DeviceClass*>::iterator nit = s_nodeTypes.find( m_nodeType );
3527 if (nit != s_nodeTypes.end())
3528 {
3529 DeviceClass* deviceClass = nit->second;
3530 return deviceClass->GetLabel();
3531 }
3532 return "";
3533 }
3534
3535 //-----------------------------------------------------------------------------
3536 // <Node::GetRoleTypeString>
3537 // Get the ZWave+ NodeType as a String
3538 //-----------------------------------------------------------------------------
IsNodeReset()3539 bool Node::IsNodeReset()
3540 {
3541 DeviceResetLocally *drl = static_cast<DeviceResetLocally *>(GetCommandClass(DeviceResetLocally::StaticGetCommandClassId()));
3542 if (drl)
3543 return drl->IsDeviceReset();
3544 else return false;
3545
3546
3547 }
3548