#include "Defs.h"
#include "Driver.h"
#include "Options.h"
#include "Manager.h"
#include "Node.h"
#include "Msg.h"
#include "Notification.h"
#include "Scene.h"
#include "ZWSecurity.h"
#include "platform/Event.h"
#include "platform/Mutex.h"
#include "platform/SerialController.h"
#ifdef WINRT
#include "platform/winRT/HidControllerWinRT.h"
#else
#include "platform/HidController.h"
#endif
#include "platform/Thread.h"
#include "platform/Log.h"
#include "platform/TimeStamp.h"
#include "command_classes/CommandClasses.h"
#include "command_classes/ApplicationStatus.h"
#include "command_classes/ControllerReplication.h"
#include "command_classes/Security.h"
#include "command_classes/WakeUp.h"
#include "command_classes/SwitchAll.h"
#include "command_classes/ManufacturerSpecific.h"
#include "command_classes/NoOperation.h"
#include "value_classes/ValueID.h"
#include "value_classes/Value.h"
#include "value_classes/ValueStore.h"
#include "tinyxml.h"
#include "Utils.h"
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
# include <unistd.h>
#elif defined _WIN32
# include <windows.h>
#define sleep(x) Sleep(1000 * x)
#endif
#include <algorithm>
#include <iostream>
using namespace OpenZWave;
uint32 const c_configVersion = 3;
static char const* c_libraryTypeNames[] =
{
"Unknown", "Static Controller", "Controller", "Enhanced Slave", "Slave", "Installer", "Routing Slave", "Bridge Controller", "Device Under Test" };
static char const* c_controllerCommandNames[] =
{
"None",
"Add Device",
"Create New Primary",
"Receive Configuration",
"Remove Device",
"Remove Failed Node",
"Has Node Failed",
"Replace Failed Node",
"Transfer Primary Role",
"Request Network Update",
"Request Node Neighbor Update",
"Assign Return Route",
"Delete All Return Routes",
"Send Node Information",
"Replication Send",
"Create Button",
"Delete Button"
};
static char const* c_sendQueueNames[] =
{
"Command",
"Security",
"NoOp",
"Controller",
"WakeUp",
"Send",
"Query",
"Poll"
};
Driver::Driver
(
string const& _controllerPath,
ControllerInterface const& _interface
):
m_driverThread( new Thread( "driver" ) ),
m_initMutex(new Mutex()),
m_exit( false ),
m_init( false ),
m_awakeNodesQueried( false ),
m_allNodesQueried( false ),
m_notifytransactions( false ),
m_controllerInterfaceType( _interface ),
m_controllerPath( _controllerPath ),
m_controller( NULL ),
m_homeId( 0 ),
m_libraryVersion( "" ),
m_libraryTypeName( "" ),
m_libraryType( 0 ),
m_manufacturerId( 0 ),
m_productType( 0 ),
m_productId ( 0 ),
m_initVersion( 0 ),
m_initCaps( 0 ),
m_controllerCaps( 0 ),
m_Controller_nodeId ( 0 ),
m_nodeMutex( new Mutex() ),
m_controllerReplication( NULL ),
m_transmitOptions( TRANSMIT_OPTION_ACK | TRANSMIT_OPTION_AUTO_ROUTE | TRANSMIT_OPTION_EXPLORE ),
m_waitingForAck( false ),
m_expectedCallbackId( 0 ),
m_expectedReply( 0 ),
m_expectedCommandClassId( 0 ),
m_expectedNodeId( 0 ),
m_pollThread( new Thread( "poll" ) ),
m_pollMutex( new Mutex() ),
m_pollInterval( 0 ),
m_bIntervalBetweenPolls( false ), m_currentControllerCommand( NULL ),
m_SUCNodeId( 0 ),
m_controllerResetEvent( NULL ),
m_sendMutex( new Mutex() ),
m_currentMsg( NULL ),
m_virtualNeighborsReceived( false ),
m_notificationsEvent( new Event() ),
m_SOFCnt( 0 ),
m_ACKWaiting( 0 ),
m_readAborts( 0 ),
m_badChecksum( 0 ),
m_readCnt( 0 ),
m_writeCnt( 0 ),
m_CANCnt( 0 ),
m_NAKCnt( 0 ),
m_ACKCnt( 0 ),
m_OOFCnt( 0 ),
m_dropped( 0 ),
m_retries( 0 ),
m_callbacks( 0 ),
m_badroutes( 0 ),
m_noack( 0 ),
m_netbusy( 0 ),
m_notidle( 0 ),
m_nondelivery( 0 ),
m_routedbusy( 0 ),
m_broadcastReadCnt( 0 ),
m_broadcastWriteCnt( 0 ),
m_nonceReportSent( 0 ),
m_nonceReportSentAttempt( 0 )
{
TimeStamp m_startTime;
for( int32 i=0; i<MsgQueue_Count; ++i )
{
m_queueEvent[i] = new Event();
}
memset( m_nodes, 0, sizeof(Node*) * 256 );
memset( m_virtualNeighbors, 0, NUM_NODE_BITFIELD_BYTES );
initNetworkKeys(false);
if( ControllerInterface_Hid == _interface )
{
m_controller = new HidController();
}
else
{
m_controller = new SerialController();
}
m_controller->SetSignalThreshold( 1 );
Options::Get()->GetOptionAsBool( "NotifyTransactions", &m_notifytransactions );
Options::Get()->GetOptionAsInt( "PollInterval", &m_pollInterval );
Options::Get()->GetOptionAsBool( "IntervalBetweenPolls", &m_bIntervalBetweenPolls );
}
Driver::~Driver
(
)
{
Notification* notification = new Notification( Notification::Type_DriverRemoved );
notification->SetHomeAndNodeIds( m_homeId, 0 );
QueueNotification( notification );
NotifyWatchers();
LogDriverStatistics();
bool save;
if( Options::Get()->GetOptionAsBool( "SaveConfiguration", &save) )
{
if( save )
{
WriteConfig();
Scene::WriteXML( "zwscene.xml" );
}
}
m_initMutex->Lock();
m_exit = true;
m_initMutex->Unlock();
m_pollThread->Stop();
m_pollThread->Release();
m_driverThread->Stop();
m_driverThread->Release();
m_sendMutex->Release();
m_controller->Close();
m_controller->Release();
m_initMutex->Release();
if( m_currentMsg != NULL )
{
RemoveCurrentMsg();
}
{
LockGuard LG(m_nodeMutex);
for( int i=0; i<256; ++i )
{
if( GetNodeUnsafe( i ) )
{
delete m_nodes[i];
m_nodes[i] = NULL;
Notification* notification = new Notification( Notification::Type_NodeRemoved );
notification->SetHomeAndNodeIds( m_homeId, i );
QueueNotification( notification );
}
}
}
m_pollMutex->Release();
for( int32 i=0; i<MsgQueue_Count; ++i )
{
while( !m_msgQueue[i].empty() )
{
MsgQueueItem const& item = m_msgQueue[i].front();
if( MsgQueueCmd_SendMsg == item.m_command )
{
delete item.m_msg;
}
else if( MsgQueueCmd_Controller == item.m_command )
{
delete item.m_cci;
}
m_msgQueue[i].pop_front();
}
m_queueEvent[i]->Release();
}
bool notify;
if( Options::Get()->GetOptionAsBool( "NotifyOnDriverUnload", ¬ify) )
{
if( notify )
{
NotifyWatchers();
}
}
if (m_controllerReplication)
delete m_controllerReplication;
m_notificationsEvent->Release();
m_nodeMutex->Release();
}
void Driver::Start
(
)
{
m_driverThread->Start( Driver::DriverThreadEntryPoint, this );
}
void Driver::DriverThreadEntryPoint
(
Event* _exitEvent,
void* _context
)
{
Driver* driver = (Driver*)_context;
if( driver )
{
driver->DriverThreadProc( _exitEvent );
}
}
void Driver::DriverThreadProc
(
Event* _exitEvent
)
{
uint32 attempts = 0;
while( true )
{
if( Init( attempts ) )
{
Wait* waitObjects[11];
waitObjects[0] = _exitEvent; waitObjects[1] = m_notificationsEvent; waitObjects[2] = m_controller; waitObjects[3] = m_queueEvent[MsgQueue_Command]; waitObjects[4] = m_queueEvent[MsgQueue_Security]; waitObjects[5] = m_queueEvent[MsgQueue_NoOp]; waitObjects[6] = m_queueEvent[MsgQueue_Controller]; waitObjects[7] = m_queueEvent[MsgQueue_WakeUp]; waitObjects[8] = m_queueEvent[MsgQueue_Send]; waitObjects[9] = m_queueEvent[MsgQueue_Query]; waitObjects[10] = m_queueEvent[MsgQueue_Poll];
TimeStamp retryTimeStamp;
int retryTimeout = RETRY_TIMEOUT;
Options::Get()->GetOptionAsInt( "RetryTimeout", &retryTimeout );
while( true )
{
Log::Write( LogLevel_StreamDetail, " Top of DriverThreadProc loop." );
uint32 count = 11;
int32 timeout = Wait::Timeout_Infinite;
if( m_waitingForAck || m_expectedCallbackId || m_expectedReply )
{
count = 3;
timeout = m_waitingForAck ? ACK_TIMEOUT : retryTimeStamp.TimeRemaining();
if( timeout < 0 )
{
timeout = 0;
}
}
else if( m_currentControllerCommand != NULL )
{
count = 7;
}
else
{
Log::QueueClear(); }
int32 res = Wait::Multiple( waitObjects, count, timeout );
switch( res )
{
case -1:
{
if( m_currentMsg != NULL )
{
Notification* notification = new Notification( Notification::Type_Notification );
notification->SetHomeAndNodeIds( m_homeId, m_currentMsg->GetTargetNodeId() );
notification->SetNotification( Notification::Code_Timeout );
QueueNotification( notification );
}
if( WriteMsg( "Wait Timeout" ) )
{
retryTimeStamp.SetTime( retryTimeout );
}
break;
}
case 0:
{
return;
}
case 1:
{
NotifyWatchers();
break;
}
case 2:
{
ReadMsg();
break;
}
default:
{
if( WriteNextMsg( (MsgQueue)(res-3) ) )
{
retryTimeStamp.SetTime( retryTimeout );
}
break;
}
}
}
}
++attempts;
uint32 maxAttempts = 0;
Options::Get()->GetOptionAsInt("DriverMaxAttempts", (int32 *)&maxAttempts);
if( maxAttempts && (attempts >= maxAttempts) )
{
Manager::Get()->Manager::SetDriverReady(this, false);
NotifyWatchers();
break;
}
if( attempts < 25 )
{
if( Wait::Single( _exitEvent, 5000 ) == 0 )
{
return;
}
}
else
{
if( Wait::Single( _exitEvent, 30000 ) == 0 )
{
return;
}
}
}
}
bool Driver::Init
(
uint32 _attempts
)
{
m_initMutex->Lock();
if (m_exit)
{
m_initMutex->Unlock();
return false;
}
m_Controller_nodeId = -1;
m_waitingForAck = false;
Log::Write( LogLevel_Info, " Opening controller %s", m_controllerPath.c_str() );
if( !m_controller->Open( m_controllerPath ) )
{
Log::Write( LogLevel_Warning, "WARNING: Failed to init the controller (attempt %d)", _attempts );
m_initMutex->Unlock();
return false;
}
m_pollThread->Start( Driver::PollThreadEntryPoint, this );
uint8 nak = NAK;
m_controller->Write( &nak, 1 );
m_controller->PlayInitSequence( this );
m_initMutex->Unlock();
return true;
}
void Driver::RemoveQueues
(
uint8 const _nodeId
)
{
if( m_currentMsg != NULL && m_currentMsg->GetTargetNodeId() == _nodeId )
{
RemoveCurrentMsg();
}
for( int32 i=0; i<MsgQueue_Count; ++i )
{
list<MsgQueueItem>::iterator it = m_msgQueue[i].begin();
while( it != m_msgQueue[i].end() )
{
bool remove = false;
MsgQueueItem const& item = *it;
if( MsgQueueCmd_SendMsg == item.m_command && _nodeId == item.m_msg->GetTargetNodeId() )
{
delete item.m_msg;
remove = true;
}
else if( MsgQueueCmd_QueryStageComplete == item.m_command && _nodeId == item.m_nodeId )
{
remove = true;
}
else if( MsgQueueCmd_Controller == item.m_command && _nodeId == item.m_cci->m_controllerCommandNode && m_currentControllerCommand != item.m_cci )
{
delete item.m_cci;
remove = true;
}
if( remove )
{
it = m_msgQueue[i].erase( it );
}
else
{
++it;
}
}
if( m_msgQueue[i].empty() )
{
m_queueEvent[i]->Reset();
}
}
}
bool Driver::ReadConfig
(
)
{
char str[32];
int32 intVal;
string userPath;
Options::Get()->GetOptionAsString( "UserPath", &userPath );
snprintf( str, sizeof(str), "zwcfg_0x%08x.xml", m_homeId );
string filename = userPath + string(str);
TiXmlDocument doc;
if( !doc.LoadFile( filename.c_str(), TIXML_ENCODING_UTF8 ) )
{
return false;
}
TiXmlElement const* driverElement = doc.RootElement();
if( TIXML_SUCCESS != driverElement->QueryIntAttribute( "version", &intVal ) || (uint32)intVal != c_configVersion )
{
Log::Write( LogLevel_Warning, "WARNING: Driver::ReadConfig - %s is from an older version of OpenZWave and cannot be loaded.", filename.c_str() );
return false;
}
char const* homeIdStr = driverElement->Attribute( "home_id" );
if( homeIdStr )
{
char* p;
uint32 homeId = (uint32)strtoul( homeIdStr, &p, 0 );
if( homeId != m_homeId )
{
Log::Write( LogLevel_Warning, "WARNING: Driver::ReadConfig - Home ID in file %s is incorrect", filename.c_str() );
return false;
}
}
else
{
Log::Write( LogLevel_Warning, "WARNING: Driver::ReadConfig - Home ID is missing from file %s", filename.c_str() );
return false;
}
if( TIXML_SUCCESS == driverElement->QueryIntAttribute( "node_id", &intVal ) )
{
if( (uint8)intVal != m_Controller_nodeId )
{
Log::Write( LogLevel_Warning, "WARNING: Driver::ReadConfig - Controller Node ID in file %s is incorrect", filename.c_str() );
return false;
}
}
else
{
Log::Write( LogLevel_Warning, "WARNING: Driver::ReadConfig - Node ID is missing from file %s", filename.c_str() );
return false;
}
if( TIXML_SUCCESS == driverElement->QueryIntAttribute( "api_capabilities", &intVal ) )
{
m_initCaps = (uint8)intVal;
}
if( TIXML_SUCCESS == driverElement->QueryIntAttribute( "controller_capabilities", &intVal ) )
{
m_controllerCaps = (uint8)intVal;
}
if( TIXML_SUCCESS == driverElement->QueryIntAttribute( "poll_interval", &intVal ) )
{
m_pollInterval = intVal;
}
char const* cstr = driverElement->Attribute( "poll_interval_between" );
if( cstr )
{
m_bIntervalBetweenPolls = !strcmp( str, "true" );
}
LockGuard LG(m_nodeMutex);
TiXmlElement const* nodeElement = driverElement->FirstChildElement();
while( nodeElement )
{
char const* str = nodeElement->Value();
if( str && !strcmp( str, "Node" ) )
{
if( TIXML_SUCCESS == nodeElement->QueryIntAttribute( "id", &intVal ) )
{
uint8 nodeId = (uint8)intVal;
Node* node = new Node( m_homeId, nodeId );
m_nodes[nodeId] = node;
Notification* notification = new Notification( Notification::Type_NodeAdded );
notification->SetHomeAndNodeIds( m_homeId, nodeId );
QueueNotification( notification );
node->ReadXML( nodeElement );
}
}
nodeElement = nodeElement->NextSiblingElement();
}
LG.Unlock();
for( int i=0; i<256; i++ )
{
if( m_nodes[i] != NULL )
{
ValueStore* vs = m_nodes[i]->m_values;
for( ValueStore::Iterator it = vs->Begin(); it != vs->End(); ++it )
{
Value* value = it->second;
if( value->m_pollIntensity != 0 )
EnablePoll( value->GetID(), value->m_pollIntensity );
}
}
}
return true;
}
void Driver::WriteConfig
(
)
{
char str[32];
if (!m_homeId) {
Log::Write( LogLevel_Warning, "WARNING: Tried to write driver config with no home ID set");
return;
}
TiXmlDocument doc;
TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "utf-8", "" );
TiXmlElement* driverElement = new TiXmlElement( "Driver" );
doc.LinkEndChild( decl );
doc.LinkEndChild( driverElement );
driverElement->SetAttribute( "xmlns", "http://code.google.com/p/open-zwave/" );
snprintf( str, sizeof(str), "%d", c_configVersion );
driverElement->SetAttribute( "version", str );
snprintf( str, sizeof(str), "0x%.8x", m_homeId );
driverElement->SetAttribute( "home_id", str );
snprintf( str, sizeof(str), "%d", m_Controller_nodeId );
driverElement->SetAttribute( "node_id", str );
snprintf( str, sizeof(str), "%d", m_initCaps );
driverElement->SetAttribute( "api_capabilities", str );
snprintf( str, sizeof(str), "%d", m_controllerCaps );
driverElement->SetAttribute( "controller_capabilities", str );
snprintf( str, sizeof(str), "%d", m_pollInterval );
driverElement->SetAttribute( "poll_interval", str );
snprintf( str, sizeof(str), "%s", m_bIntervalBetweenPolls ? "true" : "false" );
driverElement->SetAttribute( "poll_interval_between", str );
{
LockGuard LG(m_nodeMutex);
for( int i=0; i<256; ++i )
{
if( m_nodes[i] )
{
m_nodes[i]->WriteXML( driverElement );
}
}
}
string userPath;
Options::Get()->GetOptionAsString( "UserPath", &userPath );
snprintf( str, sizeof(str), "zwcfg_0x%08x.xml", m_homeId );
string filename = userPath + string(str);
doc.SaveFile( filename.c_str() );
}
Node* Driver::GetNodeUnsafe
(
uint8 _nodeId
)
{
if( Node* node = m_nodes[_nodeId] )
{
return node;
}
return NULL;
}
Node* Driver::GetNode
(
uint8 _nodeId
)
{
if (m_nodeMutex->IsSignalled()) {
Log::Write(LogLevel_Error, _nodeId, "Driver Thread is Not Locked during Call to GetNode");
return NULL;
}
if( Node* node = m_nodes[_nodeId] )
{
return node;
}
return NULL;
}
void Driver::SendQueryStageComplete
(
uint8 const _nodeId,
Node::QueryStage const _stage
)
{
MsgQueueItem item;
item.m_command = MsgQueueCmd_QueryStageComplete;
item.m_nodeId = _nodeId;
item.m_queryStage = _stage;
item.m_retry = false;
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
if( !node->IsListeningDevice() )
{
if( WakeUp* wakeUp = static_cast<WakeUp*>( node->GetCommandClass( WakeUp::StaticGetCommandClassId() ) ) )
{
if( !wakeUp->IsAwake() )
{
Log::Write( LogLevel_Info, "" );
Log::Write( LogLevel_Detail, node->GetNodeId(), "Queuing (%s) Query Stage Complete (%s)", c_sendQueueNames[MsgQueue_WakeUp], node->GetQueryStageName( _stage ).c_str() );
wakeUp->QueueMsg( item );
return;
}
}
}
Log::Write( LogLevel_Detail, node->GetNodeId(), "Queuing (%s) Query Stage Complete (%s)", c_sendQueueNames[MsgQueue_Query], node->GetQueryStageName( _stage ).c_str() );
m_sendMutex->Lock();
m_msgQueue[MsgQueue_Query].push_back( item );
m_queueEvent[MsgQueue_Query]->Set();
m_sendMutex->Unlock();
}
}
void Driver::RetryQueryStageComplete
(
uint8 const _nodeId,
Node::QueryStage const _stage
)
{
MsgQueueItem item;
item.m_command = MsgQueueCmd_QueryStageComplete;
item.m_nodeId = _nodeId;
item.m_queryStage = _stage;
m_sendMutex->Lock();
for( list<MsgQueueItem>::iterator it = m_msgQueue[MsgQueue_Query].begin(); it != m_msgQueue[MsgQueue_Query].end(); ++it )
{
if( *it == item )
{
(*it).m_retry = true;
break;
}
}
m_sendMutex->Unlock();
}
void Driver::SendMsg
(
Msg* _msg,
MsgQueue const _queue
)
{
MsgQueueItem item;
item.m_command = MsgQueueCmd_SendMsg;
item.m_msg = _msg;
_msg->SetHomeId(m_homeId);
_msg->Finalize();
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode(_msg->GetTargetNodeId()) )
{
if ( node->GetCommandClass(Security::StaticGetCommandClassId() ) )
{
CommandClass *cc = node->GetCommandClass(_msg->GetSendingCommandClass());
if ( (cc) && (cc->IsSecured()) )
{
Log::Write( LogLevel_Detail, GetNodeNumber( _msg ), "Setting Encryption Flag on Message For Command Class %s", cc->GetCommandClassName().c_str());
item.m_msg->setEncrypted();
}
}
if( !node->IsListeningDevice() )
{
if( WakeUp* wakeUp = static_cast<WakeUp*>( node->GetCommandClass( WakeUp::StaticGetCommandClassId() ) ) )
{
if( !wakeUp->IsAwake() )
{
Log::Write( LogLevel_Detail, "" );
if( m_currentControllerCommand != NULL )
{
Log::Write( LogLevel_Detail, GetNodeNumber( _msg ), "Queuing (%s) %s", c_sendQueueNames[MsgQueue_Controller], c_controllerCommandNames[m_currentControllerCommand->m_controllerCommand] );
delete _msg;
item.m_command = MsgQueueCmd_Controller;
item.m_cci = new ControllerCommandItem( *m_currentControllerCommand );
item.m_msg = NULL;
UpdateControllerState( ControllerState_Sleeping );
}
else
{
Log::Write( LogLevel_Detail, GetNodeNumber( _msg ), "Queuing (%s) %s", c_sendQueueNames[MsgQueue_WakeUp], _msg->GetAsString().c_str() );
}
wakeUp->QueueMsg( item );
return;
}
}
}
}
}
Log::Write( LogLevel_Detail, GetNodeNumber( _msg ), "Queuing (%s) %s", c_sendQueueNames[_queue], _msg->GetAsString().c_str() );
m_sendMutex->Lock();
m_msgQueue[_queue].push_back( item );
m_queueEvent[_queue]->Set();
m_sendMutex->Unlock();
}
bool Driver::WriteNextMsg
(
MsgQueue const _queue
)
{
m_sendMutex->Lock();
MsgQueueItem item = m_msgQueue[_queue].front();
if( MsgQueueCmd_SendMsg == item.m_command )
{
m_currentMsg = item.m_msg;
m_currentMsgQueueSource = _queue;
m_msgQueue[_queue].pop_front();
if( m_msgQueue[_queue].empty() )
{
m_queueEvent[_queue]->Reset();
}
m_sendMutex->Unlock();
return WriteMsg( "WriteNextMsg" );
}
if( MsgQueueCmd_QueryStageComplete == item.m_command )
{
m_currentMsg = NULL;
Node::QueryStage stage = item.m_queryStage;
m_msgQueue[_queue].pop_front();
if( m_msgQueue[_queue].empty() )
{
m_queueEvent[_queue]->Reset();
}
m_sendMutex->Unlock();
Node* node = GetNodeUnsafe( item.m_nodeId );
if( node != NULL )
{
Log::Write( LogLevel_Detail, node->GetNodeId(), "Query Stage Complete (%s)", node->GetQueryStageName( stage ).c_str() );
if( !item.m_retry )
{
node->QueryStageComplete( stage );
}
node->AdvanceQueries();
return true;
}
}
if( MsgQueueCmd_Controller == item.m_command )
{
m_currentControllerCommand = item.m_cci;
m_sendMutex->Unlock();
if ( m_currentControllerCommand->m_controllerCommandDone )
{
m_sendMutex->Lock();
m_msgQueue[_queue].pop_front();
if( m_msgQueue[_queue].empty() )
{
m_queueEvent[_queue]->Reset();
}
m_sendMutex->Unlock();
if( m_currentControllerCommand->m_controllerCallback )
{
m_currentControllerCommand->m_controllerCallback( m_currentControllerCommand->m_controllerState, m_currentControllerCommand->m_controllerReturnError, m_currentControllerCommand->m_controllerCallbackContext );
}
m_sendMutex->Lock();
delete m_currentControllerCommand;
m_currentControllerCommand = NULL;
m_sendMutex->Unlock();
}
else if( m_currentControllerCommand->m_controllerState == ControllerState_Normal )
{
DoControllerCommand();
}
else if( m_currentControllerCommand->m_controllerStateChanged )
{
if( m_currentControllerCommand->m_controllerCallback )
{
m_currentControllerCommand->m_controllerCallback( m_currentControllerCommand->m_controllerState, m_currentControllerCommand->m_controllerReturnError, m_currentControllerCommand->m_controllerCallbackContext );
m_currentControllerCommand->m_controllerStateChanged = false;
}
}
else
{
Log::Write( LogLevel_Info, "WriteNextMsg Controller nothing to do" );
m_sendMutex->Lock();
m_queueEvent[_queue]->Reset();
m_sendMutex->Unlock();
}
return true;
}
return false;
}
bool Driver::WriteMsg
(
string const &msg
)
{
if( !m_currentMsg )
{
Log::Write( LogLevel_Detail, GetNodeNumber( m_currentMsg ), "WriteMsg %s m_currentMsg=%08x", msg.c_str(), m_currentMsg );
m_expectedCallbackId = 0;
m_expectedCommandClassId = 0;
m_expectedNodeId = 0;
m_expectedReply = 0;
m_waitingForAck = false;
return false;
}
uint8 attempts;
uint8 nodeId;
if (m_nonceReportSent > 0) {
attempts = m_nonceReportSentAttempt++;
nodeId = m_nonceReportSent;
} else {
attempts = m_currentMsg->GetSendAttempts();
nodeId = m_currentMsg->GetTargetNodeId();
}
LockGuard LG(m_nodeMutex);
Node* node = GetNode( nodeId );
if( attempts >= m_currentMsg->GetMaxSendAttempts() ||
(node != NULL && !node->IsNodeAlive() && !m_currentMsg->IsNoOperation() ) )
{
if( node != NULL && !node->IsNodeAlive() )
{
Log::Write( LogLevel_Error, nodeId, "ERROR: Dropping command because node is presumed dead" );
}
else
{
Log::Write( LogLevel_Error, nodeId, "ERROR: Dropping command, expected response not received after %d attempt(s)", m_currentMsg->GetMaxSendAttempts() );
}
if( m_currentControllerCommand != NULL )
{
UpdateControllerState( ControllerState_Error, ControllerError_Failed);
}
RemoveCurrentMsg();
m_dropped++;
return false;
}
if (( attempts != 0) && (m_nonceReportSent == 0))
{
m_currentMsg->UpdateCallbackId();
}
if (m_nonceReportSent == 0) {
if (m_currentMsg->isEncrypted() && !m_currentMsg->isNonceRecieved()) {
m_currentMsg->SetSendAttempts( ++attempts );
} else if (!m_currentMsg->isEncrypted() ) {
m_currentMsg->SetSendAttempts( ++attempts );
}
m_expectedCallbackId = m_currentMsg->GetCallbackId();
m_expectedCommandClassId = m_currentMsg->GetExpectedCommandClassId();
m_expectedNodeId = m_currentMsg->GetTargetNodeId();
m_expectedReply = m_currentMsg->GetExpectedReply();
m_waitingForAck = true;
}
string attemptsstr = "";
if( attempts > 1 )
{
char buf[15];
snprintf( buf, sizeof(buf), "Attempt %d, ", attempts );
attemptsstr = buf;
m_retries++;
if( node != NULL )
{
node->m_retries++;
}
}
Log::Write( LogLevel_Detail, "" );
if (m_nonceReportSent > 0) {
SendNonceKey(m_nonceReportSent, node->GenerateNonceKey());
} else if (m_currentMsg->isEncrypted()) {
if (m_currentMsg->isNonceRecieved()) {
Log::Write( LogLevel_Info, nodeId, "Processing (%s) Encrypted message (%sCallback ID=0x%.2x, Expected Reply=0x%.2x) - %s", c_sendQueueNames[m_currentMsgQueueSource], attemptsstr.c_str(), m_expectedCallbackId, m_expectedReply, m_currentMsg->GetAsString().c_str() );
SendEncryptedMessage();
} else {
Log::Write( LogLevel_Info, nodeId, "Processing (%s) Nonce Request message (%sCallback ID=0x%.2x, Expected Reply=0x%.2x)", c_sendQueueNames[m_currentMsgQueueSource], attemptsstr.c_str(), m_expectedCallbackId, m_expectedReply);
SendNonceRequest(m_currentMsg->GetLogText());
}
} else {
Log::Write( LogLevel_Info, nodeId, "Sending (%s) message (%sCallback ID=0x%.2x, Expected Reply=0x%.2x) - %s", c_sendQueueNames[m_currentMsgQueueSource], attemptsstr.c_str(), m_expectedCallbackId, m_expectedReply, m_currentMsg->GetAsString().c_str() );
uint32 bytesWritten = m_controller->Write(m_currentMsg->GetBuffer(), m_currentMsg->GetLength());
if (bytesWritten == 0)
{
Notification* notification = new Notification(Notification::Type_DriverFailed);
notification->SetHomeAndNodeIds(m_homeId, m_currentMsg->GetTargetNodeId());
QueueNotification(notification);
NotifyWatchers();
m_driverThread->Stop();
return false;
}
}
m_writeCnt++;
if( nodeId == 0xff )
{
m_broadcastWriteCnt++; }
else
{
if( node != NULL )
{
node->m_sentCnt++;
node->m_sentTS.SetTime();
if( m_expectedReply == FUNC_ID_APPLICATION_COMMAND_HANDLER )
{
CommandClass *cc = node->GetCommandClass(m_expectedCommandClassId);
if( cc != NULL )
{
cc->SentCntIncr();
}
}
}
}
return true;
}
void Driver::RemoveCurrentMsg
(
)
{
Log::Write( LogLevel_Detail, GetNodeNumber( m_currentMsg ), "Removing current message" );
if( m_currentMsg != NULL)
{
delete m_currentMsg;
m_currentMsg = NULL;
}
m_expectedCallbackId = 0;
m_expectedCommandClassId = 0;
m_expectedNodeId = 0;
m_expectedReply = 0;
m_waitingForAck = false;
m_nonceReportSent = 0;
m_nonceReportSentAttempt = 0;
}
bool Driver::MoveMessagesToWakeUpQueue
(
uint8 const _targetNodeId,
bool const _move
)
{
if( Node* node = GetNodeUnsafe(_targetNodeId) )
{
if( !node->IsListeningDevice() && !node->IsFrequentListeningDevice() && _targetNodeId != m_Controller_nodeId )
{
if( WakeUp* wakeUp = static_cast<WakeUp*>( node->GetCommandClass( WakeUp::StaticGetCommandClassId() ) ) )
{
wakeUp->SetAwake( false );
if( _move )
{
m_sendMutex->Lock();
if( m_currentControllerCommand )
{
RemoveCurrentMsg();
}
if( m_currentMsg )
{
if( _targetNodeId == m_currentMsg->GetTargetNodeId() )
{
if( !m_currentMsg->IsWakeUpNoMoreInformationCommand() && !m_currentMsg->IsNoOperation() )
{
Log::Write( LogLevel_Info, _targetNodeId, "Node not responding - moving message to Wake-Up queue: %s", m_currentMsg->GetAsString().c_str() );
m_currentMsg->SetSendAttempts(0);
MsgQueueItem item;
item.m_command = MsgQueueCmd_SendMsg;
item.m_msg = m_currentMsg;
wakeUp->QueueMsg( item );
}
else
{
delete m_currentMsg;
}
m_currentMsg = NULL;
m_expectedCallbackId = 0;
m_expectedCommandClassId = 0;
m_expectedNodeId = 0;
m_expectedReply = 0;
m_waitingForAck = false;
}
}
for( int i=0; i<MsgQueue_Count; ++i )
{
list<MsgQueueItem>::iterator it = m_msgQueue[i].begin();
while( it != m_msgQueue[i].end() )
{
bool remove = false;
MsgQueueItem const& item = *it;
if( MsgQueueCmd_SendMsg == item.m_command )
{
if( _targetNodeId == item.m_msg->GetTargetNodeId() )
{
if( !item.m_msg->IsWakeUpNoMoreInformationCommand() && !item.m_msg->IsNoOperation() )
{
Log::Write( LogLevel_Info, item.m_msg->GetTargetNodeId(), "Node not responding - moving message to Wake-Up queue: %s", item.m_msg->GetAsString().c_str() );
item.m_msg->SetSendAttempts(0);
wakeUp->QueueMsg( item );
}
else
{
delete item.m_msg;
}
remove = true;
}
}
if( MsgQueueCmd_QueryStageComplete == item.m_command )
{
if( _targetNodeId == item.m_nodeId )
{
Log::Write( LogLevel_Info, _targetNodeId, "Node not responding - moving QueryStageComplete command to Wake-Up queue" );
wakeUp->QueueMsg( item );
remove = true;
}
}
if( MsgQueueCmd_Controller == item.m_command )
{
if( _targetNodeId == item.m_cci->m_controllerCommandNode )
{
Log::Write( LogLevel_Info, _targetNodeId, "Node not responding - moving controller command to Wake-Up queue: %s", c_controllerCommandNames[item.m_cci->m_controllerCommand] );
wakeUp->QueueMsg( item );
remove = true;
}
}
if( remove )
{
it = m_msgQueue[i].erase( it );
}
else
{
++it;
}
}
if( m_msgQueue[i].empty() )
{
m_queueEvent[i]->Reset();
}
}
if( m_currentControllerCommand )
{
UpdateControllerState( ControllerState_Sleeping );
MsgQueueItem item;
item.m_command = MsgQueueCmd_Controller;
item.m_cci = new ControllerCommandItem( *m_currentControllerCommand );
m_currentControllerCommand = item.m_cci;
m_msgQueue[MsgQueue_Controller].push_back( item );
m_queueEvent[MsgQueue_Controller]->Set();
}
m_sendMutex->Unlock();
return true;
}
}
}
}
return false;
}
bool Driver::HandleErrorResponse
(
uint8 const _error,
uint8 const _nodeId,
char const* _funcStr,
bool _sleepCheck )
{
if( _error == TRANSMIT_COMPLETE_NOROUTE )
{
m_badroutes++;
Log::Write( LogLevel_Info, _nodeId, "ERROR: %s failed. No route available.", _funcStr );
}
else if( _error == TRANSMIT_COMPLETE_NO_ACK )
{
m_noack++;
Log::Write( LogLevel_Info, _nodeId, "WARNING: %s failed. No ACK received - device may be asleep.", _funcStr );
if( m_currentMsg )
{
if( MoveMessagesToWakeUpQueue( m_currentMsg->GetTargetNodeId(), _sleepCheck ) )
{
return true;
}
Log::Write( LogLevel_Warning, _nodeId, "WARNING: Device is not a sleeping node." );
}
}
else if( _error == TRANSMIT_COMPLETE_FAIL )
{
m_netbusy++;
Log::Write( LogLevel_Info, _nodeId, "ERROR: %s failed. Network is busy.", _funcStr );
}
else if( _error == TRANSMIT_COMPLETE_NOT_IDLE )
{
m_notidle++;
Log::Write( LogLevel_Info, _nodeId, "ERROR: %s failed. Network is busy.", _funcStr );
}
if( Node* node = GetNodeUnsafe( _nodeId ) )
{
if( ++node->m_errors >= 3 )
{
node->SetNodeAlive( false );
}
}
return false;
}
void Driver::CheckCompletedNodeQueries
(
)
{
Log::Write( LogLevel_Warning, "CheckCompletedNodeQueries m_allNodesQueried=%d m_awakeNodesQueried=%d", m_allNodesQueried, m_awakeNodesQueried );
if( !m_allNodesQueried )
{
bool all = true;
bool sleepingOnly = true;
bool deadFound = false;
LockGuard LG(m_nodeMutex);
for( int i=0; i<256; ++i )
{
if( m_nodes[i] )
{
if( m_nodes[i]->GetCurrentQueryStage() != Node::QueryStage_Complete )
{
if ( !m_nodes[i]->IsNodeAlive() )
{
deadFound = true;
continue;
}
all = false;
if( m_nodes[i]->IsListeningDevice() )
{
sleepingOnly = false;
}
}
}
}
LG.Unlock();
Log::Write( LogLevel_Warning, "CheckCompletedNodeQueries all=%d, deadFound=%d sleepingOnly=%d", all, deadFound, sleepingOnly );
if( all )
{
if( deadFound )
{
Log::Write( LogLevel_Info, " Node query processing complete except for dead nodes." );
Notification* notification = new Notification( Notification::Type_AllNodesQueriedSomeDead );
notification->SetHomeAndNodeIds( m_homeId, 0xff );
QueueNotification( notification );
}
else
{
Log::Write( LogLevel_Info, " Node query processing complete." );
Notification* notification = new Notification( Notification::Type_AllNodesQueried );
notification->SetHomeAndNodeIds( m_homeId, 0xff );
QueueNotification( notification );
}
m_awakeNodesQueried = true;
m_allNodesQueried = true;
}
else if( sleepingOnly )
{
if (!m_awakeNodesQueried )
{
Log::Write( LogLevel_Info, " Node query processing complete except for sleeping nodes." );
Notification* notification = new Notification( Notification::Type_AwakeNodesQueried );
notification->SetHomeAndNodeIds( m_homeId, 0xff );
QueueNotification( notification );
m_awakeNodesQueried = true;
}
}
}
}
bool Driver::IsExpectedReply
(
const uint8 _nodeId
)
{
if( m_expectedNodeId == 255 || _nodeId == 0 )
{
return true;
}
if( m_expectedReply == FUNC_ID_ZW_GET_NODE_PROTOCOL_INFO ||
m_expectedReply == FUNC_ID_ZW_REQUEST_NODE_INFO ||
m_expectedReply == FUNC_ID_ZW_GET_ROUTING_INFO ||
m_expectedReply == FUNC_ID_ZW_ASSIGN_RETURN_ROUTE ||
m_expectedReply == FUNC_ID_ZW_DELETE_RETURN_ROUTE ||
m_expectedReply == FUNC_ID_ZW_SEND_DATA ||
m_expectedReply == FUNC_ID_ZW_SEND_NODE_INFORMATION ||
m_expectedReply == FUNC_ID_ZW_REQUEST_NODE_NEIGHBOR_UPDATE ||
m_expectedReply == FUNC_ID_ZW_ENABLE_SUC ||
m_expectedReply == FUNC_ID_ZW_SET_SUC_NODE_ID ||
m_expectedReply == FUNC_ID_ZW_REQUEST_NODE_NEIGHBOR_UPDATE_OPTIONS )
{
return true;
}
if( m_expectedNodeId == _nodeId )
{
return true;
}
Log::Write( LogLevel_Detail, "IsExpectedReply: m_expectedNodeId = %d m_expectedReply = %02x", m_expectedNodeId, m_expectedReply );
return false;
}
bool Driver::ReadMsg
(
)
{
uint8 buffer[1024] = {0};
if( !m_controller->Read( buffer, 1 ) )
{
return false;
}
switch( buffer[0] )
{
case SOF:
{
m_SOFCnt++;
if( m_waitingForAck )
{
Log::Write( LogLevel_Detail, "Unsolicited message received while waiting for ACK." );
m_ACKWaiting++;
}
m_controller->SetSignalThreshold( 1 );
int32 response = Wait::Single( m_controller, 50 );
if( response < 0 )
{
Log::Write( LogLevel_Warning, "WARNING: 50ms passed without finding the length byte...aborting frame read");
m_readAborts++;
break;
}
m_controller->Read( &buffer[1], 1 );
m_controller->SetSignalThreshold( buffer[1] );
if( Wait::Single( m_controller, 500 ) < 0 )
{
Log::Write( LogLevel_Warning, "WARNING: 500ms passed without reading the rest of the frame...aborting frame read" );
m_readAborts++;
m_controller->SetSignalThreshold( 1 );
break;
}
m_controller->Read( &buffer[2], buffer[1] );
m_controller->SetSignalThreshold( 1 );
uint32 length = buffer[1] + 2;
string str = "";
for( uint32 i=0; i<length; ++i )
{
if( i )
{
str += ", ";
}
char byteStr[8];
snprintf( byteStr, sizeof(byteStr), "0x%.2x", buffer[i] );
str += byteStr;
}
uint8 nodeId = NodeFromMessage( buffer );
if( nodeId == 0 )
{
nodeId = GetNodeNumber( m_currentMsg );
}
Log::Write( LogLevel_Detail, nodeId, " Received: %s", str.c_str() );
uint8 checksum = 0xff;
for( uint32 i=1; i<(length-1); ++i )
{
checksum ^= buffer[i];
}
if( buffer[length-1] == checksum )
{
uint8 ack = ACK;
m_controller->Write( &ack, 1 );
m_readCnt++;
ProcessMsg( &buffer[2] );
}
else
{
Log::Write( LogLevel_Warning, nodeId, "WARNING: Checksum incorrect - sending NAK" );
m_badChecksum++;
uint8 nak = NAK;
m_controller->Write( &nak, 1 );
m_controller->Purge();
}
break;
}
case CAN:
{
Log::Write( LogLevel_Detail, GetNodeNumber( m_currentMsg ), "CAN received...triggering resend" );
m_CANCnt++;
if( m_currentMsg != NULL )
{
m_currentMsg->SetMaxSendAttempts( m_currentMsg->GetMaxSendAttempts() + 1 );
}
else
{
Log::Write( LogLevel_Warning, "m_currentMsg was NULL when trying to set MaxSendAttempts" );
Log::QueueDump();
}
WriteMsg( "CAN" );
break;
}
case NAK:
{
Log::Write( LogLevel_Warning, GetNodeNumber( m_currentMsg ), "WARNING: NAK received...triggering resend" );
m_NAKCnt++;
WriteMsg( "NAK" );
break;
}
case ACK:
{
m_ACKCnt++;
m_waitingForAck = false;
if( m_currentMsg == NULL )
{
Log::Write( LogLevel_StreamDetail, 255, " ACK received" );
}
else
{
Log::Write( LogLevel_StreamDetail, GetNodeNumber( m_currentMsg ), " ACK received CallbackId 0x%.2x Reply 0x%.2x", m_expectedCallbackId, m_expectedReply );
if( ( 0 == m_expectedCallbackId ) && ( 0 == m_expectedReply ) )
{
RemoveCurrentMsg();
}
}
break;
}
default:
{
Log::Write( LogLevel_Warning, "WARNING: Out of frame flow! (0x%.2x). Sending NAK.", buffer[0] );
m_OOFCnt++;
uint8 nak = NAK;
m_controller->Write( &nak, 1 );
m_controller->Purge();
break;
}
}
return true;
}
void Driver::ProcessMsg
(
uint8* _data
)
{
bool handleCallback = true;
bool wasencrypted = false;
if ((REQUEST == _data[0]) &&
(Security::StaticGetCommandClassId() == _data[5])) {
if (SecurityCmd_NonceReport == _data[6]) {
Log::Write(LogLevel_Info, _data[3], "Received SecurityCmd_NonceReport from node %d", _data[3] );
m_currentMsg->setNonce(&_data[7]);
this->SendEncryptedMessage();
return;
} else if (SecurityCmd_NonceGet == _data[6]) {
Log::Write(LogLevel_Info, _data[3], "Received SecurityCmd_NonceGet from node %d", _data[3] );
{
uint8 *nonce = NULL;
LockGuard LG(m_nodeMutex);
Node* node = GetNode( _data[3] );
if( node ) {
nonce = node->GenerateNonceKey();
} else {
Log::Write(LogLevel_Warning, _data[3], "Couldn't Generate Nonce Key for Node %d", _data[3]);
return;
}
SendNonceKey(_data[3], nonce);
}
return;
} else if ((SecurityCmd_MessageEncap == _data[6]) || (SecurityCmd_MessageEncapNonceGet == _data[6])) {
uint8 _newdata[256];
uint8 *_nonce;
m_nonceReportSent = 0;
m_nonceReportSentAttempt = 0;
{
LockGuard LG(m_nodeMutex);
Node* node = GetNode( _data[3] );
if( node ) {
_nonce = node->GetNonceKey(_data[_data[4]-4]);
if (!_nonce) {
Log::Write(LogLevel_Warning, _data[3], "Could Not Retrieve Nonce for Node %d", _data[3]);
return;
}
} else {
Log::Write(LogLevel_Warning, _data[3], "Can't Find Node %d for Encrypted Message", _data[3]);
return;
}
}
if (DecryptBuffer(&_data[5], _data[4]+1, this, _data[3], this->GetControllerNodeId(), _nonce, &_newdata[0])) {
_data[4] = _data[4] - 8 - 8 - 2 - 2;
memcpy(&_data[5], &_newdata[1], _data[4]);
if (SecurityCmd_MessageEncapNonceGet == _data[6])
{
Log::Write(LogLevel_Info, _data[3], "Received SecurityCmd_MessageEncapNonceGet from node %d - Sending New Nonce", _data[3] );
LockGuard LG(m_nodeMutex);
Node* node = GetNode( _data[3] );
if( node ) {
_nonce = node->GenerateNonceKey();
} else {
Log::Write(LogLevel_Warning, _data[3], "Couldn't Generate Nonce Key for Node %d", _data[3]);
return;
}
SendNonceKey(_data[3], _nonce);
}
wasencrypted = true;
} else {
m_expectedReply = 0;
m_expectedNodeId = 0;
RemoveCurrentMsg();
return;
}
}
}
if( RESPONSE == _data[0] )
{
switch( _data[1] )
{
case FUNC_ID_SERIAL_API_GET_INIT_DATA:
{
Log::Write( LogLevel_Detail, "" );
HandleSerialAPIGetInitDataResponse( _data );
break;
}
case FUNC_ID_ZW_GET_CONTROLLER_CAPABILITIES:
{
Log::Write( LogLevel_Detail, "" );
HandleGetControllerCapabilitiesResponse( _data );
break;
}
case FUNC_ID_SERIAL_API_GET_CAPABILITIES:
{
Log::Write( LogLevel_Detail, "" );
HandleGetSerialAPICapabilitiesResponse( _data );
break;
}
case FUNC_ID_SERIAL_API_SOFT_RESET:
{
Log::Write( LogLevel_Detail, "" );
HandleSerialAPISoftResetResponse( _data );
break;
}
case FUNC_ID_ZW_SEND_DATA:
{
HandleSendDataResponse( _data, false );
handleCallback = false; break;
}
case FUNC_ID_ZW_GET_VERSION:
{
Log::Write( LogLevel_Detail, "" );
HandleGetVersionResponse( _data );
break;
}
case FUNC_ID_ZW_GET_RANDOM:
{
Log::Write( LogLevel_Detail, "" );
HandleGetRandomResponse( _data );
break;
}
case FUNC_ID_ZW_MEMORY_GET_ID:
{
Log::Write( LogLevel_Detail, "" );
HandleMemoryGetIdResponse( _data );
break;
}
case FUNC_ID_ZW_GET_NODE_PROTOCOL_INFO:
{
Log::Write( LogLevel_Detail, "" );
HandleGetNodeProtocolInfoResponse( _data );
break;
}
case FUNC_ID_ZW_REPLICATION_SEND_DATA:
{
HandleSendDataResponse( _data, true );
handleCallback = false; break;
}
case FUNC_ID_ZW_ASSIGN_RETURN_ROUTE:
{
Log::Write( LogLevel_Detail, "" );
if( !HandleAssignReturnRouteResponse( _data ) )
{
m_expectedCallbackId = _data[2]; m_expectedReply = 0;
m_expectedCommandClassId = 0;
m_expectedNodeId = 0;
}
break;
}
case FUNC_ID_ZW_DELETE_RETURN_ROUTE:
{
Log::Write( LogLevel_Detail, "" );
if( !HandleDeleteReturnRouteResponse( _data ) )
{
m_expectedCallbackId = _data[2]; m_expectedReply = 0;
m_expectedCommandClassId = 0;
m_expectedNodeId = 0;
}
break;
}
case FUNC_ID_ZW_ENABLE_SUC:
{
Log::Write( LogLevel_Detail, "" );
HandleEnableSUCResponse( _data );
break;
}
case FUNC_ID_ZW_REQUEST_NETWORK_UPDATE:
{
Log::Write( LogLevel_Detail, "" );
if( !HandleNetworkUpdateResponse( _data ) )
{
m_expectedCallbackId = _data[2]; m_expectedReply = 0;
m_expectedCommandClassId = 0;
m_expectedNodeId = 0;
}
break;
}
case FUNC_ID_ZW_SET_SUC_NODE_ID:
{
Log::Write( LogLevel_Detail, "" );
HandleSetSUCNodeIdResponse( _data );
break;
}
case FUNC_ID_ZW_GET_SUC_NODE_ID:
{
Log::Write( LogLevel_Detail, "" );
HandleGetSUCNodeIdResponse( _data );
break;
}
case FUNC_ID_ZW_REQUEST_NODE_INFO:
{
Log::Write( LogLevel_Detail, "" );
if( _data[2] )
{
Log::Write( LogLevel_Info, _data[3], "FUNC_ID_ZW_REQUEST_NODE_INFO Request successful." );
}
else
{
Log::Write( LogLevel_Info, _data[3], "FUNC_ID_ZW_REQUEST_NODE_INFO Request failed." );
}
break;
}
case FUNC_ID_ZW_REMOVE_FAILED_NODE_ID:
{
Log::Write( LogLevel_Detail, "" );
if( !HandleRemoveFailedNodeResponse( _data ) )
{
m_expectedCallbackId = _data[2]; m_expectedReply = 0;
m_expectedCommandClassId = 0;
m_expectedNodeId = 0;
}
break;
}
case FUNC_ID_ZW_IS_FAILED_NODE_ID:
{
Log::Write( LogLevel_Detail, "" );
HandleIsFailedNodeResponse( _data );
break;
}
case FUNC_ID_ZW_REPLACE_FAILED_NODE:
{
Log::Write( LogLevel_Detail, "" );
if( !HandleReplaceFailedNodeResponse( _data ) )
{
m_expectedCallbackId = _data[2]; m_expectedReply = 0;
m_expectedCommandClassId = 0;
m_expectedNodeId = 0;
}
break;
}
case FUNC_ID_ZW_GET_ROUTING_INFO:
{
Log::Write( LogLevel_Detail, "" );
HandleGetRoutingInfoResponse( _data );
break;
}
case FUNC_ID_ZW_R_F_POWER_LEVEL_SET:
{
Log::Write( LogLevel_Detail, "" );
HandleRfPowerLevelSetResponse( _data );
break;
}
case FUNC_ID_ZW_READ_MEMORY:
{
Log::Write( LogLevel_Detail, "" );
HandleReadMemoryResponse( _data );
break;
}
case FUNC_ID_SERIAL_API_SET_TIMEOUTS:
{
Log::Write( LogLevel_Detail, "" );
HandleSerialApiSetTimeoutsResponse( _data );
break;
}
case FUNC_ID_MEMORY_GET_BYTE:
{
Log::Write( LogLevel_Detail, "" );
HandleMemoryGetByteResponse( _data );
break;
}
case FUNC_ID_ZW_GET_VIRTUAL_NODES:
{
Log::Write( LogLevel_Detail, "" );
HandleGetVirtualNodesResponse( _data );
break;
}
case FUNC_ID_ZW_SET_SLAVE_LEARN_MODE:
{
Log::Write( LogLevel_Detail, "" );
if( !HandleSetSlaveLearnModeResponse( _data ) )
{
m_expectedCallbackId = _data[2]; m_expectedReply = 0;
m_expectedCommandClassId = 0;
m_expectedNodeId = 0;
}
break;
}
case FUNC_ID_ZW_SEND_SLAVE_NODE_INFO:
{
Log::Write( LogLevel_Detail, "" );
if( !HandleSendSlaveNodeInfoResponse( _data ) )
{
m_expectedCallbackId = _data[2]; m_expectedReply = 0;
m_expectedCommandClassId = 0;
m_expectedNodeId = 0;
}
break;
}
default:
{
Log::Write( LogLevel_Detail, "" );
Log::Write( LogLevel_Info, "**TODO: handle response for 0x%.2x** Please report this message.", _data[1] );
break;
}
}
}
else if( REQUEST == _data[0] )
{
switch( _data[1] )
{
case FUNC_ID_APPLICATION_COMMAND_HANDLER:
{
Log::Write( LogLevel_Detail, "" );
HandleApplicationCommandHandlerRequest( _data, wasencrypted );
break;
}
case FUNC_ID_ZW_SEND_DATA:
{
HandleSendDataRequest( _data, false );
break;
}
case FUNC_ID_ZW_REPLICATION_COMMAND_COMPLETE:
{
if( m_controllerReplication )
{
Log::Write( LogLevel_Detail, "" );
m_controllerReplication->SendNextData();
}
break;
}
case FUNC_ID_ZW_REPLICATION_SEND_DATA:
{
HandleSendDataRequest( _data, true );
break;
}
case FUNC_ID_ZW_ASSIGN_RETURN_ROUTE:
{
Log::Write( LogLevel_Detail, "" );
HandleAssignReturnRouteRequest( _data );
break;
}
case FUNC_ID_ZW_DELETE_RETURN_ROUTE:
{
Log::Write( LogLevel_Detail, "" );
HandleDeleteReturnRouteRequest( _data );
break;
}
case FUNC_ID_ZW_SEND_NODE_INFORMATION:
{
Log::Write( LogLevel_Detail, "" );
HandleSendNodeInformationRequest( _data );
break;
}
case FUNC_ID_ZW_REQUEST_NODE_NEIGHBOR_UPDATE:
case FUNC_ID_ZW_REQUEST_NODE_NEIGHBOR_UPDATE_OPTIONS:
{
Log::Write( LogLevel_Detail, "" );
HandleNodeNeighborUpdateRequest( _data );
break;
}
case FUNC_ID_ZW_APPLICATION_UPDATE:
{
Log::Write( LogLevel_Detail, "" );
handleCallback = !HandleApplicationUpdateRequest( _data );
break;
}
case FUNC_ID_ZW_ADD_NODE_TO_NETWORK:
{
Log::Write( LogLevel_Detail, "" );
HandleAddNodeToNetworkRequest( _data );
break;
}
case FUNC_ID_ZW_REMOVE_NODE_FROM_NETWORK:
{
Log::Write( LogLevel_Detail, "" );
HandleRemoveNodeFromNetworkRequest( _data );
break;
}
case FUNC_ID_ZW_CREATE_NEW_PRIMARY:
{
Log::Write( LogLevel_Detail, "" );
HandleCreateNewPrimaryRequest( _data );
break;
}
case FUNC_ID_ZW_CONTROLLER_CHANGE:
{
Log::Write( LogLevel_Detail, "" );
HandleControllerChangeRequest( _data );
break;
}
case FUNC_ID_ZW_SET_LEARN_MODE:
{
Log::Write( LogLevel_Detail, "" );
HandleSetLearnModeRequest( _data );
break;
}
case FUNC_ID_ZW_REQUEST_NETWORK_UPDATE:
{
Log::Write( LogLevel_Detail, "" );
HandleNetworkUpdateRequest( _data );
break;
}
case FUNC_ID_ZW_REMOVE_FAILED_NODE_ID:
{
Log::Write( LogLevel_Detail, "" );
HandleRemoveFailedNodeRequest( _data );
break;
}
case FUNC_ID_ZW_REPLACE_FAILED_NODE:
{
Log::Write( LogLevel_Detail, "" );
HandleReplaceFailedNodeRequest( _data );
break;
}
case FUNC_ID_ZW_SET_SLAVE_LEARN_MODE:
{
Log::Write( LogLevel_Detail, "" );
HandleSetSlaveLearnModeRequest( _data );
break;
}
case FUNC_ID_ZW_SEND_SLAVE_NODE_INFO:
{
Log::Write( LogLevel_Detail, "" );
HandleSendSlaveNodeInfoRequest( _data );
break;
}
case FUNC_ID_APPLICATION_SLAVE_COMMAND_HANDLER:
{
Log::Write( LogLevel_Detail, "" );
HandleApplicationSlaveCommandRequest( _data );
break;
}
case FUNC_ID_PROMISCUOUS_APPLICATION_COMMAND_HANDLER:
{
Log::Write( LogLevel_Detail, "" );
HandlePromiscuousApplicationCommandHandlerRequest( _data );
break;
}
case FUNC_ID_ZW_SET_DEFAULT:
{
Log::Write( LogLevel_Detail, "" );
HandleSerialAPIResetRequest( _data );
break;
}
default:
{
Log::Write( LogLevel_Detail, "" );
Log::Write( LogLevel_Info, "**TODO: handle request for 0x%.2x** Please report this message.", _data[1] );
break;
}
}
}
if( handleCallback )
{
if( ( m_expectedCallbackId || m_expectedReply ) )
{
if( m_expectedCallbackId )
{
if( m_expectedCallbackId == _data[2] )
{
Log::Write( LogLevel_Detail, _data[3], " Expected callbackId was received" );
m_expectedCallbackId = 0;
} else if (_data[2] == 0x02 || _data[2] == 0x01) {
return;
}
}
if( m_expectedReply )
{
if( m_expectedReply == _data[1] )
{
if( m_expectedCommandClassId && ( m_expectedReply == FUNC_ID_APPLICATION_COMMAND_HANDLER ) )
{
if( m_expectedCallbackId == 0 && m_expectedCommandClassId == _data[5] && m_expectedNodeId == _data[3] )
{
Log::Write( LogLevel_Detail, _data[3], " Expected reply and command class was received" );
m_waitingForAck = false;
m_expectedReply = 0;
m_expectedCommandClassId = 0;
m_expectedNodeId = 0;
}
}
else
{
if( IsExpectedReply( _data[3] ) )
{
Log::Write( LogLevel_Detail, _data[3], " Expected reply was received" );
m_expectedReply = 0;
m_expectedNodeId = 0;
}
}
}
}
if( !( m_expectedCallbackId || m_expectedReply ) )
{
Log::Write( LogLevel_Detail, _data[3], " Message transaction complete" );
Log::Write( LogLevel_Detail, "" );
if( m_notifytransactions )
{
Notification* notification = new Notification( Notification::Type_Notification );
notification->SetHomeAndNodeIds( m_homeId, _data[3] );
notification->SetNotification( Notification::Code_MsgComplete );
QueueNotification( notification );
}
RemoveCurrentMsg();
}
}
}
}
void Driver::HandleGetVersionResponse
(
uint8* _data
)
{
m_libraryVersion = (char*)&_data[2];
m_libraryType = _data[m_libraryVersion.size()+3];
if( m_libraryType < 9 )
{
m_libraryTypeName = c_libraryTypeNames[m_libraryType];
}
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "Received reply to FUNC_ID_ZW_GET_VERSION:" );
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), " %s library, version %s", m_libraryTypeName.c_str(), m_libraryVersion.c_str() );
}
void Driver::HandleGetRandomResponse
(
uint8* _data
)
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "Received reply to FUNC_ID_ZW_GET_RANDOM: %s", _data[2] ? "true" : "false" );
}
void Driver::HandleGetControllerCapabilitiesResponse
(
uint8* _data
)
{
m_controllerCaps = _data[2];
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "Received reply to FUNC_ID_ZW_GET_CONTROLLER_CAPABILITIES:" );
char str[256];
if( m_controllerCaps & ControllerCaps_SIS )
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), " There is a SUC ID Server (SIS) in this network." );
snprintf( str, sizeof(str), " The PC controller is an inclusion %s%s%s",
( m_controllerCaps & ControllerCaps_SUC ) ? "static update controller (SUC)" : "controller",
( m_controllerCaps & ControllerCaps_OnOtherNetwork ) ? " which is using a Home ID from another network" : "",
( m_controllerCaps & ControllerCaps_RealPrimary ) ? " and was the original primary before the SIS was added." : "." );
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), str );
}
else
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), " There is no SUC ID Server (SIS) in this network." );
snprintf( str, sizeof(str), " The PC controller is a %s%s%s",
( m_controllerCaps & ControllerCaps_Secondary ) ? "secondary" : "primary",
( m_controllerCaps & ControllerCaps_SUC ) ? " static update controller (SUC)" : " controller",
( m_controllerCaps & ControllerCaps_OnOtherNetwork ) ? " which is using a Home ID from another network." : "." );
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), str );
}
}
void Driver::HandleGetSerialAPICapabilitiesResponse
(
uint8* _data
)
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), " Received reply to FUNC_ID_SERIAL_API_GET_CAPABILITIES" );
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), " Serial API Version: %d.%d", _data[2], _data[3] );
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), " Manufacturer ID: 0x%.2x%.2x", _data[4], _data[5] );
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), " Product Type: 0x%.2x%.2x", _data[6], _data[7] );
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), " Product ID: 0x%.2x%.2x", _data[8], _data[9] );
m_serialAPIVersion[0] = _data[2];
m_serialAPIVersion[1] = _data[3];
m_manufacturerId = ( ( (uint16)_data[4] )<<8) | (uint16)_data[5];
m_productType = ( ( (uint16)_data[6] )<<8 ) | (uint16)_data[7];
m_productId = ( ( (uint16)_data[8] )<<8 ) | (uint16)_data[9];
memcpy( m_apiMask, &_data[10], sizeof( m_apiMask ) );
if( IsBridgeController() )
{
SendMsg( new Msg( "FUNC_ID_ZW_GET_VIRTUAL_NODES", 0xff, REQUEST, FUNC_ID_ZW_GET_VIRTUAL_NODES, false ), MsgQueue_Command);
}
else if( IsAPICallSupported( FUNC_ID_ZW_GET_RANDOM ) )
{
Msg *msg = new Msg( "FUNC_ID_ZW_GET_RANDOM", 0xff, REQUEST, FUNC_ID_ZW_GET_RANDOM, false );
msg->Append( 32 ); SendMsg( msg, MsgQueue_Command );
}
SendMsg( new Msg( "FUNC_ID_SERIAL_API_GET_INIT_DATA", 0xff, REQUEST, FUNC_ID_SERIAL_API_GET_INIT_DATA, false ), MsgQueue_Command);
if( !IsBridgeController() )
{
Msg* msg = new Msg( "FUNC_ID_SERIAL_API_SET_TIMEOUTS", 0xff, REQUEST, FUNC_ID_SERIAL_API_SET_TIMEOUTS, false );
msg->Append( ACK_TIMEOUT / 10 );
msg->Append( BYTE_TIMEOUT / 10 );
SendMsg( msg, MsgQueue_Command );
}
Msg* msg = new Msg( "FUNC_ID_SERIAL_API_APPL_NODE_INFORMATION", 0xff, REQUEST, FUNC_ID_SERIAL_API_APPL_NODE_INFORMATION, false, false );
msg->Append( APPLICATION_NODEINFO_LISTENING );
msg->Append( 0x02 ); msg->Append( 0x01 ); msg->Append( 0x00 ); SendMsg( msg, MsgQueue_Command );
}
void Driver::HandleSerialAPISoftResetResponse
(
uint8* _data
)
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "Received reply to Soft Reset." );
}
void Driver::HandleSerialAPIResetRequest
(
uint8* _data
)
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "Received reply to complete Controller Reset." );
if( m_controllerResetEvent != NULL )
{
m_controllerResetEvent->Set();
m_controllerResetEvent = NULL;
}
}
void Driver::HandleEnableSUCResponse
(
uint8* _data
)
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "Received reply to Enable SUC." );
}
bool Driver::HandleNetworkUpdateResponse
(
uint8* _data
)
{
bool res = true;
ControllerState state = ControllerState_InProgress;
if( _data[2] )
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "Received reply to FUNC_ID_ZW_REQUEST_NETWORK_UPDATE - command in progress" );
}
else
{
Log::Write( LogLevel_Warning, GetNodeNumber( m_currentMsg ), "WARNING: Received reply to FUNC_ID_ZW_REQUEST_NETWORK_UPDATE - command failed" );
state = ControllerState_Failed;
res = false;
}
UpdateControllerState( state );
return res;
}
void Driver::HandleSetSUCNodeIdResponse
(
uint8* _data
)
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "Received reply to SET_SUC_NODE_ID." );
}
void Driver::HandleGetSUCNodeIdResponse
(
uint8* _data
)
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "Received reply to GET_SUC_NODE_ID. Node ID = %d", _data[2] );
m_SUCNodeId = _data[2];
if( _data[2] == 0)
{
bool enableSIS = true;
Options::Get()->GetOptionAsBool("EnableSIS", &enableSIS);
if (enableSIS) {
if (IsAPICallSupported(FUNC_ID_ZW_ENABLE_SUC) && IsAPICallSupported(FUNC_ID_ZW_SET_SUC_NODE_ID)) {
Log::Write( LogLevel_Info, " No SUC, so we become SIS" );
Msg* msg;
msg = new Msg( "Enable SUC", m_Controller_nodeId, REQUEST, FUNC_ID_ZW_ENABLE_SUC, false );
msg->Append( 1 );
msg->Append( SUC_FUNC_NODEID_SERVER ); SendMsg( msg, MsgQueue_Send );
msg = new Msg( "Set SUC node ID", m_Controller_nodeId, REQUEST, FUNC_ID_ZW_SET_SUC_NODE_ID, false );
msg->Append( m_Controller_nodeId );
msg->Append( 1 ); msg->Append( 0 ); msg->Append( SUC_FUNC_NODEID_SERVER );
SendMsg( msg, MsgQueue_Send );
} else {
Log::Write (LogLevel_Info, "Controller Does not Support SUC - Cannot Setup Controller as SUC Node");
}
} else {
Log::Write( LogLevel_Info, " No SUC, not becoming SUC as option is disabled" );
}
}
}
void Driver::HandleMemoryGetIdResponse
(
uint8* _data
)
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "Received reply to FUNC_ID_ZW_MEMORY_GET_ID. Home ID = 0x%02x%02x%02x%02x. Our node ID = %d", _data[2], _data[3], _data[4], _data[5], _data[6] );
m_homeId = ( ( (uint32)_data[2] )<<24 ) | ( ( (uint32)_data[3] )<<16 ) | ( ( (uint32)_data[4] )<<8 ) | ( (uint32)_data[5] );
m_Controller_nodeId = _data[6];
m_controllerReplication = static_cast<ControllerReplication*>(ControllerReplication::Create( m_homeId, m_Controller_nodeId ));
}
void Driver::HandleSerialAPIGetInitDataResponse
(
uint8* _data
)
{
int32 i;
if( !m_init )
{
Manager::Get()->SetDriverReady( this, true );
ReadConfig();
}
else
{
Notification* notification = new Notification( Notification::Type_DriverReset );
notification->SetHomeAndNodeIds( m_homeId, 0 );
QueueNotification( notification );
}
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "Received reply to FUNC_ID_SERIAL_API_GET_INIT_DATA:" );
m_initVersion = _data[2];
m_initCaps = _data[3];
if( _data[4] == NUM_NODE_BITFIELD_BYTES )
{
for( i=0; i<NUM_NODE_BITFIELD_BYTES; ++i)
{
for( int32 j=0; j<8; ++j )
{
uint8 nodeId = (i*8)+j+1;
if( _data[i+5] & (0x01 << j) )
{
if( IsVirtualNode( nodeId ) )
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), " Node %.3d - Virtual (ignored)", nodeId );
}
else
{
LockGuard LG(m_nodeMutex);
Node* node = GetNode( nodeId );
if( node )
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), " Node %.3d - Known", nodeId );
if( !m_init )
{
node->SetQueryStage( Node::QueryStage_CacheLoad );
}
}
else
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), " Node %.3d - New", nodeId );
Notification* notification = new Notification( Notification::Type_NodeNew );
notification->SetHomeAndNodeIds( m_homeId, nodeId );
QueueNotification( notification );
InitNode( nodeId );
}
}
}
else
{
LockGuard LG(m_nodeMutex);
if( GetNode(nodeId) )
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), " Node %.3d - Removed", nodeId );
delete m_nodes[nodeId];
m_nodes[nodeId] = NULL;
Notification* notification = new Notification( Notification::Type_NodeRemoved );
notification->SetHomeAndNodeIds( m_homeId, nodeId );
QueueNotification( notification );
}
}
}
}
}
m_init = true;
}
void Driver::HandleGetNodeProtocolInfoResponse
(
uint8* _data
)
{
if( !m_currentMsg )
{
Log::Write( LogLevel_Warning, "WARNING: Received unexpected FUNC_ID_ZW_GET_NODE_PROTOCOL_INFO message - ignoring.");
return;
}
uint8 nodeId = m_currentMsg->GetTargetNodeId();
Log::Write( LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_GET_NODE_PROTOCOL_INFO" );
if( Node* node = GetNodeUnsafe( nodeId ) )
{
node->UpdateProtocolInfo( &_data[2] );
}
}
bool Driver::HandleAssignReturnRouteResponse
(
uint8* _data
)
{
bool res = true;
ControllerState state = ControllerState_InProgress;
if( _data[2] )
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "Received reply to FUNC_ID_ZW_ASSIGN_RETURN_ROUTE - command in progress" );
}
else
{
Log::Write( LogLevel_Warning, GetNodeNumber( m_currentMsg ), "WARNING: Received reply to FUNC_ID_ZW_ASSIGN_RETURN_ROUTE - command failed" );
state = ControllerState_Failed;
res = false;
}
UpdateControllerState( state );
return res;
}
bool Driver::HandleDeleteReturnRouteResponse
(
uint8* _data
)
{
bool res = true;
ControllerState state = ControllerState_InProgress;
if( _data[2] )
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "Received reply to FUNC_ID_ZW_DELETE_RETURN_ROUTE - command in progress" );
}
else
{
Log::Write( LogLevel_Warning, GetNodeNumber( m_currentMsg ), "WARNING: Received reply to FUNC_ID_ZW_DELETE_RETURN_ROUTE - command failed" );
state = ControllerState_Failed;
res = false;
}
UpdateControllerState( state );
return res;
}
bool Driver::HandleRemoveFailedNodeResponse
(
uint8* _data
)
{
bool res = true;
ControllerState state = ControllerState_InProgress;
ControllerError error = ControllerError_None;
if( _data[2] )
{
string reason;
switch( _data[2] )
{
case FAILED_NODE_NOT_FOUND:
{
reason = "Node not found";
error = ControllerError_NotFound;
break;
}
case FAILED_NODE_REMOVE_PROCESS_BUSY:
{
reason = "Remove process busy";
error = ControllerError_Busy;
break;
}
case FAILED_NODE_REMOVE_FAIL:
{
reason = "Remove failed";
error = ControllerError_Failed;
break;
}
case FAILED_NODE_NOT_PRIMARY_CONTROLLER:
{
reason = "Not Primary Controller";
error = ControllerError_NotPrimary;
break;
}
default:
{
reason = "Command failed";
break;
}
}
Log::Write( LogLevel_Warning, GetNodeNumber( m_currentMsg ), "WARNING: Received reply to FUNC_ID_ZW_REMOVE_FAILED_NODE_ID - %s", reason.c_str() );
state = ControllerState_Failed;
res = false;
}
else
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "Received reply to FUNC_ID_ZW_REMOVE_FAILED_NODE_ID - Command in progress" );
}
UpdateControllerState( state, error );
return res;
}
void Driver::HandleIsFailedNodeResponse
(
uint8* _data
)
{
ControllerState state;
uint8 nodeId = m_currentControllerCommand ? m_currentControllerCommand->m_controllerCommandNode : GetNodeNumber( m_currentMsg );
if( _data[2] )
{
Log::Write( LogLevel_Warning, nodeId, "WARNING: Received reply to FUNC_ID_ZW_IS_FAILED_NODE_ID - node %d failed", nodeId );
state = ControllerState_NodeFailed;
if( Node* node = GetNodeUnsafe( nodeId ) )
{
if (node->IsNodeReset()) {
if (!BeginControllerCommand(Driver::ControllerCommand_RemoveFailedNode, NULL, NULL, true, nodeId, 0))
Log::Write(LogLevel_Warning, nodeId, "RemoveFailedNode for DeviceResetLocally Command Failed");
Notification* notification = new Notification( Notification::Type_NodeReset );
notification->SetHomeAndNodeIds( m_homeId, nodeId );
QueueNotification( notification );
state = ControllerState_Completed;
} else {
node->SetNodeAlive( false );
}
}
}
else
{
Log::Write( LogLevel_Warning, nodeId, "Received reply to FUNC_ID_ZW_IS_FAILED_NODE_ID - node %d has not failed", nodeId );
if( Node* node = GetNodeUnsafe( nodeId ) )
{
node->SetNodeAlive( true );
}
state = ControllerState_NodeOK;
}
UpdateControllerState( state );
}
bool Driver::HandleReplaceFailedNodeResponse
(
uint8* _data
)
{
bool res = true;
ControllerState state = ControllerState_InProgress;
if( _data[2] )
{
Log::Write( LogLevel_Warning, GetNodeNumber( m_currentMsg ), "WARNING: Received reply to FUNC_ID_ZW_REPLACE_FAILED_NODE - command failed" );
state = ControllerState_Failed;
res = false;
}
else
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "Received reply to FUNC_ID_ZW_REPLACE_FAILED_NODE - command in progress" );
}
UpdateControllerState( state );
return res;
}
void Driver::HandleSendDataResponse
(
uint8* _data,
bool _replication
)
{
if( _data[2] )
{
Log::Write( LogLevel_Detail, GetNodeNumber( m_currentMsg ), " %s delivered to Z-Wave stack", _replication ? "ZW_REPLICATION_SEND_DATA" : "ZW_SEND_DATA" );
}
else
{
Log::Write( LogLevel_Error, GetNodeNumber( m_currentMsg ), "ERROR: %s could not be delivered to Z-Wave stack", _replication ? "ZW_REPLICATION_SEND_DATA" : "ZW_SEND_DATA" );
m_nondelivery++;
if( Node* node = GetNodeUnsafe( GetNodeNumber( m_currentMsg ) ) )
{
node->m_sentFailed++;
}
}
}
void Driver::HandleGetRoutingInfoResponse
(
uint8* _data
)
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "Received reply to FUNC_ID_ZW_GET_ROUTING_INFO" );
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( GetNodeNumber( m_currentMsg ) ) )
{
memcpy( node->m_neighbors, &_data[2], 29 );
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), " Neighbors of this node are:" );
bool bNeighbors = false;
for( int by=0; by<29; by++ )
{
for( int bi=0; bi<8; bi++ )
{
if( (_data[2+by] & (0x01<<bi)) )
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), " Node %d", (by<<3)+bi+1 );
bNeighbors = true;
}
}
}
if( !bNeighbors )
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), " (none reported)" );
}
}
}
void Driver::HandleSendDataRequest
(
uint8* _data,
bool _replication
)
{
uint8 nodeId = GetNodeNumber( m_currentMsg );
Log::Write( LogLevel_Detail, nodeId, " %s Request with callback ID 0x%.2x received (expected 0x%.2x)", _replication ? "ZW_REPLICATION_SEND_DATA" : "ZW_SEND_DATA", _data[2], _data[2] < 10 ? _data[2] : m_expectedCallbackId );
if ((_data[2] > 10 ) && ( _data[2] != m_expectedCallbackId )) {
m_callbacks++;
Log::Write( LogLevel_Warning, nodeId, "WARNING: Unexpected Callback ID received" );
} else {
Node* node = GetNodeUnsafe( nodeId );
if( node != NULL )
{
if( _data[3] != 0 )
{
node->m_sentFailed++;
}
else
{
node->m_lastRequestRTT = -node->m_sentTS.TimeRemaining();
if( node->m_averageRequestRTT )
{
node->m_averageRequestRTT = ( node->m_averageRequestRTT + node->m_lastRequestRTT ) >> 1;
}
else
{
node->m_averageRequestRTT = node->m_lastRequestRTT;
}
Log::Write(LogLevel_Info, nodeId, "Request RTT %d Average Request RTT %d", node->m_lastRequestRTT, node->m_averageRequestRTT );
}
}
if( m_currentMsg && m_currentMsg->IsNoOperation() )
{
Notification* notification = new Notification( Notification::Type_Notification );
notification->SetHomeAndNodeIds( m_homeId, GetNodeNumber( m_currentMsg) );
notification->SetNotification( Notification::Code_NoOperation );
QueueNotification( notification );
}
if( _data[3] != 0 )
{
if( !HandleErrorResponse( _data[3], nodeId, _replication ? "ZW_REPLICATION_END_DATA" : "ZW_SEND_DATA", !_replication ) )
{
if( m_currentMsg && m_currentMsg->IsNoOperation() && node != NULL &&
( node->GetCurrentQueryStage() == Node::QueryStage_Probe ||
node->GetCurrentQueryStage() == Node::QueryStage_CacheLoad ) )
{
node->QueryStageRetry( node->GetCurrentQueryStage(), 3 );
}
}
}
else if( node != NULL )
{
if( m_currentMsg && m_currentMsg->IsWakeUpNoMoreInformationCommand() )
{
if( WakeUp* wakeUp = static_cast<WakeUp*>( node->GetCommandClass( WakeUp::StaticGetCommandClassId() ) ) )
{
wakeUp->SetAwake( false );
}
}
if( !node->IsNodeAlive() )
{
node->SetNodeAlive( true );
}
}
}
}
void Driver::HandleNetworkUpdateRequest
(
uint8* _data
)
{
ControllerState state = ControllerState_Failed;
ControllerError error = ControllerError_None;
uint8 nodeId = GetNodeNumber( m_currentMsg );
switch( _data[3] )
{
case SUC_UPDATE_DONE:
{
Log::Write( LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_REQUEST_NETWORK_UPDATE: Success" );
state = ControllerState_Completed;
break;
}
case SUC_UPDATE_ABORT:
{
Log::Write( LogLevel_Warning, nodeId, "WARNING: Received reply to FUNC_ID_ZW_REQUEST_NETWORK_UPDATE: Failed - Error. Process aborted." );
error = ControllerError_Failed;
break;
}
case SUC_UPDATE_WAIT:
{
Log::Write( LogLevel_Warning, nodeId, "WARNING: Received reply to FUNC_ID_ZW_REQUEST_NETWORK_UPDATE: Failed - SUC is busy." );
error = ControllerError_Busy;
break;
}
case SUC_UPDATE_DISABLED:
{
Log::Write( LogLevel_Warning, nodeId, "WARNING: Received reply to FUNC_ID_ZW_REQUEST_NETWORK_UPDATE: Failed - SUC is disabled." );
error = ControllerError_Disabled;
break;
}
case SUC_UPDATE_OVERFLOW:
{
Log::Write( LogLevel_Warning, nodeId, "WARNING: Received reply to FUNC_ID_ZW_REQUEST_NETWORK_UPDATE: Failed - Overflow. Full replication required." );
error = ControllerError_Overflow;
break;
}
default:
{
}
}
UpdateControllerState( state, error );
}
void Driver::HandleAddNodeToNetworkRequest
(
uint8* _data
)
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "FUNC_ID_ZW_ADD_NODE_TO_NETWORK:" );
CommonAddNodeStatusRequestHandler( FUNC_ID_ZW_ADD_NODE_TO_NETWORK, _data );
}
void Driver::HandleRemoveNodeFromNetworkRequest
(
uint8* _data
)
{
if( m_currentControllerCommand == NULL )
{
return;
}
ControllerState state = m_currentControllerCommand->m_controllerState;
Log::Write( LogLevel_Info, "FUNC_ID_ZW_REMOVE_NODE_FROM_NETWORK:" );
switch( _data[3] )
{
case REMOVE_NODE_STATUS_LEARN_READY:
{
Log::Write( LogLevel_Info, "REMOVE_NODE_STATUS_LEARN_READY" );
state = ControllerState_Waiting;
m_currentControllerCommand->m_controllerCommandNode = 0;
break;
}
case REMOVE_NODE_STATUS_NODE_FOUND:
{
Log::Write( LogLevel_Info, "REMOVE_NODE_STATUS_NODE_FOUND" );
state = ControllerState_InProgress;
break;
}
case REMOVE_NODE_STATUS_REMOVING_SLAVE:
{
Log::Write( LogLevel_Info, "REMOVE_NODE_STATUS_REMOVING_SLAVE" );
if (_data[4] != 0)
{
Log::Write( LogLevel_Info, "Removing node ID %d", _data[4] );
m_currentControllerCommand->m_controllerCommandNode = _data[4];
}
else
{
Log::Write( LogLevel_Warning, "Remove Node Failed - NodeID 0 Returned");
state = ControllerState_Failed;
}
break;
}
case REMOVE_NODE_STATUS_REMOVING_CONTROLLER:
{
Log::Write( LogLevel_Info, "REMOVE_NODE_STATUS_REMOVING_CONTROLLER" );
m_currentControllerCommand->m_controllerCommandNode = _data[4];
if( m_currentControllerCommand->m_controllerCommandNode == 0 ) {
if( _data[5] >= 3 )
{
LockGuard LG(m_nodeMutex);
for( int i=0; i<256; i++ )
{
if( m_nodes[i] == NULL )
{
continue;
}
if( m_nodes[i]->m_nodeId == m_Controller_nodeId )
{
continue;
}
if( m_nodes[i]->m_basic == _data[6] &&
m_nodes[i]->m_generic == _data[7] &&
m_nodes[i]->m_specific == _data[8] )
{
if( m_currentControllerCommand->m_controllerCommandNode != 0 )
{
Log::Write( LogLevel_Info, "Alternative controller lookup found more then one match. Using the first one found." );
}
else
{
m_currentControllerCommand->m_controllerCommandNode = m_nodes[i]->m_nodeId;
}
}
}
LG.Unlock();
}
else
{
Log::Write( LogLevel_Warning, "WARNING: Node is 0 but not enough data to perform alternative match." );
}
}
else
{
m_currentControllerCommand->m_controllerCommandNode = _data[4];
}
Log::Write( LogLevel_Info, "Removing controller ID %d", m_currentControllerCommand->m_controllerCommandNode );
break;
}
case REMOVE_NODE_STATUS_DONE:
{
Log::Write( LogLevel_Info, "REMOVE_NODE_STATUS_DONE" );
if( !m_currentControllerCommand->m_controllerCommandDone )
{
UpdateControllerState( ControllerState_Completed );
if ( m_currentControllerCommand->m_controllerCommandNode == 0 ) {
if ( _data[4] != 0 ) {
m_currentControllerCommand->m_controllerCommandNode = _data[4];
}
}
if ( m_currentControllerCommand->m_controllerCommandNode != 0 && m_currentControllerCommand->m_controllerCommandNode != 0xff )
{
LockGuard LG(m_nodeMutex);
delete m_nodes[m_currentControllerCommand->m_controllerCommandNode];
m_nodes[m_currentControllerCommand->m_controllerCommandNode] = NULL;
LG.Unlock();
Notification* notification = new Notification( Notification::Type_NodeRemoved );
notification->SetHomeAndNodeIds( m_homeId, m_currentControllerCommand->m_controllerCommandNode );
QueueNotification( notification );
}
}
return;
}
case REMOVE_NODE_STATUS_FAILED:
{
Log::Write( LogLevel_Warning, "WARNING: REMOVE_NODE_STATUS_FAILED" );
state = ControllerState_Failed;
break;
}
default:
{
break;
}
}
UpdateControllerState( state );
}
void Driver::HandleControllerChangeRequest
(
uint8* _data
)
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "FUNC_ID_ZW_CONTROLLER_CHANGE:" );
CommonAddNodeStatusRequestHandler( FUNC_ID_ZW_CONTROLLER_CHANGE, _data );
}
void Driver::HandleCreateNewPrimaryRequest
(
uint8* _data
)
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "FUNC_ID_ZW_CREATE_NEW_PRIMARY:" );
CommonAddNodeStatusRequestHandler( FUNC_ID_ZW_CREATE_NEW_PRIMARY, _data );
}
void Driver::HandleSetLearnModeRequest
(
uint8* _data
)
{
uint8 nodeId = GetNodeNumber( m_currentMsg );
if( m_currentControllerCommand == NULL )
{
return;
}
ControllerState state = m_currentControllerCommand->m_controllerState;
Log::Write( LogLevel_Info, nodeId, "FUNC_ID_ZW_SET_LEARN_MODE:" );
switch( _data[3] )
{
case LEARN_MODE_STARTED:
{
Log::Write( LogLevel_Info, nodeId, "LEARN_MODE_STARTED" );
state = ControllerState_Waiting;
break;
}
case LEARN_MODE_DONE:
{
Log::Write( LogLevel_Info, nodeId, "LEARN_MODE_DONE" );
state = ControllerState_Completed;
Msg* msg = new Msg( "End Learn Mode", 0xff, REQUEST, FUNC_ID_ZW_SET_LEARN_MODE, false, false );
msg->Append( 0 );
SendMsg( msg, MsgQueue_Command );
InitAllNodes();
break;
}
case LEARN_MODE_FAILED:
{
Log::Write( LogLevel_Warning, nodeId, "WARNING: LEARN_MODE_FAILED" );
state = ControllerState_Failed;
Msg* msg = new Msg( "End Learn Mode", 0xff, REQUEST, FUNC_ID_ZW_SET_LEARN_MODE, false, false );
msg->Append( 0 );
SendMsg( msg, MsgQueue_Command );
InitAllNodes();
break;
}
case LEARN_MODE_DELETED:
{
Log::Write( LogLevel_Info, nodeId, "LEARN_MODE_DELETED" );
state = ControllerState_Failed;
Msg* msg = new Msg( "End Learn Mode", 0xff, REQUEST, FUNC_ID_ZW_SET_LEARN_MODE, false, false );
msg->Append( 0 );
SendMsg( msg, MsgQueue_Command );
break;
}
}
UpdateControllerState( state );
}
void Driver::HandleRemoveFailedNodeRequest
(
uint8* _data
)
{
ControllerState state = ControllerState_Completed;
uint8 nodeId = GetNodeNumber( m_currentMsg );
switch( _data[3] )
{
case FAILED_NODE_OK:
{
Log::Write( LogLevel_Warning, nodeId, "WARNING: Received reply to FUNC_ID_ZW_REMOVE_FAILED_NODE_ID - Node %d is OK, so command failed", m_currentControllerCommand->m_controllerCommandNode );
state = ControllerState_NodeOK;
break;
}
case FAILED_NODE_REMOVED:
{
Log::Write( LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_REMOVE_FAILED_NODE_ID - node %d successfully moved to failed nodes list", m_currentControllerCommand->m_controllerCommandNode );
state = ControllerState_Completed;
LockGuard LG(m_nodeMutex);
delete m_nodes[m_currentControllerCommand->m_controllerCommandNode];
m_nodes[m_currentControllerCommand->m_controllerCommandNode] = NULL;
LG.Unlock();
Notification* notification = new Notification( Notification::Type_NodeRemoved );
notification->SetHomeAndNodeIds( m_homeId, m_currentControllerCommand->m_controllerCommandNode );
QueueNotification( notification );
break;
}
case FAILED_NODE_NOT_REMOVED:
{
Log::Write( LogLevel_Warning, nodeId, "WARNING: Received reply to FUNC_ID_ZW_REMOVE_FAILED_NODE_ID - unable to move node %d to failed nodes list", m_currentControllerCommand->m_controllerCommandNode );
state = ControllerState_Failed;
break;
}
}
UpdateControllerState( state );
}
void Driver::HandleReplaceFailedNodeRequest
(
uint8* _data
)
{
ControllerState state = ControllerState_Completed;
uint8 nodeId = GetNodeNumber( m_currentMsg );
switch( _data[3] )
{
case FAILED_NODE_OK:
{
Log::Write( LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_REPLACE_FAILED_NODE - Node is OK, so command failed" );
state = ControllerState_NodeOK;
break;
}
case FAILED_NODE_REPLACE_WAITING:
{
Log::Write( LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_REPLACE_FAILED_NODE - Waiting for new node" );
state = ControllerState_Waiting;
break;
}
case FAILED_NODE_REPLACE_DONE:
{
Log::Write( LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_REPLACE_FAILED_NODE - Node successfully replaced" );
state = ControllerState_Completed;
if( m_currentControllerCommand != NULL )
{
InitNode( m_currentControllerCommand->m_controllerCommandNode, true );
}
break;
}
case FAILED_NODE_REPLACE_FAILED:
{
Log::Write( LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_REPLACE_FAILED_NODE - Node replacement failed" );
state = ControllerState_Failed;
break;
}
}
UpdateControllerState( state );
}
void Driver::HandleApplicationCommandHandlerRequest
(
uint8* _data,
bool encrypted
)
{
uint8 status = _data[2];
uint8 nodeId = _data[3];
uint8 classId = _data[5];
Node* node = GetNodeUnsafe( nodeId );
if( ( status & RECEIVE_STATUS_ROUTED_BUSY ) != 0 )
{
m_routedbusy++;
}
if( ( status & RECEIVE_STATUS_TYPE_BROAD ) != 0 )
{
m_broadcastReadCnt++;
}
if( node != NULL )
{
node->m_receivedCnt++;
node->m_errors = 0;
int cmp = memcmp( _data, node->m_lastReceivedMessage, sizeof(node->m_lastReceivedMessage));
if( cmp == 0 && node->m_receivedTS.TimeRemaining() > -500 )
{
node->m_receivedDups++;
}
else
{
memcpy( node->m_lastReceivedMessage, _data, sizeof(node->m_lastReceivedMessage) );
}
node->m_receivedTS.SetTime();
if( m_expectedReply == FUNC_ID_APPLICATION_COMMAND_HANDLER && m_expectedNodeId == nodeId )
{
node->m_lastResponseRTT = -node->m_sentTS.TimeRemaining();
if( node->m_averageResponseRTT )
{
node->m_averageResponseRTT = ( node->m_averageResponseRTT + node->m_lastResponseRTT ) >> 1;
}
else
{
node->m_averageResponseRTT = node->m_lastResponseRTT;
}
Log::Write(LogLevel_Info, nodeId, "Response RTT %d Average Response RTT %d", node->m_lastResponseRTT, node->m_averageResponseRTT );
}
else
{
node->m_receivedUnsolicited++;
}
if ( !node->IsNodeAlive() )
{
node->SetNodeAlive( true );
}
}
if( ApplicationStatus::StaticGetCommandClassId() == classId )
{
}
else if( ControllerReplication::StaticGetCommandClassId() == classId )
{
if( m_controllerReplication && m_currentControllerCommand && ( ControllerCommand_ReceiveConfiguration == m_currentControllerCommand->m_controllerCommand ) )
{
m_controllerReplication->HandleMsg( &_data[6], _data[4] );
UpdateControllerState( ControllerState_InProgress );
}
}
else
{
if( node != NULL )
{
node->ApplicationCommandHandler( _data, encrypted );
}
}
}
void Driver::HandlePromiscuousApplicationCommandHandlerRequest
(
uint8* _data
)
{
}
void Driver::HandleAssignReturnRouteRequest
(
uint8* _data
)
{
ControllerState state;
uint8 nodeId = GetNodeNumber( m_currentMsg );
if( m_currentControllerCommand == NULL )
{
return;
}
if( _data[3] )
{
HandleErrorResponse( _data[3], m_currentControllerCommand->m_controllerCommandNode, "ZW_ASSIGN_RETURN_ROUTE", true );
state = ControllerState_Failed;
}
else
{
Log::Write( LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_ASSIGN_RETURN_ROUTE for node %d - SUCCESS", m_currentControllerCommand->m_controllerCommandNode );
state = ControllerState_Completed;
}
UpdateControllerState( state );
}
void Driver::HandleDeleteReturnRouteRequest
(
uint8* _data
)
{
ControllerState state;
uint8 nodeId = GetNodeNumber( m_currentMsg );
if( m_currentControllerCommand == NULL )
{
return;
}
if( _data[3] )
{
HandleErrorResponse( _data[3], m_currentControllerCommand->m_controllerCommandNode, "ZW_DELETE_RETURN_ROUTE", true );
state = ControllerState_Failed;
}
else
{
Log::Write( LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_DELETE_RETURN_ROUTE for node %d - SUCCESS", m_currentControllerCommand->m_controllerCommandNode );
state = ControllerState_Completed;
}
UpdateControllerState( state );
}
void Driver::HandleSendNodeInformationRequest
(
uint8* _data
)
{
ControllerState state;
uint8 nodeId = GetNodeNumber( m_currentMsg );
if( m_currentControllerCommand == NULL )
{
return;
}
if( _data[3] )
{
HandleErrorResponse( _data[3], m_currentControllerCommand->m_controllerCommandNode, "ZW_SEND_NODE_INFORMATION" );
state = ControllerState_Failed;
}
else
{
Log::Write( LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_SEND_NODE_INFORMATION - SUCCESS" );
state = ControllerState_Completed;
}
UpdateControllerState( state );
}
void Driver::HandleNodeNeighborUpdateRequest
(
uint8* _data
)
{
uint8 nodeId = GetNodeNumber( m_currentMsg );
ControllerState state = ControllerState_Normal;
switch( _data[3] )
{
case REQUEST_NEIGHBOR_UPDATE_STARTED:
{
Log::Write( LogLevel_Info, nodeId, "REQUEST_NEIGHBOR_UPDATE_STARTED" );
state = ControllerState_InProgress;
break;
}
case REQUEST_NEIGHBOR_UPDATE_DONE:
{
Log::Write( LogLevel_Info, nodeId, "REQUEST_NEIGHBOR_UPDATE_DONE" );
state = ControllerState_Completed;
if( m_currentControllerCommand != NULL )
{
RequestNodeNeighbors( m_currentControllerCommand->m_controllerCommandNode, 0 );
}
break;
}
case REQUEST_NEIGHBOR_UPDATE_FAILED:
{
Log::Write( LogLevel_Warning, nodeId, "WARNING: REQUEST_NEIGHBOR_UPDATE_FAILED" );
state = ControllerState_Failed;
break;
}
default:
{
break;
}
}
UpdateControllerState( state );
}
bool Driver::HandleApplicationUpdateRequest
(
uint8* _data
)
{
bool messageRemoved = false;
uint8 nodeId = _data[3];
Node* node = GetNodeUnsafe( nodeId );
if( node != NULL && !node->IsNodeAlive() )
{
node->SetNodeAlive( true );
}
switch( _data[2] )
{
case UPDATE_STATE_SUC_ID:
{
Log::Write( LogLevel_Info, nodeId, "UPDATE_STATE_SUC_ID from node %d", nodeId );
m_SUCNodeId = nodeId; break;
}
case UPDATE_STATE_DELETE_DONE:
{
Log::Write( LogLevel_Info, nodeId, "** Network change **: Z-Wave node %d was removed", nodeId );
LockGuard LG(m_nodeMutex);
delete m_nodes[nodeId];
m_nodes[nodeId] = NULL;
LG.Unlock();
Notification* notification = new Notification( Notification::Type_NodeRemoved );
notification->SetHomeAndNodeIds( m_homeId, nodeId );
QueueNotification( notification );
break;
}
case UPDATE_STATE_NEW_ID_ASSIGNED:
{
Log::Write( LogLevel_Info, nodeId, "** Network change **: ID %d was assigned to a new Z-Wave node", nodeId );
if ( _data[3] != _data[6] )
{
InitNode( nodeId );
}
else
{
Log::Write(LogLevel_Info, nodeId, "Not Re-assigning NodeID as old and new NodeID match");
}
break;
}
case UPDATE_STATE_ROUTING_PENDING:
{
Log::Write( LogLevel_Info, nodeId, "UPDATE_STATE_ROUTING_PENDING from node %d", nodeId );
break;
}
case UPDATE_STATE_NODE_INFO_REQ_FAILED:
{
Log::Write( LogLevel_Warning, nodeId, "WARNING: FUNC_ID_ZW_APPLICATION_UPDATE: UPDATE_STATE_NODE_INFO_REQ_FAILED received" );
if( m_currentMsg )
{
Node* tnode = GetNodeUnsafe( m_currentMsg->GetTargetNodeId() );
if( tnode )
{
tnode->QueryStageRetry( Node::QueryStage_NodeInfo, 2 );
if( MoveMessagesToWakeUpQueue( tnode->GetNodeId(), true ) )
{
messageRemoved = true;
}
}
}
break;
}
case UPDATE_STATE_NODE_INFO_REQ_DONE:
{
Log::Write( LogLevel_Info, nodeId, "UPDATE_STATE_NODE_INFO_REQ_DONE from node %d", nodeId );
break;
}
case UPDATE_STATE_NODE_INFO_RECEIVED:
{
Log::Write( LogLevel_Info, nodeId, "UPDATE_STATE_NODE_INFO_RECEIVED from node %d", nodeId );
if( node )
{
node->UpdateNodeInfo( &_data[8], _data[4] - 3 );
}
break;
}
}
if( messageRemoved )
{
m_waitingForAck = false;
m_expectedCallbackId = 0;
m_expectedReply = 0;
m_expectedCommandClassId = 0;
m_expectedNodeId = 0;
}
return messageRemoved;
}
void Driver::CommonAddNodeStatusRequestHandler
(
uint8 _funcId,
uint8* _data
)
{
uint8 nodeId = GetNodeNumber( m_currentMsg );
ControllerState state = ControllerState_Normal;
if( m_currentControllerCommand != NULL )
{
state = m_currentControllerCommand->m_controllerState;
}
switch( _data[3] )
{
case ADD_NODE_STATUS_LEARN_READY:
{
Log::Write( LogLevel_Info, nodeId, "ADD_NODE_STATUS_LEARN_READY" );
m_currentControllerCommand->m_controllerAdded = false;
state = ControllerState_Waiting;
break;
}
case ADD_NODE_STATUS_NODE_FOUND:
{
Log::Write( LogLevel_Info, nodeId, "ADD_NODE_STATUS_NODE_FOUND" );
state = ControllerState_InProgress;
break;
}
case ADD_NODE_STATUS_ADDING_SLAVE:
{
Log::Write( LogLevel_Info, nodeId, "ADD_NODE_STATUS_ADDING_SLAVE" );
Log::Write( LogLevel_Info, nodeId, "Adding node ID %d - %s", _data[4], m_currentControllerCommand->m_controllerCommandArg ? "Secure" : "Non-Secure");
if( m_currentControllerCommand != NULL )
{
m_currentControllerCommand->m_controllerAdded = false;
m_currentControllerCommand->m_controllerCommandNode = _data[4];
uint8 length = _data[5];
if (length > 254) length = 254;
memcpy(&m_currentControllerCommand->m_controllerDeviceProtocolInfo, &_data[6], length);
m_currentControllerCommand->m_controllerDeviceProtocolInfoLength = length;
}
break;
}
case ADD_NODE_STATUS_ADDING_CONTROLLER:
{
Log::Write( LogLevel_Info, nodeId, "ADD_NODE_STATUS_ADDING_CONTROLLER");
Log::Write( LogLevel_Info, nodeId, "Adding controller ID %d", _data[4] );
if( m_currentControllerCommand != NULL )
{
m_currentControllerCommand->m_controllerAdded = true;
m_currentControllerCommand->m_controllerCommandNode = _data[4];
}
break;
}
case ADD_NODE_STATUS_PROTOCOL_DONE:
{
Log::Write( LogLevel_Info, nodeId, "ADD_NODE_STATUS_PROTOCOL_DONE" );
AddNodeStop( _funcId );
break;
}
case ADD_NODE_STATUS_DONE:
{
if (state == ControllerState_Failed) {
state = ControllerState_Completed;
break;
}
Log::Write( LogLevel_Info, nodeId, "ADD_NODE_STATUS_DONE" );
state = ControllerState_Completed;
if( m_currentControllerCommand != NULL && m_currentControllerCommand->m_controllerCommandNode != 0xff )
{
InitNode( m_currentControllerCommand->m_controllerCommandNode, true, m_currentControllerCommand->m_controllerCommandArg != 0, m_currentControllerCommand->m_controllerDeviceProtocolInfo, m_currentControllerCommand->m_controllerDeviceProtocolInfoLength );
}
if( _funcId != FUNC_ID_ZW_ADD_NODE_TO_NETWORK && m_currentControllerCommand != NULL && m_currentControllerCommand->m_controllerAdded )
{
InitAllNodes();
}
break;
}
case ADD_NODE_STATUS_FAILED:
{
Log::Write( LogLevel_Info, nodeId, "ADD_NODE_STATUS_FAILED" );
state = ControllerState_Failed;
RemoveCurrentMsg();
AddNodeStop( _funcId );
break;
}
default:
{
break;
}
}
UpdateControllerState( state );
}
bool Driver::EnablePoll
(
ValueID const &_valueId,
uint8 const _intensity
)
{
m_pollMutex->Lock();
uint8 nodeId = _valueId.GetNodeId();
LockGuard LG(m_nodeMutex);
Node* node = GetNode( nodeId );
if( node != NULL )
{
if( Value* value = node->GetValue( _valueId ) )
{
value->SetPollIntensity( _intensity );
for( list<PollEntry>::iterator it = m_pollList.begin(); it != m_pollList.end(); ++it )
{
if( (*it).m_id == _valueId )
{
Log::Write( LogLevel_Detail, "EnablePoll not required to do anything (value is already in the poll list)" );
value->Release();
m_pollMutex->Unlock();
return true;
}
}
PollEntry pe;
pe.m_id = _valueId;
pe.m_pollCounter = value->GetPollIntensity();
m_pollList.push_back( pe );
value->Release();
m_pollMutex->Unlock();
Notification* notification = new Notification( Notification::Type_PollingEnabled );
notification->SetHomeAndNodeIds( m_homeId, _valueId.GetNodeId() );
QueueNotification( notification );
Log::Write( LogLevel_Info, nodeId, "EnablePoll for HomeID 0x%.8x, value(cc=0x%02x,in=0x%02x,id=0x%02x)--poll list has %d items",
_valueId.GetHomeId(), _valueId.GetCommandClassId(), _valueId.GetIndex(), _valueId.GetInstance(), m_pollList.size() );
return true;
}
m_pollMutex->Unlock();
Log::Write( LogLevel_Info, nodeId, "EnablePoll failed - value not found for node %d", nodeId );
return false;
}
m_pollMutex->Unlock();
Log::Write( LogLevel_Info, "EnablePoll failed - node %d not found", nodeId );
return false;
}
bool Driver::DisablePoll
(
ValueID const &_valueId
)
{
m_pollMutex->Lock();
uint8 nodeId = _valueId.GetNodeId();
LockGuard LG(m_nodeMutex);
Node* node = GetNode( nodeId );
if( node != NULL)
{
for( list<PollEntry>::iterator it = m_pollList.begin(); it != m_pollList.end(); ++it )
{
if( (*it).m_id == _valueId )
{
m_pollList.erase( it );
Value* value = GetValue( _valueId );
if (!value)
continue;
value->SetPollIntensity( 0 );
value->Release();
m_pollMutex->Unlock();
Notification* notification = new Notification( Notification::Type_PollingDisabled );
notification->SetHomeAndNodeIds( m_homeId, _valueId.GetNodeId() );
QueueNotification( notification );
Log::Write( LogLevel_Info, nodeId, "DisablePoll for HomeID 0x%.8x, value(cc=0x%02x,in=0x%02x,id=0x%02x)--poll list has %d items",
_valueId.GetHomeId(), _valueId.GetCommandClassId(), _valueId.GetIndex(), _valueId.GetInstance(), m_pollList.size() );
return true;
}
}
m_pollMutex->Unlock();
Log::Write( LogLevel_Info, nodeId, "DisablePoll failed - value not on list");
return false;
}
m_pollMutex->Unlock();
Log::Write( LogLevel_Info, "DisablePoll failed - node %d not found", nodeId );
return false;
}
bool Driver::isPolled
(
ValueID const &_valueId
)
{
bool bPolled;
m_pollMutex->Lock();
Value* value = GetValue( _valueId );
if( value && value->GetPollIntensity() != 0 )
{
bPolled = true;
}
else
{
bPolled = false;
}
if (value) value->Release();
uint8 nodeId = _valueId.GetNodeId();
LockGuard LG(m_nodeMutex);
Node* node = GetNode( nodeId );
if( node != NULL)
{
for( list<PollEntry>::iterator it = m_pollList.begin(); it != m_pollList.end(); ++it )
{
if( (*it).m_id == _valueId )
{
if( bPolled )
{
m_pollMutex->Unlock();
return true;
}
else
{
Log::Write( LogLevel_Error, nodeId, "IsPolled setting for valueId 0x%016x is not consistent with the poll list", _valueId.GetId() );
}
}
}
if( !bPolled )
{
m_pollMutex->Unlock();
return false;
}
else
{
Log::Write( LogLevel_Error, nodeId, "IsPolled setting for valueId 0x%016x is not consistent with the poll list", _valueId.GetId() );
}
}
m_pollMutex->Unlock();
Log::Write( LogLevel_Info, "isPolled failed - node %d not found (the value reported that it is%s polled)", nodeId, bPolled?"":" not" );
return false;
}
void Driver::SetPollIntensity
(
ValueID const &_valueId,
uint8 const _intensity
)
{
m_pollMutex->Lock();
Value* value = GetValue( _valueId );
if (!value)
return;
value->SetPollIntensity( _intensity );
value->Release();
m_pollMutex->Unlock();
}
void Driver::PollThreadEntryPoint
(
Event* _exitEvent,
void* _context
)
{
Driver* driver = (Driver*)_context;
if( driver )
{
driver->PollThreadProc( _exitEvent );
}
}
void Driver::PollThreadProc
(
Event* _exitEvent
)
{
while( 1 )
{
int32 pollInterval = m_pollInterval;
if( m_awakeNodesQueried && !m_pollList.empty() )
{
m_pollMutex->Lock();
PollEntry pe = m_pollList.front();
m_pollList.pop_front();
ValueID valueId = pe.m_id;
if( pe.m_pollCounter != 1)
{
pe.m_pollCounter--;
m_pollList.push_back( pe );
m_pollMutex->Unlock();
continue;
}
{
LockGuard LG(m_nodeMutex);
(void)GetNode( valueId.GetNodeId() );
Value* value = GetValue( valueId );
if (!value)
continue;
pe.m_pollCounter = value->GetPollIntensity();
m_pollList.push_back( pe );
value->Release();
}
if( !m_bIntervalBetweenPolls )
{
if( pollInterval < 100 )
{
Log::Write( LogLevel_Info, "The pollInterval setting is only %d, which appears to be a legacy setting. Multiplying by 1000 to convert to ms.", pollInterval );
pollInterval *= 1000;
}
pollInterval /= (int32) m_pollList.size();
}
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( valueId.GetNodeId() ) )
{
bool requestState = true;
if( !node->IsListeningDevice() )
{
if( WakeUp* wakeUp = static_cast<WakeUp*>( node->GetCommandClass( WakeUp::StaticGetCommandClassId() ) ) )
{
if( !wakeUp->IsAwake() )
{
wakeUp->SetPollRequired();
requestState = false;
}
}
}
if( requestState )
{
CommandClass* cc = node->GetCommandClass( valueId.GetCommandClassId() );
if (cc) {
uint8 index = valueId.GetIndex();
uint8 instance = valueId.GetInstance();
Log::Write( LogLevel_Detail, node->m_nodeId, "Polling: %s index = %d instance = %d (poll queue has %d messages)", cc->GetCommandClassName().c_str(), index, instance, m_msgQueue[MsgQueue_Poll].size() );
cc->RequestValue( 0, index, instance, MsgQueue_Poll );
}
}
}
}
m_pollMutex->Unlock();
int i32;
int loopCount = 0;
while( !m_msgQueue[MsgQueue_Poll].empty()
|| !m_msgQueue[MsgQueue_Send].empty()
|| !m_msgQueue[MsgQueue_Command].empty()
|| !m_msgQueue[MsgQueue_Query].empty()
|| m_currentMsg != NULL )
{
i32 = Wait::Single( _exitEvent, 10); if( i32 == 0 )
{
return;
}
loopCount++;
if( loopCount == 3000*10 ) {
Log::Write( LogLevel_Warning, "Poll queue hasn't been able to execute for 300 secs or more" );
Log::QueueDump();
}
}
i32 = Wait::Single( _exitEvent, pollInterval );
if( i32 == 0 )
{
return;
}
}
else {
int32 i32 = Wait::Single( _exitEvent, 500 );
if( i32 == 0 )
{
return;
}
}
}
}
void Driver::InitAllNodes
(
)
{
LockGuard LG(m_nodeMutex);
for( int i=0; i<256; ++i )
{
if( m_nodes[i] )
{
delete m_nodes[i];
m_nodes[i] = NULL;
}
}
LG.Unlock();
m_controller->PlayInitSequence( this );
}
void Driver::InitNode
(
uint8 const _nodeId,
bool newNode,
bool secure,
uint8 const *_protocolInfo,
uint8 const _length
)
{
{
LockGuard LG(m_nodeMutex);
if( m_nodes[_nodeId] )
{
delete m_nodes[_nodeId];
Notification* notification = new Notification( Notification::Type_NodeRemoved );
notification->SetHomeAndNodeIds( m_homeId, _nodeId );
QueueNotification( notification );
}
m_nodes[_nodeId] = new Node( m_homeId, _nodeId );
if (newNode == true) static_cast<Node *>(m_nodes[_nodeId])->SetAddingNode();
}
Notification* notification = new Notification( Notification::Type_NodeAdded );
notification->SetHomeAndNodeIds( m_homeId, _nodeId );
QueueNotification( notification );
if (_length == 0) {
m_nodes[_nodeId]->SetQueryStage( Node::QueryStage_ProtocolInfo );
} else {
if (isNetworkKeySet())
m_nodes[_nodeId]->SetSecured(secure);
else
Log::Write(LogLevel_Info, _nodeId, "Network Key Not Set - Secure Option is %s", secure ? "required" : "not required");
m_nodes[_nodeId]->SetProtocolInfo(_protocolInfo, _length);
}
Log::Write(LogLevel_Info, _nodeId, "Initilizing Node. New Node: %s (%s)", static_cast<Node *>(m_nodes[_nodeId])->IsAddingNode() ? "true" : "false", newNode ? "true" : "false");
}
bool Driver::IsNodeListeningDevice
(
uint8 const _nodeId
)
{
bool res = false;
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
res = node->IsListeningDevice();
}
return res;
}
bool Driver::IsNodeFrequentListeningDevice
(
uint8 const _nodeId
)
{
bool res = false;
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
res = node->IsFrequentListeningDevice();
}
return res;
}
bool Driver::IsNodeBeamingDevice
(
uint8 const _nodeId
)
{
bool res = false;
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
res = node->IsBeamingDevice();
}
return res;
}
bool Driver::IsNodeRoutingDevice
(
uint8 const _nodeId
)
{
bool res = false;
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
res = node->IsRoutingDevice();
}
return res;
}
bool Driver::IsNodeSecurityDevice
(
uint8 const _nodeId
)
{
bool security = false;
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
security = node->IsSecurityDevice();
}
return security;
}
uint32 Driver::GetNodeMaxBaudRate
(
uint8 const _nodeId
)
{
uint32 baud = 0;
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
baud = node->GetMaxBaudRate();
}
return baud;
}
uint8 Driver::GetNodeVersion
(
uint8 const _nodeId
)
{
uint8 version = 0;
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
version = node->GetVersion();
}
return version;
}
uint8 Driver::GetNodeSecurity
(
uint8 const _nodeId
)
{
uint8 security = 0;
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
security = node->GetSecurity();
}
return security;
}
uint8 Driver::GetNodeBasic
(
uint8 const _nodeId
)
{
uint8 basic = 0;
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
basic = node->GetBasic();
}
return basic;
}
uint8 Driver::GetNodeGeneric
(
uint8 const _nodeId
)
{
uint8 genericType = 0;
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
genericType = node->GetGeneric();
}
return genericType;
}
uint8 Driver::GetNodeSpecific
(
uint8 const _nodeId
)
{
uint8 specific = 0;
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
specific = node->GetSpecific();
}
return specific;
}
string Driver::GetNodeType
(
uint8 const _nodeId
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
return node->GetType();
}
return "Unknown";
}
bool Driver::IsNodeZWavePlus
(
uint8 const _nodeId
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
return node->IsNodeZWavePlus();
}
return false;
}
uint32 Driver::GetNodeNeighbors
(
uint8 const _nodeId,
uint8** o_neighbors
)
{
uint32 numNeighbors = 0;
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
numNeighbors = node->GetNeighbors( o_neighbors );
}
return numNeighbors;
}
string Driver::GetNodeManufacturerName
(
uint8 const _nodeId
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
return node->GetManufacturerName();
}
return "";
}
string Driver::GetNodeProductName
(
uint8 const _nodeId
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
return node->GetProductName();
}
return "";
}
string Driver::GetNodeName
(
uint8 const _nodeId
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
return node->GetNodeName();
}
return "";
}
string Driver::GetNodeLocation
(
uint8 const _nodeId
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
return node->GetLocation();
}
return "";
}
uint16 Driver::GetNodeManufacturerId
(
uint8 const _nodeId
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
return node->GetManufacturerId();
}
return 0;
}
uint16 Driver::GetNodeProductType
(
uint8 const _nodeId
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
return node->GetProductType();
}
return 0;
}
uint16 Driver::GetNodeProductId
(
uint8 const _nodeId
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
return node->GetProductId();
}
return 0;
}
uint16 Driver::GetNodeDeviceType
(
uint8 const _nodeId
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
return node->GetDeviceType();
}
return 0x00; }
string Driver::GetNodeDeviceTypeString
(
uint8 const _nodeId
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
return node->GetDeviceTypeString();
}
return ""; }
uint8 Driver::GetNodeRole
(
uint8 const _nodeId
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
return node->GetRoleType();
}
return 0x00; }
string Driver::GetNodeRoleString
(
uint8 const _nodeId
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
return node->GetRoleTypeString();
}
return ""; }
uint8 Driver::GetNodePlusType
(
uint8 const _nodeId
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
return node->GetNodeType();
}
return 0x00; }
string Driver::GetNodePlusTypeString
(
uint8 const _nodeId
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
return node->GetNodeTypeString();
}
return ""; }
void Driver::SetNodeManufacturerName
(
uint8 const _nodeId,
string const& _manufacturerName
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
node->SetManufacturerName( _manufacturerName );
}
}
void Driver::SetNodeProductName
(
uint8 const _nodeId,
string const& _productName
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
node->SetProductName( _productName );
}
}
void Driver::SetNodeName
(
uint8 const _nodeId,
string const& _nodeName
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
node->SetNodeName( _nodeName );
}
}
void Driver::SetNodeLocation
(
uint8 const _nodeId,
string const& _location
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
node->SetLocation( _location );
}
}
void Driver::SetNodeLevel
(
uint8 const _nodeId,
uint8 const _level
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
node->SetLevel( _level );
}
}
void Driver::SetNodeOn
(
uint8 const _nodeId
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
node->SetNodeOn();
}
}
void Driver::SetNodeOff
(
uint8 const _nodeId
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
node->SetNodeOff();
}
}
Value* Driver::GetValue
(
ValueID const& _id
)
{
if( Node* node = m_nodes[_id.GetNodeId()] )
{
return node->GetValue( _id );
}
return NULL;
}
void Driver::ResetController
(
Event* _evt
)
{
m_controllerResetEvent = _evt;
Log::Write( LogLevel_Info, "Reset controller and erase all node information");
Msg* msg = new Msg( "Reset controller and erase all node information", 0xff, REQUEST, FUNC_ID_ZW_SET_DEFAULT, true );
SendMsg( msg, MsgQueue_Command );
}
void Driver::SoftReset
(
)
{
Log::Write( LogLevel_Info, "Soft-resetting the Z-Wave controller chip");
Msg* msg = new Msg( "Soft-resetting the Z-Wave controller chip", 0xff, REQUEST, FUNC_ID_SERIAL_API_SOFT_RESET, false, false );
SendMsg( msg, MsgQueue_Command );
}
void Driver::RequestNodeNeighbors
(
uint8 const _nodeId,
uint32 const _requestFlags
)
{
if( IsAPICallSupported( FUNC_ID_ZW_GET_ROUTING_INFO ) )
{
Log::Write( LogLevel_Detail, GetNodeNumber( m_currentMsg ), "Requesting routing info (neighbor list) for Node %d", _nodeId );
Msg* msg = new Msg( "Get Routing Info", _nodeId, REQUEST, FUNC_ID_ZW_GET_ROUTING_INFO, false );
msg->Append( _nodeId );
msg->Append( 0 ); msg->Append( 0 ); msg->Append( 3 ); SendMsg( msg, MsgQueue_Command );
}
}
bool Driver::BeginControllerCommand
(
ControllerCommand _command,
pfnControllerCallback_t _callback,
void* _context,
bool _highPower,
uint8 _nodeId,
uint8 _arg
)
{
ControllerCommandItem* cci;
MsgQueueItem item;
if( _command == ControllerCommand_None )
{
return false;
}
Log::Write( LogLevel_Detail, _nodeId, "Queuing (%s) %s", c_sendQueueNames[MsgQueue_Controller], c_controllerCommandNames[_command] );
cci = new ControllerCommandItem();
cci->m_controllerCommand = _command;
cci->m_controllerCallback = _callback;
cci->m_controllerCallbackContext = _context;
cci->m_highPower = _highPower;
cci->m_controllerCommandNode = _nodeId;
cci->m_controllerCommandArg = _arg;
cci->m_controllerState = ControllerState_Normal;
cci->m_controllerStateChanged = false;
cci->m_controllerCommandDone = false;
item.m_command = MsgQueueCmd_Controller;
item.m_cci = cci;
m_sendMutex->Lock();
m_msgQueue[MsgQueue_Controller].push_back( item );
m_queueEvent[MsgQueue_Controller]->Set();
m_sendMutex->Unlock();
return true;
}
void Driver::DoControllerCommand
(
)
{
UpdateControllerState( ControllerState_Starting );
switch( m_currentControllerCommand->m_controllerCommand )
{
case ControllerCommand_AddDevice:
{
if( !IsPrimaryController() )
{
UpdateControllerState( ControllerState_Error, ControllerError_NotPrimary );
}
else
{
Log::Write( LogLevel_Info, 0, "Add Device" );
Msg* msg = new Msg( "ControllerCommand_AddDevice", 0xff, REQUEST, FUNC_ID_ZW_ADD_NODE_TO_NETWORK, true );
uint8 options = ADD_NODE_ANY;
if (m_currentControllerCommand->m_highPower) options |= OPTION_HIGH_POWER;
if (IsAPICallSupported(FUNC_ID_ZW_EXPLORE_REQUEST_INCLUSION)) options |= OPTION_NWI;
msg->Append( options);
SendMsg( msg, MsgQueue_Command );
}
break;
}
case ControllerCommand_CreateNewPrimary:
{
if( IsPrimaryController() )
{
UpdateControllerState( ControllerState_Error, ControllerError_NotSecondary );
}
else if( !IsStaticUpdateController() )
{
UpdateControllerState( ControllerState_Error, ControllerError_NotSUC );
}
else
{
Log::Write( LogLevel_Info, 0, "Create New Primary" );
Msg* msg = new Msg( "ControllerCommand_CreateNewPrimary", 0xff, REQUEST, FUNC_ID_ZW_CREATE_NEW_PRIMARY, true );
msg->Append( CREATE_PRIMARY_START );
SendMsg( msg, MsgQueue_Command );
}
break;
}
case ControllerCommand_ReceiveConfiguration:
{
Log::Write( LogLevel_Info, 0, "Receive Configuration" );
Msg* msg = new Msg( "ControllerCommand_ReceiveConfiguration", 0xff, REQUEST, FUNC_ID_ZW_SET_LEARN_MODE, true );
msg->Append( 0xff );
SendMsg( msg, MsgQueue_Command );
break;
}
case ControllerCommand_RemoveDevice:
{
if( !IsPrimaryController() )
{
UpdateControllerState( ControllerState_Error, ControllerError_NotPrimary );
}
else
{
Log::Write( LogLevel_Info, 0, "Remove Device" );
Msg* msg = new Msg( "ControllerCommand_RemoveDevice", 0xff, REQUEST, FUNC_ID_ZW_REMOVE_NODE_FROM_NETWORK, true );
msg->Append( m_currentControllerCommand->m_highPower ? REMOVE_NODE_ANY | OPTION_HIGH_POWER : REMOVE_NODE_ANY );
SendMsg( msg, MsgQueue_Command );
}
break;
}
case ControllerCommand_HasNodeFailed:
{
Log::Write( LogLevel_Info, 0, "Requesting whether node %d has failed", m_currentControllerCommand->m_controllerCommandNode );
Msg* msg = new Msg( "ControllerCommand_HasNodeFailed", 0xff, REQUEST, FUNC_ID_ZW_IS_FAILED_NODE_ID, false );
msg->Append( m_currentControllerCommand->m_controllerCommandNode );
SendMsg( msg, MsgQueue_Command );
break;
}
case ControllerCommand_RemoveFailedNode:
{
Log::Write( LogLevel_Info, 0, "ControllerCommand_RemoveFailedNode", m_currentControllerCommand->m_controllerCommandNode );
Msg* msg = new Msg( "ControllerCommand_RemoveFailedNode", 0xff, REQUEST, FUNC_ID_ZW_REMOVE_FAILED_NODE_ID, true );
msg->Append( m_currentControllerCommand->m_controllerCommandNode );
SendMsg( msg, MsgQueue_Command );
break;
}
case ControllerCommand_ReplaceFailedNode:
{
Log::Write( LogLevel_Info, 0, "Replace Failed Node %d", m_currentControllerCommand->m_controllerCommandNode );
Msg* msg = new Msg( "ControllerCommand_ReplaceFailedNode", 0xff, REQUEST, FUNC_ID_ZW_REPLACE_FAILED_NODE, true );
msg->Append( m_currentControllerCommand->m_controllerCommandNode );
SendMsg( msg, MsgQueue_Command );
break;
}
case ControllerCommand_TransferPrimaryRole:
{
if( !IsPrimaryController() )
{
UpdateControllerState( ControllerState_Error, ControllerError_NotPrimary );
}
else
{
Log::Write( LogLevel_Info, 0, "Transfer Primary Role" );
Msg* msg = new Msg( "ControllerCommand_TransferPrimaryRole", 0xff, REQUEST, FUNC_ID_ZW_CONTROLLER_CHANGE, true );
msg->Append( m_currentControllerCommand->m_highPower ? CONTROLLER_CHANGE_START | OPTION_HIGH_POWER : CONTROLLER_CHANGE_START );
SendMsg( msg, MsgQueue_Command );
}
break;
}
case ControllerCommand_RequestNetworkUpdate:
{
if( !IsStaticUpdateController() )
{
UpdateControllerState( ControllerState_Error, ControllerError_NotSUC );
}
else
{
Log::Write( LogLevel_Info, 0, "Request Network Update" );
Msg* msg = new Msg( "ControllerCommand_RequestNetworkUpdate", 0xff, REQUEST, FUNC_ID_ZW_REQUEST_NETWORK_UPDATE, true );
SendMsg( msg, MsgQueue_Command );
}
break;
}
case ControllerCommand_RequestNodeNeighborUpdate:
{
if( !IsPrimaryController() )
{
UpdateControllerState( ControllerState_Error, ControllerError_NotPrimary );
}
else
{
Log::Write( LogLevel_Info, 0, "Requesting Neighbor Update for node %d", m_currentControllerCommand->m_controllerCommandNode );
bool opts = IsAPICallSupported( FUNC_ID_ZW_REQUEST_NODE_NEIGHBOR_UPDATE_OPTIONS );
Msg* msg;
if( opts )
{
msg = new Msg( "ControllerCommand_RequestNodeNeighborUpdate", m_currentControllerCommand->m_controllerCommandNode, REQUEST, FUNC_ID_ZW_REQUEST_NODE_NEIGHBOR_UPDATE_OPTIONS, true );
}
else
{
msg = new Msg( "ControllerCommand_RequestNodeNeighborUpdate", m_currentControllerCommand->m_controllerCommandNode, REQUEST, FUNC_ID_ZW_REQUEST_NODE_NEIGHBOR_UPDATE, true );
}
msg->Append( m_currentControllerCommand->m_controllerCommandNode );
if( opts )
{
msg->Append( GetTransmitOptions() );
}
SendMsg( msg, MsgQueue_Command );
}
break;
}
case ControllerCommand_AssignReturnRoute:
{
Log::Write( LogLevel_Info, 0, "Assigning return route from node %d to node %d", m_currentControllerCommand->m_controllerCommandNode, m_currentControllerCommand->m_controllerCommandArg );
Msg* msg = new Msg( "ControllerCommand_AssignReturnRoute", m_currentControllerCommand->m_controllerCommandNode, REQUEST, FUNC_ID_ZW_ASSIGN_RETURN_ROUTE, true );
msg->Append( m_currentControllerCommand->m_controllerCommandNode ); msg->Append( m_currentControllerCommand->m_controllerCommandArg ); SendMsg( msg, MsgQueue_Command );
break;
}
case ControllerCommand_DeleteAllReturnRoutes:
{
Log::Write( LogLevel_Info, 0, "Deleting all return routes from node %d", m_currentControllerCommand->m_controllerCommandNode );
Msg* msg = new Msg( "ControllerCommand_DeleteAllReturnRoutess", m_currentControllerCommand->m_controllerCommandNode, REQUEST, FUNC_ID_ZW_DELETE_RETURN_ROUTE, true );
msg->Append( m_currentControllerCommand->m_controllerCommandNode ); SendMsg( msg, MsgQueue_Command );
break;
}
case ControllerCommand_SendNodeInformation:
{
Log::Write( LogLevel_Info, 0, "Sending a node information frame" );
Msg* msg = new Msg( "ControllerCommand_SendNodeInformation", m_currentControllerCommand->m_controllerCommandNode, REQUEST, FUNC_ID_ZW_SEND_NODE_INFORMATION, true );
msg->Append( m_currentControllerCommand->m_controllerCommandNode ); msg->Append( GetTransmitOptions() );
SendMsg( msg, MsgQueue_Command );
break;
}
case ControllerCommand_ReplicationSend:
{
if( !IsPrimaryController() )
{
UpdateControllerState( ControllerState_Error, ControllerError_NotPrimary );
}
else
{
Log::Write( LogLevel_Info, 0, "Replication Send" );
Msg* msg = new Msg( "ControllerCommand_ReplicationSend", 0xff, REQUEST, FUNC_ID_ZW_ADD_NODE_TO_NETWORK, true );
msg->Append( m_currentControllerCommand->m_highPower ? ADD_NODE_CONTROLLER | OPTION_HIGH_POWER : ADD_NODE_CONTROLLER );
SendMsg( msg, MsgQueue_Command );
}
break;
}
case ControllerCommand_CreateButton:
{
if( IsBridgeController() )
{
Node* node = GetNodeUnsafe( m_currentControllerCommand->m_controllerCommandNode );
if( node != NULL )
{
if( node->m_buttonMap.find( m_currentControllerCommand->m_controllerCommandArg ) == node->m_buttonMap.end() && m_virtualNeighborsReceived )
{
bool found = false;
for( uint8 n = 1; n <= 232 && !found; n++ )
{
if( !IsVirtualNode( n ))
continue;
map<uint8,uint8>::iterator it = node->m_buttonMap.begin();
for( ; it != node->m_buttonMap.end(); ++it )
{
if( it->second == n )
break;
}
if( it == node->m_buttonMap.end() ) {
node->m_buttonMap[m_currentControllerCommand->m_controllerCommandArg] = n;
SendVirtualNodeInfo( n, m_currentControllerCommand->m_controllerCommandNode );
found = true;
}
}
if( !found ) {
Log::Write( LogLevel_Info, 0, "AddVirtualNode" );
Msg* msg = new Msg( "FUNC_ID_SERIAL_API_SLAVE_NODE_INFO", 0xff, REQUEST, FUNC_ID_SERIAL_API_SLAVE_NODE_INFO, false, false );
msg->Append( 0 ); msg->Append( 1 ); msg->Append( 0x09 ); msg->Append( 0x00 ); msg->Append( 0 ); SendMsg( msg, MsgQueue_Command );
msg = new Msg( "FUNC_ID_ZW_SET_SLAVE_LEARN_MODE", 0xff, REQUEST, FUNC_ID_ZW_SET_SLAVE_LEARN_MODE, true );
msg->Append( 0 ); if( IsPrimaryController() || IsInclusionController() )
{
msg->Append( SLAVE_LEARN_MODE_ADD );
}
else
{
msg->Append( SLAVE_LEARN_MODE_ENABLE );
}
SendMsg( msg, MsgQueue_Command );
}
}
else
{
UpdateControllerState( ControllerState_Error, ControllerError_ButtonNotFound );
}
}
else
{
UpdateControllerState( ControllerState_Error, ControllerError_NodeNotFound );
}
} else
{
UpdateControllerState( ControllerState_Error, ControllerError_NotBridge );
}
break;
}
case ControllerCommand_DeleteButton:
{
if( IsBridgeController() )
{
Node* node = GetNodeUnsafe( m_currentControllerCommand->m_controllerCommandNode );
if( node != NULL )
{
if( node->m_buttonMap.find( m_currentControllerCommand->m_controllerCommandArg ) != node->m_buttonMap.end() )
{
#ifdef notdef
Log::Write( LogLevel_Info, 0, "RemoveVirtualNode %d", m_currentControllerCommand->m_controllerCommandNode );
Msg* msg = new Msg( "Remove Virtual Node", 0xff, REQUEST, FUNC_ID_ZW_SET_SLAVE_LEARN_MODE, true );
msg->Append( m_currentControllerCommand->m_controllerCommandNode ); if( IsPrimaryController() || IsInclusionController() )
msg->Append( SLAVE_LEARN_MODE_REMOVE );
else
msg->Append( SLAVE_LEARN_MODE_ENABLE );
SendMsg( msg );
#endif
node->m_buttonMap.erase( m_currentControllerCommand->m_controllerCommandArg );
SaveButtons();
Notification* notification = new Notification( Notification::Type_DeleteButton );
notification->SetHomeAndNodeIds( m_homeId, m_currentControllerCommand->m_controllerCommandNode );
notification->SetButtonId( m_currentControllerCommand->m_controllerCommandArg );
QueueNotification( notification );
}
else
{
UpdateControllerState( ControllerState_Error, ControllerError_ButtonNotFound );
}
}
else
{
UpdateControllerState( ControllerState_Error, ControllerError_NodeNotFound );
}
}
else
{
UpdateControllerState( ControllerState_Error, ControllerError_NotBridge );
}
break;
}
case ControllerCommand_None:
{
break;
}
}
}
void Driver::UpdateControllerState( ControllerState const _state, ControllerError const _error )
{
if( m_currentControllerCommand != NULL )
{
if( _state != m_currentControllerCommand->m_controllerState )
{
m_currentControllerCommand->m_controllerStateChanged = true;
m_currentControllerCommand->m_controllerState = _state;
switch( _state )
{
case ControllerState_Error:
case ControllerState_Cancel:
case ControllerState_Failed:
case ControllerState_Sleeping:
case ControllerState_NodeFailed:
case ControllerState_NodeOK:
case ControllerState_Completed:
{
m_currentControllerCommand->m_controllerCommandDone = true;
m_sendMutex->Lock();
m_queueEvent[MsgQueue_Controller]->Set();
m_sendMutex->Unlock();
break;
}
default:
{
break;
}
}
}
Notification* notification = new Notification( Notification::Type_ControllerCommand );
notification->SetHomeAndNodeIds(m_homeId, 0);
notification->SetEvent(_state);
if( _error != ControllerError_None )
{
m_currentControllerCommand->m_controllerReturnError = _error;
notification->SetNotification(_error);
}
QueueNotification( notification );
}
}
bool Driver::CancelControllerCommand
(
)
{
if( m_currentControllerCommand == NULL )
{
return false;
}
switch( m_currentControllerCommand->m_controllerCommand )
{
case ControllerCommand_AddDevice:
{
Log::Write( LogLevel_Info, 0, "Cancel Add Node" );
m_currentControllerCommand->m_controllerCommandNode = 0xff; AddNodeStop( FUNC_ID_ZW_ADD_NODE_TO_NETWORK );
break;
}
case ControllerCommand_CreateNewPrimary:
{
Log::Write( LogLevel_Info, 0, "Cancel Create New Primary" );
Msg* msg = new Msg( "CreateNewPrimary Stop", 0xff, REQUEST, FUNC_ID_ZW_CREATE_NEW_PRIMARY, true );
msg->Append( CREATE_PRIMARY_STOP );
SendMsg( msg, MsgQueue_Command );
break;
}
case ControllerCommand_ReceiveConfiguration:
{
Log::Write( LogLevel_Info, 0, "Cancel Receive Configuration" );
Msg* msg = new Msg( "ReceiveConfiguration Stop", 0xff, REQUEST, FUNC_ID_ZW_SET_LEARN_MODE, false, false );
msg->Append( 0 );
SendMsg( msg, MsgQueue_Command );
break;
}
case ControllerCommand_RemoveDevice:
{
Log::Write( LogLevel_Info, 0, "Cancel Remove Device" );
m_currentControllerCommand->m_controllerCommandNode = 0xff; AddNodeStop( FUNC_ID_ZW_REMOVE_NODE_FROM_NETWORK );
break;
}
case ControllerCommand_TransferPrimaryRole:
{
Log::Write( LogLevel_Info, 0, "Cancel Transfer Primary Role" );
Msg* msg = new Msg( "Transfer Primary Role Stop", 0xff, REQUEST, FUNC_ID_ZW_CONTROLLER_CHANGE, true );
msg->Append( CONTROLLER_CHANGE_STOP );
SendMsg( msg, MsgQueue_Command );
break;
}
case ControllerCommand_ReplicationSend:
{
Log::Write( LogLevel_Info, 0, "Cancel Replication Send" );
m_currentControllerCommand->m_controllerCommandNode = 0xff; AddNodeStop( FUNC_ID_ZW_ADD_NODE_TO_NETWORK );
break;
}
case ControllerCommand_CreateButton:
case ControllerCommand_DeleteButton:
{
if( m_currentControllerCommand->m_controllerCommandNode != 0 )
{
SendSlaveLearnModeOff();
}
break;
}
case ControllerCommand_None:
case ControllerCommand_RequestNetworkUpdate:
case ControllerCommand_RequestNodeNeighborUpdate:
case ControllerCommand_AssignReturnRoute:
case ControllerCommand_DeleteAllReturnRoutes:
case ControllerCommand_RemoveFailedNode:
case ControllerCommand_HasNodeFailed:
case ControllerCommand_ReplaceFailedNode:
case ControllerCommand_SendNodeInformation:
{
return false;
}
}
UpdateControllerState( ControllerState_Cancel );
return true;
}
void Driver::AddNodeStop
(
uint8 const _funcId
)
{
if( m_currentControllerCommand == NULL )
{
return;
}
if( m_serialAPIVersion[0] == 2 && m_serialAPIVersion[1] == 76 )
{
Msg* msg = new Msg( "Add Node Stop", 0xff, REQUEST, _funcId, false, false );
msg->Append( ADD_NODE_STOP );
SendMsg( msg, Driver::MsgQueue_Command );
}
else
{
Msg* msg = new Msg( "Add Node Stop", 0xff, REQUEST, _funcId, false, true );
msg->Append( ADD_NODE_STOP );
SendMsg( msg, Driver::MsgQueue_Command );
}
}
void Driver::TestNetwork
(
uint8 const _nodeId,
uint32 const _count
)
{
LockGuard LG(m_nodeMutex);
if( _nodeId == 0 ) {
for( int i=0; i<256; ++i )
{
if( i == m_Controller_nodeId ) {
continue;
}
if( m_nodes[i] != NULL )
{
NoOperation *noop = static_cast<NoOperation*>( m_nodes[i]->GetCommandClass( NoOperation::StaticGetCommandClassId() ) );
for( int j=0; j < (int)_count; j++ )
{
noop->Set( true );
}
}
}
}
else if( _nodeId != m_Controller_nodeId && m_nodes[_nodeId] != NULL )
{
NoOperation *noop = static_cast<NoOperation*>( m_nodes[_nodeId]->GetCommandClass( NoOperation::StaticGetCommandClassId() ) );
for( int i=0; i < (int)_count; i++ )
{
noop->Set( true );
}
}
}
void Driver::SwitchAllOn
(
)
{
SwitchAll::On( this, 0xff );
LockGuard LG(m_nodeMutex);
for( int i=0; i<256; ++i )
{
if( GetNodeUnsafe( i ) )
{
if( m_nodes[i]->GetCommandClass( SwitchAll::StaticGetCommandClassId() ) )
{
SwitchAll::On( this, (uint8)i );
}
}
}
}
void Driver::SwitchAllOff
(
)
{
SwitchAll::Off( this, 0xff );
LockGuard LG(m_nodeMutex);
for( int i=0; i<256; ++i )
{
if( GetNodeUnsafe( i ) )
{
if( m_nodes[i]->GetCommandClass( SwitchAll::StaticGetCommandClassId() ) )
{
SwitchAll::Off( this, (uint8)i );
}
}
}
}
bool Driver::SetConfigParam
(
uint8 const _nodeId,
uint8 const _param,
int32 _value,
uint8 _size
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
return node->SetConfigParam( _param, _value, _size );
}
return false;
}
void Driver::RequestConfigParam
(
uint8 const _nodeId,
uint8 const _param
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
node->RequestConfigParam( _param );
}
}
uint8 Driver::GetNumGroups
(
uint8 const _nodeId
)
{
uint8 numGroups = 0;
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
numGroups = node->GetNumGroups();
}
return numGroups;
}
uint32 Driver::GetAssociations
(
uint8 const _nodeId,
uint8 const _groupIdx,
uint8** o_associations
)
{
uint32 numAssociations = 0;
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
numAssociations = node->GetAssociations( _groupIdx, o_associations );
}
return numAssociations;
}
uint32 Driver::GetAssociations
(
uint8 const _nodeId,
uint8 const _groupIdx,
InstanceAssociation** o_associations
)
{
uint32 numAssociations = 0;
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
numAssociations = node->GetAssociations( _groupIdx, o_associations );
}
return numAssociations;
}
uint8 Driver::GetMaxAssociations
(
uint8 const _nodeId,
uint8 const _groupIdx
)
{
uint8 maxAssociations = 0;
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
maxAssociations = node->GetMaxAssociations( _groupIdx );
}
return maxAssociations;
}
string Driver::GetGroupLabel
(
uint8 const _nodeId,
uint8 const _groupIdx
)
{
string label = "";
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
label = node->GetGroupLabel( _groupIdx );
}
return label;
}
void Driver::AddAssociation
(
uint8 const _nodeId,
uint8 const _groupIdx,
uint8 const _targetNodeId,
uint8 const _instance
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
node->AddAssociation( _groupIdx, _targetNodeId, _instance );
}
}
void Driver::RemoveAssociation
(
uint8 const _nodeId,
uint8 const _groupIdx,
uint8 const _targetNodeId,
uint8 const _instance
)
{
LockGuard LG(m_nodeMutex);
if( Node* node = GetNode( _nodeId ) )
{
node->RemoveAssociation( _groupIdx, _targetNodeId, _instance );
}
}
void Driver::QueueNotification
(
Notification* _notification
)
{
m_notifications.push_back( _notification );
m_notificationsEvent->Set();
}
void Driver::NotifyWatchers
(
)
{
list<Notification*>::iterator nit = m_notifications.begin();
while( nit != m_notifications.end() )
{
Notification* notification = m_notifications.front();
m_notifications.pop_front();
switch (notification->GetType()) {
case Notification::Type_ValueChanged:
case Notification::Type_ValueRefreshed: {
Value *val = GetValue(notification->GetValueID());
if (!val) {
Log::Write(LogLevel_Info, notification->GetNodeId(), "Dropping Notification as ValueID does not exist");
nit = m_notifications.begin();
delete notification;
val->Release();
continue;
}
break;
}
default:
break;
}
Log::Write(LogLevel_Detail, notification->GetNodeId(), "Notification: %s", notification->GetAsString().c_str());
Manager::Get()->NotifyWatchers( notification );
delete notification;
nit = m_notifications.begin();
}
m_notificationsEvent->Reset();
}
bool Driver::HandleRfPowerLevelSetResponse
(
uint8* _data
)
{
bool res = true;
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "Received reply to FUNC_ID_ZW_R_F_POWER_LEVEL_SET" );
return res;
}
bool Driver::HandleSerialApiSetTimeoutsResponse
(
uint8* _data
)
{
bool res = true;
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "Received reply to FUNC_ID_SERIAL_API_SET_TIMEOUTS" );
return res;
}
bool Driver::HandleMemoryGetByteResponse
(
uint8* _data
)
{
bool res = true;
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "Received reply to FUNC_ID_ZW_MEMORY_GET_BYTE, returned data: 0x%02hx 0x%02hx 0x%02hx", _data[0], _data[1], _data[2] );
return res;
}
bool Driver::HandleReadMemoryResponse
(
uint8* _data
)
{
bool res = true;
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "Received reply to FUNC_ID_MEMORY_GET_BYTE" );
return res;
}
void Driver::HandleGetVirtualNodesResponse
(
uint8* _data
)
{
uint8 nodeId = GetNodeNumber( m_currentMsg );
Log::Write( LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_GET_VIRTUAL_NODES" );
memcpy( m_virtualNeighbors, &_data[2], 29 );
m_virtualNeighborsReceived = true;
bool bNeighbors = false;
for( int by=0; by<29; by++ )
{
for( int bi=0; bi<8; bi++ )
{
if( (_data[2+by] & (0x01<<bi)) )
{
Log::Write( LogLevel_Info, nodeId, " Node %d", (by<<3)+bi+1 );
bNeighbors = true;
}
}
}
if( !bNeighbors )
Log::Write( LogLevel_Info, nodeId, " (none reported)" );
}
uint32 Driver::GetVirtualNeighbors
(
uint8** o_neighbors
)
{
int i;
uint32 numNeighbors = 0;
if( !m_virtualNeighborsReceived )
{
*o_neighbors = NULL;
return 0;
}
for( i = 0; i < 29; i++ )
{
for( unsigned char mask = 0x80; mask != 0; mask >>= 1 )
if( m_virtualNeighbors[i] & mask )
numNeighbors++;
}
if( !numNeighbors )
{
*o_neighbors = NULL;
return 0;
}
uint8* neighbors = new uint8[numNeighbors];
uint32 index = 0;
for( int by=0; by<29; by++ )
{
for( int bi=0; bi<8; bi++ )
{
if( (m_virtualNeighbors[by] & (0x01<<bi)) )
neighbors[index++] = ( (by<<3) + bi + 1 );
}
}
*o_neighbors = neighbors;
return numNeighbors;
}
void Driver::RequestVirtualNeighbors
(
MsgQueue const _queue
)
{
Msg* msg = new Msg( "Get Virtual Neighbor List", 0xff, REQUEST, FUNC_ID_ZW_GET_VIRTUAL_NODES, false );
SendMsg( msg, _queue );
}
void Driver::SendVirtualNodeInfo
(
uint8 const _FromNodeId,
uint8 const _ToNodeId
)
{
char str[80];
snprintf( str, sizeof(str), "Send Virtual Node Info from %d to %d", _FromNodeId, _ToNodeId );
Msg* msg = new Msg( str, 0xff, REQUEST, FUNC_ID_ZW_SEND_SLAVE_NODE_INFO, true );
msg->Append( _FromNodeId ); msg->Append( _ToNodeId ); msg->Append( TRANSMIT_OPTION_ACK );
SendMsg( msg, MsgQueue_Command );
}
void Driver::SendSlaveLearnModeOff
(
)
{
if( !( IsPrimaryController() || IsInclusionController() ) )
{
Msg* msg = new Msg( "Set Slave Learn Mode Off ", 0xff, REQUEST, FUNC_ID_ZW_SET_SLAVE_LEARN_MODE, true );
msg->Append( 0 ); msg->Append( SLAVE_LEARN_MODE_DISABLE );
SendMsg( msg, MsgQueue_Command );
}
}
void Driver::SaveButtons
(
)
{
char str[16];
TiXmlDocument doc;
TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "utf-8", "" );
TiXmlElement* nodesElement = new TiXmlElement( "Nodes" );
doc.LinkEndChild( decl );
doc.LinkEndChild( nodesElement );
nodesElement->SetAttribute( "xmlns", "http://code.google.com/p/open-zwave/" );
snprintf( str, sizeof(str), "%d", 1 );
nodesElement->SetAttribute( "version", str);
LockGuard LG(m_nodeMutex);
for( int i = 1; i < 256; i++ )
{
if( m_nodes[i] == NULL || m_nodes[i]->m_buttonMap.empty() )
{
continue;
}
TiXmlElement* nodeElement = new TiXmlElement( "Node" );
snprintf( str, sizeof(str), "%d", i );
nodeElement->SetAttribute( "id", str );
for( map<uint8,uint8>::iterator it = m_nodes[i]->m_buttonMap.begin(); it != m_nodes[i]->m_buttonMap.end(); ++it )
{
TiXmlElement* valueElement = new TiXmlElement( "Button" );
snprintf( str, sizeof(str), "%d", it->first );
valueElement->SetAttribute( "id", str );
snprintf( str, sizeof(str), "%d", it->second );
TiXmlText* textElement = new TiXmlText( str );
valueElement->LinkEndChild( textElement );
nodeElement->LinkEndChild( valueElement );
}
nodesElement->LinkEndChild( nodeElement );
}
string userPath;
Options::Get()->GetOptionAsString( "UserPath", &userPath );
string filename = userPath + "zwbutton.xml";
doc.SaveFile( filename.c_str() );
}
void Driver::ReadButtons
(
uint8 const _nodeId
)
{
int32 intVal;
int32 nodeId;
int32 buttonId;
char const* str;
string userPath;
Options::Get()->GetOptionAsString( "UserPath", &userPath );
string filename = userPath + "zwbutton.xml";
TiXmlDocument doc;
if( !doc.LoadFile( filename.c_str(), TIXML_ENCODING_UTF8 ) )
{
Log::Write( LogLevel_Debug, "Driver::ReadButtons - zwbutton.xml file not found.");
return;
}
TiXmlElement const* nodesElement = doc.RootElement();
str = nodesElement->Value();
if( str && strcmp( str, "Nodes" ))
{
Log::Write( LogLevel_Warning, "WARNING: Driver::ReadButtons - zwbutton.xml is malformed");
return;
}
if( TIXML_SUCCESS == nodesElement->QueryIntAttribute( "version", &intVal ) )
{
if( (uint32)intVal != 1 )
{
Log::Write( LogLevel_Info, "Driver::ReadButtons - %s is from an older version of OpenZWave and cannot be loaded.", "zwbutton.xml" );
return;
}
}
else
{
Log::Write( LogLevel_Warning, "WARNING: Driver::ReadButtons - zwbutton.xml is from an older version of OpenZWave and cannot be loaded." );
return;
}
TiXmlElement const* nodeElement = nodesElement->FirstChildElement();
while( nodeElement )
{
str = nodeElement->Value();
if( str && !strcmp( str, "Node" ))
{
Node* node = NULL;
if( TIXML_SUCCESS == nodeElement->QueryIntAttribute( "id", &intVal ) )
{
if( _nodeId == intVal )
{
node = GetNodeUnsafe( intVal );
}
}
if( node != NULL )
{
TiXmlElement const* buttonElement = nodeElement->FirstChildElement();
while( buttonElement )
{
str = buttonElement->Value();
if( str && !strcmp( str, "Button"))
{
if (TIXML_SUCCESS != buttonElement->QueryIntAttribute( "id", &buttonId ) )
{
Log::Write( LogLevel_Warning, "WARNING: Driver::ReadButtons - cannot find Button Id for node %d", _nodeId );
return;
}
str = buttonElement->GetText();
if( str )
{
char *p;
nodeId = (int32)strtol( str, &p, 0 );
}
else
{
Log::Write( LogLevel_Info, "Driver::ReadButtons - missing virtual node value for node %d button id %d", _nodeId, buttonId );
return;
}
node->m_buttonMap[buttonId] = nodeId;
Notification* notification = new Notification( Notification::Type_CreateButton );
notification->SetHomeAndNodeIds( m_homeId, nodeId );
notification->SetButtonId( buttonId );
QueueNotification( notification );
}
buttonElement = buttonElement->NextSiblingElement();
}
}
}
nodeElement = nodeElement->NextSiblingElement();
}
}
bool Driver::HandleSetSlaveLearnModeResponse
(
uint8* _data
)
{
bool res = true;
ControllerState state = ControllerState_InProgress;
uint8 nodeId = GetNodeNumber( m_currentMsg );
if( _data[2] )
{
Log::Write( LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_SET_SLAVE_LEARN_MODE - command in progress" );
}
else
{
Log::Write( LogLevel_Warning, nodeId, "WARNING: Received reply to FUNC_ID_ZW_SET_SLAVE_LEARN_MODE - command failed" );
state = ControllerState_Failed;
res = false;
SendSlaveLearnModeOff();
}
UpdateControllerState( state );
return res;
}
void Driver::HandleSetSlaveLearnModeRequest
(
uint8* _data
)
{
ControllerState state = ControllerState_Waiting;
uint8 nodeId = GetNodeNumber( m_currentMsg );
if( m_currentControllerCommand == NULL )
{
return;
}
SendSlaveLearnModeOff();
switch( _data[3] )
{
case SLAVE_ASSIGN_COMPLETE:
{
Log::Write( LogLevel_Info, nodeId, "SLAVE_ASSIGN_COMPLETE" );
if( _data[4] == 0 ) {
Log::Write( LogLevel_Info, nodeId, "Adding virtual node ID %d", _data[5] );
Node* node = GetNodeUnsafe( m_currentControllerCommand->m_controllerCommandNode );
if( node != NULL )
{
node->m_buttonMap[m_currentControllerCommand->m_controllerCommandArg] = _data[5];
SendVirtualNodeInfo( _data[5], m_currentControllerCommand->m_controllerCommandNode );
}
}
else
if( _data[5] == 0 )
{
Log::Write( LogLevel_Info, nodeId, "Removing virtual node ID %d", _data[4] );
}
break;
}
case SLAVE_ASSIGN_NODEID_DONE:
{
Log::Write( LogLevel_Info, nodeId, "SLAVE_ASSIGN_NODEID_DONE" );
if( _data[4] == 0 ) {
Log::Write( LogLevel_Info, nodeId, "Adding virtual node ID %d", _data[5] );
Node* node = GetNodeUnsafe( m_currentControllerCommand->m_controllerCommandNode );
if( node != NULL )
{
node->m_buttonMap[m_currentControllerCommand->m_controllerCommandArg] = _data[5];
SendVirtualNodeInfo( _data[5], m_currentControllerCommand->m_controllerCommandNode );
}
}
else
if( _data[5] == 0 )
{
Log::Write( LogLevel_Info, nodeId, "Removing virtual node ID %d", _data[4] );
}
break;
}
case SLAVE_ASSIGN_RANGE_INFO_UPDATE:
{
Log::Write( LogLevel_Info, nodeId, "SLAVE_ASSIGN_RANGE_INFO_UPDATE" );
break;
}
}
m_currentControllerCommand->m_controllerAdded = false;
UpdateControllerState( state );
}
bool Driver::HandleSendSlaveNodeInfoResponse
(
uint8* _data
)
{
bool res = true;
ControllerState state = ControllerState_InProgress;
uint8 nodeId = GetNodeNumber( m_currentMsg );
if( m_currentControllerCommand == NULL )
{
return false;
}
if( _data[2] )
{
Log::Write( LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_SEND_SLAVE_NODE_INFO - command in progress" );
}
else
{
Log::Write( LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_SEND_SLAVE_NODE_INFO - command failed" );
state = ControllerState_Failed;
Node* node = GetNodeUnsafe( m_currentControllerCommand->m_controllerCommandNode );
if( node != NULL )
{
node->m_buttonMap.erase( m_currentControllerCommand->m_controllerCommandArg );
}
res = false;
}
UpdateControllerState( state );
return res;
}
void Driver::HandleSendSlaveNodeInfoRequest
(
uint8* _data
)
{
if( m_currentControllerCommand == NULL )
{
return;
}
if( _data[3] == 0 ) {
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "SEND_SLAVE_NODE_INFO_COMPLETE OK" );
SaveButtons();
Notification* notification = new Notification( Notification::Type_CreateButton );
notification->SetHomeAndNodeIds( m_homeId, m_currentControllerCommand->m_controllerCommandNode );
notification->SetButtonId( m_currentControllerCommand->m_controllerCommandArg );
QueueNotification( notification );
UpdateControllerState( ControllerState_Completed );
RequestVirtualNeighbors( MsgQueue_Send );
}
else {
HandleErrorResponse( _data[3], m_currentControllerCommand->m_controllerCommandNode, "SLAVE_NODE_INFO_COMPLETE" );
Node* node = GetNodeUnsafe( m_currentControllerCommand->m_controllerCommandNode );
if( node != NULL)
{
SendVirtualNodeInfo( node->m_buttonMap[m_currentControllerCommand->m_controllerCommandArg], m_currentControllerCommand->m_controllerCommandNode );
}
}
}
void Driver::HandleApplicationSlaveCommandRequest
(
uint8* _data
)
{
Log::Write( LogLevel_Info, GetNodeNumber( m_currentMsg ), "APPLICATION_SLAVE_COMMAND_HANDLER rxStatus %x dest %d source %d len %d", _data[2], _data[3], _data[4], _data[5] );
Node* node = GetNodeUnsafe( _data[4] );
if( node != NULL && _data[5] == 3 && _data[6] == 0x20 && _data[7] == 0x01 ) {
map<uint8,uint8>::iterator it = node->m_buttonMap.begin();
for( ; it != node->m_buttonMap.end(); ++it )
{
if( it->second == _data[3] )
break;
}
if( it != node->m_buttonMap.end() )
{
Notification *notification;
if( _data[8] == 0 )
{
notification = new Notification( Notification::Type_ButtonOff );
}
else
{
notification = new Notification( Notification::Type_ButtonOn );
}
notification->SetHomeAndNodeIds( m_homeId, _data[4] );
notification->SetButtonId( it->first );
QueueNotification( notification );
}
}
}
uint8 Driver::NodeFromMessage
(
uint8 const* buffer
)
{
uint8 nodeId = 0;
if( buffer[1] >= 5 )
{
switch( buffer[3] )
{
case FUNC_ID_APPLICATION_COMMAND_HANDLER: nodeId = buffer[5]; break;
case FUNC_ID_ZW_APPLICATION_UPDATE: nodeId = buffer[5]; break;
}
}
return nodeId;
}
void Driver::UpdateNodeRoutes
(
uint8 const _nodeId,
bool _doUpdate )
{
Node* node = GetNodeUnsafe( _nodeId );
if( node != NULL && node->GetBasic() == 0x04 )
{
uint8 numGroups = GetNumGroups( _nodeId );
uint8 numNodes = 0;
uint8 nodes[5];
InstanceAssociation* associations;
uint8 i;
memset( nodes, 0, sizeof(nodes) );
for( i = 1; i <= numGroups && numNodes < sizeof(nodes) ; i++ )
{
associations = NULL;
uint32 len = GetAssociations( _nodeId, i, &associations );
for( uint8 j = 0; j < len; j++ )
{
uint8 k;
for( k = 0; k < numNodes && k < sizeof(nodes); k++ )
{
if( nodes[k] == associations[j].m_nodeId )
{
break;
}
}
if( k >= numNodes && numNodes < sizeof(nodes) ) {
nodes[numNodes++] = associations[j].m_nodeId;
}
}
if( associations != NULL )
{
delete [] associations;
}
}
if( _doUpdate || numNodes != node->m_numRouteNodes || memcmp( nodes, node->m_routeNodes, sizeof(node->m_routeNodes) ) != 0 )
{
BeginControllerCommand( ControllerCommand_DeleteAllReturnRoutes, NULL, NULL, true, _nodeId, 0 );
for( i = 0; i < numNodes; i++ )
{
BeginControllerCommand( ControllerCommand_AssignReturnRoute, NULL, NULL, true, _nodeId, nodes[i] );
}
node->m_numRouteNodes = numNodes;
memcpy( node->m_routeNodes, nodes, sizeof(nodes) );
}
}
}
void Driver::GetDriverStatistics
(
DriverData* _data
)
{
_data->m_SOFCnt = m_SOFCnt;
_data->m_ACKWaiting = m_ACKWaiting;
_data->m_readAborts = m_readAborts;
_data->m_badChecksum = m_badChecksum;
_data->m_readCnt = m_readCnt;
_data->m_writeCnt = m_writeCnt;
_data->m_CANCnt = m_CANCnt;
_data->m_NAKCnt = m_NAKCnt;
_data->m_ACKCnt = m_ACKCnt;
_data->m_OOFCnt = m_OOFCnt;
_data->m_dropped = m_dropped;
_data->m_retries = m_retries;
_data->m_callbacks = m_callbacks;
_data->m_badroutes = m_badroutes;
_data->m_noack = m_noack;
_data->m_netbusy = m_netbusy;
_data->m_notidle = m_notidle;
_data->m_nondelivery = m_nondelivery;
_data->m_routedbusy = m_routedbusy;
_data->m_broadcastReadCnt = m_broadcastReadCnt;
_data->m_broadcastWriteCnt = m_broadcastWriteCnt;
}
void Driver::GetNodeStatistics
(
uint8 const _nodeId,
Node::NodeData* _data
)
{
LockGuard LG(m_nodeMutex);
Node* node = GetNode( _nodeId );
if( node != NULL )
{
node->GetNodeStatistics( _data );
}
}
void Driver::LogDriverStatistics
(
)
{
DriverData data;
GetDriverStatistics(&data);
int32 totalElapsed = -m_startTime.TimeRemaining();
int32 days = totalElapsed / (1000*60*60*24);
totalElapsed -= days*1000*60*60*24;
int32 hours = totalElapsed/(1000*60*60);
totalElapsed -= hours*1000*60*60;
int32 minutes = totalElapsed/(1000*60);
Log::Write( LogLevel_Always, "***************************************************************************" );
Log::Write( LogLevel_Always, "********************* Cumulative Network Statistics *********************" );
Log::Write( LogLevel_Always, "*** General" );
Log::Write( LogLevel_Always, "Driver run time: . . . %ld days, %ld hours, %ld minutes", days, hours, minutes);
Log::Write( LogLevel_Always, "Frames processed: . . . . . . . . . . . . . . . . . . . . %ld", data.m_SOFCnt );
Log::Write( LogLevel_Always, "Total messages successfully received: . . . . . . . . . . %ld", data.m_readCnt );
Log::Write( LogLevel_Always, "Total Messages successfully sent: . . . . . . . . . . . . %ld", data.m_writeCnt );
Log::Write( LogLevel_Always, "ACKs received from controller: . . . . . . . . . . . . . %ld", data.m_ACKCnt );
Log::Write( LogLevel_Always, "*** Errors" );
Log::Write( LogLevel_Always, "Unsolicited messages received while waiting for ACK: . . %ld", data.m_ACKWaiting );
Log::Write( LogLevel_Always, "Reads aborted due to timeouts: . . . . . . . . . . . . . %ld", data.m_readAborts );
Log::Write( LogLevel_Always, "Bad checksum errors: . . . . . . . . . . . . . . . . . . %ld", data.m_badChecksum );
Log::Write( LogLevel_Always, "CANs received from controller: . . . . . . . . . . . . . %ld", data.m_CANCnt );
Log::Write( LogLevel_Always, "NAKs received from controller: . . . . . . . . . . . . . %ld", data.m_NAKCnt );
Log::Write( LogLevel_Always, "Out of frame data flow errors: . . . . . . . . . . . . . %ld", data.m_OOFCnt );
Log::Write( LogLevel_Always, "Messages retransmitted: . . . . . . . . . . . . . . . . . %ld", data.m_retries );
Log::Write( LogLevel_Always, "Messages dropped and not delivered: . . . . . . . . . . . %ld", data.m_dropped );
Log::Write( LogLevel_Always, "***************************************************************************" );
}
uint8 *Driver::GetNetworkKey() {
std::string networkKey;
std::vector<std::string> elems;
unsigned int tempkey[16];
static uint8 keybytes[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static bool keySet = false;
if (keySet == false) {
Options::Get()->GetOptionAsString("NetworkKey", &networkKey );
OpenZWave::split(elems, networkKey, ",", true);
if (elems.size() != 16) {
Log::Write(LogLevel_Warning, "Invalid Network Key. Does not contain 16 Bytes - Contains %d", elems.size());
Log::Write(LogLevel_Warning, "Raw Key: %s", networkKey.c_str());
Log::Write(LogLevel_Warning, "Parsed Key:");
int i = 0;
for (std::vector<std::string>::iterator it = elems.begin(); it != elems.end(); it++)
Log::Write(LogLevel_Warning, "%d) - %s", ++i, (*it).c_str());
OZW_FATAL_ERROR(OZWException::OZWEXCEPTION_SECURITY_FAILED, "Failed to Read Network Key");
}
int i = 0;
for (std::vector<std::string>::iterator it = elems.begin(); it != elems.end(); it++) {
if (0 == sscanf(OpenZWave::trim(*it).c_str(), "%x", &tempkey[i])) {
Log::Write(LogLevel_Warning, "Cannot Convert Network Key Byte %s to Key", (*it).c_str());
OZW_FATAL_ERROR(OZWException::OZWEXCEPTION_SECURITY_FAILED, "Failed to Convert Network Key");
} else {
keybytes[i] = (tempkey[i] & 0xFF);
}
i++;
}
keySet = true;
}
return keybytes;
}
bool Driver::SendEncryptedMessage() {
uint8 *buffer = m_currentMsg->GetBuffer();
uint8 length = m_currentMsg->GetLength();
m_expectedCallbackId = m_currentMsg->GetCallbackId();
Log::Write(LogLevel_Info, m_currentMsg->GetTargetNodeId(), "Sending (%s) message (Callback ID=0x%.2x, Expected Reply=0x%.2x) - %s", c_sendQueueNames[m_currentMsgQueueSource], m_expectedCallbackId, m_expectedReply, m_currentMsg->GetAsString().c_str());
m_controller->Write( buffer, length );
m_currentMsg->clearNonce();
return true;
}
bool Driver::SendNonceRequest(string logmsg) {
uint8 m_buffer[11];
m_buffer[0] = SOF;
m_buffer[1] = 9; m_buffer[2] = REQUEST;
m_buffer[3] = FUNC_ID_ZW_SEND_DATA;
m_buffer[4] = m_currentMsg->GetTargetNodeId();
m_buffer[5] = 2; m_buffer[6] = Security::StaticGetCommandClassId();
m_buffer[7] = SecurityCmd_NonceGet;
m_buffer[8] = TRANSMIT_OPTION_ACK | TRANSMIT_OPTION_AUTO_ROUTE;
m_buffer[9] = 2;
m_buffer[10] = 0xff;
for( uint32 i=1; i<10; ++i )
{
m_buffer[10] ^= m_buffer[i];
}
Log::Write(LogLevel_Info, m_currentMsg->GetTargetNodeId(), "Sending (%s) message (Callback ID=0x%.2x, Expected Reply=0x%.2x) - Nonce_Get(%s) - %s:", c_sendQueueNames[m_currentMsgQueueSource], m_expectedCallbackId, m_expectedReply, logmsg.c_str(), PktToString(m_buffer, 10).c_str());
m_controller->Write(m_buffer, 11);
return true;
}
bool Driver::initNetworkKeys(bool newnode) {
uint8_t EncryptPassword[16] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
uint8_t AuthPassword[16] = {0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
uint8_t SecuritySchemes[1][16] = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
};
this->m_inclusionkeySet = newnode;
this->AuthKey = new aes_encrypt_ctx;
this->EncryptKey = new aes_encrypt_ctx;
Log::Write(LogLevel_Info, GetControllerNodeId(), "Setting Up %s Network Key for Secure Communications", newnode == true ? "Inclusion" : "Provided");
if (!isNetworkKeySet()) {
Log::Write(LogLevel_Warning, GetControllerNodeId(), "Failed - Network Key Not Set");
return false;
}
if (aes_init() == EXIT_FAILURE) {
Log::Write(LogLevel_Warning, GetControllerNodeId(), "Failed to Init AES Engine");
return false;
}
if (aes_encrypt_key128(newnode == false ? this->GetNetworkKey() : SecuritySchemes[0], this->EncryptKey) == EXIT_FAILURE) {
Log::Write(LogLevel_Warning, GetControllerNodeId(), "Failed to Set Initial Network Key for Encryption");
return false;
}
if (aes_encrypt_key128(newnode == false ? this->GetNetworkKey() : SecuritySchemes[0], this->AuthKey) == EXIT_FAILURE) {
Log::Write(LogLevel_Warning, GetControllerNodeId(), "Failed to Set Initial Network Key for Authentication");
return false;
}
uint8 tmpEncKey[32];
uint8 tmpAuthKey[32];
aes_mode_reset(this->EncryptKey);
aes_mode_reset(this->AuthKey);
if (aes_ecb_encrypt(EncryptPassword, tmpEncKey, 16, this->EncryptKey) == EXIT_FAILURE) {
Log::Write(LogLevel_Warning, GetControllerNodeId(), "Failed to Generate Encrypted Network Key for Encryption");
return false;
}
if (aes_ecb_encrypt(AuthPassword, tmpAuthKey, 16, this->AuthKey) == EXIT_FAILURE) {
Log::Write(LogLevel_Warning, GetControllerNodeId(), "Failed to Generate Encrypted Network Key for Authentication");
return false;
}
aes_mode_reset(this->EncryptKey);
aes_mode_reset(this->AuthKey);
if (aes_encrypt_key128(tmpEncKey, this->EncryptKey) == EXIT_FAILURE) {
Log::Write(LogLevel_Warning, GetControllerNodeId(), "Failed to set Encrypted Network Key for Encryption");
return false;
}
if (aes_encrypt_key128(tmpAuthKey, this->AuthKey) == EXIT_FAILURE) {
Log::Write(LogLevel_Warning, GetControllerNodeId(), "Failed to set Encrypted Network Key for Authentication");
return false;
}
aes_mode_reset(this->EncryptKey);
aes_mode_reset(this->AuthKey);
return true;
}
void Driver::SendNonceKey(uint8 nodeId, uint8 *nonce) {
uint8 m_buffer[19];
m_buffer[0] = SOF;
m_buffer[1] = 17; m_buffer[2] = REQUEST;
m_buffer[3] = FUNC_ID_ZW_SEND_DATA;
m_buffer[4] = nodeId;
m_buffer[5] = 10; m_buffer[6] = Security::StaticGetCommandClassId();
m_buffer[7] = SecurityCmd_NonceReport;
for (int i = 0; i < 8; ++i) {
m_buffer[8+i] = nonce[i];
}
m_buffer[16] = TRANSMIT_OPTION_ACK | TRANSMIT_OPTION_AUTO_ROUTE;
m_buffer[17] = 1;
m_buffer[18] = 0xff;
for( uint32 i=1; i<18; ++i )
{
m_buffer[18] ^= m_buffer[i];
}
Log::Write(LogLevel_Info, nodeId, "Sending (%s) message (Callback ID=0x%.2x, Expected Reply=0x%.2x) - Nonce_Report - %s:", c_sendQueueNames[m_currentMsgQueueSource], m_buffer[17], m_expectedReply, PktToString(m_buffer, 19).c_str());
m_controller->Write(m_buffer, 19);
m_nonceReportSent = nodeId;
}
aes_encrypt_ctx *Driver::GetAuthKey
(
)
{
if( m_currentControllerCommand != NULL &&
m_currentControllerCommand->m_controllerCommand == ControllerCommand_AddDevice &&
m_currentControllerCommand->m_controllerState == ControllerState_Completed ) {
initNetworkKeys(true);
} else if (m_inclusionkeySet) {
initNetworkKeys(false);
}
return this->AuthKey;
};
aes_encrypt_ctx *Driver::GetEncKey
(
)
{
if( m_currentControllerCommand != NULL &&
m_currentControllerCommand->m_controllerCommand == ControllerCommand_AddDevice &&
m_currentControllerCommand->m_controllerState == ControllerState_Completed ) {
initNetworkKeys(true);
} else if (m_inclusionkeySet) {
initNetworkKeys(false);
}
return this->EncryptKey;
};
bool Driver::isNetworkKeySet() {
std::string networkKey;
if (!Options::Get()->GetOptionAsString("NetworkKey", &networkKey )) {
return false;
} else {
return networkKey.length() <= 0 ? false : true;
}
}