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