1 //-----------------------------------------------------------------------------
2 //
3 //	ControllerReplication.cpp
4 //
5 //	Implementation of the Z-Wave COMMAND_CLASS_CONTROLLER_REPLICATION
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/ControllerReplication.h"
30 #include "Defs.h"
31 #include "Msg.h"
32 #include "Driver.h"
33 #include "Node.h"
34 #include "Utils.h"
35 
36 
37 #include "value_classes/ValueByte.h"
38 #include "value_classes/ValueList.h"
39 #include "value_classes/ValueButton.h"
40 
41 using namespace OpenZWave;
42 
43 enum ControllerReplicationCmd
44 {
45 	ControllerReplicationCmd_TransferGroup		= 0x31,
46 	ControllerReplicationCmd_TransferGroupName	= 0x32,
47 	ControllerReplicationCmd_TransferScene		= 0x33,
48 	ControllerReplicationCmd_TransferSceneName	= 0x34
49 };
50 
51 enum
52 {
53 	ControllerReplicationIndex_NodeId = 0,
54 	ControllerReplicationIndex_Function,
55 	ControllerReplicationIndex_Replicate
56 };
57 
58 static char const* c_controllerReplicationFunctionNames[] =
59 {
60 	"Groups",
61 	"Group Names",
62 	"Scenes",
63 	"Scene Names",
64 };
65 
66 //-----------------------------------------------------------------------------
67 // <ControllerReplication::HandleMsg>
68 // Handle a message from the Z-Wave network
69 //-----------------------------------------------------------------------------
ControllerReplication(uint32 const _homeId,uint8 const _nodeId)70 ControllerReplication::ControllerReplication
71 (
72 	uint32 const _homeId,
73 	uint8 const _nodeId
74 ):
75 	CommandClass( _homeId, _nodeId ),
76 	m_busy( false ),
77 	m_targetNodeId( 0 ),
78 	m_funcId( 0 ),
79 	m_nodeId( -1 ),
80 	m_groupCount( -1 ),
81 	m_groupIdx( -1 )
82 {
83 }
84 
85 //-----------------------------------------------------------------------------
86 // <ControllerReplication::HandleMsg>
87 // Handle a message from the Z-Wave network
88 //-----------------------------------------------------------------------------
HandleMsg(uint8 const * _data,uint32 const _length,uint32 const _instance)89 bool ControllerReplication::HandleMsg
90 (
91 	uint8 const* _data,
92 	uint32 const _length,
93 	uint32 const _instance	// = 1
94 )
95 {
96 	// When creating replication messages, use FUNC_ID_ZW_SEND_REPLICATION_DATA instead of FUNC_ID_ZW_SEND_DATA
97 	// e.g. Msg* msg = new Msg( "TransferGroup", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_REPLICATION_DATA, true, false );
98 
99 	switch( _data[0] )
100 	{
101 		case ControllerReplicationCmd_TransferGroup:
102 		{
103 			break;
104 		}
105 		case ControllerReplicationCmd_TransferGroupName:
106 		{
107 			break;
108 		}
109 		case  ControllerReplicationCmd_TransferScene:
110 		{
111 			break;
112 		}
113 		case ControllerReplicationCmd_TransferSceneName:
114 		{
115 			break;
116 		}
117 	}
118 
119 	Msg* msg = new Msg( "ControllerReplicationCmd_Complete", GetNodeId(), REQUEST, FUNC_ID_ZW_REPLICATION_COMMAND_COMPLETE, false, false );
120 	GetDriver()->SendMsg( msg, Driver::MsgQueue_Command );
121 	return true;
122 }
123 
124 //-----------------------------------------------------------------------------
125 // <ControllerReplication::SetValue>
126 // Set a value on the Z-Wave device
127 //-----------------------------------------------------------------------------
SetValue(Value const & _value)128 bool ControllerReplication::SetValue
129 (
130 	Value const& _value
131 )
132 {
133 	bool res = false;
134 	uint8 instance = _value.GetID().GetInstance();
135 
136 	switch( _value.GetID().GetIndex() )
137 	{
138 		case ControllerReplicationIndex_NodeId:
139 		{
140 			if( ValueByte* value = static_cast<ValueByte*>( GetValue( instance, ControllerReplicationIndex_NodeId ) ) )
141 			{
142 				value->OnValueRefreshed( (static_cast<ValueByte const*>( &_value))->GetValue() );
143 				value->Release();
144 				res = true;
145 			}
146 			break;
147 		}
148 		case ControllerReplicationIndex_Function:
149 		{
150 			if( ValueList* value = static_cast<ValueList*>( GetValue( instance, ControllerReplicationIndex_Function ) ) )
151 			{
152 				ValueList::Item const *item = (static_cast<ValueList const*>( &_value))->GetItem();
153 				value->OnValueRefreshed( item->m_value );
154 				value->Release();
155 				res = true;
156 			}
157 			break;
158 		}
159 		case ControllerReplicationIndex_Replicate:
160 		{
161 			if( ValueButton* button = static_cast<ValueButton*>( GetValue( instance, ControllerReplicationIndex_Replicate ) ) )
162 			{
163 				if( button->IsPressed() )
164 				{
165 					res = StartReplication( instance );
166 				}
167 				button->Release();
168 			}
169 			break;
170 		}
171 	}
172 	return res;
173 }
174 
175 //-----------------------------------------------------------------------------
176 // <ControllerReplication::StartReplication>
177 // Set up the group and scene data to be sent to the other controller
178 //-----------------------------------------------------------------------------
StartReplication(uint8 const _instance)179 bool ControllerReplication::StartReplication
180 (
181 	uint8 const _instance
182 )
183 {
184 	if( m_busy )
185 	{
186 		return false;
187 	}
188 
189 	if( ValueByte* value = static_cast<ValueByte*>( GetValue( _instance, ControllerReplicationIndex_NodeId ) ) )
190 	{
191 		m_targetNodeId = value->GetValue();
192 		value->Release();
193 	}
194 	else
195 	{
196 		return false;
197 	}
198 
199 	if( ValueList* value = static_cast<ValueList*>( GetValue( _instance, ControllerReplicationIndex_Function ) ) )
200 	{
201 		ValueList::Item const *item = value->GetItem();
202 		if (item)
203 			m_funcId = item->m_value;
204 		value->Release();
205 	}
206 	else
207 	{
208 		return false;
209 	}
210 
211 	// Store the Z-Wave command we should use when replication has completed.
212 	m_nodeId = -1;
213 	m_groupCount = -1;
214 	m_groupIdx = -1;
215 	m_busy = true;
216 
217 	// Set up the groups and scenes to be sent
218 	SendNextData();
219 	return true;
220 }
221 
222 //-----------------------------------------------------------------------------
223 // <ControllerReplication::SendNextData>
224 // Send the next block of replication data
225 //-----------------------------------------------------------------------------
SendNextData()226 void ControllerReplication::SendNextData
227 (
228 )
229 {
230 	uint16 i = 255;
231 
232 	if( !m_busy )
233 	{
234 		return;
235 	}
236 
237 	while( 1 )
238 	{
239 		if( m_groupIdx != -1 )
240 		{
241 			m_groupIdx++;
242 			if( m_groupIdx <= m_groupCount )
243 			{
244 				break;
245 			}
246 		}
247 		i = m_nodeId == -1 ? 0 : m_nodeId+1;
248 		LockGuard LG(GetDriver()->m_nodeMutex);
249 		while( i < 256 )
250 		{
251 			if( GetDriver()->m_nodes[i] )
252 			{
253 				m_groupCount = GetDriver()->m_nodes[i]->GetNumGroups();
254 				if( m_groupCount != 0 )
255 				{
256 					m_groupName = GetDriver()->m_nodes[i]->GetGroupLabel( m_groupIdx );
257 					m_groupIdx = m_groupName.length() > 0 ? 0 : 1;
258 					break;
259 				}
260 			}
261 			i++;
262 		}
263 		m_nodeId = i;
264 		break;
265 	}
266 	if( i < 255 )
267 	{
268 		Msg* msg = new Msg( (m_groupName.length() > 0 ? "ControllerReplicationCmd_TransferGroupName" : "ControllerReplicationCmd_TransferGroup"), m_targetNodeId, REQUEST, FUNC_ID_ZW_REPLICATION_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
269 		msg->Append( m_targetNodeId );
270 		if( m_groupName.length() > 0 )
271 		{
272 			msg->Append((uint8) (m_groupName.length() + 4 ));
273 			msg->Append( GetCommandClassId() );
274 			msg->Append( ControllerReplicationCmd_TransferGroupName );
275 			msg->Append( 0 );
276 			msg->Append( m_groupIdx );
277 			for( uint8 j = 0; j < m_groupName.length(); j++ )
278 			{
279 				msg->Append( m_groupName[j] );
280 			}
281 			m_groupName = "";
282 		}
283 		else
284 		{
285 			msg->Append( 5 );
286 			msg->Append( GetCommandClassId() );
287 			msg->Append( ControllerReplicationCmd_TransferGroup );
288 			msg->Append( 0 );
289 			msg->Append( m_groupIdx );
290 			msg->Append( m_nodeId );
291 		}
292 		msg->Append( TRANSMIT_OPTION_ACK );
293 		GetDriver()->SendMsg( msg, Driver::MsgQueue_Command );
294 	}
295 	else
296 	{
297 		GetDriver()->AddNodeStop( m_funcId );
298 		m_busy = false;
299 	}
300 }
301 
302 //-----------------------------------------------------------------------------
303 // <ControllerReplication::CreateVars>
304 // Create the values managed by this command class
305 //-----------------------------------------------------------------------------
CreateVars(uint8 const _instance)306 void ControllerReplication::CreateVars
307 (
308 	uint8 const _instance
309 )
310 {
311 	if( Node* node = GetNodeUnsafe() )
312 	{
313 		node->CreateValueByte( ValueID::ValueGenre_System, GetCommandClassId(), _instance, ControllerReplicationIndex_NodeId, "Node", "", false, false, 0, 0 );
314 		vector<ValueList::Item> items;
315 
316 		ValueList::Item item;
317 		for( uint8 i=0; i<4; ++i )
318 		{
319 			item.m_label = c_controllerReplicationFunctionNames[i];
320 			item.m_value = ControllerReplicationCmd_TransferGroup + i;
321 			items.push_back( item );
322 		}
323 
324 		node->CreateValueList( ValueID::ValueGenre_System, GetCommandClassId(), _instance, ControllerReplicationIndex_Function, "Functions", "", false, false, 1, items, 0, 0 );
325 		node->CreateValueButton( ValueID::ValueGenre_System, GetCommandClassId(), _instance, ControllerReplicationIndex_Replicate, "Replicate", 0 );
326 	}
327 }
328