//----------------------------------------------------------------------------- // <MultiInstance::HandleMultiChannelCapabilityReport> // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- void MultiInstance::HandleMultiChannelCapabilityReport ( uint8 const* _data, uint32 const _length ) { bool dynamic = ((_data[1] & 0x80)!=0); if( Node* node = GetNodeUnsafe() ) { /* if you having problems with Dynamic Devices not correctly * updating the commandclasses, see this email thread: * https://groups.google.com/d/topic/openzwave/IwepxScRAVo/discussion */ if ((m_ignoreUnsolicitedMultiChannelCapabilityReport && (node->GetCurrentQueryStage() != Node::QueryStage_Instances)) && !dynamic && m_endPointCommandClasses.size() > 0) { Log::Write(LogLevel_Error, GetNodeId(), "Received a Unsolicited MultiChannelEncap when we are not in QueryState_Instances"); return; } uint8 endPoint = _data[1] & 0x7f; Log::Write( LogLevel_Info, GetNodeId(), "Received MultiChannelCapabilityReport from node %d for endpoint %d", GetNodeId(), endPoint ); Log::Write( LogLevel_Info, GetNodeId(), " Endpoint is%sdynamic, and is a %s", dynamic ? " " : " not ", node->GetEndPointDeviceClassLabel( _data[2], _data[3] ).c_str() ); Log::Write( LogLevel_Info, GetNodeId(), " Command classes supported by the endpoint are:" ); // Store the command classes for later use bool afterMark = false; m_endPointCommandClasses.clear(); uint8 numCommandClasses = _length - 5; for( uint8 i = 0; i < numCommandClasses; ++i ) { uint8 commandClassId = _data[i+4]; if( commandClassId == 0xef ) { afterMark = true; continue; } m_endPointCommandClasses.insert( commandClassId ); // Ensure the node supports this command class CommandClass* cc = node->GetCommandClass( commandClassId ); if( !cc ) { cc = node->AddCommandClass( commandClassId ); if( cc && afterMark ) { cc->SetAfterMark(); } } if( cc ) { Log::Write( LogLevel_Info, GetNodeId(), " %s", cc->GetCommandClassName().c_str() ); } } // Create internal library instances for each command class in the list // Also set up mapping from intances to endpoints for encapsulation Basic* basic = static_cast<Basic*>( node->GetCommandClass( Basic::StaticGetCommandClassId() ) ); if( m_endPointsAreSameClass ) // Create all the same instances here { int len; if( m_endPointMap == MultiInstanceMapAll ) // Include the non-endpoint instance { endPoint = 0; len = m_numEndPoints + 1; } else { endPoint = 1; len = m_numEndPoints; } // Create all the command classes for all the endpoints for( uint8 i = 1; i <= len; i++ ) { //std::cout << "Num Instances: " << len << std::endl; for( set<uint8>::iterator it = m_endPointCommandClasses.begin(); it != m_endPointCommandClasses.end(); ++it ) { uint8 commandClassId = *it; CommandClass* cc = node->GetCommandClass( commandClassId ); if( cc ) { cc->SetInstance( i ); if( m_endPointMap != MultiInstanceMapAll || i != 1 ) { cc->SetEndPoint( i, endPoint ); } // If we support the BASIC command class and it is mapped to a command class // assigned to this end point, make sure the BASIC command class is also associated // with this end point. if( basic != NULL && basic->GetMapping() == commandClassId ) { basic->SetInstance( i ); if( m_endPointMap != MultiInstanceMapAll || i != 1 ) { basic->SetEndPoint( i, endPoint ); } } } } endPoint++; } } else // Endpoints are different { for( set<uint8>::iterator it = m_endPointCommandClasses.begin(); it != m_endPointCommandClasses.end(); ++it ) { uint8 commandClassId = *it; CommandClass* cc = node->GetCommandClass( commandClassId ); if( cc ) { // get instance gets an instance for an endpoint // but i'm only interested if there is a related instance for an endpoint and not in the actual result // soo if the result is != 0, the endpoint is already handled bool endpointAlreadyHandled = cc->GetInstance( endPoint ) != 0 ; if ( endpointAlreadyHandled ) { Log::Write( LogLevel_Warning, GetNodeId(), "Received MultiChannelCapabilityReport from node %d for endpoint %d - Endpoint already handled for CommandClass %d", GetNodeId(), endPoint, cc->GetCommandClassId() ); continue; } uint8 i; // Find the next free instance of this class for( i = 1; i <= 127; i++ ) { if( m_endPointMap == MultiInstanceMapAll ) // Include the non-endpoint instance { if( !cc->GetInstances()->IsSet( i ) ) { break; } } // Reuse non-endpoint instances first time we see it else if( i == 1 && cc->GetInstances()->IsSet( i ) && cc->GetEndPoint( i ) == 0 ) { break; } // Find the next free instance else if( !cc->GetInstances()->IsSet( i ) ) { break; } } cc->SetInstance( i ); cc->SetEndPoint( i, endPoint ); // If we support the BASIC command class and it is mapped to a command class // assigned to this end point, make sure the BASIC command class is also associated // with this end point. if( basic != NULL && basic->GetMapping() == commandClassId ) { basic->SetInstance( i ); basic->SetEndPoint( i, endPoint ); } } } } } }
//----------------------------------------------------------------------------- // <MultiInstance::RequestInstances> // Request number of instances of the specified command class from the device //----------------------------------------------------------------------------- bool MultiInstance::RequestInstances ( ) { bool res = false; if( GetVersion() == 1 ) { if( Node* node = GetNodeUnsafe() ) { // MULTI_INSTANCE char str[128]; for( map<uint8,CommandClass*>::const_iterator it = node->m_commandClassMap.begin(); it != node->m_commandClassMap.end(); ++it ) { CommandClass* cc = it->second; if( cc->GetCommandClassId() == NoOperation::StaticGetCommandClassId() ) { continue; } if( cc->HasStaticRequest( StaticRequest_Instances ) ) { snprintf( str, sizeof( str ), "MultiInstanceCmd_Get for %s", cc->GetCommandClassName().c_str() ); Msg* msg = new Msg( str, GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 3 ); msg->Append( GetCommandClassId() ); msg->Append( MultiInstanceCmd_Get ); msg->Append( cc->GetCommandClassId() ); msg->Append( GetDriver()->GetTransmitOptions() ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Query ); res = true; } } } } else { // MULTI_CHANNEL char str[128]; snprintf( str, sizeof( str ), "MultiChannelCmd_EndPointGet for node %d", GetNodeId() ); Msg* msg = new Msg( str, GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 2 ); msg->Append( GetCommandClassId() ); msg->Append( MultiChannelCmd_EndPointGet ); msg->Append( GetDriver()->GetTransmitOptions() ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Query ); res = true; } return res; }