Add promiscuous message handling but left commented out.

Added tracking and returning driver specific message count and error data. see Manager::GetDriverStatistics
Random formatting changes for consistency.
Class SensorMultilevel will use multiple indexes for multiple sensors.
Node::GetNeighbors will only return valid data. Wait for proper query stage to complete.
On Driver shutdown stop threads then remove controller object.
Add extra comments to Driver::IsControllerCommand so we can better track commands.
Update Mac OS X example Main.cpp to be consistent with Linux version. Handle more notifications
and add a thread to wait for query completion.
Add statistics print out to both Linux and Mac OS X example apps.
Fix Mac hidapi to terminate its background CFRunLoop upon hid_close.
This commit is contained in:
glsatz 2011-08-16 20:25:14 +00:00
parent 01aa2c7853
commit 3a85a66464
12 changed files with 381 additions and 177 deletions

View file

@ -34,6 +34,7 @@
#include <pthread.h>
#include "Options.h"
#include "Manager.h"
#include "Driver.h"
#include "Node.h"
#include "Group.h"
#include "Notification.h"
@ -180,6 +181,7 @@ void OnNotification
{
// We have received an event from the node, caused by a
// basic_set or hail message.
// TBD...
nodeInfo = nodeInfo;
}
break;
@ -208,7 +210,7 @@ void OnNotification
g_homeId = _notification->GetHomeId();
break;
}
case Notification::Type_DriverFailed:
{
@ -217,7 +219,7 @@ void OnNotification
break;
}
case Notification::Type_AwakeNodesQueried:
case Notification::Type_AwakeNodesQueried:
case Notification::Type_AllNodesQueried:
{
pthread_cond_broadcast(&initCond);
@ -239,13 +241,13 @@ int main( int argc, char* argv[] )
{
pthread_mutexattr_t mutexattr;
pthread_mutexattr_init ( &mutexattr );
pthread_mutexattr_init ( &mutexattr );
pthread_mutexattr_settype( &mutexattr, PTHREAD_MUTEX_RECURSIVE );
pthread_mutex_init( &g_criticalSection, &mutexattr );
pthread_mutexattr_destroy(&mutexattr);
pthread_mutex_lock(&initMutex);
pthread_mutexattr_destroy( &mutexattr );
pthread_mutex_lock( &initMutex );
// Create the OpenZWave Manager.
// The first argument is the path to the config files (where the manufacturer_specific.xml file is located
// The second argument is the path for saved Z-Wave network state and the log file. If you leave it NULL
@ -263,18 +265,19 @@ int main( int argc, char* argv[] )
// Add a Z-Wave Driver
// Modify this line to set the correct serial port for your PC interface.
string port = "/dev/ttyUSB0";
Manager::Get()->AddDriver((argc > 1) ? argv[1] : port);
Manager::Get()->AddDriver( ( argc > 1 ) ? argv[1] : port );
//Manager::Get()->AddDriver( "HID Controller", Driver::ControllerInterface_Hid );
// Now we just wait for the driver to become ready, and then write out the loaded config.
// In a normal app, we would be handling notifications and building a UI for the user.
pthread_cond_wait(&initCond, &initMutex);
if (!g_initFailed) {
pthread_cond_wait( &initCond, &initMutex );
if( !g_initFailed )
{
//Manager::Get()->BeginAddNode( g_homeId );
//sleep(10);
//Manager::Get()->EndAddNode( g_homeId );
@ -282,11 +285,19 @@ int main( int argc, char* argv[] )
//sleep(10);
//Manager::Get()->EndRemoveNode( g_homeId );
//sleep(10);
Manager::Get()->WriteConfig(g_homeId);
while(true)
Manager::Get()->WriteConfig( g_homeId );
Driver::DriverData data;
Manager::Get()->GetDriverStatistics( g_homeId, &data );
printf("SOF: %d ACK Waiting: %d Read Aborts: %d Bad Checksums: %d\n", data.s_SOFCnt, data.s_ACKWaiting, data.s_readAborts, data.s_badChecksum);
printf("Reads: %d Writes: %d CAN: %d NAK: %d ACK: %d Out of Frame: %d\n", data.s_readCnt, data.s_writeCnt, data.s_CANCnt, data.s_NAKCnt, data.s_ACKCnt, data.s_OOFCnt);
printf("Dropped: %d Retries: %d\n", data.s_dropped, data.s_retries);
while( true )
{
sleep(10);
pthread_mutex_lock( &g_criticalSection );
// Do stuff
pthread_mutex_unlock( &g_criticalSection );

View file

@ -34,6 +34,7 @@
#include <pthread.h>
#include "Options.h"
#include "Manager.h"
#include "Driver.h"
#include "Node.h"
#include "Group.h"
#include "Notification.h"
@ -44,8 +45,9 @@
using namespace OpenZWave;
static uint32 g_homeId = 0;
static bool g_initFailed = false;
typedef struct
typedef struct
{
uint32 m_homeId;
uint8 m_nodeId;
@ -55,6 +57,8 @@ typedef struct
static list<NodeInfo*> g_nodes;
static pthread_mutex_t g_criticalSection;
static pthread_cond_t initCond = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t initMutex = PTHREAD_MUTEX_INITIALIZER;
//-----------------------------------------------------------------------------
// <GetNodeInfo>
@ -127,6 +131,7 @@ void OnNotification
{
// One of the node values has changed
// TBD...
nodeInfo = nodeInfo;
}
break;
}
@ -137,6 +142,7 @@ void OnNotification
{
// One of the node's association groups has changed
// TBD...
nodeInfo = nodeInfo;
}
break;
}
@ -176,6 +182,7 @@ void OnNotification
// We have received an event from the node, caused by a
// basic_set or hail message.
// TBD...
nodeInfo = nodeInfo;
}
break;
}
@ -203,11 +210,29 @@ void OnNotification
g_homeId = _notification->GetHomeId();
break;
}
case Notification::Type_DriverFailed:
{
g_initFailed = true;
pthread_cond_broadcast(&initCond);
break;
}
case Notification::Type_AwakeNodesQueried:
case Notification::Type_AllNodesQueried:
{
pthread_cond_broadcast(&initCond);
break;
}
default:
{
}
}
pthread_mutex_unlock( &g_criticalSection );
}
//-----------------------------------------------------------------------------
// <main>
// Create the driver and then wait
@ -216,10 +241,13 @@ int main( int argc, char* argv[] )
{
pthread_mutexattr_t mutexattr;
pthread_mutexattr_init ( &mutexattr );
pthread_mutexattr_settype( &mutexattr, PTHREAD_MUTEX_RECURSIVE );
pthread_mutex_init( &g_criticalSection, &mutexattr );
pthread_mutexattr_destroy( &mutexattr );
pthread_mutex_lock( &initMutex );
// Create the OpenZWave Manager.
// The first argument is the path to the config files (where the manufacturer_specific.xml file is located
// The second argument is the path for saved Z-Wave network state and the log file. If you leave it NULL
@ -237,33 +265,47 @@ int main( int argc, char* argv[] )
// Add a Z-Wave Driver
// Modify this line to set the correct serial port for your PC interface.
Manager::Get()->AddDriver( "/dev/cu.usbserial");
string port = "/dev/cu.usbserial";
Manager::Get()->AddDriver( ( argc > 1 ) ? argv[1] : port );
//Manager::Get()->AddDriver( "HID Controller", Driver::ControllerInterface_Hid );
// Now we just wait for the driver to become ready, and then write out the loaded config.
// In a normal app, we would be handling notifications and building a UI for the user.
while( !g_homeId )
pthread_cond_wait( &initCond, &initMutex );
if( !g_initFailed )
{
sleep(1);
//Manager::Get()->BeginAddNode( g_homeId );
//sleep(10);
//Manager::Get()->EndAddNode( g_homeId );
//Manager::Get()->BeginRemoveNode( g_homeId );
//sleep(10);
//Manager::Get()->EndRemoveNode( g_homeId );
//sleep(10);
Manager::Get()->WriteConfig( g_homeId );
Driver::DriverData data;
Manager::Get()->GetDriverStatistics( g_homeId, &data );
printf("SOF: %d ACK Waiting: %d Read Aborts: %d Bad Checksums: %d\n", data.s_SOFCnt, data.s_ACKWaiting, data.s_readAborts, data.s_badChecksum);
printf("Reads: %d Writes: %d CAN: %d NAK: %d ACK: %d Out of Frame: %d\n", data.s_readCnt, data.s_writeCnt, data.s_CANCnt, data.s_NAKCnt, data.s_ACKCnt, data.s_OOFCnt);
printf("Dropped: %d Retries: %d\n", data.s_dropped, data.s_retries);
while( true )
{
sleep(10);
pthread_mutex_lock( &g_criticalSection );
// Do stuff
pthread_mutex_unlock( &g_criticalSection );
sleep(5);
}
}
//Manager::Get()->BeginAddNode( g_homeId );
//sleep(10);
//Manager::Get()->EndAddNode( g_homeId );
//Manager::Get()->BeginRemoveNode( g_homeId );
//sleep(10);
//Manager::Get()->EndRemoveNode( g_homeId );
sleep(10);
Manager::Get()->WriteConfig( g_homeId );
while( true )
{
sleep(10);
pthread_mutex_lock( &g_criticalSection );
// Do stuff
pthread_mutex_unlock( &g_criticalSection );
}
Manager::Destroy();
pthread_mutex_destroy( &g_criticalSection );
return 0;

View file

@ -42,6 +42,7 @@ struct hid_device_ {
int uses_numbered_reports;
int disconnected;
CFStringRef run_loop_mode;
CFRunLoopRef runloopref;
uint8_t *input_report_buf;
struct input_report *input_reports;
pthread_mutex_t mutex;
@ -624,7 +625,8 @@ int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
Need to get some from the OS. */
/* Move the device's run loop to this thread. */
IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetCurrent(), dev->run_loop_mode);
dev->runloopref = CFRunLoopGetCurrent();
IOHIDDeviceScheduleWithRunLoop(dev->device_handle, dev->runloopref, dev->run_loop_mode);
if (dev->blocking) {
/* Run the Run Loop until it stops timing out. In other
@ -633,7 +635,7 @@ int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
SInt32 code;
while (1) {
code = CFRunLoopRunInMode(dev->run_loop_mode, 1000, TRUE);
/* Return if the device has been disconnected */
if (code == kCFRunLoopRunFinished) {
dev->disconnected = 1;
@ -729,6 +731,8 @@ void HID_API_EXPORT hid_close(hid_device *dev)
if (!dev)
return;
CFRunLoopStop(dev->runloopref);
/* Close the OS handle to the device, but only if it's not
been unplugged. If it's been unplugged, then calling
IOHIDDeviceClose() will crash. */

View file

@ -106,44 +106,46 @@ namespace OpenZWave
#define RECEIVE_STATUS_TYPE_BROAD 0x04
#define FUNC_ID_SERIAL_API_GET_INIT_DATA 0x02
#define FUNC_ID_APPLICATION_COMMAND_HANDLER 0x04
#define FUNC_ID_SERIAL_API_GET_INIT_DATA 0x02
#define FUNC_ID_APPLICATION_COMMAND_HANDLER 0x04
#define FUNC_ID_ZW_GET_CONTROLLER_CAPABILITIES 0x05
#define FUNC_ID_SERIAL_API_SET_TIMEOUTS 0x06
#define FUNC_ID_SERIAL_API_GET_CAPABILITIES 0x07
#define FUNC_ID_SERIAL_API_SOFT_RESET 0x08
#define FUNC_ID_SERIAL_API_SET_TIMEOUTS 0x06
#define FUNC_ID_SERIAL_API_GET_CAPABILITIES 0x07
#define FUNC_ID_SERIAL_API_SOFT_RESET 0x08
#define FUNC_ID_ZW_SEND_DATA 0x13
#define FUNC_ID_ZW_GET_VERSION 0x15
#define FUNC_ID_ZW_R_F_POWER_LEVEL_SET 0x17
#define FUNC_ID_ZW_MEMORY_GET_ID 0x20
#define FUNC_ID_MEMORY_GET_BYTE 0x21
#define FUNC_ID_ZW_READ_MEMORY 0x23
#define FUNC_ID_ZW_SEND_DATA 0x13
#define FUNC_ID_ZW_GET_VERSION 0x15
#define FUNC_ID_ZW_R_F_POWER_LEVEL_SET 0x17
#define FUNC_ID_ZW_MEMORY_GET_ID 0x20
#define FUNC_ID_MEMORY_GET_BYTE 0x21
#define FUNC_ID_ZW_READ_MEMORY 0x23
#define FUNC_ID_ZW_SET_LEARN_NODE_STATE 0x40 // Not implemented
#define FUNC_ID_ZW_GET_NODE_PROTOCOL_INFO 0x41 // Get protocol info (baud rate, listening, etc.) for a given node
#define FUNC_ID_ZW_SET_DEFAULT 0x42 // Reset controller and node info to default (original) values
#define FUNC_ID_ZW_NEW_CONTROLLER 0x43 // Not implemented
#define FUNC_ID_ZW_SET_LEARN_NODE_STATE 0x40 // Not implemented
#define FUNC_ID_ZW_GET_NODE_PROTOCOL_INFO 0x41 // Get protocol info (baud rate, listening, etc.) for a given node
#define FUNC_ID_ZW_SET_DEFAULT 0x42 // Reset controller and node info to default (original) values
#define FUNC_ID_ZW_NEW_CONTROLLER 0x43 // Not implemented
#define FUNC_ID_ZW_REPLICATION_COMMAND_COMPLETE 0x44 // Replication isn't implemented (yet)
#define FUNC_ID_ZW_REPLICATION_SEND_DATA 0x45 // Replication isn't implemented (yet)
#define FUNC_ID_ZW_ASSIGN_RETURN_ROUTE 0x46 // Assign a return route from the specified node to the controller
#define FUNC_ID_ZW_DELETE_RETURN_ROUTE 0x47 // Delete all return routes from the specified node
#define FUNC_ID_ZW_REPLICATION_SEND_DATA 0x45 // Replication isn't implemented (yet)
#define FUNC_ID_ZW_ASSIGN_RETURN_ROUTE 0x46 // Assign a return route from the specified node to the controller
#define FUNC_ID_ZW_DELETE_RETURN_ROUTE 0x47 // Delete all return routes from the specified node
#define FUNC_ID_ZW_REQUEST_NODE_NEIGHBOR_UPDATE 0x48 // Ask the specified node to update its neighbors (then read them from the controller)
#define FUNC_ID_ZW_APPLICATION_UPDATE 0x49 // Get a list of supported (and controller) command classes
#define FUNC_ID_ZW_ADD_NODE_TO_NETWORK 0x4a // Control the addnode (or addcontroller) process...start, stop, etc.
#define FUNC_ID_ZW_REMOVE_NODE_FROM_NETWORK 0x4b // Control the removenode (or removecontroller) process...start, stop, etc.
#define FUNC_ID_ZW_CREATE_NEW_PRIMARY 0x4c // Control the createnewprimary process...start, stop, etc.
#define FUNC_ID_ZW_CONTROLLER_CHANGE 0x4d // Control the transferprimary process...start, stop, etc.
#define FUNC_ID_ZW_SET_LEARN_MODE 0x50 // Put a controller into learn mode for replication/ receipt of configuration info
#define FUNC_ID_ZW_ENABLE_SUC 0x52 // Make a controller a Static Update Controller
#define FUNC_ID_ZW_REQUEST_NETWORK_UPDATE 0x53 // Network update for a SUC(?)
#define FUNC_ID_ZW_SET_SUC_NODE_ID 0x54 // Identify a Static Update Controller node id
#define FUNC_ID_ZW_GET_SUC_NODE_ID 0x56 // Try to retrieve a Static Update Controller node id (zero if no SUC present)
#define FUNC_ID_ZW_REQUEST_NODE_INFO 0x60 // Get info (supported command classes) for the specified node
#define FUNC_ID_ZW_REMOVE_FAILED_NODE_ID 0x61 // Mark a specified node id as failed
#define FUNC_ID_ZW_IS_FAILED_NODE_ID 0x62 // Check to see if a specified node has failed
#define FUNC_ID_ZW_REPLACE_FAILED_NODE 0x63 // Remove a failed node from the controller's list (?)
#define FUNC_ID_ZW_GET_ROUTING_INFO 0x80 // Get a specified node's neighbor information from the controller
#define FUNC_ID_ZW_APPLICATION_UPDATE 0x49 // Get a list of supported (and controller) command classes
#define FUNC_ID_ZW_ADD_NODE_TO_NETWORK 0x4a // Control the addnode (or addcontroller) process...start, stop, etc.
#define FUNC_ID_ZW_REMOVE_NODE_FROM_NETWORK 0x4b // Control the removenode (or removecontroller) process...start, stop, etc.
#define FUNC_ID_ZW_CREATE_NEW_PRIMARY 0x4c // Control the createnewprimary process...start, stop, etc.
#define FUNC_ID_ZW_CONTROLLER_CHANGE 0x4d // Control the transferprimary process...start, stop, etc.
#define FUNC_ID_ZW_SET_LEARN_MODE 0x50 // Put a controller into learn mode for replication/ receipt of configuration info
#define FUNC_ID_ZW_ENABLE_SUC 0x52 // Make a controller a Static Update Controller
#define FUNC_ID_ZW_REQUEST_NETWORK_UPDATE 0x53 // Network update for a SUC(?)
#define FUNC_ID_ZW_SET_SUC_NODE_ID 0x54 // Identify a Static Update Controller node id
#define FUNC_ID_ZW_GET_SUC_NODE_ID 0x56 // Try to retrieve a Static Update Controller node id (zero if no SUC present)
#define FUNC_ID_ZW_REQUEST_NODE_INFO 0x60 // Get info (supported command classes) for the specified node
#define FUNC_ID_ZW_REMOVE_FAILED_NODE_ID 0x61 // Mark a specified node id as failed
#define FUNC_ID_ZW_IS_FAILED_NODE_ID 0x62 // Check to see if a specified node has failed
#define FUNC_ID_ZW_REPLACE_FAILED_NODE 0x63 // Remove a failed node from the controller's list (?)
#define FUNC_ID_ZW_GET_ROUTING_INFO 0x80 // Get a specified node's neighbor information from the controller
#define FUNC_ID_ZW_SET_PROMISCUOUS_MODE 0xD0 // Set controller into promiscuous mode to listen to all frames
#define FUNC_ID_PROMISCUOUS_APPLICATION_COMMAND_HANDLER 0xD1
#define ADD_NODE_ANY 0x01
#define ADD_NODE_CONTROLLER 0x02

View file

@ -116,29 +116,39 @@ Driver::Driver
m_controllerCallback( NULL ),
m_controllerCallbackContext( NULL ),
m_controllerAdded( false ),
m_controllerCommandNode( 0 )
m_controllerCommandNode( 0 ),
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 )
{
// Clear the nodes array
memset( m_nodes, 0, sizeof(Node*) * 256 );
switch (_interface)
{
switch (_interface)
{
case ControllerInterface_Serial:
{
m_controller = (IController*) new SerialController();
break;
}
{
m_controller = (IController*) new SerialController();
break;
}
case ControllerInterface_Hid:
{
m_controller = (IController*) new HidController();
break;
}
{
m_controller = (IController*) new HidController();
break;
}
default:
{
m_controller = (IController*) new SerialController();
break;
}
}
{
m_controller = (IController*) new SerialController();
break;
}
}
}
//-----------------------------------------------------------------------------
@ -159,11 +169,12 @@ Driver::~Driver
m_exitEvent->Set();
m_wakeEvent->Set();
m_pollThread->Stop();
m_controllerThread->Stop();
m_driverThread->Stop();
delete m_controller;
m_controllerThread->Stop();
m_driverThread->Stop();
delete m_pollThread;
delete m_controllerThread;
delete m_driverThread;
@ -301,6 +312,7 @@ void Driver::DriverThreadProc
{
node->m_queryStageCompleted = true;
}
m_dropped++;
RemoveMsg();
}
else
@ -329,6 +341,7 @@ void Driver::DriverThreadProc
{
node->m_queryStageCompleted = true;
}
m_dropped++;
RemoveMsg();
}
}
@ -336,7 +349,8 @@ void Driver::DriverThreadProc
{
// Node is listening, so we'll just retry sending the message.
Log::Write( "Resending message (attempt %d)", msg->GetSendAttempts() );
}
m_retries++;
}
}
}
}
@ -418,12 +432,16 @@ bool Driver::Init
uint8 nak = NAK;
m_controller->Write( &nak, 1 );
// Get/set ZWave controller information in its preferred initialization order
list<Msg*>* const pMsgInitArray = m_controller->GetMsgInitializationSequence();
for (list<Msg*>::iterator it = pMsgInitArray->begin(); it != pMsgInitArray->end(); it++)
{
SendMsg(*it);
}
// Get/set ZWave controller information in its preferred initialization order
list<Msg*>* const pMsgInitArray = m_controller->GetMsgInitializationSequence();
for (list<Msg*>::iterator it = pMsgInitArray->begin(); it != pMsgInitArray->end(); it++)
{
SendMsg(*it);
}
//If we ever want promiscuous mode uncomment this code.
//Msg* msg = new Msg( "FUNC_ID_ZW_SET_PROMISCUOUS_MODE", 0xff, REQUEST, FUNC_ID_ZW_SET_PROMISCUOUS_MODE, false, false );
//msg->Append( 0xff );
//SendMsg( msg );
// Init successful
return true;
@ -769,6 +787,7 @@ bool Driver::WriteMsg()
Log::Write( "" );
Log::Write( "Sending command (Callback ID=0x%.2x, Expected Reply=0x%.2x) - %s", msg->GetCallbackId(), msg->GetExpectedReply(), msg->GetAsString().c_str() );
m_controller->Write( msg->GetBuffer(), msg->GetLength() );
m_writeCnt++;
dataWritten = true;
}
else
@ -945,14 +964,16 @@ bool Driver::IsControllerCommand
// ranges of commands are used to enhance performance
// the commands identified as "Controller Commands" needs to be reviewed as we
// understand the protocol better and implement handlers
if( ( _command >= FUNC_ID_ZW_SET_DEFAULT ) &&
( _command <= FUNC_ID_ZW_REQUEST_NODE_NEIGHBOR_UPDATE ) )
if( ( _command >= FUNC_ID_ZW_SET_DEFAULT ) && // 0x42
( _command <= FUNC_ID_ZW_REQUEST_NODE_NEIGHBOR_UPDATE ) ) // 0x48
return true;
if( ( _command >= FUNC_ID_ZW_ADD_NODE_TO_NETWORK ) &&
( _command <= FUNC_ID_ZW_SET_LEARN_MODE ) )
if( ( _command >= FUNC_ID_ZW_ADD_NODE_TO_NETWORK ) && // 0x4a
( _command <= FUNC_ID_ZW_SET_LEARN_MODE ) ) // 0x50
return true;
if( ( _command >= FUNC_ID_ZW_REMOVE_FAILED_NODE_ID ) &&
( _command <= FUNC_ID_ZW_REPLACE_FAILED_NODE ) )
if( ( _command >= FUNC_ID_ZW_REMOVE_FAILED_NODE_ID ) && // 0x61
( _command <= FUNC_ID_ZW_REPLACE_FAILED_NODE ) ) // 0x63
return true;
if( _command == FUNC_ID_ZW_GET_ROUTING_INFO ) // 0x80
return true;
return false;
@ -982,9 +1003,11 @@ bool Driver::ReadMsg
{
case SOF:
{
m_SOFCnt++;
if( m_waitingForAck )
{
Log::Write( "Unsolicited message received while waiting for ACK." );
m_ACKWaiting++;
}
// Read the length byte. Keep trying until we get it.
@ -1005,6 +1028,7 @@ bool Driver::ReadMsg
if( loops == 10 )
{
Log::Write( "100ms passed without finding the length byte...aborting frame read");
m_readAborts++;
break;
}
@ -1028,6 +1052,7 @@ bool Driver::ReadMsg
if( loops == 50 )
{
Log::Write( "500ms passed without reading the rest of the frame...aborting frame read" );
m_readAborts++;
break;
}
@ -1061,12 +1086,14 @@ bool Driver::ReadMsg
uint8 ack = ACK;
m_controller->Write( &ack, 1 );
m_readCnt++;
// Process the received message
ProcessMsg( &buffer[2] );
}
else
{
Log::Write( "Checksum incorrect - sending NAK" );
m_badChecksum++;
uint8 nak = NAK;
m_controller->Write( &nak, 1 );
}
@ -1076,6 +1103,7 @@ bool Driver::ReadMsg
case CAN:
{
Log::Write( "CAN received...triggering resend" );
m_CANCnt++;
TriggerResend();
break;
}
@ -1083,6 +1111,7 @@ bool Driver::ReadMsg
case NAK:
{
Log::Write( "NAK received...triggering resend" );
m_NAKCnt++;
TriggerResend();
break;
}
@ -1090,6 +1119,7 @@ bool Driver::ReadMsg
case ACK:
{
Log::Write( " ACK received CallbackId 0x%.2x Reply 0x%.2x", m_expectedCallbackId, m_expectedReply );
m_ACKCnt++;
m_waitingForAck = false;
if( ( 0 == m_expectedCallbackId ) && ( 0 == m_expectedReply ) )
@ -1103,6 +1133,7 @@ bool Driver::ReadMsg
default:
{
Log::Write( "ERROR! Out of frame flow! (0x%.2x). Sending NAK.", buffer[0] );
m_OOFCnt++;
uint8 nak = NAK;
m_controller->Write( &nak, 1 );
break;
@ -1399,6 +1430,12 @@ void Driver::ProcessMsg
HandleReplaceFailedNodeRequest( _data );
break;
}
case FUNC_ID_PROMISCUOUS_APPLICATION_COMMAND_HANDLER:
{
Log::Write( "" );
HandlePromiscuousApplicationCommandHandlerRequest( _data );
break;
}
default:
{
break;
@ -1990,6 +2027,7 @@ bool Driver::HandleSendDataRequest
{
node->m_queryStageCompleted = true;
}
m_dropped++;
RemoveMsg();
messageRemoved = true;
}
@ -2461,6 +2499,21 @@ void Driver::HandleApplicationCommandHandlerRequest
}
}
//-----------------------------------------------------------------------------
// <Driver::HandlePromiscuousApplicationCommandHandlerRequest>
// Process a request from the Z-Wave PC interface when in promiscuous mode.
//-----------------------------------------------------------------------------
void Driver::HandlePromiscuousApplicationCommandHandlerRequest
(
uint8* _data
)
{
//uint8 nodeId = _data[3];
//uint8 len = _data[4];
//uint8 classId = _data[5];
//uint8 destNodeId = _data[5+len];
}
//-----------------------------------------------------------------------------
// <Driver::HandleAssignReturnRouteRequest>
// Process a request from the Z-Wave PC interface
@ -4339,3 +4392,27 @@ bool Driver::HandleReadMemoryResponse
Log::Write("Received reply to FUNC_ID_MEMORY_GET_BYTE");
return res;
}
//-----------------------------------------------------------------------------
// <Driver::GetDriverStatistics>
// Return driver statistics
//-----------------------------------------------------------------------------
void Driver::GetDriverStatistics
(
DriverData* _data
)
{
_data->s_SOFCnt = m_SOFCnt;
_data->s_ACKWaiting = m_ACKWaiting;
_data->s_readAborts = m_readAborts;
_data->s_badChecksum = m_badChecksum;
_data->s_readCnt = m_readCnt;
_data->s_writeCnt = m_writeCnt;
_data->s_writeCnt = m_writeCnt;
_data->s_CANCnt = m_CANCnt;
_data->s_NAKCnt = m_NAKCnt;
_data->s_ACKCnt = m_ACKCnt;
_data->s_OOFCnt = m_OOFCnt;
_data->s_dropped = m_dropped;
_data->s_retries = m_retries;
}

