//----------------------------------------------------------------------------- // <MultiInstance::HandleMultiChannelEndPointFindReport> // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- void MultiInstance::HandleMultiChannelEndPointFindReport ( uint8 const* _data, uint32 const _length ) { Log::Write( LogLevel_Info, GetNodeId(), "Received MultiChannelEndPointFindReport from node %d", GetNodeId() ); uint8 numEndPoints = _length - 5; for( uint8 i=0; i<numEndPoints; ++i ) { uint8 endPoint = _data[i+4] & 0x7f; if( m_endPointsAreSameClass ) { // Use the stored command class list to set up the endpoint. if( Node* node = GetNodeUnsafe() ) { for( set<uint8>::iterator it=m_endPointCommandClasses.begin(); it!=m_endPointCommandClasses.end(); ++it ) { uint8 commandClassId = *it; CommandClass* cc = node->GetCommandClass( commandClassId ); if( cc ) { Log::Write( LogLevel_Info, GetNodeId(), " Endpoint %d: Adding %s", endPoint, cc->GetCommandClassName().c_str() ); cc->SetInstance( endPoint ); } } } } else { // Endpoints are different, so request the capabilities char str[128]; snprintf( str, 128, "MultiChannelCmd_CapabilityGet for node %d, endpoint %d", GetNodeId(), endPoint ); 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( MultiChannelCmd_CapabilityGet ); msg->Append( endPoint ); msg->Append( GetDriver()->GetTransmitOptions() ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Send ); } } m_numEndPointsFound += numEndPoints; if( !m_endPointsAreSameClass ) { if( _data[1] == 0 ) { // No more reports to follow this one, so we can continue the search. if( m_numEndPointsFound < numEndPoints ) { // We have not yet found all the endpoints, so move to the next generic class request ++m_endPointFindIndex; if( c_genericClass[m_endPointFindIndex] > 0 ) { char str[128]; snprintf( str, 128, "MultiChannelCmd_EndPointFind for generic device class 0x%.2x (%s)", c_genericClass[m_endPointFindIndex], c_genericClassName[m_endPointFindIndex] ); 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( 4 ); msg->Append( GetCommandClassId() ); msg->Append( MultiChannelCmd_EndPointFind ); msg->Append( c_genericClass[m_endPointFindIndex] ); // Generic device class msg->Append( 0xff ); // Any specific device class msg->Append( GetDriver()->GetTransmitOptions() ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Send ); } } } } }
//----------------------------------------------------------------------------- // <MultiInstance::HandleMultiChannelCapabilityReport> // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- void MultiInstance::HandleMultiChannelCapabilityReport ( uint8 const* _data, uint32 const _length ) { if( Node* node = GetNodeUnsafe() ) { uint8 endPoint = _data[1] & 0x7f; bool dynamic = ((_data[1] & 0x80)!=0); 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++ ) { 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 ) { 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::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(), "Recieved 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 ) { 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::HandleMultiChannelCapabilityReport> // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- void MultiInstance::HandleMultiChannelCapabilityReport ( uint8 const* _data, uint32 const _length ) { if( Node* node = GetNodeUnsafe() ) { uint8 endPoint = _data[1] & 0x7f; bool dynamic = ((_data[1] & 0x80)!=0); 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() ); } } if( ( endPoint == 1 ) && m_endPointsAreSameClass ) { Log::Write( LogLevel_Info, GetNodeId(), "All endpoints in this device are the same as endpoint 1. Searching for the other endpoints..." ); // All end points have the same command classes. // We just need to find them... if (node->MultiEndPointFindSupported()) { char str[128]; snprintf( str, sizeof( str ), "MultiChannelCmd_EndPointFind for generic device class 0x%.2x", _data[2] ); 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( 4 ); msg->Append( GetCommandClassId() ); msg->Append( MultiChannelCmd_EndPointFind ); msg->Append( _data[2] ); // Generic device class msg->Append( 0xff ); // Any specific device class msg->Append( TRANSMIT_OPTION_ACK | TRANSMIT_OPTION_AUTO_ROUTE ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Send ); } else { // no way to find them, assume they are in ascending order for( uint8 endPoint=1; endPoint<=m_numEndpoints; ++endPoint ) { // Use the stored command class list to set up the endpoint. for( set<uint8>::iterator it=m_endPointCommandClasses.begin(); it!=m_endPointCommandClasses.end(); ++it ) { uint8 commandClassId = *it; CommandClass* cc = node->GetCommandClass( commandClassId ); if( cc ) { Log::Write( LogLevel_Info, GetNodeId(), " Endpoint %d: Adding %s", endPoint, cc->GetCommandClassName().c_str() ); cc->SetInstance( endPoint ); } } } } } else { // Create instances (endpoints) for each command class in the list 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( 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; }