1 //-----------------------------------------------------------------------------
2 //
3 // Version.cpp
4 //
5 // Implementation of the Z-Wave COMMAND_CLASS_VERSION
6 //
7 // Copyright (c) 2010 Mal Lansell <openzwave@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
15 // by the Free Software Foundation, either version 3 of the License,
16 // or (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 "command_classes/CommandClasses.h"
29 #include "command_classes/Version.h"
30 #include "Defs.h"
31 #include "Msg.h"
32 #include "Driver.h"
33 #include "Node.h"
34 #include "platform/Log.h"
35
36 #include "value_classes/ValueString.h"
37
38 #include "tinyxml.h"
39
40 using namespace OpenZWave;
41
42 enum VersionCmd
43 {
44 VersionCmd_Get = 0x11,
45 VersionCmd_Report = 0x12,
46 VersionCmd_CommandClassGet = 0x13,
47 VersionCmd_CommandClassReport = 0x14
48 };
49
50 enum
51 {
52 VersionIndex_Library = 0,
53 VersionIndex_Protocol,
54 VersionIndex_Application
55 };
56
57 //-----------------------------------------------------------------------------
58 // <Version::Version>
59 // Constructor
60 //-----------------------------------------------------------------------------
Version(uint32 const _homeId,uint8 const _nodeId)61 Version::Version
62 (
63 uint32 const _homeId,
64 uint8 const _nodeId
65 ):
66 CommandClass( _homeId, _nodeId ),
67 m_classGetSupported( true )
68 {
69 SetStaticRequest( StaticRequest_Values );
70 }
71
72 //-----------------------------------------------------------------------------
73 // <Version::ReadXML>
74 // Read configuration.
75 //-----------------------------------------------------------------------------
ReadXML(TiXmlElement const * _ccElement)76 void Version::ReadXML
77 (
78 TiXmlElement const* _ccElement
79 )
80 {
81 CommandClass::ReadXML( _ccElement );
82
83 char const* str = _ccElement->Attribute("classgetsupported");
84 if( str )
85 {
86 m_classGetSupported = !strcmp( str, "true");
87 }
88 }
89
90 //-----------------------------------------------------------------------------
91 // <Version::WriteXML>
92 // Save changed configuration
93 //-----------------------------------------------------------------------------
WriteXML(TiXmlElement * _ccElement)94 void Version::WriteXML
95 (
96 TiXmlElement* _ccElement
97 )
98 {
99 CommandClass::WriteXML( _ccElement );
100
101 if( !m_classGetSupported )
102 {
103 _ccElement->SetAttribute( "classgetsupported", "false" );
104 }
105 }
106
107 //-----------------------------------------------------------------------------
108 // <Version::RequestState>
109 // Request current state from the device
110 //-----------------------------------------------------------------------------
RequestState(uint32 const _requestFlags,uint8 const _instance,Driver::MsgQueue const _queue)111 bool Version::RequestState
112 (
113 uint32 const _requestFlags,
114 uint8 const _instance,
115 Driver::MsgQueue const _queue
116 )
117 {
118 if( ( _requestFlags & RequestFlag_Static ) && HasStaticRequest( StaticRequest_Values ) )
119 {
120 return RequestValue( _requestFlags, 0, _instance, _queue );
121 }
122
123 return false;
124 }
125
126 //-----------------------------------------------------------------------------
127 // <Version::RequestValue>
128 // Request current value from the device
129 //-----------------------------------------------------------------------------
RequestValue(uint32 const _requestFlags,uint8 const _dummy1,uint8 const _instance,Driver::MsgQueue const _queue)130 bool Version::RequestValue
131 (
132 uint32 const _requestFlags,
133 uint8 const _dummy1, // = 0
134 uint8 const _instance,
135 Driver::MsgQueue const _queue
136 )
137 {
138 if( _instance != 1 )
139 {
140 // This command class doesn't work with multiple instances
141 return false;
142 }
143 if ( IsGetSupported() )
144 {
145 Msg* msg = new Msg( "VersionCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
146 msg->Append( GetNodeId() );
147 msg->Append( 2 );
148 msg->Append( GetCommandClassId() );
149 msg->Append( VersionCmd_Get );
150 msg->Append( GetDriver()->GetTransmitOptions() );
151 GetDriver()->SendMsg( msg, _queue );
152 return true;
153 } else {
154 Log::Write( LogLevel_Info, GetNodeId(), "VersionCmd_Get Not Supported on this node");
155 }
156 return false;
157 }
158
159 //-----------------------------------------------------------------------------
160 // <Version::HandleMsg>
161 // Handle a message from the Z-Wave network
162 //-----------------------------------------------------------------------------
HandleMsg(uint8 const * _data,uint32 const _length,uint32 const _instance)163 bool Version::HandleMsg
164 (
165 uint8 const* _data,
166 uint32 const _length,
167 uint32 const _instance // = 1
168 )
169 {
170 if( Node* node = GetNodeUnsafe() )
171 {
172 if( VersionCmd_Report == (VersionCmd)_data[0] )
173 {
174 char library[8];
175 char protocol[16];
176 char application[16];
177
178 snprintf( library, sizeof(library), "%d", _data[1] );
179 snprintf( protocol, sizeof(protocol), "%d.%.2d", _data[2], _data[3] );
180 snprintf( application, sizeof(application), "%d.%.2d", _data[4], _data[5] );
181
182 Log::Write( LogLevel_Info, GetNodeId(), "Received Version report from node %d: Library=%s, Protocol=%s, Application=%s", GetNodeId(), library, protocol, application );
183 ClearStaticRequest( StaticRequest_Values );
184
185 if( ValueString* libraryValue = static_cast<ValueString*>( GetValue( _instance, VersionIndex_Library ) ) )
186 {
187 libraryValue->OnValueRefreshed( library );
188 libraryValue->Release();
189 }
190 if( ValueString* protocolValue = static_cast<ValueString*>( GetValue( _instance, VersionIndex_Protocol ) ) )
191 {
192 protocolValue->OnValueRefreshed( protocol );
193 protocolValue->Release();
194 }
195 if( ValueString* applicationValue = static_cast<ValueString*>( GetValue( _instance, VersionIndex_Application ) ) )
196 {
197 applicationValue->OnValueRefreshed( application );
198 applicationValue->Release();
199 }
200
201 return true;
202 }
203
204 if (VersionCmd_CommandClassReport == (VersionCmd)_data[0])
205 {
206 if( CommandClass* pCommandClass = node->GetCommandClass( _data[1] ) )
207 {
208 Log::Write( LogLevel_Info, GetNodeId(), "Received Command Class Version report from node %d: CommandClass=%s, Version=%d", GetNodeId(), pCommandClass->GetCommandClassName().c_str(), _data[2] );
209 pCommandClass->ClearStaticRequest( StaticRequest_Version );
210 pCommandClass->SetVersion( _data[2] );
211 }
212
213 return true;
214 }
215 }
216
217 return false;
218 }
219
220 //-----------------------------------------------------------------------------
221 // <Version::RequestCommandClassVersion>
222 // Request the version of a command class used by the device
223 //-----------------------------------------------------------------------------
RequestCommandClassVersion(CommandClass const * _commandClass)224 bool Version::RequestCommandClassVersion
225 (
226 CommandClass const* _commandClass
227 )
228 {
229 if( m_classGetSupported )
230 {
231 if( _commandClass->HasStaticRequest( StaticRequest_Version ) )
232 {
233 Msg* msg = new Msg( "VersionCmd_CommandClassGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
234 msg->Append( GetNodeId() );
235 msg->Append( 3 );
236 msg->Append( GetCommandClassId() );
237 msg->Append( VersionCmd_CommandClassGet );
238 msg->Append( _commandClass->GetCommandClassId() );
239 msg->Append( GetDriver()->GetTransmitOptions() );
240 GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
241 return true;
242 }
243 }
244
245 return false;
246 }
247
248 //-----------------------------------------------------------------------------
249 // <Version::CreateVars>
250 // Create the values managed by this command class
251 //-----------------------------------------------------------------------------
CreateVars(uint8 const _instance)252 void Version::CreateVars
253 (
254 uint8 const _instance
255 )
256 {
257 if( Node* node = GetNodeUnsafe() )
258 {
259 node->CreateValueString( ValueID::ValueGenre_System, GetCommandClassId(), _instance, VersionIndex_Library, "Library Version", "", true, false, "Unknown", 0 );
260 node->CreateValueString( ValueID::ValueGenre_System, GetCommandClassId(), _instance, VersionIndex_Protocol, "Protocol Version", "", true, false, "Unknown", 0 );
261 node->CreateValueString( ValueID::ValueGenre_System, GetCommandClassId(), _instance, VersionIndex_Application, "Application Version", "", true, false, "Unknown", 0 );
262 }
263 }
264