View file

@ -319,6 +319,7 @@ namespace OpenZWave
void HandleReplaceFailedNodeRequest( uint8* _data );
void HandleRemoveNodeFromNetworkRequest( uint8* _data );
void HandleApplicationCommandHandlerRequest( uint8* _data );
void HandlePromiscuousApplicationCommandHandlerRequest( uint8* _data );
void HandleAssignReturnRouteRequest( uint8* _data );
void HandleDeleteReturnRouteRequest( uint8* _data );
void HandleNodeNeighborUpdateRequest( uint8* _data );
@ -529,9 +530,44 @@ namespace OpenZWave
void NotifyWatchers(); // Passes the notifications to all the registered watcher callbacks in turn.
list<Notification*> m_notifications;
//-----------------------------------------------------------------------------
// Statistics
//-----------------------------------------------------------------------------
public:
struct DriverData
{
uint32 s_SOFCnt; // Number of SOF bytes received
uint32 s_ACKWaiting; // Number of unsolcited messages while waiting for an ACK
uint32 s_readAborts; // Number of times read were aborted due to timeouts
uint32 s_badChecksum; // Number of bad checksums
uint32 s_readCnt; // Number of messages successfully read
uint32 s_writeCnt; // Number of messages successfully sent
uint32 s_CANCnt; // Number of CAN bytes received
uint32 s_NAKCnt; // Number of NAK bytes received
uint32 s_ACKCnt; // Number of ACK bytes received
uint32 s_OOFCnt; // Number of bytes out of framing
uint32 s_dropped; // Number of messages dropped & not delivered
uint32 s_retries; // Number of messages retransmitted
};
private:
void GetDriverStatistics( DriverData* _data );
uint32 m_SOFCnt; // Number of SOF bytes received
uint32 m_ACKWaiting; // Number of unsolcited messages while waiting for an ACK
uint32 m_readAborts; // Number of times read were aborted due to timeouts
uint32 m_badChecksum; // Number of bad checksums
uint32 m_readCnt; // Number of messages successfully read
uint32 m_writeCnt; // Number of messages successfully sent
uint32 m_CANCnt; // Number of CAN bytes received
uint32 m_NAKCnt; // Number of NAK bytes received
uint32 m_ACKCnt; // Number of ACK bytes received
uint32 m_OOFCnt; // Number of bytes out of framing
uint32 m_dropped; // Number of messages dropped & not delivered
uint32 m_retries; // Number of messages retransmitted
};
} // namespace OpenZWave
#endif // _Driver_H

