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