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