View file

@ -3329,3 +3329,20 @@ bool Manager::ActivateScene
return false;
}
//-----------------------------------------------------------------------------
// <Manager::DriverStatistics>
// Retrieve driver based counters.
//-----------------------------------------------------------------------------
void Manager::GetDriverStatistics
(
uint32 const _homeId,
Driver::DriverData* _data
)
{
if( Driver* driver = GetDriver( _homeId ) )
{
driver->GetDriverStatistics( _data );
}
}

View file

@ -1660,8 +1660,24 @@ namespace OpenZWave
bool ActivateScene( uint8 const _sceneId );
/*@}*/
};
//-----------------------------------------------------------------------------
// Statistics interface
//-----------------------------------------------------------------------------
/** \name Statistics retrieval interface
* Commands for Z-Wave statistics interface.
*/
/*@{*/
public:
/**
* \brief Retrieve statistics from driver
* \param _homeId The Home ID of the driver to obtain counters
* \param _data Pointer to structure DriverData to return values
*/
void GetDriverStatistics( uint32 const _homeId, Driver::DriverData* _data );
};
/*@}*/
} // namespace OpenZWave
#endif // _Manager_H

View file

@ -517,6 +517,11 @@ uint32 Node::GetNeighbors
// determine how many neighbors there are
int i;
uint32 numNeighbors = 0;
if( m_queryStage < QueryStage_Session )
{
*o_neighbors = NULL;
return 0;
}
for( i = 0; i < 29; i++ )
{
for( unsigned char mask = 0x80; mask != 0; mask >>= 1 )

View file

@ -166,48 +166,53 @@ bool SensorMultilevel::HandleMsg
if (SensorMultilevelCmd_Report == (SensorMultilevelCmd)_data[0])
{
uint8 scale;
uint8 sensorType = _data[1];
string valueStr = ExtractValue( &_data[2], &scale );
if( ValueDecimal* value = static_cast<ValueDecimal*>( GetValue( _instance, 0 ) ) )
Node* node = GetNodeUnsafe();
if( node != NULL )
{
value->SetLabel( c_sensorTypeNames[_data[1]] );
switch( _data[1] )
ValueDecimal* value = static_cast<ValueDecimal*>( GetValue( _instance, sensorType ) );
if( value == NULL)
{
case SensorType_Temperature: value->SetUnits( scale ? "F" : "C" ); break;
case SensorType_General: value->SetUnits( scale ? "" : "%" ); break;
case SensorType_Luminance: value->SetUnits( scale ? "lux" : "%" ); break;
case SensorType_Power: value->SetUnits( scale ? "BTU/h" : "W" ); break;
case SensorType_RelativeHumidity: value->SetUnits( "%" ); break;
case SensorType_Velocity: value->SetUnits( scale ? "mph" : "m/s" ); break;
case SensorType_Direction: value->SetUnits( "" ); break;
case SensorType_AtmosphericPressure: value->SetUnits( scale ? "inHg" : "kPa" ); break;
case SensorType_BarometricPressure: value->SetUnits( scale ? "inHg" : "kPa" ); break;
case SensorType_SolarRadiation: value->SetUnits( "W/m2" ); break;
case SensorType_DewPoint: value->SetUnits( scale ? "in/h" : "mm/h" ); break;
case SensorType_RainRate: value->SetUnits( scale ? "F" : "C" ); break;
case SensorType_TideLevel: value->SetUnits( scale ? "ft" : "m" ); break;
case SensorType_Weight: value->SetUnits( scale ? "lb" : "kg" ); break;
case SensorType_Voltage: value->SetUnits( scale ? "mV" : "V" ); break;
case SensorType_Current: value->SetUnits( scale ? "mA" : "A" ); break;
case SensorType_CO2: value->SetUnits( "ppm" ); break;
case SensorType_AirFlow: value->SetUnits( scale ? "cfm" : "m3/h" ); break;
case SensorType_TankCapacity: value->SetUnits( c_tankCapcityUnits[scale] ); break;
case SensorType_Distance: value->SetUnits( c_distanceUnits[scale] ); break;
default: break;
char const* units = "";
switch( sensorType )
{
case SensorType_Temperature: units = scale ? "F" : "C"; break;
case SensorType_General: units = scale ? "" : "%"; break;
case SensorType_Luminance: units = scale ? "lux" : "%"; break;
case SensorType_Power: units = scale ? "BTU/h" : "W"; break;
case SensorType_RelativeHumidity: units = "%"; break;
case SensorType_Velocity: units = scale ? "mph" : "m/s"; break;
case SensorType_Direction: units = ""; break;
case SensorType_AtmosphericPressure: units = scale ? "inHg" : "kPa"; break;
case SensorType_BarometricPressure: units = scale ? "inHg" : "kPa"; break;
case SensorType_SolarRadiation: units = "W/m2"; break;
case SensorType_DewPoint: units = scale ? "in/h" : "mm/h"; break;
case SensorType_RainRate: units = scale ? "F" : "C"; break;
case SensorType_TideLevel: units = scale ? "ft" : "m"; break;
case SensorType_Weight: units = scale ? "lb" : "kg"; break;
case SensorType_Voltage: units = scale ? "mV" : "V"; break;
case SensorType_Current: units = scale ? "mA" : "A"; break;
case SensorType_CO2: units = "ppm"; break;
case SensorType_AirFlow: units = scale ? "cfm" : "m3/h"; break;
case SensorType_TankCapacity: units = c_tankCapcityUnits[scale]; break;
case SensorType_Distance: units = c_distanceUnits[scale]; break;
default: break;
}
value = node->CreateValueDecimal( ValueID::ValueGenre_User, GetCommandClassId(), _instance, sensorType, c_sensorTypeNames[sensorType], units, true, false, "0.0" );
}
Log::Write( "Received SensorMultiLevel report from node %d, instance %d: value=%s%s", GetNodeId(), _instance, valueStr.c_str(), value->GetUnits().c_str() );
value->OnValueChanged( valueStr );
}
Node* node = GetNodeUnsafe();
if( node != NULL && node->m_queryPending )
{
node->m_queryStageCompleted = true;
if( node->m_queryPending )
{
node->m_queryStageCompleted = true;
}
return true;
}
return true;
}
return false;
}
@ -220,10 +225,7 @@ void SensorMultilevel::CreateVars
uint8 const _instance
)
{
if( Node* node = GetNodeUnsafe() )
{
node->CreateValueDecimal( ValueID::ValueGenre_User, GetCommandClassId(), _instance, 0, "Unknown", "", true, false, "0.0" );
}
// Don't create anything here. We do it in the report.
}

