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 <pthread.h>
#include "Options.h" #include "Options.h"
#include "Manager.h" #include "Manager.h"
#include "Driver.h"
#include "Node.h" #include "Node.h"
#include "Group.h" #include "Group.h"
#include "Notification.h" #include "Notification.h"
@ -180,6 +181,7 @@ void OnNotification
{ {
// We have received an event from the node, caused by a // We have received an event from the node, caused by a
// basic_set or hail message. // basic_set or hail message.
// TBD...
nodeInfo = nodeInfo; nodeInfo = nodeInfo;
} }
break; break;
@ -208,7 +210,7 @@ void OnNotification
g_homeId = _notification->GetHomeId(); g_homeId = _notification->GetHomeId();
break; break;
} }
case Notification::Type_DriverFailed: case Notification::Type_DriverFailed:
{ {
@ -217,7 +219,7 @@ void OnNotification
break; break;
} }
case Notification::Type_AwakeNodesQueried: case Notification::Type_AwakeNodesQueried:
case Notification::Type_AllNodesQueried: case Notification::Type_AllNodesQueried:
{ {
pthread_cond_broadcast(&initCond); pthread_cond_broadcast(&initCond);
@ -239,13 +241,13 @@ int main( int argc, char* argv[] )
{ {
pthread_mutexattr_t mutexattr; pthread_mutexattr_t mutexattr;
pthread_mutexattr_init ( &mutexattr ); pthread_mutexattr_init ( &mutexattr );
pthread_mutexattr_settype( &mutexattr, PTHREAD_MUTEX_RECURSIVE ); pthread_mutexattr_settype( &mutexattr, PTHREAD_MUTEX_RECURSIVE );
pthread_mutex_init( &g_criticalSection, &mutexattr ); pthread_mutex_init( &g_criticalSection, &mutexattr );
pthread_mutexattr_destroy(&mutexattr); pthread_mutexattr_destroy( &mutexattr );
pthread_mutex_lock(&initMutex); pthread_mutex_lock( &initMutex );
// Create the OpenZWave Manager. // Create the OpenZWave Manager.
// The first argument is the path to the config files (where the manufacturer_specific.xml file is located // 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 // 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 // Add a Z-Wave Driver
// Modify this line to set the correct serial port for your PC interface. // Modify this line to set the correct serial port for your PC interface.
string port = "/dev/ttyUSB0"; 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 ); //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. // 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. // In a normal app, we would be handling notifications and building a UI for the user.
pthread_cond_wait(&initCond, &initMutex); pthread_cond_wait( &initCond, &initMutex );
if (!g_initFailed) { if( !g_initFailed )
{
//Manager::Get()->BeginAddNode( g_homeId ); //Manager::Get()->BeginAddNode( g_homeId );
//sleep(10); //sleep(10);
//Manager::Get()->EndAddNode( g_homeId ); //Manager::Get()->EndAddNode( g_homeId );
@ -282,11 +285,19 @@ int main( int argc, char* argv[] )
//sleep(10); //sleep(10);
//Manager::Get()->EndRemoveNode( g_homeId ); //Manager::Get()->EndRemoveNode( g_homeId );
//sleep(10); //sleep(10);
Manager::Get()->WriteConfig(g_homeId); Manager::Get()->WriteConfig( g_homeId );
while(true) 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 ); pthread_mutex_lock( &g_criticalSection );
// Do stuff // Do stuff
pthread_mutex_unlock( &g_criticalSection ); pthread_mutex_unlock( &g_criticalSection );

View file

@ -34,6 +34,7 @@
#include <pthread.h> #include <pthread.h>
#include "Options.h" #include "Options.h"
#include "Manager.h" #include "Manager.h"
#include "Driver.h"
#include "Node.h" #include "Node.h"
#include "Group.h" #include "Group.h"
#include "Notification.h" #include "Notification.h"
@ -44,8 +45,9 @@
using namespace OpenZWave; using namespace OpenZWave;
static uint32 g_homeId = 0; static uint32 g_homeId = 0;
static bool g_initFailed = false;
typedef struct typedef struct
{ {
uint32 m_homeId; uint32 m_homeId;
uint8 m_nodeId; uint8 m_nodeId;
@ -55,6 +57,8 @@ typedef struct
static list<NodeInfo*> g_nodes; static list<NodeInfo*> g_nodes;
static pthread_mutex_t g_criticalSection; static pthread_mutex_t g_criticalSection;
static pthread_cond_t initCond = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t initMutex = PTHREAD_MUTEX_INITIALIZER;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// <GetNodeInfo> // <GetNodeInfo>
@ -127,6 +131,7 @@ void OnNotification
{ {
// One of the node values has changed // One of the node values has changed
// TBD... // TBD...
nodeInfo = nodeInfo;
} }
break; break;
} }
@ -137,6 +142,7 @@ void OnNotification
{ {
// One of the node's association groups has changed // One of the node's association groups has changed
// TBD... // TBD...
nodeInfo = nodeInfo;
} }
break; break;
} }
@ -176,6 +182,7 @@ void OnNotification
// We have received an event from the node, caused by a // We have received an event from the node, caused by a
// basic_set or hail message. // basic_set or hail message.
// TBD... // TBD...
nodeInfo = nodeInfo;
} }
break; break;
} }
@ -203,11 +210,29 @@ void OnNotification
g_homeId = _notification->GetHomeId(); g_homeId = _notification->GetHomeId();
break; 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 ); pthread_mutex_unlock( &g_criticalSection );
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// <main> // <main>
// Create the driver and then wait // Create the driver and then wait
@ -216,10 +241,13 @@ int main( int argc, char* argv[] )
{ {
pthread_mutexattr_t mutexattr; pthread_mutexattr_t mutexattr;
pthread_mutexattr_init ( &mutexattr );
pthread_mutexattr_settype( &mutexattr, PTHREAD_MUTEX_RECURSIVE ); pthread_mutexattr_settype( &mutexattr, PTHREAD_MUTEX_RECURSIVE );
pthread_mutex_init( &g_criticalSection, &mutexattr ); pthread_mutex_init( &g_criticalSection, &mutexattr );
pthread_mutexattr_destroy( &mutexattr ); pthread_mutexattr_destroy( &mutexattr );
pthread_mutex_lock( &initMutex );
// Create the OpenZWave Manager. // Create the OpenZWave Manager.
// The first argument is the path to the config files (where the manufacturer_specific.xml file is located // 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 // 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 // Add a Z-Wave Driver
// Modify this line to set the correct serial port for your PC interface. // 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 ); //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. // 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. // 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 ); Manager::Destroy();
//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 );
}
pthread_mutex_destroy( &g_criticalSection ); pthread_mutex_destroy( &g_criticalSection );
return 0; return 0;

View file

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

View file

@ -106,44 +106,46 @@ namespace OpenZWave
#define RECEIVE_STATUS_TYPE_BROAD 0x04 #define RECEIVE_STATUS_TYPE_BROAD 0x04
#define FUNC_ID_SERIAL_API_GET_INIT_DATA 0x02 #define FUNC_ID_SERIAL_API_GET_INIT_DATA 0x02
#define FUNC_ID_APPLICATION_COMMAND_HANDLER 0x04 #define FUNC_ID_APPLICATION_COMMAND_HANDLER 0x04
#define FUNC_ID_ZW_GET_CONTROLLER_CAPABILITIES 0x05 #define FUNC_ID_ZW_GET_CONTROLLER_CAPABILITIES 0x05
#define FUNC_ID_SERIAL_API_SET_TIMEOUTS 0x06 #define FUNC_ID_SERIAL_API_SET_TIMEOUTS 0x06
#define FUNC_ID_SERIAL_API_GET_CAPABILITIES 0x07 #define FUNC_ID_SERIAL_API_GET_CAPABILITIES 0x07
#define FUNC_ID_SERIAL_API_SOFT_RESET 0x08 #define FUNC_ID_SERIAL_API_SOFT_RESET 0x08
#define FUNC_ID_ZW_SEND_DATA 0x13 #define FUNC_ID_ZW_SEND_DATA 0x13
#define FUNC_ID_ZW_GET_VERSION 0x15 #define FUNC_ID_ZW_GET_VERSION 0x15
#define FUNC_ID_ZW_R_F_POWER_LEVEL_SET 0x17 #define FUNC_ID_ZW_R_F_POWER_LEVEL_SET 0x17
#define FUNC_ID_ZW_MEMORY_GET_ID 0x20 #define FUNC_ID_ZW_MEMORY_GET_ID 0x20
#define FUNC_ID_MEMORY_GET_BYTE 0x21 #define FUNC_ID_MEMORY_GET_BYTE 0x21
#define FUNC_ID_ZW_READ_MEMORY 0x23 #define FUNC_ID_ZW_READ_MEMORY 0x23
#define FUNC_ID_ZW_SET_LEARN_NODE_STATE 0x40 // 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_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_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_NEW_CONTROLLER 0x43 // Not implemented
#define FUNC_ID_ZW_REPLICATION_COMMAND_COMPLETE 0x44 // Replication isn't implemented (yet) #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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_ANY 0x01
#define ADD_NODE_CONTROLLER 0x02 #define ADD_NODE_CONTROLLER 0x02

View file

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

View file

@ -3329,3 +3329,20 @@ bool Manager::ActivateScene
return false; 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 ); 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 } // namespace OpenZWave
#endif // _Manager_H #endif // _Manager_H

View file

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

View file

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

View file

@ -41,20 +41,20 @@ namespace OpenZWave
/** /**
* ReadPacketSegment enum * ReadPacketSegment enum
* Signals the IController::Read() which part of the rx packet is being retrieved by the caller. * 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 enum ReadPacketSegment
{ {
ReadPacketSegment_FrameType = 0, ReadPacketSegment_FrameType = 0,
ReadPacketSegment_FrameLength, ReadPacketSegment_FrameLength,
ReadPacketSegment_FrameData ReadPacketSegment_FrameData
}; };
/** /**
* Destructor. * Destructor.
* Destroys the controller object. * 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. * 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 ); m_hHidController = hid_open( _vendorId, _productId, NULL );
if ( !m_hHidController ) 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 // Enumerate connected HIDs for debugging purposes
// Note: most OS intentionally hide keyboard/mouse devices from HID access // Note: most OS intentionally hide keyboard/mouse devices from HID access
struct hid_device_info *devices, *currentDevice; struct hid_device_info *devices, *currentDevice;
devices = hid_enumerate(0x0, 0x0); devices = hid_enumerate( 0x0, 0x0 );
currentDevice = devices; currentDevice = devices;
Log::Write( "Enumerating connected HIDs:\n" ); Log::Write( "Enumerating connected HIDs:" );
while (currentDevice) while( currentDevice )
{ {
Log::Write( "\tVID:%04hx\tPID:0x%04hx\tSN:%ls\tMfg:%ls\tProd:%ls\tPath:%s\n", Log::Write( "\tVID:%04hx\tPID:0x%04hx\tSN:%ls\tMfg:%ls\tProd:%ls\tPath:%s",
currentDevice->vendor_id, currentDevice->vendor_id,
currentDevice->product_id, currentDevice->product_id,
currentDevice->serial_number, currentDevice->serial_number,
currentDevice->manufacturer_string, currentDevice->manufacturer_string,
currentDevice->product_string, currentDevice->product_string,
currentDevice->path); currentDevice->path);
currentDevice = currentDevice->next; currentDevice = currentDevice->next;
} }
hid_free_enumeration( devices ); hid_free_enumeration( devices );
goto HidOpenFailure; goto HidOpenFailure;
@ -222,7 +222,7 @@ uint32 HidControllerImpl::Read
if( !m_hidControllerOpen ) if( !m_hidControllerOpen )
{ {
//Error //Error
Log::Write( "Error: HID port must be opened before reading\n" ); Log::Write( "Error: HID port must be opened before reading" );
return 0; return 0;
} }
@ -275,8 +275,7 @@ uint32 HidControllerImpl::Read
return _length; return _length;
HidPortError: HidPortError:
//Error //Error
Log::Write( "Error: HID port returned error reading rest of packet: 0x%08hx, HIDAPI error string:", m_hidFeatureReportReadBufferBytes ); Log::Write( "Error: HID port returned error reading rest of packet: %d, HIDAPI error string: %ls", m_hidFeatureReportReadBufferBytes, hid_error(m_hHidController));
Log::Write("%ls\n", hid_error(m_hHidController));
return 0; return 0;
} }
@ -293,14 +292,14 @@ uint32 HidControllerImpl::Write
if( !m_hidControllerOpen ) if( !m_hidControllerOpen )
{ {
//Error //Error
Log::Write( "Error: HID port must be opened before writing\n" ); Log::Write( "Error: HID port must be opened before writing" );
return 0; return 0;
} }
if ( FEATURE_REPORT_LENGTH - 2 < _length) if ( FEATURE_REPORT_LENGTH - 2 < _length)
{ {
//Error //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, _length,
FEATURE_REPORT_LENGTH - 2 ); FEATURE_REPORT_LENGTH - 2 );
return 0; return 0;
@ -320,9 +319,7 @@ uint32 HidControllerImpl::Write
if (bytesSent < 2) if (bytesSent < 2)
{ {
//Error //Error
Log::Write( "Error: HID port returned error sending bytes: 0x%08hx, HIDAPI error string:", bytesSent ); Log::Write( "Error: HID port returned error sending bytes: %d, HIDAPI error string: %ls", bytesSent, hid_error( m_hHidController ) );
const wchar_t* errString = hid_error( m_hHidController );
Log::Write( "%ls\n", errString );
return 0; return 0;
} }
@ -373,18 +370,13 @@ bool HidControllerImpl::Wait
default: default:
{ {
//Error //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; return false;
break; break;
} }
} }
// continue looping until some rx feature report data is reported via input report // 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; return false;
@ -406,7 +398,7 @@ int HidControllerImpl::GetFeatureReport
result = hid_get_feature_report( m_hHidController, _buffer, _length ); result = hid_get_feature_report( m_hHidController, _buffer, _length );
if (result < 0) 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; return result;
} }
@ -426,7 +418,7 @@ int HidControllerImpl::SendFeatureReport
result = hid_send_feature_report( m_hHidController, _data, _length ); result = hid_send_feature_report( m_hHidController, _data, _length );
if (result < 0) 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; return result;
} }