View file

@ -41,20 +41,20 @@ namespace OpenZWave
/**
* ReadPacketSegment enum
* Signals the IController::Read() which part of the rx packet is being retrieved by the caller.
* This is used by controllers that must internally read the entire rx packet in one operation.
* This is used by controllers that must internally read the entire rx packet in one operation.
*/
enum ReadPacketSegment
{
ReadPacketSegment_FrameType = 0,
ReadPacketSegment_FrameLength,
ReadPacketSegment_FrameData
ReadPacketSegment_FrameLength,
ReadPacketSegment_FrameData
};
/**
* Destructor.
* Destroys the controller object.
*/
virtual ~IController() {};
virtual ~IController() {};
/**
* Retrieves an array of Msg object pointers in the correct order needed to initialize the IController implementation.

View file

@ -89,26 +89,26 @@ bool HidControllerImpl::Open
m_hHidController = hid_open( _vendorId, _productId, NULL );
if ( !m_hHidController )
{
Log::Write( "Cannot find specified HID port with VID:%04hx and PID:0x%04hx.\n", _vendorId, _productId );
Log::Write( "Cannot find specified HID port with VID:%04hx and PID:0x%04hx.", _vendorId, _productId );
// Enumerate connected HIDs for debugging purposes
// Note: most OS intentionally hide keyboard/mouse devices from HID access
struct hid_device_info *devices, *currentDevice;
devices = hid_enumerate(0x0, 0x0);
devices = hid_enumerate( 0x0, 0x0 );
currentDevice = devices;
Log::Write( "Enumerating connected HIDs:\n" );
while (currentDevice)
{
Log::Write( "\tVID:%04hx\tPID:0x%04hx\tSN:%ls\tMfg:%ls\tProd:%ls\tPath:%s\n",
currentDevice->vendor_id,
currentDevice->product_id,
currentDevice->serial_number,
currentDevice->manufacturer_string,
currentDevice->product_string,
currentDevice->path);
currentDevice = currentDevice->next;
}
Log::Write( "Enumerating connected HIDs:" );
while( currentDevice )
{
Log::Write( "\tVID:%04hx\tPID:0x%04hx\tSN:%ls\tMfg:%ls\tProd:%ls\tPath:%s",
currentDevice->vendor_id,
currentDevice->product_id,
currentDevice->serial_number,
currentDevice->manufacturer_string,
currentDevice->product_string,
currentDevice->path);
currentDevice = currentDevice->next;
}
hid_free_enumeration( devices );
goto HidOpenFailure;
@ -222,7 +222,7 @@ uint32 HidControllerImpl::Read
if( !m_hidControllerOpen )
{
//Error
Log::Write( "Error: HID port must be opened before reading\n" );
Log::Write( "Error: HID port must be opened before reading" );
return 0;
}
@ -275,8 +275,7 @@ uint32 HidControllerImpl::Read
return _length;
HidPortError:
//Error
Log::Write( "Error: HID port returned error reading rest of packet: 0x%08hx, HIDAPI error string:", m_hidFeatureReportReadBufferBytes );
Log::Write("%ls\n", hid_error(m_hHidController));
Log::Write( "Error: HID port returned error reading rest of packet: %d, HIDAPI error string: %ls", m_hidFeatureReportReadBufferBytes, hid_error(m_hHidController));
return 0;
}
@ -293,14 +292,14 @@ uint32 HidControllerImpl::Write
if( !m_hidControllerOpen )
{
//Error
Log::Write( "Error: HID port must be opened before writing\n" );
Log::Write( "Error: HID port must be opened before writing" );
return 0;
}
if ( FEATURE_REPORT_LENGTH - 2 < _length)
{
//Error
Log::Write( "Error: Write buffer length %d exceeded feature report data capacity %d\n",
Log::Write( "Error: Write buffer length %d exceeded feature report data capacity %d",
_length,
FEATURE_REPORT_LENGTH - 2 );
return 0;
@ -320,9 +319,7 @@ uint32 HidControllerImpl::Write
if (bytesSent < 2)
{
//Error
Log::Write( "Error: HID port returned error sending bytes: 0x%08hx, HIDAPI error string:", bytesSent );
const wchar_t* errString = hid_error( m_hHidController );
Log::Write( "%ls\n", errString );
Log::Write( "Error: HID port returned error sending bytes: %d, HIDAPI error string: %ls", bytesSent, hid_error( m_hHidController ) );
return 0;
}
@ -373,18 +370,13 @@ bool HidControllerImpl::Wait
default:
{
//Error
Log::Write( "Error: HID port returned unexpected input report data in byte 2 during Wait(): 0x%08hx\n", inputReport[2] );
Log::Write( "Error: HID port returned unexpected input report data in byte 2 during Wait(): 0x%08hx", inputReport[2] );
return false;
break;
}
}
// continue looping until some rx feature report data is reported via input report
}
//Error
Log::Write( "Error: HID port returned error reading input bytes: 0x%08hx, HIDAPI error string:", hidApiResult );
const wchar_t* errString = hid_error( m_hHidController );
Log::Write( "%ls\n", errString );
}
return false;
@ -406,7 +398,7 @@ int HidControllerImpl::GetFeatureReport
result = hid_get_feature_report( m_hHidController, _buffer, _length );
if (result < 0)
{
Log::Write( "Error: HID GetFeatureReport on ID 0x%hx returned (0x%.8x)\n", _reportId, result );
Log::Write( "Error: HID GetFeatureReport on ID 0x%hx returned (0x%.8x)", _reportId, result );
}
return result;
}
@ -426,7 +418,7 @@ int HidControllerImpl::SendFeatureReport
result = hid_send_feature_report( m_hHidController, _data, _length );
if (result < 0)
{
Log::Write( "Error: HID SendFeatureReport on ID 0x%hx returned (0x%.8x)\n", _data[0], result );
Log::Write( "Error: HID SendFeatureReport on ID 0x%hx returned (0x%.8x)", _data[0], result );
}
return result;
}