update esppilight lib
content of the library is not filtered on 433mhz only
This commit is contained in:
1 parent
a275e48ee1
commit
67dd7ac078
1030 files changed
+203335
-116
No files matched your search
@@ -0,0 +1,162 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Bitfield.h
|
||||
//
|
||||
// Variable length bitfield implementation
|
||||
//
|
||||
// Copyright (c) 2011 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _Bitfield_H
|
||||
#define _Bitfield_H
|
||||
|
||||
#include <vector>
|
||||
#include "Defs.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class OPENZWAVE_EXPORT Bitfield
|
||||
{
|
||||
friend class Iterator;
|
||||
|
||||
public:
|
||||
Bitfield():m_numSetBits(0){}
|
||||
~Bitfield(){}
|
||||
|
||||
void Set( uint32 _idx )
|
||||
{
|
||||
if( !IsSet(_idx) )
|
||||
{
|
||||
uint32 newSize = (_idx>>5)+1;
|
||||
if( newSize > m_bits.size() )
|
||||
{
|
||||
m_bits.resize( newSize, 0 );
|
||||
}
|
||||
m_bits[_idx>>5] |= (1<<(_idx&0x1f));
|
||||
++m_numSetBits;
|
||||
}
|
||||
}
|
||||
|
||||
void Clear( uint32 _idx )
|
||||
{
|
||||
if( IsSet(_idx) )
|
||||
{
|
||||
m_bits[_idx>>5] &= ~(1<<(_idx&0x1f));
|
||||
--m_numSetBits;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsSet( uint32 _idx )const
|
||||
{
|
||||
if( (_idx>>5) < m_bits.size() )
|
||||
{
|
||||
return( ( m_bits[_idx>>5] & (1<<(_idx&0x1f)) ) !=0 );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 GetNumSetBits()const{ return m_numSetBits; }
|
||||
|
||||
class Iterator
|
||||
{
|
||||
friend class Bitfield;
|
||||
|
||||
public:
|
||||
uint32 operator *() const
|
||||
{
|
||||
return m_idx;
|
||||
}
|
||||
|
||||
Iterator& operator++()
|
||||
{
|
||||
// Search forward to next set bit
|
||||
NextSetBit();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Iterator operator++(int)
|
||||
{
|
||||
Iterator tmp = *this;
|
||||
++tmp;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator ==(const Iterator &rhs)
|
||||
{
|
||||
return m_idx == rhs.m_idx;
|
||||
}
|
||||
|
||||
bool operator !=(const Iterator &rhs)
|
||||
{
|
||||
return m_idx != rhs.m_idx;
|
||||
}
|
||||
|
||||
private:
|
||||
Iterator( Bitfield const* _bitfield, uint32 _idx ): m_idx( _idx ), m_bitfield( _bitfield )
|
||||
{
|
||||
// If this is a begin iterator, move it to the first set bit
|
||||
if( ( _idx == 0 ) && ( !m_bitfield->IsSet(0) ) )
|
||||
{
|
||||
NextSetBit();
|
||||
}
|
||||
}
|
||||
|
||||
void NextSetBit()
|
||||
{
|
||||
while( ((++m_idx)>>5)<m_bitfield->m_bits.size() )
|
||||
{
|
||||
// See if there are any bits left to find in the current uint32
|
||||
if( ( m_bitfield->m_bits[m_idx>>5] & ~((1<<(m_idx&0x1f))-1) ) == 0 )
|
||||
{
|
||||
// No more bits - move on to next uint32 (or rather one less than
|
||||
// the next uint32 because of the preincrement in the while statement)
|
||||
m_idx = (m_idx&0xffffffe0)+31;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (m_bitfield->m_bits[m_idx>>5] & (1<<(m_idx&0x1f))) !=0 )
|
||||
{
|
||||
// This bit is set
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 m_idx;
|
||||
Bitfield const* m_bitfield;
|
||||
};
|
||||
|
||||
Iterator Begin()const{ return Iterator( this, 0 ); }
|
||||
Iterator End()const{ return Iterator( this, (uint32) m_bits.size()<<5 ); }
|
||||
|
||||
private:
|
||||
OPENZWAVE_EXPORT_WARNINGS_OFF
|
||||
vector<uint32> m_bits;
|
||||
OPENZWAVE_EXPORT_WARNINGS_ON
|
||||
uint32 m_numSetBits;
|
||||
};
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
project(openzwave)
|
||||
|
||||
file(GLOB ${PROJECT_NAME}_sources "${PROJECT_SOURCE_DIR}/*.cpp")
|
||||
file(GLOB ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/*.h")
|
||||
|
||||
add_subdirectory(aes)
|
||||
add_subdirectory(command_classes)
|
||||
add_subdirectory(platform)
|
||||
add_subdirectory(value_classes)
|
||||
|
||||
set(${PROJECT_NAME}_files
|
||||
${${PROJECT_NAME}_aes_files}
|
||||
${${PROJECT_NAME}_command_classes_files}
|
||||
${${PROJECT_NAME}_platform_files}
|
||||
${${PROJECT_NAME}_value_classes_files}
|
||||
${${PROJECT_NAME}_sources}
|
||||
${${PROJECT_NAME}_headers}
|
||||
CACHE INTERNAL "")
|
||||
@@ -0,0 +1,363 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Defs.h
|
||||
//
|
||||
// Basic types and preprocessor directives
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _Defs_H
|
||||
#define _Defs_H
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
// Compilation export flags
|
||||
#if (defined _WINDOWS || defined WIN32 || defined _WIN32) && !defined MINGW
|
||||
# if defined OPENZWAVE_MAKEDLL // Create the dynamic library.
|
||||
# define OPENZWAVE_EXPORT __declspec(dllexport)
|
||||
# elif defined OPENZWAVE_USEDLL // Use the dynamic library
|
||||
# define OPENZWAVE_EXPORT __declspec(dllimport)
|
||||
# else // Create/Use the static library
|
||||
# define OPENZWAVE_EXPORT
|
||||
# endif
|
||||
// Disable export warnings
|
||||
# define OPENZWAVE_EXPORT
|
||||
# define OPENZWAVE_EXPORT_WARNINGS_OFF
|
||||
# define OPENZWAVE_EXPORT_WARNINGS_ON
|
||||
#else
|
||||
# define OPENZWAVE_EXPORT
|
||||
# define OPENZWAVE_EXPORT_WARNINGS_OFF
|
||||
# define OPENZWAVE_EXPORT_WARNINGS_ON
|
||||
#endif
|
||||
|
||||
#ifdef NULL
|
||||
#undef NULL
|
||||
#endif
|
||||
#define NULL 0
|
||||
|
||||
// Basic types
|
||||
typedef signed char int8;
|
||||
typedef unsigned char uint8;
|
||||
|
||||
typedef signed short int16;
|
||||
typedef unsigned short uint16;
|
||||
|
||||
typedef signed int int32;
|
||||
typedef unsigned int uint32;
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef signed __int64 int64;
|
||||
typedef unsigned __int64 uint64;
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
typedef signed long long int64;
|
||||
typedef unsigned long long uint64;
|
||||
#endif
|
||||
|
||||
typedef float float32;
|
||||
typedef double float64;
|
||||
|
||||
typedef struct ozwversion {
|
||||
uint32_t _v; /* major << 16 | minor */
|
||||
} ozwversion;
|
||||
|
||||
/**
|
||||
* \brief version_major - return the major version of the given struct
|
||||
* \param v: the version number to obtain the major number from
|
||||
* \return the Major Version Number
|
||||
*/
|
||||
static inline uint16_t version_major(struct ozwversion v) {
|
||||
return (v._v & 0xFFFF0000) >> 16;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief version_minor - return the minor version of the given struct
|
||||
* \param v: the version number to obtain the minor number from
|
||||
* \return the Minor Version Number
|
||||
*/
|
||||
static inline uint16_t version_minor(const struct ozwversion &v) {
|
||||
return v._v & 0xFFFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief version - create a new version number
|
||||
* \param major: major version number
|
||||
* \param minor: minor version number
|
||||
* \return the Version Number Struct
|
||||
*/
|
||||
static inline struct ozwversion version(uint16_t major, uint16_t minor)
|
||||
{
|
||||
struct ozwversion v;
|
||||
v._v = (uint32_t)(major << 16) | (uint32_t)minor;
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief version_cmp - compare two versions
|
||||
* \param a: the first version number
|
||||
* \param b: the second version number
|
||||
* \return a number greater, equal, or less than 0 if a is greater, equal or
|
||||
* less than b, respectively
|
||||
*
|
||||
* Example:
|
||||
* struct version a = version(1, 0);
|
||||
* struct version b = version(1, 3);
|
||||
* if (version_cmp(a, b) < 0)
|
||||
* printf("b is smaller than b\n");
|
||||
*/
|
||||
static inline int version_cmp(struct ozwversion a, struct ozwversion b)
|
||||
{
|
||||
return (a._v == b._v) ? 0 : (a._v > b._v) ? 1 : - 1;
|
||||
}
|
||||
|
||||
|
||||
// Declare the OpenZWave namespace
|
||||
namespace std {}
|
||||
namespace OpenZWave
|
||||
{
|
||||
// Include the STL namespace
|
||||
using namespace std;
|
||||
}
|
||||
|
||||
// Modifications for Microsoft compilers
|
||||
// #ifdef _WIN32
|
||||
|
||||
// // Fix for namespace-related compiler bug
|
||||
// namespace OpenZWave
|
||||
// {
|
||||
// }
|
||||
|
||||
// // Rename safe versions of sprintf etc
|
||||
// #define snprintf sprintf_s
|
||||
// #define strcasecmp _stricmp
|
||||
// #define sscanf sscanf_s
|
||||
|
||||
// #endif
|
||||
|
||||
// Modifications for MiNGW32 compiler
|
||||
#ifdef _WIN32
|
||||
|
||||
// Replace "safe" versions of sprintf
|
||||
#define sprintf_s snprintf
|
||||
|
||||
// seems some MINGW versions don't have a errno_t
|
||||
#ifndef errno_t
|
||||
#define errno_t int
|
||||
#endif
|
||||
|
||||
#define fopen_s fopen
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#define MAX_TRIES 3 // Retry sends up to 3 times
|
||||
#define MAX_MAX_TRIES 7 // Don't exceed this retry limit
|
||||
#define ACK_TIMEOUT 1000 // How long to wait for an ACK
|
||||
#define BYTE_TIMEOUT 150
|
||||
#define RETRY_TIMEOUT 40000 // Retry send after 40 seconds
|
||||
|
||||
#define SOF 0x01
|
||||
#define ACK 0x06
|
||||
#define NAK 0x15
|
||||
#define CAN 0x18
|
||||
|
||||
#define NUM_NODE_BITFIELD_BYTES 29 // 29 bytes = 232 bits, one for each possible node in the network.
|
||||
|
||||
#define REQUEST 0x00
|
||||
#define RESPONSE 0x01
|
||||
|
||||
#define ZW_CLOCK_SET 0x30
|
||||
|
||||
#define TRANSMIT_OPTION_ACK 0x01
|
||||
#define TRANSMIT_OPTION_LOW_POWER 0x02
|
||||
#define TRANSMIT_OPTION_AUTO_ROUTE 0x04
|
||||
#define TRANSMIT_OPTION_NO_ROUTE 0x10
|
||||
#define TRANSMIT_OPTION_EXPLORE 0x20
|
||||
|
||||
#define TRANSMIT_COMPLETE_OK 0x00
|
||||
#define TRANSMIT_COMPLETE_NO_ACK 0x01
|
||||
#define TRANSMIT_COMPLETE_FAIL 0x02
|
||||
#define TRANSMIT_COMPLETE_NOT_IDLE 0x03
|
||||
#define TRANSMIT_COMPLETE_NOROUTE 0x04
|
||||
|
||||
#define RECEIVE_STATUS_ROUTED_BUSY 0x01
|
||||
#define RECEIVE_STATUS_TYPE_BROAD 0x04
|
||||
|
||||
#define FUNC_ID_SERIAL_API_GET_INIT_DATA 0x02
|
||||
#define FUNC_ID_SERIAL_API_APPL_NODE_INFORMATION 0x03
|
||||
#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_ZW_SEND_NODE_INFORMATION 0x12
|
||||
#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_GET_RANDOM 0x1c
|
||||
#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_REPLICATION_COMMAND_COMPLETE 0x44 // Replication send data complete
|
||||
#define FUNC_ID_ZW_REPLICATION_SEND_DATA 0x45 // Replication send data
|
||||
#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_ASSIGN_SUC_RETURN_ROUTE 0x51 // Assign a return route to the SUC
|
||||
#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_DELETE_SUC_RETURN_ROUTE 0x55 // Remove return routes to the SUC
|
||||
#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_NEIGHBOR_UPDATE_OPTIONS 0x5a // Allow options for request node neighbor update
|
||||
#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_SERIAL_API_SLAVE_NODE_INFO 0xA0 // Set application virtual slave node information
|
||||
#define FUNC_ID_APPLICATION_SLAVE_COMMAND_HANDLER 0xA1 // Slave command handler
|
||||
#define FUNC_ID_ZW_SEND_SLAVE_NODE_INFO 0xA2 // Send a slave node information frame
|
||||
#define FUNC_ID_ZW_SEND_SLAVE_DATA 0xA3 // Send data from slave
|
||||
#define FUNC_ID_ZW_SET_SLAVE_LEARN_MODE 0xA4 // Enter slave learn mode
|
||||
#define FUNC_ID_ZW_GET_VIRTUAL_NODES 0xA5 // Return all virtual nodes
|
||||
#define FUNC_ID_ZW_IS_VIRTUAL_NODE 0xA6 // Virtual node test
|
||||
#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
|
||||
#define ADD_NODE_SLAVE 0x03
|
||||
#define ADD_NODE_EXISTING 0x04
|
||||
#define ADD_NODE_STOP 0x05
|
||||
#define ADD_NODE_STOP_FAILED 0x06
|
||||
|
||||
#define ADD_NODE_STATUS_LEARN_READY 0x01
|
||||
#define ADD_NODE_STATUS_NODE_FOUND 0x02
|
||||
#define ADD_NODE_STATUS_ADDING_SLAVE 0x03
|
||||
#define ADD_NODE_STATUS_ADDING_CONTROLLER 0x04
|
||||
#define ADD_NODE_STATUS_PROTOCOL_DONE 0x05
|
||||
#define ADD_NODE_STATUS_DONE 0x06
|
||||
#define ADD_NODE_STATUS_FAILED 0x07
|
||||
|
||||
#define REMOVE_NODE_ANY 0x01
|
||||
#define REMOVE_NODE_CONTROLLER 0x02
|
||||
#define REMOVE_NODE_SLAVE 0x03
|
||||
#define REMOVE_NODE_STOP 0x05
|
||||
|
||||
#define REMOVE_NODE_STATUS_LEARN_READY 0x01
|
||||
#define REMOVE_NODE_STATUS_NODE_FOUND 0x02
|
||||
#define REMOVE_NODE_STATUS_REMOVING_SLAVE 0x03
|
||||
#define REMOVE_NODE_STATUS_REMOVING_CONTROLLER 0x04
|
||||
#define REMOVE_NODE_STATUS_DONE 0x06
|
||||
#define REMOVE_NODE_STATUS_FAILED 0x07
|
||||
|
||||
#define CREATE_PRIMARY_START 0x02
|
||||
#define CREATE_PRIMARY_STOP 0x05
|
||||
#define CREATE_PRIMARY_STOP_FAILED 0x06
|
||||
|
||||
#define CONTROLLER_CHANGE_START 0x02
|
||||
#define CONTROLLER_CHANGE_STOP 0x05
|
||||
#define CONTROLLER_CHANGE_STOP_FAILED 0x06
|
||||
|
||||
#define LEARN_MODE_STARTED 0x01
|
||||
#define LEARN_MODE_DONE 0x06
|
||||
#define LEARN_MODE_FAILED 0x07
|
||||
#define LEARN_MODE_DELETED 0x80
|
||||
|
||||
#define REQUEST_NEIGHBOR_UPDATE_STARTED 0x21
|
||||
#define REQUEST_NEIGHBOR_UPDATE_DONE 0x22
|
||||
#define REQUEST_NEIGHBOR_UPDATE_FAILED 0x23
|
||||
|
||||
#define FAILED_NODE_OK 0x00
|
||||
#define FAILED_NODE_REMOVED 0x01
|
||||
#define FAILED_NODE_NOT_REMOVED 0x02
|
||||
|
||||
#define FAILED_NODE_REPLACE_WAITING 0x03
|
||||
#define FAILED_NODE_REPLACE_DONE 0x04
|
||||
#define FAILED_NODE_REPLACE_FAILED 0x05
|
||||
|
||||
#define FAILED_NODE_REMOVE_STARTED 0x00
|
||||
#define FAILED_NODE_NOT_PRIMARY_CONTROLLER 0x02
|
||||
#define FAILED_NODE_NO_CALLBACK_FUNCTION 0x04
|
||||
#define FAILED_NODE_NOT_FOUND 0x08
|
||||
#define FAILED_NODE_REMOVE_PROCESS_BUSY 0x10
|
||||
#define FAILED_NODE_REMOVE_FAIL 0x20
|
||||
|
||||
#define SUC_UPDATE_DONE 0x00
|
||||
#define SUC_UPDATE_ABORT 0x01
|
||||
#define SUC_UPDATE_WAIT 0x02
|
||||
#define SUC_UPDATE_DISABLED 0x03
|
||||
#define SUC_UPDATE_OVERFLOW 0x04
|
||||
|
||||
#define SUC_FUNC_BASIC_SUC 0x00
|
||||
#define SUC_FUNC_NODEID_SERVER 0x01
|
||||
|
||||
#define UPDATE_STATE_NODE_INFO_RECEIVED 0x84
|
||||
#define UPDATE_STATE_NODE_INFO_REQ_DONE 0x82
|
||||
#define UPDATE_STATE_NODE_INFO_REQ_FAILED 0x81
|
||||
#define UPDATE_STATE_ROUTING_PENDING 0x80
|
||||
#define UPDATE_STATE_NEW_ID_ASSIGNED 0x40
|
||||
#define UPDATE_STATE_DELETE_DONE 0x20
|
||||
#define UPDATE_STATE_SUC_ID 0x10
|
||||
|
||||
#define APPLICATION_NODEINFO_LISTENING 0x01
|
||||
#define APPLICATION_NODEINFO_OPTIONAL_FUNCTIONALITY 0x02
|
||||
|
||||
#define SLAVE_ASSIGN_COMPLETE 0x00
|
||||
#define SLAVE_ASSIGN_NODEID_DONE 0x01 // Node ID has been assigned
|
||||
#define SLAVE_ASSIGN_RANGE_INFO_UPDATE 0x02 // Node is doing neighbor discovery
|
||||
|
||||
#define SLAVE_LEARN_MODE_DISABLE 0x00 // disable add/remove virtual slave nodes
|
||||
#define SLAVE_LEARN_MODE_ENABLE 0x01 // enable ability to include/exclude virtual slave nodes
|
||||
#define SLAVE_LEARN_MODE_ADD 0x02 // add node directly but only if primary/inclusion controller
|
||||
#define SLAVE_LEARN_MODE_REMOVE 0x03 // remove node directly but only if primary/inclusion controller
|
||||
|
||||
#define OPTION_HIGH_POWER 0x80
|
||||
|
||||
//Device request related
|
||||
#define BASIC_SET 0x01
|
||||
#define BASIC_REPORT 0x03
|
||||
|
||||
#define COMMAND_CLASS_BASIC 0x20
|
||||
#define COMMAND_CLASS_CONTROLLER_REPLICATION 0x21
|
||||
#define COMMAND_CLASS_APPLICATION_STATUS 0x22
|
||||
#define COMMAND_CLASS_HAIL 0x82
|
||||
|
||||
#endif // _Defs_H
|
||||
@@ -0,0 +1,154 @@
|
||||
|
||||
/**
|
||||
* \mainpage OpenZWave
|
||||
* \section Introduction Introduction to OpenZWave
|
||||
* OpenZWave is an open-source, cross-platform library designed to enable
|
||||
* anyone to add support for Z-Wave home-automation devices to their
|
||||
* applications, without requiring any in depth knowledge of the Z-Wave
|
||||
* protocol.
|
||||
* <p>
|
||||
* Z-Wave employs a proprietary protocol which the owners, Sigma Designs,
|
||||
* have chosen not to release into the public domain. There is also no
|
||||
* official free or low-cost SDK that can be used to develop applications
|
||||
* (The ControlThink SDK is now tied exclusively to their own Z-Wave PC
|
||||
* interface). The only way to obtain the protocol documentation and sample
|
||||
* code is to purchase an expensive development kit, and sign a non-disclosure
|
||||
* agreement (NDA) preventing the release of that knowledge.
|
||||
* <p>
|
||||
* OpenZWave was created to fill that gap. We do not have the official
|
||||
* documentation, have signed no NDA, and are free to develop the library as
|
||||
* we see fit. Our knowledge comes from existing bodies of open-source code
|
||||
* (principally the Z-Wave parts of LinuxMCE), and through examining the
|
||||
* messages sent by Z-Wave devices.
|
||||
* <p>
|
||||
* The goal of the project is to make a positive contribution to the Z-Wave
|
||||
* community by creating a library that supports as much of the Z-Wave
|
||||
* specification as possible, and that can be used as a "black-box"
|
||||
* solution by anyone wanting to add Z-Wave to their application. It is NOT
|
||||
* our aim to publish alternative documentation of the Z-Wave protocol, or
|
||||
* to attempt to "punish" Sigma Designs for their decision to keep the
|
||||
* protocol closed.
|
||||
|
||||
* \section ZWave Z-Wave Concepts
|
||||
* Z-Wave is a proprietary wireless communications protocol employing mesh
|
||||
* networking technology. A mesh network allows low power devices to
|
||||
* communicate over long ranges, and around radio blackspots by passing
|
||||
* messages from one node to another. It is important to note that not all
|
||||
* Z-Wave devices are active all the time, especially those that are battery
|
||||
* powered. These nodes cannot take part in the forwarding of messages
|
||||
* across the mesh.
|
||||
* <p>
|
||||
* Each Z-Wave device is known as "Node" in the network. A Z-Wave network
|
||||
* can contain up to 232 nodes. If more devices are required, then
|
||||
* multiple networks need to be set up using separate Z-Wave controller.
|
||||
* OpenZWave supports multiple controllers, but on its own does not bridge
|
||||
* the networks allowing a device on one to directly control a device on
|
||||
* another. This functionality would have to be supplied by the application.
|
||||
* <p>
|
||||
* Z-Wave nodes can be divided into two types: Controllers and Slaves. The
|
||||
* controllers are usually in the form of hand-held remote controls, or PC
|
||||
* interfaces. The switches, dimmers, movement sensors etc are all slaves.
|
||||
* Controllers and Devices
|
||||
* Replication
|
||||
* Command Classes
|
||||
* Values
|
||||
|
||||
* <hr>
|
||||
* \section Library The OpenZWave Library
|
||||
* \subsection Overview Overview
|
||||
|
||||
* \subsection Manager The Manager
|
||||
* All Z-Wave functionality is accessed via the Manager class. While this
|
||||
* does not make for the most efficient code structure, it does enable
|
||||
* the library to handle potentially complex and hard-to-debug issues
|
||||
* such as multi-threading and object lifespans behind the scenes.
|
||||
* Application development is therefore simplified and less prone to bugs.
|
||||
* <p>
|
||||
|
||||
* \subsection Notifications Notifications
|
||||
* Communication between the PC and devices on the the Z-Wave network occurs
|
||||
* asynchronously. Some devices, notably movement sensors, sleep most of the
|
||||
* time to save battery power, and can only receive commands when awake.
|
||||
* Therefore a command to change a value in a device may not occur immediately.
|
||||
* It may take several seconds or minutes, or even never arrive at all.
|
||||
* For this reason, many OpenZWave methods, even those that request
|
||||
* information, do not return that information directly. A request will be
|
||||
* sent to the network, and the response sent to the application some time
|
||||
* later via a system of notification callbacks. The notification handler
|
||||
* will be at the core of any application using OpenZWave. It is here that
|
||||
* all information regarding device configurations and states will be reported.
|
||||
* <p>
|
||||
* A Z-Wave network is a dynamic entity. Controllers and devices can be
|
||||
* added or removed at any time. Once a network has been set up, this
|
||||
* probably won't happen very often, but OpenZWave, and any application
|
||||
* built upon it, must cope all the same. The notification callback system
|
||||
* is used to inform the application of any changes to the structure of the
|
||||
* network.
|
||||
|
||||
* \subsection Values Working with Values
|
||||
*
|
||||
|
||||
* \subsection Guidelines Application Development Guidelines
|
||||
* The main considerations when designing an application based upon
|
||||
* OpenZWave are:
|
||||
*
|
||||
* - Communication with Z-Wave devices is asynchronous and not guaranteed
|
||||
* to be reliable. Do not rely on receiving a response to any request.
|
||||
*
|
||||
* - A Z-Wave network may change at any time. The application's notification
|
||||
* callback handler must deal woth all notifications, and any representation
|
||||
* of the state of the Z-Wave network held by the application must be
|
||||
* modified to match. User interfaces should be built dynamically from the
|
||||
* information reported in the notification callbacks, and must be able to cope
|
||||
* with the addition and removal of devices.
|
||||
*
|
||||
* Some users will have more than one Z-Wave controller, to allow for remote
|
||||
* locations or to work around the 232 device limit. OpenZWave is designed
|
||||
* for use with multiple controllers, and all applications should be written
|
||||
* to support this.
|
||||
*
|
||||
* - There is no need to save the state of the network and restore it on
|
||||
* the next run. OpenZWave does this automatically, and is designed to cope
|
||||
* with any changes that occur to the network while the application is not
|
||||
* running.
|
||||
*
|
||||
|
||||
* <hr>
|
||||
* \section Structure Source Code Structure
|
||||
*
|
||||
|
||||
* <hr>
|
||||
* \section Samples Samples
|
||||
* The SDK package includes skeleton code for creating xPL-enabled
|
||||
* applications. Code is provided for three types of application - a Windows
|
||||
* service, a Windowed application, and a console application. The Windows
|
||||
* service is quite flexible - it will run as a console application if no
|
||||
* command line parameters are passed to it. This makes it possible to
|
||||
* ship one application that will run on all versions of Windows, whether or
|
||||
* not there is support for services. It is also useful for debugging.
|
||||
* <p>
|
||||
* The full source code for the W800RF32 service is also provided as a real
|
||||
* life example of using the SDK to build a complete xPL application.
|
||||
|
||||
* <hr>
|
||||
* \section Licensing Licensing
|
||||
* OpenZWave is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License,
|
||||
* or (at your option) any later version.
|
||||
* <p>
|
||||
* OpenZWave is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
* <hr>
|
||||
* \section Support Support
|
||||
* Assistance with all OpenZWave issues can be obtained by posting a message
|
||||
* to the OpenZWave Google Group (http://groups.google.com/group/openzwave)
|
||||
* <p>
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,856 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Driver.h
|
||||
//
|
||||
// Communicates with a Z-Wave network
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _Driver_H
|
||||
#define _Driver_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
#include "Defs.h"
|
||||
#include "value_classes/ValueID.h"
|
||||
#include "Node.h"
|
||||
#include "platform/Event.h"
|
||||
#include "platform/Mutex.h"
|
||||
#include "platform/TimeStamp.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class Msg;
|
||||
class Value;
|
||||
class Event;
|
||||
class Mutex;
|
||||
class Controller;
|
||||
class Thread;
|
||||
class ControllerReplication;
|
||||
class Notification;
|
||||
|
||||
/** \brief The Driver class handles communication between OpenZWave
|
||||
* and a device attached via a serial port (typically a controller).
|
||||
*/
|
||||
class OPENZWAVE_EXPORT Driver
|
||||
{
|
||||
friend class Manager;
|
||||
friend class Node;
|
||||
friend class Group;
|
||||
friend class CommandClass;
|
||||
friend class ControllerReplication;
|
||||
friend class Value;
|
||||
friend class ValueStore;
|
||||
friend class ValueButton;
|
||||
friend class Association;
|
||||
friend class Basic;
|
||||
friend class ManufacturerSpecific;
|
||||
friend class NodeNaming;
|
||||
friend class NoOperation;
|
||||
friend class SceneActivation;
|
||||
friend class WakeUp;
|
||||
friend class Security;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Controller Interfaces
|
||||
//-----------------------------------------------------------------------------
|
||||
public:
|
||||
enum ControllerInterface
|
||||
{
|
||||
ControllerInterface_Unknown = 0,
|
||||
ControllerInterface_Serial,
|
||||
ControllerInterface_Hid
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Construction / Destruction
|
||||
//-----------------------------------------------------------------------------
|
||||
private:
|
||||
/**
|
||||
* Creates threads, events and initializes member variables and the node array.
|
||||
*/
|
||||
Driver( string const& _controllerPath, ControllerInterface const& _interface );
|
||||
/** Sets "exit" flags and stops the three background threads (pollThread, serialThread
|
||||
* and driverThread). Then clears out the send queue and node array. Notifies
|
||||
* watchers and exits.
|
||||
*/
|
||||
virtual ~Driver();
|
||||
|
||||
/**
|
||||
* Start the driverThread
|
||||
*/
|
||||
void Start();
|
||||
/**
|
||||
* Entry point for driverThread
|
||||
*/
|
||||
static void DriverThreadEntryPoint( Event* _exitEvent, void* _context );
|
||||
/**
|
||||
* ThreadProc for driverThread. This is where all the "action" takes place.
|
||||
* <p>
|
||||
* First, the thread is initialized by calling Init(). If Init() fails, it will be retried
|
||||
* every 5 seconds for the first two minutes and every 30 seconds thereafter.
|
||||
* <p>
|
||||
* After the thread is successfully initialized, the thread enters a loop with the
|
||||
* following elements:
|
||||
* - Confirm that m_exit is still false (or exit from the thread if it is true)
|
||||
* - Call ReadMsg() to consume any available messages from the controller
|
||||
* - Call NotifyWatchers() to send any pending notifications
|
||||
* - If the thread is not waiting for an ACK, a callback or a message reply, send [any][the next] queued message[s]
|
||||
* - If there was no message read or sent (workDone=false), sleep for 5 seconds. If nothing happened
|
||||
* within this time frame and something was expected (ACK, callback or reply), retrieve the
|
||||
* last message from the send queue and examine GetSendAttempts(). If greater than 2, give up
|
||||
* and remove the message from the queue. Otherwise, resend the message.
|
||||
* - If something did happen [reset m_wakeEvent]
|
||||
*/
|
||||
void DriverThreadProc( Event* _exitEvent );
|
||||
/**
|
||||
* Initialize the controller. Open the specified serial port, start the serialThread
|
||||
* and pollThread, then send a NAK to the device [presumably to flush it].
|
||||
* <p>
|
||||
* Then queue the commands to retrieve the Z-Wave interface:
|
||||
* - Get version
|
||||
* - Get home and node IDs
|
||||
* - Get controller capabilities
|
||||
* - Get serial API capabilties
|
||||
* - [Get SUC node ID]
|
||||
* - Get init data [identifying the nodes on the network]
|
||||
* Init() will return false if the serial port could not be opened.
|
||||
*/
|
||||
bool Init( uint32 _attempts );
|
||||
|
||||
/**
|
||||
* Remove any messages to a node on the queues
|
||||
* Used when deleting a node.
|
||||
*/
|
||||
void RemoveQueues( uint8 const _nodeId );
|
||||
|
||||
Thread* m_driverThread; /**< Thread for reading from the Z-Wave controller, and for creating and managing the other threads for sending, polling etc. */
|
||||
bool m_exit; /**< Flag that is set when the application is exiting. */
|
||||
bool m_init; /**< Set to true once the driver has been initialised */
|
||||
bool m_awakeNodesQueried; /**< Set to true once the driver has polled all awake nodes */
|
||||
bool m_allNodesQueried; /**< Set to true once the driver has polled all nodes */
|
||||
bool m_notifytransactions;
|
||||
TimeStamp m_startTime; /**< Time this driver started (for log report purposes) */
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Configuration
|
||||
//-----------------------------------------------------------------------------
|
||||
private:
|
||||
void RequestConfig(); // Get the network configuration from the Z-Wave network
|
||||
bool ReadConfig(); // Read the configuration from a file
|
||||
void WriteConfig(); // Save the configuration to a file
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Controller
|
||||
//-----------------------------------------------------------------------------
|
||||
private:
|
||||
// Controller Capabilities (return in FUNC_ID_ZW_GET_CONTROLLER_CAPABILITIES)
|
||||
enum
|
||||
{
|
||||
ControllerCaps_Secondary = 0x01, /**< The controller is a secondary. */
|
||||
ControllerCaps_OnOtherNetwork = 0x02, /**< The controller is not using its default HomeID. */
|
||||
ControllerCaps_SIS = 0x04, /**< There is a SUC ID Server on the network. */
|
||||
ControllerCaps_RealPrimary = 0x08, /**< Controller was the primary before the SIS was added. */
|
||||
ControllerCaps_SUC = 0x10 /**< Controller is a static update controller. */
|
||||
};
|
||||
|
||||
// Init Capabilities (return in FUNC_ID_SERIAL_API_GET_INIT_DATA)
|
||||
enum
|
||||
{
|
||||
InitCaps_Slave = 0x01, /**< */
|
||||
InitCaps_TimerSupport = 0x02, /**< Controller supports timers. */
|
||||
InitCaps_Secondary = 0x04, /**< Controller is a secondary. */
|
||||
InitCaps_SUC = 0x08 /**< Controller is a static update controller. */
|
||||
};
|
||||
|
||||
bool IsPrimaryController()const{ return ((m_initCaps & InitCaps_Secondary) == 0); }
|
||||
bool IsStaticUpdateController()const{ return ((m_initCaps & InitCaps_SUC) != 0); }
|
||||
bool IsBridgeController()const{ return (m_libraryType == 7); }
|
||||
bool IsInclusionController()const{ return ((m_controllerCaps & ControllerCaps_SIS) != 0); }
|
||||
|
||||
|
||||
uint32 GetHomeId()const{ return m_homeId; }
|
||||
uint8 GetNodeId()const{ return m_nodeId; }
|
||||
uint8 GetSUCNodeId()const{ return m_SUCNodeId; }
|
||||
uint16 GetManufacturerId()const{ return m_manufacturerId; }
|
||||
uint16 GetProductType()const{ return m_productType; }
|
||||
uint16 GetProductId()const{ return m_productId; }
|
||||
string GetControllerPath()const{ return m_controllerPath; }
|
||||
ControllerInterface GetControllerInterfaceType()const{ return m_controllerInterfaceType; }
|
||||
string GetLibraryVersion()const{ return m_libraryVersion; }
|
||||
string GetLibraryTypeName()const{ return m_libraryTypeName; }
|
||||
int32 GetSendQueueCount()const
|
||||
{
|
||||
int32 count = 0;
|
||||
for( int32 i=0; i<MsgQueue_Count; ++i )
|
||||
{
|
||||
count += (int32) (m_msgQueue[i].size());
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of GetNode that does not have the protective "lock" and "release" requirement.
|
||||
* This function can be used within driverThread, which "knows" that the node will not be
|
||||
* changed or deleted while it is being used.
|
||||
* \param _nodeId The nodeId (index into the node array) identifying the node to be returned
|
||||
* \return
|
||||
* A pointer to the specified node (if it exists) or NULL if not.
|
||||
* \see GetNode
|
||||
*/
|
||||
Node* GetNodeUnsafe( uint8 _nodeId );
|
||||
/**
|
||||
* Locks the node array and returns the specified node (if it exists). If a node is returned,
|
||||
* the lock must be released after the node has been processed via a call to ReleaseNodes().
|
||||
* If the node specified by _nodeId does not exist, the lock is released and NULL is returned.
|
||||
* \param _nodeId The nodeId (index into the node array) identifying the node to be returned
|
||||
* \return
|
||||
* A pointer to the specified node (if it exists) or NULL if not.
|
||||
* \see LockNodes, ReleaseNodes
|
||||
*/
|
||||
Node* GetNode( uint8 _nodeId );
|
||||
/**
|
||||
* Lock the nodes so no other thread can modify them.
|
||||
*/
|
||||
void LockNodes();
|
||||
/**
|
||||
* Release the lock on the nodes so other threads can modify them.
|
||||
*/
|
||||
void ReleaseNodes();
|
||||
|
||||
ControllerInterface m_controllerInterfaceType; // Specifies the controller's hardware interface
|
||||
string m_controllerPath; // name or path used to open the controller hardware.
|
||||
Controller* m_controller; // Handles communications with the controller hardware.
|
||||
uint32 m_homeId; // Home ID of the Z-Wave controller. Not valid until the DriverReady notification has been received.
|
||||
|
||||
string m_libraryVersion; // Verison of the Z-Wave Library used by the controller.
|
||||
string m_libraryTypeName; // Name describing the library type.
|
||||
uint8 m_libraryType; // Type of library used by the controller.
|
||||
|
||||
uint8 m_serialAPIVersion[2];
|
||||
uint16 m_manufacturerId;
|
||||
uint16 m_productType;
|
||||
uint16 m_productId;
|
||||
uint8 m_apiMask[32];
|
||||
|
||||
uint8 m_initVersion; // Version of the Serial API used by the controller.
|
||||
uint8 m_initCaps; // Set of flags indicating the serial API capabilities (See IsSlave, HasTimerSupport, IsPrimaryController and IsStaticUpdateController above).
|
||||
uint8 m_controllerCaps; // Set of flags indicating the controller's capabilities (See IsInclusionController above).
|
||||
uint8 m_nodeId; // Z-Wave Controller's own node ID.
|
||||
Node* m_nodes[256]; // Array containing all the node objects.
|
||||
Mutex* m_nodeMutex; // Serializes access to node data
|
||||
|
||||
ControllerReplication* m_controllerReplication; // Controller replication is handled separately from the other command classes, due to older hand-held controllers using invalid node IDs.
|
||||
|
||||
uint8 m_transmitOptions;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Receiving Z-Wave messages
|
||||
//-----------------------------------------------------------------------------
|
||||
private:
|
||||
bool ReadMsg();
|
||||
void ProcessMsg( uint8* _data );
|
||||
|
||||
void HandleGetVersionResponse( uint8* _data );
|
||||
void HandleGetRandomResponse( uint8* _data );
|
||||
void HandleGetControllerCapabilitiesResponse( uint8* _data );
|
||||
void HandleGetSerialAPICapabilitiesResponse( uint8* _data );
|
||||
void HandleSerialAPISoftResetResponse( uint8* _data );
|
||||
void HandleEnableSUCResponse( uint8* _data );
|
||||
void HandleSetSUCNodeIdResponse( uint8* _data );
|
||||
void HandleGetSUCNodeIdResponse( uint8* _data );
|
||||
void HandleMemoryGetIdResponse( uint8* _data );
|
||||
/**
|
||||
* Process a response to a FUNC_ID_SERIAL_API_GET_INIT_DATA request.
|
||||
* <p>
|
||||
* The response message contains a bitmap identifying which of the 232 possible nodes
|
||||
* in the network are actually present. These bitmap values are compared with the
|
||||
* node map (read in from zwcfg_0x[homeid].xml) to see if the node has already been registered
|
||||
* by the OpenZWave library. If it has (the log will show it as "Known") and this is
|
||||
* the first time this message was sent (m_init is false), then AddNodeQuery() is called
|
||||
* to retrieve its current state. If this is a "New" node to OpenZWave, then InitNode()
|
||||
* is called.
|
||||
* \see AddNodeQuery, InitNode, GetNode, ReleaseNodes
|
||||
*/
|
||||
void HandleSerialAPIGetInitDataResponse( uint8* _data );
|
||||
void HandleGetNodeProtocolInfoResponse( uint8* _data );
|
||||
bool HandleRemoveFailedNodeResponse( uint8* _data );
|
||||
void HandleIsFailedNodeResponse( uint8* _data );
|
||||
bool HandleReplaceFailedNodeResponse( uint8* _data );
|
||||
bool HandleAssignReturnRouteResponse( uint8* _data );
|
||||
bool HandleDeleteReturnRouteResponse( uint8* _data );
|
||||
void HandleSendNodeInformationRequest( uint8* _data );
|
||||
void HandleSendDataResponse( uint8* _data, bool _replication );
|
||||
bool HandleNetworkUpdateResponse( uint8* _data );
|
||||
void HandleGetRoutingInfoResponse( uint8* _data );
|
||||
|
||||
void HandleSendDataRequest( uint8* _data, bool _replication );
|
||||
void HandleAddNodeToNetworkRequest( uint8* _data );
|
||||
void HandleCreateNewPrimaryRequest( uint8* _data );
|
||||
void HandleControllerChangeRequest( uint8* _data );
|
||||
void HandleSetLearnModeRequest( uint8* _data );
|
||||
void HandleRemoveFailedNodeRequest( uint8* _data );
|
||||
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 );
|
||||
void HandleNetworkUpdateRequest( uint8* _data );
|
||||
bool HandleApplicationUpdateRequest( uint8* _data );
|
||||
bool HandleRfPowerLevelSetResponse( uint8* _data );
|
||||
bool HandleSerialApiSetTimeoutsResponse( uint8* _data );
|
||||
bool HandleMemoryGetByteResponse( uint8* _data );
|
||||
bool HandleReadMemoryResponse( uint8* _data );
|
||||
void HandleGetVirtualNodesResponse( uint8* _data );
|
||||
bool HandleSetSlaveLearnModeResponse( uint8* _data );
|
||||
void HandleSetSlaveLearnModeRequest( uint8* _data );
|
||||
bool HandleSendSlaveNodeInfoResponse( uint8* _data );
|
||||
void HandleSendSlaveNodeInfoRequest( uint8* _data );
|
||||
void HandleApplicationSlaveCommandRequest( uint8* _data );
|
||||
void HandleSerialAPIResetRequest( uint8* _data );
|
||||
|
||||
void CommonAddNodeStatusRequestHandler( uint8 _funcId, uint8* _data );
|
||||
|
||||
bool m_waitingForAck; // True when we are waiting for an ACK from the dongle
|
||||
uint8 m_expectedCallbackId; // If non-zero, we wait for a message with this callback Id
|
||||
uint8 m_expectedReply; // If non-zero, we wait for a message with this function Id
|
||||
uint8 m_expectedCommandClassId; // If the expected reply is FUNC_ID_APPLICATION_COMMAND_HANDLER, this value stores the command class we're waiting to hear from
|
||||
uint8 m_expectedNodeId; // If we are waiting for a FUNC_ID_APPLICATION_COMMAND_HANDLER, make sure we only accept it from this node.
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Polling Z-Wave devices
|
||||
//-----------------------------------------------------------------------------
|
||||
private:
|
||||
int32 GetPollInterval(){ return m_pollInterval ; }
|
||||
void SetPollInterval( int32 _milliseconds, bool _bIntervalBetweenPolls ){ m_pollInterval = _milliseconds; m_bIntervalBetweenPolls = _bIntervalBetweenPolls; }
|
||||
bool EnablePoll( const ValueID &_valueId, uint8 _intensity = 1 );
|
||||
bool DisablePoll( const ValueID &_valueId );
|
||||
bool isPolled( const ValueID &_valueId );
|
||||
void SetPollIntensity( const ValueID &_valueId, uint8 _intensity );
|
||||
static void PollThreadEntryPoint( Event* _exitEvent, void* _context );
|
||||
void PollThreadProc( Event* _exitEvent );
|
||||
|
||||
Thread* m_pollThread; // Thread for polling devices on the Z-Wave network
|
||||
struct PollEntry
|
||||
{
|
||||
ValueID m_id;
|
||||
uint8 m_pollCounter;
|
||||
};
|
||||
OPENZWAVE_EXPORT_WARNINGS_OFF
|
||||
list<PollEntry> m_pollList; // List of nodes that need to be polled
|
||||
OPENZWAVE_EXPORT_WARNINGS_ON
|
||||
Mutex* m_pollMutex; // Serialize access to the polling list
|
||||
int32 m_pollInterval; // Time interval during which all nodes must be polled
|
||||
bool m_bIntervalBetweenPolls; // if true, the library intersperses m_pollInterval between polls; if false, the library attempts to complete all polls within m_pollInterval
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Retrieving Node information
|
||||
//-----------------------------------------------------------------------------
|
||||
public:
|
||||
uint8 GetNodeNumber( Msg const* _msg )const{ return ( _msg == NULL ? 0 : _msg->GetTargetNodeId() ); }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Creates a new Node object (deleting any previous Node object with the same nodeId) and
|
||||
* queues a full query of the node's parameters (starting at the beginning of the query
|
||||
* stages--Node::QueryStage_None). This function will send Notification::Type_NodeAdded
|
||||
* and Notification::Type_NodeRemoved messages to identify these modifications.
|
||||
* \param _nodeId The node ID of the node to create and query.
|
||||
* \see Notification::Type_NodeAdded, Notification::Type_NodeRemoved, Node::QueryStage_None,
|
||||
*/
|
||||
void InitNode( uint8 const _nodeId, bool newNode = false );
|
||||
|
||||
void InitAllNodes(); // Delete all nodes and fetch the data from the Z-Wave network again.
|
||||
|
||||
bool IsNodeListeningDevice( uint8 const _nodeId );
|
||||
bool IsNodeFrequentListeningDevice( uint8 const _nodeId );
|
||||
bool IsNodeBeamingDevice( uint8 const _nodeId );
|
||||
bool IsNodeRoutingDevice( uint8 const _nodeId );
|
||||
bool IsNodeSecurityDevice( uint8 const _nodeId );
|
||||
uint32 GetNodeMaxBaudRate( uint8 const _nodeId );
|
||||
uint8 GetNodeVersion( uint8 const _nodeId );
|
||||
uint8 GetNodeSecurity( uint8 const _nodeId );
|
||||
uint8 GetNodeBasic( uint8 const _nodeId );
|
||||
uint8 GetNodeGeneric( uint8 const _nodeId );
|
||||
uint8 GetNodeSpecific( uint8 const _nodeId );
|
||||
string GetNodeType( uint8 const _nodeId );
|
||||
uint32 GetNodeNeighbors( uint8 const _nodeId, uint8** o_neighbors );
|
||||
|
||||
string GetNodeManufacturerName( uint8 const _nodeId );
|
||||
string GetNodeProductName( uint8 const _nodeId );
|
||||
string GetNodeName( uint8 const _nodeId );
|
||||
string GetNodeLocation( uint8 const _nodeId );
|
||||
|
||||
string GetNodeManufacturerId( uint8 const _nodeId );
|
||||
string GetNodeProductType( uint8 const _nodeId );
|
||||
string GetNodeProductId( uint8 const _nodeId );
|
||||
void SetNodeManufacturerName( uint8 const _nodeId, string const& _manufacturerName );
|
||||
void SetNodeProductName( uint8 const _nodeId, string const& _productName );
|
||||
void SetNodeName( uint8 const _nodeId, string const& _nodeName );
|
||||
void SetNodeLocation( uint8 const _nodeId, string const& _location );
|
||||
void SetNodeLevel( uint8 const _nodeId, uint8 const _level );
|
||||
void SetNodeOn( uint8 const _nodeId );
|
||||
void SetNodeOff( uint8 const _nodeId );
|
||||
|
||||
Value* GetValue( ValueID const& _id );
|
||||
|
||||
bool IsAPICallSupported( uint8 const _apinum )const{ return (( m_apiMask[( _apinum - 1 ) >> 3] & ( 1 << (( _apinum - 1 ) & 0x07 ))) != 0 ); }
|
||||
void SetAPICall( uint8 const _apinum, bool _toSet )
|
||||
{
|
||||
if( _toSet )
|
||||
{
|
||||
m_apiMask[( _apinum - 1 ) >> 3] |= ( 1 << (( _apinum - 1 ) & 0x07 ));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_apiMask[( _apinum - 1 ) >> 3] &= ~( 1 << (( _apinum - 1 ) & 0x07 ));
|
||||
}
|
||||
}
|
||||
uint8 NodeFromMessage( uint8 const* buffer );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Controller commands
|
||||
//-----------------------------------------------------------------------------
|
||||
public:
|
||||
/**
|
||||
* Controller Commands.
|
||||
* Commands to be used with the BeginControllerCommand method.
|
||||
* \see Manager::BeginControllerCommand
|
||||
*/
|
||||
enum ControllerCommand
|
||||
{
|
||||
ControllerCommand_None = 0, /**< No command. */
|
||||
ControllerCommand_AddDevice, /**< Add a new device or controller to the Z-Wave network. */
|
||||
ControllerCommand_CreateNewPrimary, /**< Add a new controller to the Z-Wave network. Used when old primary fails. Requires SUC. */
|
||||
ControllerCommand_ReceiveConfiguration, /**< Receive Z-Wave network configuration information from another controller. */
|
||||
ControllerCommand_RemoveDevice, /**< Remove a device or controller from the Z-Wave network. */
|
||||
ControllerCommand_RemoveFailedNode, /**< Move a node to the controller's failed nodes list. This command will only work if the node cannot respond. */
|
||||
ControllerCommand_HasNodeFailed, /**< Check whether a node is in the controller's failed nodes list. */
|
||||
ControllerCommand_ReplaceFailedNode, /**< Replace a non-responding node with another. The node must be in the controller's list of failed nodes for this command to succeed. */
|
||||
ControllerCommand_TransferPrimaryRole, /**< Make a different controller the primary. */
|
||||
ControllerCommand_RequestNetworkUpdate, /**< Request network information from the SUC/SIS. */
|
||||
ControllerCommand_RequestNodeNeighborUpdate, /**< Get a node to rebuild its neighbour list. This method also does RequestNodeNeighbors */
|
||||
ControllerCommand_AssignReturnRoute, /**< Assign a network return routes to a device. */
|
||||
ControllerCommand_DeleteAllReturnRoutes, /**< Delete all return routes from a device. */
|
||||
ControllerCommand_SendNodeInformation, /**< Send a node information frame */
|
||||
ControllerCommand_ReplicationSend, /**< Send information from primary to secondary */
|
||||
ControllerCommand_CreateButton, /**< Create an id that tracks handheld button presses */
|
||||
ControllerCommand_DeleteButton /**< Delete id that tracks handheld button presses */
|
||||
};
|
||||
|
||||
/**
|
||||
* Controller States.
|
||||
* States reported via the callback handler passed into the BeginControllerCommand method.
|
||||
* \see Manager::BeginControllerCommand
|
||||
*/
|
||||
enum ControllerState
|
||||
{
|
||||
ControllerState_Normal = 0, /**< No command in progress. */
|
||||
ControllerState_Starting, /**< The command is starting. */
|
||||
ControllerState_Cancel, /**< The command was cancelled. */
|
||||
ControllerState_Error, /**< Command invocation had error(s) and was aborted */
|
||||
ControllerState_Waiting, /**< Controller is waiting for a user action. */
|
||||
ControllerState_Sleeping, /**< Controller command is on a sleep queue wait for device. */
|
||||
ControllerState_InProgress, /**< The controller is communicating with the other device to carry out the command. */
|
||||
ControllerState_Completed, /**< The command has completed successfully. */
|
||||
ControllerState_Failed, /**< The command has failed. */
|
||||
ControllerState_NodeOK, /**< Used only with ControllerCommand_HasNodeFailed to indicate that the controller thinks the node is OK. */
|
||||
ControllerState_NodeFailed /**< Used only with ControllerCommand_HasNodeFailed to indicate that the controller thinks the node has failed. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Controller Errors
|
||||
* Provide some more information about controller failures.
|
||||
*/
|
||||
enum ControllerError
|
||||
{
|
||||
ControllerError_None = 0,
|
||||
ControllerError_ButtonNotFound, /**< Button */
|
||||
ControllerError_NodeNotFound, /**< Button */
|
||||
ControllerError_NotBridge, /**< Button */
|
||||
ControllerError_NotSUC, /**< CreateNewPrimary */
|
||||
ControllerError_NotSecondary, /**< CreateNewPrimary */
|
||||
ControllerError_NotPrimary, /**< RemoveFailedNode, AddNodeToNetwork */
|
||||
ControllerError_IsPrimary, /**< ReceiveConfiguration */
|
||||
ControllerError_NotFound, /**< RemoveFailedNode */
|
||||
ControllerError_Busy, /**< RemoveFailedNode, RequestNetworkUpdate */
|
||||
ControllerError_Failed, /**< RemoveFailedNode, RequestNetworkUpdate */
|
||||
ControllerError_Disabled, /**< RequestNetworkUpdate error */
|
||||
ControllerError_Overflow /**< RequestNetworkUpdate error */
|
||||
};
|
||||
|
||||
typedef void (*pfnControllerCallback_t)( ControllerState _state, ControllerError _err, void* _context );
|
||||
|
||||
private:
|
||||
// The public interface is provided via the wrappers in the Manager class
|
||||
void ResetController( Event* _evt );
|
||||
void SoftReset();
|
||||
void RequestNodeNeighbors( uint8 const _nodeId, uint32 const _requestFlags );
|
||||
|
||||
bool BeginControllerCommand( ControllerCommand _command, pfnControllerCallback_t _callback, void* _context, bool _highPower, uint8 _nodeId, uint8 _arg );
|
||||
bool CancelControllerCommand();
|
||||
void AddNodeStop( uint8 const _funcId ); // Handle different controller behaviors
|
||||
|
||||
struct ControllerCommandItem
|
||||
{
|
||||
ControllerState m_controllerState;
|
||||
bool m_controllerStateChanged;
|
||||
bool m_controllerCommandDone;
|
||||
ControllerCommand m_controllerCommand;
|
||||
pfnControllerCallback_t m_controllerCallback;
|
||||
ControllerError m_controllerReturnError;
|
||||
void* m_controllerCallbackContext;
|
||||
bool m_highPower;
|
||||
bool m_controllerAdded;
|
||||
uint8 m_controllerCommandNode;
|
||||
uint8 m_controllerCommandArg;
|
||||
};
|
||||
|
||||
ControllerCommandItem* m_currentControllerCommand;
|
||||
|
||||
void DoControllerCommand();
|
||||
void UpdateControllerState( ControllerState const _state, ControllerError const _error = ControllerError_None )
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if( _error != ControllerError_None )
|
||||
{
|
||||
m_currentControllerCommand->m_controllerReturnError = _error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8 m_SUCNodeId;
|
||||
|
||||
void UpdateNodeRoutes( uint8 const_nodeId, bool _doUpdate = false );
|
||||
|
||||
Event* m_controllerResetEvent;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sending Z-Wave messages
|
||||
//-----------------------------------------------------------------------------
|
||||
public:
|
||||
enum MsgQueue
|
||||
{
|
||||
MsgQueue_Command = 0,
|
||||
MsgQueue_Security,
|
||||
MsgQueue_NoOp,
|
||||
MsgQueue_Controller,
|
||||
MsgQueue_WakeUp,
|
||||
MsgQueue_Send,
|
||||
MsgQueue_Query,
|
||||
MsgQueue_Poll,
|
||||
MsgQueue_Count // Number of message queues
|
||||
};
|
||||
|
||||
void SendMsg( Msg* _msg, MsgQueue const _queue );
|
||||
|
||||
/**
|
||||
* Fetch the transmit options
|
||||
*/
|
||||
uint8 GetTransmitOptions()const{ return m_transmitOptions; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* If there are messages in the send queue (m_sendQueue), gets the next message in the
|
||||
* queue and writes it to the serial port. In sending the message, SendMsg also initializes
|
||||
* variables tracking the message's callback ID (m_expectedCallbackId), expected reply
|
||||
* (m_expectedReply) and expected command class ID (m_expectedCommandClassId). It also
|
||||
* sets m_waitingForAck to true and increments the message's send attempts counter.
|
||||
* <p>
|
||||
* If there are no messages in the send queue, then SendMsg checks the query queue to
|
||||
* see if there are any outstanding queries that can be processed (target node not asleep).
|
||||
* If so, it retrieves the Node object that needs to be queried and calls that node's
|
||||
* AdvanceQueries member function. If this call results in all of the node's queries to be
|
||||
* completed, SendMsg will remove the node query item from the query queue.
|
||||
* \return TRUE if data was written, FALSE if not
|
||||
* \see Msg, m_sendQueue, m_expectedCallbackId, m_expectedReply, m_expectedCommandClassId,
|
||||
* m_waitingForAck, Msg::GetSendAttempts, Node::AdvanceQueries, GetCurrentNodeQuery,
|
||||
* RemoveNodeQuery, Node::AllQueriesCompleted
|
||||
*/
|
||||
bool WriteNextMsg( MsgQueue const _queue ); // Extracts the first message from the queue, and makes it the current one.
|
||||
bool WriteMsg( string const &str); // Sends the current message to the Z-Wave network
|
||||
void RemoveCurrentMsg(); // Deletes the current message and cleans up the callback etc states
|
||||
bool MoveMessagesToWakeUpQueue( uint8 const _targetNodeId, bool const _move ); // If a node does not respond, and is of a type that can sleep, this method is used to move all its pending messages to another queue ready for when it mext wakes up.
|
||||
bool HandleErrorResponse( uint8 const _error, uint8 const _nodeId, char const* _funcStr, bool _sleepCheck = false ); // Handle data errors and process consistently. If message is moved to wake-up queue, return true.
|
||||
bool IsExpectedReply( uint8 const _nodeId ); // Determine if reply message is the one we are expecting
|
||||
void SendQueryStageComplete( uint8 const _nodeId, Node::QueryStage const _stage );
|
||||
void RetryQueryStageComplete( uint8 const _nodeId, Node::QueryStage const _stage );
|
||||
void CheckCompletedNodeQueries(); // Send notifications if all awake and/or sleeping nodes have completed their queries
|
||||
|
||||
// Requests to be sent to nodes are assigned to one of five queues.
|
||||
// From highest to lowest priority, these are
|
||||
//
|
||||
// 0) The security queue, for handling encrypted messages. This is the
|
||||
// highest priority send queue, because the security process inserts
|
||||
// messages to handle the encryption process that must be sent before
|
||||
// a new message can be wrapped.
|
||||
//
|
||||
// 1) The command queue, for controller commands. This is the 2nd highest
|
||||
// priority send queue, because the controller command processes are not
|
||||
// permitted to be interupted by other requests.
|
||||
//
|
||||
// 2) The controller queue exists to handle multi-step controller commands. These
|
||||
// typically require user interaction or affect the network in some way.
|
||||
//
|
||||
// 3) The No Operation command class queue. This is used for device probing
|
||||
// at startup as well as network diagostics.
|
||||
//
|
||||
// 4) The wakeup queue. This holds messages that have been held for a
|
||||
// sleeping device that has now woken up. These get a high priority
|
||||
// because such devices do not stay awake for very long.
|
||||
//
|
||||
// 5) The send queue. This is for normal messages, usually triggered by
|
||||
// a user interaction with the application.
|
||||
//
|
||||
// 6) The query queue. For node query messages sent when a new node is
|
||||
// discovered. The query process generates a large number of requests,
|
||||
// so the query queue has a low priority to avoid making the system
|
||||
// unresponsive.
|
||||
//
|
||||
// 7) The poll queue. Requests to devices that need their state polling
|
||||
// at regular intervals. These are of the lowest priority, and are only
|
||||
// sent when nothing else is going on
|
||||
//
|
||||
enum MsgQueueCmd
|
||||
{
|
||||
MsgQueueCmd_SendMsg = 0,
|
||||
MsgQueueCmd_QueryStageComplete,
|
||||
MsgQueueCmd_Controller
|
||||
};
|
||||
|
||||
class MsgQueueItem
|
||||
{
|
||||
public:
|
||||
MsgQueueItem() :
|
||||
m_msg(NULL),
|
||||
m_nodeId(0),
|
||||
m_queryStage(Node::QueryStage_None),
|
||||
m_retry(false),
|
||||
m_cci(NULL)
|
||||
{}
|
||||
|
||||
bool operator == ( MsgQueueItem const& _other )const
|
||||
{
|
||||
if( _other.m_command == m_command )
|
||||
{
|
||||
if( m_command == MsgQueueCmd_SendMsg )
|
||||
{
|
||||
return( (*_other.m_msg) == (*m_msg) );
|
||||
}
|
||||
else if( m_command == MsgQueueCmd_QueryStageComplete )
|
||||
{
|
||||
return( (_other.m_nodeId == m_nodeId) && (_other.m_queryStage == m_queryStage) );
|
||||
}
|
||||
else if( m_command == MsgQueueCmd_Controller )
|
||||
{
|
||||
return( (_other.m_cci->m_controllerCommand == m_cci->m_controllerCommand) && (_other.m_cci->m_controllerCallback == m_cci->m_controllerCallback) );
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
MsgQueueCmd m_command;
|
||||
Msg* m_msg;
|
||||
uint8 m_nodeId;
|
||||
Node::QueryStage m_queryStage;
|
||||
bool m_retry;
|
||||
ControllerCommandItem* m_cci;
|
||||
};
|
||||
|
||||
OPENZWAVE_EXPORT_WARNINGS_OFF
|
||||
list<MsgQueueItem> m_msgQueue[MsgQueue_Count];
|
||||
OPENZWAVE_EXPORT_WARNINGS_ON
|
||||
Event* m_queueEvent[MsgQueue_Count]; // Events for each queue, which are signalled when the queue is not empty
|
||||
Mutex* m_sendMutex; // Serialize access to the queues
|
||||
Msg* m_currentMsg;
|
||||
MsgQueue m_currentMsgQueueSource; // identifies which queue held m_currentMsg
|
||||
TimeStamp m_resendTimeStamp;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Network functions
|
||||
//-----------------------------------------------------------------------------
|
||||
private:
|
||||
void TestNetwork( uint8 const _nodeId, uint32 const _count );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Virtual Node commands
|
||||
//-----------------------------------------------------------------------------
|
||||
public:
|
||||
/**
|
||||
* Virtual Node Commands.
|
||||
* Commands to be used with virtual nodes.
|
||||
*/
|
||||
private:
|
||||
uint32 GetVirtualNeighbors( uint8** o_neighbors );
|
||||
void RequestVirtualNeighbors( MsgQueue const _queue );
|
||||
bool IsVirtualNode( uint8 const _nodeId )const{ return (( m_virtualNeighbors[( _nodeId - 1 ) >> 3] & 1 << (( _nodeId - 1 ) & 0x07 )) != 0 ); }
|
||||
void SendVirtualNodeInfo( uint8 const _fromNodeId, uint8 const _ToNodeId );
|
||||
void SendSlaveLearnModeOff();
|
||||
void SaveButtons();
|
||||
void ReadButtons( uint8 const _nodeId );
|
||||
|
||||
bool m_virtualNeighborsReceived;
|
||||
uint8 m_virtualNeighbors[NUM_NODE_BITFIELD_BYTES]; // Bitmask containing virtual neighbors
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SwitchAll
|
||||
//-----------------------------------------------------------------------------
|
||||
private:
|
||||
// The public interface is provided via the wrappers in the Manager class
|
||||
void SwitchAllOn();
|
||||
void SwitchAllOff();
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Configuration Parameters (wrappers for the Node methods)
|
||||
//-----------------------------------------------------------------------------
|
||||
private:
|
||||
// The public interface is provided via the wrappers in the Manager class
|
||||
bool SetConfigParam( uint8 const _nodeId, uint8 const _param, int32 _value, uint8 const _size );
|
||||
void RequestConfigParam( uint8 const _nodeId, uint8 const _param );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Groups (wrappers for the Node methods)
|
||||
//-----------------------------------------------------------------------------
|
||||
private:
|
||||
// The public interface is provided via the wrappers in the Manager class
|
||||
uint8 GetNumGroups( uint8 const _nodeId );
|
||||
uint32 GetAssociations( uint8 const _nodeId, uint8 const _groupIdx, uint8** o_associations );
|
||||
uint8 GetMaxAssociations( uint8 const _nodeId, uint8 const _groupIdx );
|
||||
string GetGroupLabel( uint8 const _nodeId, uint8 const _groupIdx );
|
||||
void AddAssociation( uint8 const _nodeId, uint8 const _groupIdx, uint8 const _targetNodeId );
|
||||
void RemoveAssociation( uint8 const _nodeId, uint8 const _groupIdx, uint8 const _targetNodeId );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Notifications
|
||||
//-----------------------------------------------------------------------------
|
||||
private:
|
||||
void QueueNotification( Notification* _notification ); // Adds a notification to the list. Notifications are queued until a point in the thread where we know we do not have any nodes locked.
|
||||
void NotifyWatchers(); // Passes the notifications to all the registered watcher callbacks in turn.
|
||||
|
||||
OPENZWAVE_EXPORT_WARNINGS_OFF
|
||||
list<Notification*> m_notifications;
|
||||
OPENZWAVE_EXPORT_WARNINGS_ON
|
||||
Event* m_notificationsEvent;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Statistics
|
||||
//-----------------------------------------------------------------------------
|
||||
public:
|
||||
struct DriverData
|
||||
{
|
||||
uint32 m_SOFCnt; // Number of SOF bytes received
|
||||
uint32 m_ACKWaiting; // Number of unsolicited 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
|
||||
uint32 m_callbacks; // Number of unexpected callbacks
|
||||
uint32 m_badroutes; // Number of failed messages due to bad route response
|
||||
uint32 m_noack; // Number of no ACK returned errors
|
||||
uint32 m_netbusy; // Number of network busy/failure messages
|
||||
uint32 m_notidle;
|
||||
uint32 m_nondelivery; // Number of messages not delivered to network
|
||||
uint32 m_routedbusy; // Number of messages received with routed busy status
|
||||
uint32 m_broadcastReadCnt; // Number of broadcasts read
|
||||
uint32 m_broadcastWriteCnt; // Number of broadcasts sent
|
||||
};
|
||||
|
||||
void LogDriverStatistics();
|
||||
|
||||
private:
|
||||
void GetDriverStatistics( DriverData* _data );
|
||||
void GetNodeStatistics( uint8 const _nodeId, Node::NodeData* _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 retransmitted messages
|
||||
uint32 m_callbacks; // Number of unexpected callbacks
|
||||
uint32 m_badroutes; // Number of failed messages due to bad route response
|
||||
uint32 m_noack; // Number of no ACK returned errors
|
||||
uint32 m_netbusy; // Number of network busy/failure messages
|
||||
uint32 m_notidle; // Number of not idle messages
|
||||
uint32 m_nondelivery; // Number of messages not delivered to network
|
||||
uint32 m_routedbusy; // Number of messages received with routed busy status
|
||||
uint32 m_broadcastReadCnt; // Number of broadcasts read
|
||||
uint32 m_broadcastWriteCnt; // Number of broadcasts sent
|
||||
//time_t m_commandStart; // Start time of last command
|
||||
//time_t m_timeoutLost; // Cumulative time lost to timeouts
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Security Command Class Related (Version 1.1)
|
||||
//-----------------------------------------------------------------------------
|
||||
private:
|
||||
uint8 *GetNetworkKey();
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif // _Driver_H
|
||||
@@ -0,0 +1,422 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Group.cpp
|
||||
//
|
||||
// A set of associations in a Z-Wave device.
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <cstring>
|
||||
#include "Group.h"
|
||||
#include "Manager.h"
|
||||
#include "Driver.h"
|
||||
#include "Node.h"
|
||||
#include "Notification.h"
|
||||
#include "Options.h"
|
||||
#include "command_classes/Association.h"
|
||||
#include "command_classes/AssociationCommandConfiguration.h"
|
||||
|
||||
#include "tinyxml.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Group::Group>
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
Group::Group
|
||||
(
|
||||
uint32 const _homeId,
|
||||
uint8 const _nodeId,
|
||||
uint8 const _groupIdx,
|
||||
uint8 const _maxAssociations
|
||||
):
|
||||
m_homeId( _homeId ),
|
||||
m_nodeId( _nodeId ),
|
||||
m_groupIdx( _groupIdx ),
|
||||
m_maxAssociations( _maxAssociations ),
|
||||
m_auto( false )
|
||||
{
|
||||
char str[16];
|
||||
snprintf( str, sizeof(str), "Group %d", m_groupIdx );
|
||||
m_label = str;
|
||||
|
||||
// Auto-association by default is with group 1 or 255, with group 1 taking precedence.
|
||||
// Group 255 is always created first, so if this is group 1, we need to turn off the
|
||||
// auto flag in group 255. All this messing about is to support the various behaviours
|
||||
// of certain Cooper devices.
|
||||
if( _groupIdx == 255 )
|
||||
{
|
||||
m_auto = true;
|
||||
}
|
||||
else if( _groupIdx == 1 )
|
||||
{
|
||||
m_auto = true;
|
||||
|
||||
// Clear the flag from Group 255, if it exists.
|
||||
if( Driver* driver = Manager::Get()->GetDriver( m_homeId ) )
|
||||
{
|
||||
if( Node* node = driver->GetNodeUnsafe( m_nodeId ) )
|
||||
{
|
||||
if( Group* group = node->GetGroup( 255 ) )
|
||||
{
|
||||
group->SetAuto( false );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Group::Group>
|
||||
// Constructor (from XML)
|
||||
//-----------------------------------------------------------------------------
|
||||
Group::Group
|
||||
(
|
||||
uint32 const _homeId,
|
||||
uint8 const _nodeId,
|
||||
TiXmlElement const* _groupElement
|
||||
):
|
||||
m_homeId( _homeId ),
|
||||
m_nodeId( _nodeId ),
|
||||
m_groupIdx( 0 ),
|
||||
m_maxAssociations( 0 ),
|
||||
m_auto( false )
|
||||
{
|
||||
int intVal;
|
||||
char const* str;
|
||||
vector<uint8> pending;
|
||||
|
||||
if( TIXML_SUCCESS == _groupElement->QueryIntAttribute( "index", &intVal ) )
|
||||
{
|
||||
m_groupIdx = (uint8)intVal;
|
||||
}
|
||||
|
||||
if( TIXML_SUCCESS == _groupElement->QueryIntAttribute( "max_associations", &intVal ) )
|
||||
{
|
||||
m_maxAssociations = (uint8)intVal;
|
||||
}
|
||||
|
||||
str = _groupElement->Attribute( "auto" );
|
||||
if( str )
|
||||
{
|
||||
m_auto = !strcmp( str, "true" );
|
||||
}
|
||||
|
||||
str = _groupElement->Attribute( "label" );
|
||||
if( str )
|
||||
{
|
||||
m_label = str;
|
||||
}
|
||||
|
||||
// Read the associations for this group
|
||||
TiXmlElement const* associationElement = _groupElement->FirstChildElement();
|
||||
while( associationElement )
|
||||
{
|
||||
char const* elementName = associationElement->Value();
|
||||
if( elementName && !strcmp( elementName, "Node" ) )
|
||||
{
|
||||
if (associationElement->QueryIntAttribute( "id", &intVal ) == TIXML_SUCCESS)
|
||||
pending.push_back( (uint8)intVal );
|
||||
}
|
||||
|
||||
associationElement = associationElement->NextSiblingElement();
|
||||
}
|
||||
|
||||
// Group must be added before OnGroupChanged is called so UpdateNodeRoutes can find it.
|
||||
// Since we do not want to update return routes UpdateNodeRoutes won't find the group
|
||||
// so nothing will go out from here. The not sending of return routes information
|
||||
// only works by a side effect of not finding the group.
|
||||
OnGroupChanged( pending );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Group::WriteXML>
|
||||
// Write ourselves to an XML document
|
||||
//-----------------------------------------------------------------------------
|
||||
void Group::WriteXML
|
||||
(
|
||||
TiXmlElement* _groupElement
|
||||
)
|
||||
{
|
||||
char str[16];
|
||||
|
||||
snprintf( str, 16, "%d", m_groupIdx );
|
||||
_groupElement->SetAttribute( "index", str );
|
||||
|
||||
snprintf( str, 16, "%d", m_maxAssociations );
|
||||
_groupElement->SetAttribute( "max_associations", str );
|
||||
|
||||
_groupElement->SetAttribute( "label", m_label.c_str() );
|
||||
_groupElement->SetAttribute( "auto", m_auto ? "true" : "false" );
|
||||
|
||||
for( map<uint8,AssociationCommandVec>::iterator it = m_associations.begin(); it != m_associations.end(); ++it )
|
||||
{
|
||||
TiXmlElement* associationElement = new TiXmlElement( "Node" );
|
||||
|
||||
snprintf( str, 16, "%d", it->first );
|
||||
associationElement->SetAttribute( "id", str );
|
||||
|
||||
_groupElement->LinkEndChild( associationElement );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Group::Contains>
|
||||
// Whether a group contains a particular node
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Group::Contains
|
||||
(
|
||||
uint8 const _nodeId
|
||||
)
|
||||
{
|
||||
map<uint8,AssociationCommandVec>::iterator it = m_associations.find( _nodeId );
|
||||
return( it != m_associations.end() );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Group::AddAssociation>
|
||||
// Associate a node with this group
|
||||
//-----------------------------------------------------------------------------
|
||||
void Group::AddAssociation
|
||||
(
|
||||
uint8 const _nodeId
|
||||
)
|
||||
{
|
||||
if( Driver* driver = Manager::Get()->GetDriver( m_homeId ) )
|
||||
{
|
||||
if( Node* node = driver->GetNodeUnsafe( m_nodeId ) )
|
||||
{
|
||||
if( Association* cc = static_cast<Association*>( node->GetCommandClass( Association::StaticGetCommandClassId() ) ) )
|
||||
{
|
||||
cc->Set( m_groupIdx, _nodeId );
|
||||
cc->QueryGroup( m_groupIdx, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Group:RemoveAssociation>
|
||||
// Remove a node from this group
|
||||
//-----------------------------------------------------------------------------
|
||||
void Group::RemoveAssociation
|
||||
(
|
||||
uint8 const _nodeId
|
||||
)
|
||||
{
|
||||
if( Driver* driver = Manager::Get()->GetDriver( m_homeId ) )
|
||||
{
|
||||
if( Node* node = driver->GetNodeUnsafe( m_nodeId ) )
|
||||
{
|
||||
if( Association* cc = static_cast<Association*>( node->GetCommandClass( Association::StaticGetCommandClassId() ) ) )
|
||||
{
|
||||
cc->Remove( m_groupIdx, _nodeId );
|
||||
cc->QueryGroup( m_groupIdx, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Group::OnGroupChanged>
|
||||
// Change the group contents and notify the watchers
|
||||
//-----------------------------------------------------------------------------
|
||||
void Group::OnGroupChanged
|
||||
(
|
||||
vector<uint8> const& _associations
|
||||
)
|
||||
{
|
||||
bool notify = false;
|
||||
|
||||
// If the number of associations is different, we'll save
|
||||
// ourselves some work and clear the old set now.
|
||||
if( _associations.size() != m_associations.size() )
|
||||
{
|
||||
m_associations.clear();
|
||||
notify = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Handle initial group creation case
|
||||
if ( _associations.size() == 0 && m_associations.size() == 0 )
|
||||
{
|
||||
notify = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the new associations.
|
||||
uint8 oldSize = (uint8)m_associations.size();
|
||||
|
||||
uint8 i;
|
||||
for( i=0; i<_associations.size(); ++i )
|
||||
{
|
||||
m_associations[_associations[i]] = AssociationCommandVec();
|
||||
}
|
||||
|
||||
if( (!notify) && ( oldSize != m_associations.size() ) )
|
||||
{
|
||||
// The number of nodes in the original and new groups is the same, but
|
||||
// the number of associations has grown. There must be different nodes
|
||||
// in the original and new sets of nodes in the group. The easiest way
|
||||
// to sort this out is to clear the associations and add the new nodes again.
|
||||
m_associations.clear();
|
||||
for( i=0; i<_associations.size(); ++i )
|
||||
{
|
||||
m_associations[_associations[i]] = AssociationCommandVec();
|
||||
}
|
||||
notify = true;
|
||||
}
|
||||
|
||||
if( notify )
|
||||
{
|
||||
// If the node supports COMMAND_CLASS_ASSOCIATION_COMMAND_CONFIGURATION, we need to request the command data.
|
||||
if( Driver* driver = Manager::Get()->GetDriver( m_homeId ) )
|
||||
{
|
||||
if( Node* node = driver->GetNodeUnsafe( m_nodeId ) )
|
||||
{
|
||||
if( AssociationCommandConfiguration* cc = static_cast<AssociationCommandConfiguration*>( node->GetCommandClass( AssociationCommandConfiguration::StaticGetCommandClassId() ) ) )
|
||||
{
|
||||
for( map<uint8,AssociationCommandVec>::iterator it = m_associations.begin(); it != m_associations.end(); ++it )
|
||||
{
|
||||
cc->RequestCommands( m_groupIdx, it->first );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send notification that the group contents have changed
|
||||
Notification* notification = new Notification( Notification::Type_Group );
|
||||
notification->SetHomeAndNodeIds( m_homeId, m_nodeId );
|
||||
notification->SetGroupIdx( m_groupIdx );
|
||||
Manager::Get()->GetDriver( m_homeId )->QueueNotification( notification );
|
||||
// Update routes on remote node if necessary
|
||||
bool update = false;
|
||||
Options::Get()->GetOptionAsBool( "PerformReturnRoutes", &update );
|
||||
if( update )
|
||||
{
|
||||
Driver *drv = Manager::Get()->GetDriver( m_homeId );
|
||||
if (drv)
|
||||
drv->UpdateNodeRoutes( m_nodeId );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Group::GetAssociations>
|
||||
// Get a list of associations for this group
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32 Group::GetAssociations
|
||||
(
|
||||
uint8** o_associations
|
||||
)
|
||||
{
|
||||
size_t numNodes = m_associations.size();
|
||||
if( !numNodes )
|
||||
{
|
||||
*o_associations = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8* associations = new uint8[numNodes];
|
||||
uint32 i = 0;
|
||||
for( map<uint8,AssociationCommandVec>::iterator it = m_associations.begin(); it != m_associations.end(); ++it )
|
||||
{
|
||||
associations[i++] = it->first;
|
||||
}
|
||||
|
||||
*o_associations = associations;
|
||||
return (uint32) numNodes;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Command methods (COMMAND_CLASS_ASSOCIATION_COMMAND_CONFIGURATION)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Group::ClearCommands>
|
||||
// Clear all the commands for the specified node
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Group::ClearCommands
|
||||
(
|
||||
uint8 const _nodeId
|
||||
)
|
||||
{
|
||||
map<uint8,AssociationCommandVec>::iterator it = m_associations.find( _nodeId );
|
||||
if( it != m_associations.end() )
|
||||
{
|
||||
it->second.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Group::AddCommand>
|
||||
// Add a command to the list for the specified node
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Group::AddCommand
|
||||
(
|
||||
uint8 const _nodeId,
|
||||
uint8 const _length,
|
||||
uint8 const* _data
|
||||
)
|
||||
{
|
||||
map<uint8,AssociationCommandVec>::iterator it = m_associations.find( _nodeId );
|
||||
if( it != m_associations.end() )
|
||||
{
|
||||
it->second.push_back( AssociationCommand( _length, _data ) );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Group::AssociationCommand::AssociationCommand>
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
Group::AssociationCommand::AssociationCommand
|
||||
(
|
||||
uint8 const _length,
|
||||
uint8 const* _data
|
||||
):
|
||||
m_length( _length )
|
||||
{
|
||||
m_data = new uint8[_length];
|
||||
memcpy( m_data, _data, _length );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Group::AssociationCommand::AssociationCommand>
|
||||
// Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
Group::AssociationCommand::~AssociationCommand
|
||||
(
|
||||
)
|
||||
{
|
||||
delete [] m_data;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Group.h
|
||||
//
|
||||
// A set of associations in a Z-Wave device.
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _Group_H
|
||||
#define _Group_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "Defs.h"
|
||||
|
||||
class TiXmlElement;
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class Node;
|
||||
|
||||
/** \brief Manages a group of devices (various nodes associated with each other).
|
||||
*/
|
||||
class Group
|
||||
{
|
||||
friend class Node;
|
||||
friend class Association;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Construction
|
||||
//-----------------------------------------------------------------------------
|
||||
public:
|
||||
Group( uint32 const _homeId, uint8 const _nodeId, uint8 const _groupIdx, uint8 const _maxAssociations );
|
||||
Group( uint32 const _homeId, uint8 const _nodeId, TiXmlElement const* _valueElement );
|
||||
~Group(){}
|
||||
|
||||
void WriteXML( TiXmlElement* _groupElement );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Association methods (COMMAND_CLASS_ASSOCIATION)
|
||||
//-----------------------------------------------------------------------------
|
||||
public:
|
||||
string const& GetLabel()const{ return m_label; }
|
||||
uint32 GetAssociations( uint8** o_associations );
|
||||
uint8 GetMaxAssociations()const{ return m_maxAssociations; }
|
||||
uint8 GetIdx()const{ return m_groupIdx; }
|
||||
bool Contains( uint8 const _nodeId );
|
||||
|
||||
private:
|
||||
bool IsAuto()const{ return m_auto; }
|
||||
void SetAuto( bool const _state ){ m_auto = _state; }
|
||||
|
||||
void AddAssociation( uint8 const _nodeId );
|
||||
void RemoveAssociation( uint8 const _nodeId );
|
||||
void OnGroupChanged( vector<uint8> const& _associations );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Command methods (COMMAND_CLASS_ASSOCIATION_COMMAND_CONFIGURATION)
|
||||
//-----------------------------------------------------------------------------
|
||||
public:
|
||||
bool ClearCommands( uint8 const _nodeId );
|
||||
bool AddCommand( uint8 const _nodeId, uint8 const _length, uint8 const* _data );
|
||||
|
||||
private:
|
||||
class AssociationCommand
|
||||
{
|
||||
public:
|
||||
AssociationCommand( uint8 const _length, uint8 const* _data );
|
||||
~AssociationCommand();
|
||||
|
||||
private:
|
||||
uint8 m_length;
|
||||
uint8* m_data;
|
||||
};
|
||||
|
||||
typedef vector<AssociationCommand> AssociationCommandVec;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Member variables
|
||||
//-----------------------------------------------------------------------------
|
||||
private:
|
||||
string m_label;
|
||||
uint32 m_homeId;
|
||||
uint8 m_nodeId;
|
||||
uint8 m_groupIdx;
|
||||
uint8 m_maxAssociations;
|
||||
bool m_auto; // If true, the controller will automatically be associated with the group
|
||||
map<uint8,AssociationCommandVec> m_associations;
|
||||
};
|
||||
|
||||
} //namespace OpenZWave
|
||||
|
||||
#endif //_Group_H
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,283 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Msg.cpp
|
||||
//
|
||||
// Represents a Z-Wave message
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "Defs.h"
|
||||
#include "Msg.h"
|
||||
#include "Node.h"
|
||||
#include "platform/Log.h"
|
||||
#include "command_classes/MultiInstance.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
uint8 Msg::s_nextCallbackId = 1;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Msg::Msg>
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
Msg::Msg
|
||||
(
|
||||
string const& _logText,
|
||||
uint8 _targetNodeId,
|
||||
uint8 const _msgType,
|
||||
uint8 const _function,
|
||||
bool const _bCallbackRequired,
|
||||
bool const _bReplyRequired, // = true
|
||||
uint8 const _expectedReply, // = 0
|
||||
uint8 const _expectedCommandClassId // = 0
|
||||
):
|
||||
m_logText( _logText ),
|
||||
m_bFinal( false ),
|
||||
m_bCallbackRequired( _bCallbackRequired ),
|
||||
m_callbackId( 0 ),
|
||||
m_expectedReply( 0 ),
|
||||
m_expectedCommandClassId( _expectedCommandClassId ),
|
||||
m_length( 4 ),
|
||||
m_targetNodeId( _targetNodeId ),
|
||||
m_sendAttempts( 0 ),
|
||||
m_maxSendAttempts( MAX_TRIES ),
|
||||
m_instance( 1 ),
|
||||
m_endPoint( 0 ),
|
||||
m_flags( 0 )
|
||||
{
|
||||
if( _bReplyRequired )
|
||||
{
|
||||
// Wait for this message before considering the transaction complete
|
||||
m_expectedReply = _expectedReply ? _expectedReply : _function;
|
||||
}
|
||||
|
||||
m_buffer[0] = SOF;
|
||||
m_buffer[1] = 0; // Length of the following data, filled in during Finalize.
|
||||
m_buffer[2] = _msgType;
|
||||
m_buffer[3] = _function;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Msg::SetInstance>
|
||||
// Used to enable wrapping with MultiInstance/MultiChannel during finalize.
|
||||
//-----------------------------------------------------------------------------
|
||||
void Msg::SetInstance
|
||||
(
|
||||
CommandClass* _cc,
|
||||
uint8 const _instance
|
||||
)
|
||||
{
|
||||
// Determine whether we should encapsulate the message in MultiInstance or MultiCommand
|
||||
if( Node* node = _cc->GetNodeUnsafe() )
|
||||
{
|
||||
MultiInstance* micc = static_cast<MultiInstance*>( node->GetCommandClass( MultiInstance::StaticGetCommandClassId() ) );
|
||||
m_instance = _instance;
|
||||
if( micc )
|
||||
{
|
||||
if( micc->GetVersion() > 1 )
|
||||
{
|
||||
m_endPoint = _cc->GetEndPoint( _instance );
|
||||
if( m_endPoint != 0 )
|
||||
{
|
||||
// Set the flag bit to indicate MultiChannel rather than MultiInstance
|
||||
m_flags |= m_MultiChannel;
|
||||
m_expectedCommandClassId = MultiInstance::StaticGetCommandClassId();
|
||||
}
|
||||
}
|
||||
else if( m_instance > 1 )
|
||||
{
|
||||
// Set the flag bit to indicate MultiInstance rather than MultiChannel
|
||||
m_flags |= m_MultiInstance;
|
||||
m_expectedCommandClassId = MultiInstance::StaticGetCommandClassId();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Msg::Append>
|
||||
// Add a byte to the message
|
||||
//-----------------------------------------------------------------------------
|
||||
void Msg::Append
|
||||
(
|
||||
uint8 const _data
|
||||
)
|
||||
{
|
||||
m_buffer[m_length++] = _data;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Msg::Finalize>
|
||||
// Fill in the length and checksum values for the message
|
||||
//-----------------------------------------------------------------------------
|
||||
void Msg::Finalize()
|
||||
{
|
||||
if( m_bFinal )
|
||||
{
|
||||
// Already finalized
|
||||
return;
|
||||
}
|
||||
|
||||
// Deal with Multi-Channel/Instance encapsulation
|
||||
if( ( m_flags & ( m_MultiChannel | m_MultiInstance ) ) != 0 )
|
||||
{
|
||||
MultiEncap();
|
||||
}
|
||||
|
||||
// Add the callback id
|
||||
if( m_bCallbackRequired )
|
||||
{
|
||||
// Set the length byte
|
||||
m_buffer[1] = m_length; // Length of following data
|
||||
|
||||
if( 0 == s_nextCallbackId )
|
||||
{
|
||||
s_nextCallbackId = 1;
|
||||
}
|
||||
|
||||
m_buffer[m_length++] = s_nextCallbackId;
|
||||
m_callbackId = s_nextCallbackId++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set the length byte
|
||||
m_buffer[1] = m_length - 1; // Length of following data
|
||||
}
|
||||
|
||||
// Calculate the checksum
|
||||
uint8 checksum = 0xff;
|
||||
for( uint32 i=1; i<m_length; ++i )
|
||||
{
|
||||
checksum ^= m_buffer[i];
|
||||
}
|
||||
m_buffer[m_length++] = checksum;
|
||||
|
||||
m_bFinal = true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Msg::UpdateCallbackId>
|
||||
// If this message has a callback ID, increment it and recalculate the checksum
|
||||
//-----------------------------------------------------------------------------
|
||||
void Msg::UpdateCallbackId()
|
||||
{
|
||||
if( m_bCallbackRequired )
|
||||
{
|
||||
// update the callback ID
|
||||
m_buffer[m_length-2] = s_nextCallbackId;
|
||||
m_callbackId = s_nextCallbackId++;
|
||||
|
||||
// Recalculate the checksum
|
||||
uint8 checksum = 0xff;
|
||||
for( int32 i=1; i<m_length-1; ++i )
|
||||
{
|
||||
checksum ^= m_buffer[i];
|
||||
}
|
||||
m_buffer[m_length-1] = checksum;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Msg::GetAsString>
|
||||
// Create a string containing the raw data
|
||||
//-----------------------------------------------------------------------------
|
||||
string Msg::GetAsString()
|
||||
{
|
||||
string str = m_logText;
|
||||
|
||||
char byteStr[16];
|
||||
if( m_targetNodeId != 0xff )
|
||||
{
|
||||
snprintf( byteStr, sizeof(byteStr), " (Node=%d)", m_targetNodeId );
|
||||
str += byteStr;
|
||||
}
|
||||
|
||||
str += ": ";
|
||||
|
||||
for( uint32 i=0; i<m_length; ++i )
|
||||
{
|
||||
if( i )
|
||||
{
|
||||
str += ", ";
|
||||
}
|
||||
|
||||
snprintf( byteStr, sizeof(byteStr), "0x%.2x", m_buffer[i] );
|
||||
str += byteStr;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Msg::MultiEncap>
|
||||
// Encapsulate the data inside a MultiInstance/Multicommand message
|
||||
//-----------------------------------------------------------------------------
|
||||
void Msg::MultiEncap
|
||||
(
|
||||
)
|
||||
{
|
||||
char str[256];
|
||||
if( m_buffer[3] != FUNC_ID_ZW_SEND_DATA )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Insert the encap header
|
||||
if( ( m_flags & m_MultiChannel ) != 0 )
|
||||
{
|
||||
// MultiChannel
|
||||
for( uint32 i=m_length-1; i>=6; --i )
|
||||
{
|
||||
m_buffer[i+4] = m_buffer[i];
|
||||
}
|
||||
|
||||
m_buffer[5] += 4;
|
||||
m_buffer[6] = MultiInstance::StaticGetCommandClassId();
|
||||
m_buffer[7] = MultiInstance::MultiChannelCmd_Encap;
|
||||
m_buffer[8] = 1;
|
||||
m_buffer[9] = m_endPoint;
|
||||
m_length += 4;
|
||||
|
||||
snprintf( str, sizeof(str), "MultiChannel Encapsulated (instance=%d): %s", m_instance, m_logText.c_str() );
|
||||
m_logText = str;
|
||||
}
|
||||
else
|
||||
{
|
||||
// MultiInstance
|
||||
for( uint32 i=m_length-1; i>=6; --i )
|
||||
{
|
||||
m_buffer[i+3] = m_buffer[i];
|
||||
}
|
||||
|
||||
m_buffer[5] += 3;
|
||||
m_buffer[6] = MultiInstance::StaticGetCommandClassId();
|
||||
m_buffer[7] = MultiInstance::MultiInstanceCmd_Encap;
|
||||
m_buffer[8] = m_instance;
|
||||
m_length += 3;
|
||||
|
||||
snprintf( str, sizeof(str), "MultiInstance Encapsulated (instance=%d): %s", m_instance, m_logText.c_str() );
|
||||
m_logText = str;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Msg.h
|
||||
//
|
||||
// Represents a Z-Wave message
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _Msg_H
|
||||
#define _Msg_H
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include "Defs.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class CommandClass;
|
||||
|
||||
/** \brief Message object to be passed to and from devices on the Z-Wave network.
|
||||
*/
|
||||
class OPENZWAVE_EXPORT Msg
|
||||
{
|
||||
public:
|
||||
enum MessageFlags
|
||||
{
|
||||
m_MultiChannel = 0x01, // Indicate MultiChannel encapsulation
|
||||
m_MultiInstance = 0x02, // Indicate MultiInstance encapsulation
|
||||
};
|
||||
|
||||
Msg( string const& _logtext, uint8 _targetNodeId, uint8 const _msgType, uint8 const _function, bool const _bCallbackRequired, bool const _bReplyRequired = true, uint8 const _expectedReply = 0, uint8 const _expectedCommandClassId = 0 );
|
||||
~Msg(){}
|
||||
|
||||
void SetInstance( CommandClass* _cc, uint8 const _instance ); // Used to enable wrapping with MultiInstance/MultiChannel during finalize.
|
||||
|
||||
void Append( uint8 const _data );
|
||||
void Finalize();
|
||||
void UpdateCallbackId();
|
||||
|
||||
/**
|
||||
* \brief Identifies the Node ID of the "target" node (if any) for this function.
|
||||
* \return Node ID of the target.
|
||||
*/
|
||||
uint8 GetTargetNodeId()const{ return m_targetNodeId; }
|
||||
|
||||
/**
|
||||
* \brief Identifies the Callback ID (if any) for this message. Callback ID is a value (OpenZWave uses sequential IDs) that
|
||||
* helps the application associate message responses with the original message request.
|
||||
* \return Callback ID for this message.
|
||||
*/
|
||||
uint8 GetCallbackId()const{ return m_callbackId; }
|
||||
|
||||
/**
|
||||
* \brief Identifies the expected reply type (if any) for this message. The expected reply is a function code...one
|
||||
* of the FUNC_ID... values defined in Defs.h. Many Z-Wave functions generate responses with the same function code
|
||||
* (for example, a FUNC_ID_ZW_GET_VERSION message generates a FUNC_ID_ZW_GET_VERSION response. But other functions
|
||||
* generate a different response. FUNC_ID_ZW_SEND_DATA triggers several responses, but ultimately, a "Get" sent with
|
||||
* this function should result in a FUNC_ID_APPLICATION_COMMAND_HANDLER response.
|
||||
* \return Expected reply (function code) for this message.
|
||||
*/
|
||||
uint8 GetExpectedReply()const{ return m_expectedReply; }
|
||||
|
||||
/**
|
||||
* \brief Identifies the expected Command Class ID (if any) for this message.
|
||||
* \return Expected command class ID for this message.
|
||||
*/
|
||||
uint8 GetExpectedCommandClassId()const{ return m_expectedCommandClassId; }
|
||||
|
||||
/**
|
||||
* \brief For messages that request a Report for a specified command class, identifies the expected Instance
|
||||
* for the variable being obtained in the report.
|
||||
* \return Expected Instance value for this message.
|
||||
*/
|
||||
uint8 GetExpectedInstance()const{ return m_instance; }
|
||||
|
||||
/**
|
||||
* \brief For messages that request a Report for a specified command class, identifies the expected Index
|
||||
* for the variable being obtained in the report.
|
||||
* \return Expected Index value for this message.
|
||||
*/
|
||||
// uint8 GetExpectedIndex()const{ return m_expectedIndex; }
|
||||
/**
|
||||
* \brief get the LogText Associated with this message
|
||||
* \return the LogText used during the constructor
|
||||
*/
|
||||
string GetLogText()const{ return m_logText; }
|
||||
|
||||
uint32 GetLength()const{ return m_length; }
|
||||
uint8* GetBuffer(){ return m_buffer; }
|
||||
string GetAsString();
|
||||
|
||||
uint8 GetSendAttempts()const{ return m_sendAttempts; }
|
||||
void SetSendAttempts( uint8 _count ){ m_sendAttempts = _count; }
|
||||
|
||||
uint8 GetMaxSendAttempts()const{ return m_maxSendAttempts; }
|
||||
void SetMaxSendAttempts( uint8 _count ){ if( _count < MAX_MAX_TRIES ) m_maxSendAttempts = _count; }
|
||||
|
||||
bool IsWakeUpNoMoreInformationCommand()
|
||||
{
|
||||
return( m_bFinal && (m_length==11) && (m_buffer[3]==0x13) && (m_buffer[6]==0x84) && (m_buffer[7]==0x08) );
|
||||
}
|
||||
bool IsNoOperation()
|
||||
{
|
||||
return( m_bFinal && (m_length==11) && (m_buffer[3]==0x13) && (m_buffer[6]==0x00) && (m_buffer[7]==0x00) );
|
||||
}
|
||||
|
||||
bool operator == ( Msg const& _other )const
|
||||
{
|
||||
if( m_bFinal && _other.m_bFinal )
|
||||
{
|
||||
// Do not include the callback Id or checksum in the comparison.
|
||||
uint8 length = m_length - (m_bCallbackRequired ? 2: 1 );
|
||||
return( !memcmp( m_buffer, _other.m_buffer, length ) );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
uint8 GetSendingCommandClass() {
|
||||
if (m_buffer[3] == 0x13) {
|
||||
return m_buffer[6];
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
void MultiEncap(); // Encapsulate the data inside a MultiInstance/Multicommand message
|
||||
|
||||
string m_logText;
|
||||
bool m_bFinal;
|
||||
bool m_bCallbackRequired;
|
||||
|
||||
uint8 m_callbackId;
|
||||
uint8 m_expectedReply;
|
||||
uint8 m_expectedCommandClassId;
|
||||
uint8 m_length;
|
||||
uint8 m_buffer[256];
|
||||
|
||||
uint8 m_targetNodeId;
|
||||
uint8 m_sendAttempts;
|
||||
uint8 m_maxSendAttempts;
|
||||
|
||||
uint8 m_instance;
|
||||
uint8 m_endPoint; // Endpoint to use if the message must be wrapped in a multiInstance or multiChannel command class
|
||||
uint8 m_flags;
|
||||
|
||||
static uint8 s_nextCallbackId; // counter to get a unique callback id
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif //_Msg_H
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,577 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Node.h
|
||||
//
|
||||
// A node in the Z-Wave network
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _Node_H
|
||||
#define _Node_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include "Defs.h"
|
||||
#include "value_classes/ValueID.h"
|
||||
#include "value_classes/ValueList.h"
|
||||
#include "Msg.h"
|
||||
#include "platform/TimeStamp.h"
|
||||
|
||||
class TiXmlElement;
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class CommandClass;
|
||||
class Driver;
|
||||
class Group;
|
||||
class ValueStore;
|
||||
class Value;
|
||||
class ValueBool;
|
||||
class ValueButton;
|
||||
class ValueByte;
|
||||
class ValueDecimal;
|
||||
class ValueInt;
|
||||
class ValueSchedule;
|
||||
class ValueShort;
|
||||
class ValueString;
|
||||
class Mutex;
|
||||
|
||||
/** \brief The Node class describes a Z-Wave node object...typically a device on the
|
||||
* Z-Wave network.
|
||||
*/
|
||||
class Node
|
||||
{
|
||||
friend class Manager;
|
||||
friend class Driver;
|
||||
friend class Group;
|
||||
friend class Value;
|
||||
friend class ValueButton;
|
||||
friend class Alarm;
|
||||
friend class Association;
|
||||
friend class AssociationCommandConfiguration;
|
||||
friend class Basic;
|
||||
friend class Battery;
|
||||
friend class ClimateControlSchedule;
|
||||
friend class Clock;
|
||||
friend class CommandClass;
|
||||
friend class ControllerReplication;
|
||||
friend class EnergyProduction;
|
||||
friend class Hail;
|
||||
friend class Indicator;
|
||||
friend class Language;
|
||||
friend class Lock;
|
||||
friend class ManufacturerSpecific;
|
||||
friend class Meter;
|
||||
friend class MeterPulse;
|
||||
friend class MultiInstance;
|
||||
friend class NodeNaming;
|
||||
friend class Protection;
|
||||
friend class Security;
|
||||
friend class SensorAlarm;
|
||||
friend class SensorBinary;
|
||||
friend class SensorMultilevel;
|
||||
friend class SwitchAll;
|
||||
friend class SwitchBinary;
|
||||
friend class SwitchMultilevel;
|
||||
friend class SwitchToggleBinary;
|
||||
friend class SwitchToggleMultilevel;
|
||||
friend class ThermostatFanMode;
|
||||
friend class ThermostatFanState;
|
||||
friend class ThermostatMode;
|
||||
friend class ThermostatOperatingState;
|
||||
friend class ThermostatSetpoint;
|
||||
friend class Version;
|
||||
friend class WakeUp;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Construction
|
||||
//-----------------------------------------------------------------------------
|
||||
public:
|
||||
/** Constructor initializes the node object, associating it with a specific
|
||||
* network (_homeId) and network node (_nodeId).
|
||||
* \param _homeId The homeId of the network to which this node is connected.
|
||||
* \param _nodeId The nodeId of this node.
|
||||
*/
|
||||
Node( uint32 const _homeId, uint8 const _nodeId );
|
||||
/** Destructor cleans up memory allocated to node and its child objects.
|
||||
*/
|
||||
virtual ~Node();
|
||||
|
||||
private:
|
||||
/** Returns a pointer to the driver (interface with a Z-Wave controller)
|
||||
* associated with this node.
|
||||
*/
|
||||
Driver* GetDriver()const;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Initialization
|
||||
//-----------------------------------------------------------------------------
|
||||
public:
|
||||
enum QueryStage
|
||||
{
|
||||
QueryStage_ProtocolInfo, /**< Retrieve protocol information */
|
||||
QueryStage_Probe, /**< Ping device to see if alive */
|
||||
QueryStage_WakeUp, /**< Start wake up process if a sleeping node */
|
||||
QueryStage_ManufacturerSpecific1, /**< Retrieve manufacturer name and product ids if ProtocolInfo lets us */
|
||||
QueryStage_NodeInfo, /**< Retrieve info about supported, controlled command classes */
|
||||
QueryStage_SecurityReport, /**< Retrive a list of Command Classes that require Security */
|
||||
QueryStage_ManufacturerSpecific2, /**< Retrieve manufacturer name and product ids */
|
||||
QueryStage_Versions, /**< Retrieve version information */
|
||||
QueryStage_Instances, /**< Retrieve information about multiple command class instances */
|
||||
QueryStage_Static, /**< Retrieve static information (doesn't change) */
|
||||
QueryStage_Probe1, /**< Ping a device upon starting with configuration */
|
||||
QueryStage_Associations, /**< Retrieve information about associations */
|
||||
QueryStage_Neighbors, /**< Retrieve node neighbor list */
|
||||
QueryStage_Session, /**< Retrieve session information (changes infrequently) */
|
||||
QueryStage_Dynamic, /**< Retrieve dynamic information (changes frequently) */
|
||||
QueryStage_Configuration, /**< Retrieve configurable parameter information (only done on request) */
|
||||
QueryStage_Complete, /**< Query process is completed for this node */
|
||||
QueryStage_None /**< Query process hasn't started for this node */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This function advances the query process (see Remarks below for more detail on the
|
||||
* process). It iterates through the various query stages enumerated in Node::QueryStage.
|
||||
*
|
||||
* \remark
|
||||
* For OpenZWave to discover everything about a node, we have to follow a certain
|
||||
* order of queries, because the results of one stage may affect what is requested
|
||||
* in the next stage. The stage is saved with the node data, so that any incomplete
|
||||
* queries can be restarted the next time the application runs.
|
||||
* <p>
|
||||
* The individual command classes also store some state information as to whether
|
||||
* they have had a response to certain queries. This state information is
|
||||
* initilized by the SetStaticRequests call in QueryStage_None. It is also saved,
|
||||
* so we do not need to request state from every command class if some have previously
|
||||
* responded.
|
||||
*/
|
||||
void AdvanceQueries();
|
||||
|
||||
/**
|
||||
* Signal that a specific query stage has been completed for this node. This will
|
||||
* only work if the query process for this node is indeed at the specified stage.
|
||||
* Otherwise, the function returns with no action.
|
||||
* \param _stage The current stage of the query process.
|
||||
*/
|
||||
void QueryStageComplete( QueryStage const _stage );
|
||||
|
||||
/**
|
||||
* Retry the specified query stage (up to _maxAttempts retries). This will
|
||||
* only work if the query process for this node is indeed at the specified stage.
|
||||
* Otherwise, the function returns with no action.
|
||||
* \param _stage The query stage to retry.
|
||||
* \param _maxAttempts
|
||||
*/
|
||||
void QueryStageRetry( QueryStage const _stage, uint8 const _maxAttempts = 0 ); // maxAttempts of zero means no limit
|
||||
|
||||
/**
|
||||
* This function sets the query stage for the node (but only to an earlier stage).
|
||||
* If a later stage is specified than the current one, it is ignored.
|
||||
* \param _stage The desired query stage.
|
||||
* \see m_queryStage, m_queryPending
|
||||
*/
|
||||
void SetQueryStage( QueryStage const _stage, bool const _advance = true );
|
||||
|
||||
/**
|
||||
* Returns the current query stage enum.
|
||||
* \return Enum value with the current query stage.
|
||||
* \see m_queryStage
|
||||
*/
|
||||
Node::QueryStage GetCurrentQueryStage() { return m_queryStage; }
|
||||
|
||||
/**
|
||||
* Returns the specified query stage string.
|
||||
* \param _stage The query stage.
|
||||
* \return Specified query stage string.
|
||||
* \see m_queryStage, m_queryPending
|
||||
*/
|
||||
string GetQueryStageName( QueryStage const _stage );
|
||||
|
||||
/**
|
||||
* Returns whether the library thinks a node is functioning properly
|
||||
* \return boolean status of node.
|
||||
*/
|
||||
bool IsNodeAlive()const{ return m_nodeAlive; }
|
||||
|
||||
/**
|
||||
* This function handles a response to the FUNC_ID_ZW_GET_NODE_PROTOCOL_INFO
|
||||
* command for this node. If protocol information has already been retrieved
|
||||
* for the node, the function simply returns. Otherwise, it populates several
|
||||
* member variables about the device at this node:
|
||||
* - m_routing (whether it is a routing node (capable of passing commands along to other nodes in the network) or not
|
||||
* - m_maxBaudRate (the maximum baud rate at which this device can communicate)
|
||||
* - m_version (TODO)
|
||||
* - m_security (whether device supports security features)
|
||||
* - m_listening (device is powered and listening constantly)
|
||||
* - m_frequentListening (device can be woken up with a beam)
|
||||
* - m_beaming (device is beam capable)
|
||||
*/
|
||||
void UpdateProtocolInfo( uint8 const* _data );
|
||||
void UpdateNodeInfo( uint8 const* _data, uint8 const _length );
|
||||
|
||||
bool ProtocolInfoReceived()const{ return m_protocolInfoReceived; }
|
||||
bool NodeInfoReceived()const{ return m_nodeInfoReceived; }
|
||||
|
||||
bool AllQueriesCompleted()const{ return( QueryStage_Complete == m_queryStage ); }
|
||||
|
||||
/**
|
||||
* Handle dead node detection tracking.
|
||||
* Use this routine to set state of nodes.
|
||||
* Tracks state as well as send notifications.
|
||||
*/
|
||||
void SetNodeAlive( bool const _isAlive );
|
||||
|
||||
private:
|
||||
void SetStaticRequests();
|
||||
|
||||
QueryStage m_queryStage;
|
||||
bool m_queryPending;
|
||||
bool m_queryConfiguration;
|
||||
uint8 m_queryRetries;
|
||||
bool m_protocolInfoReceived;
|
||||
bool m_nodeInfoReceived;
|
||||
bool m_manufacturerSpecificClassReceived;
|
||||
bool m_nodeInfoSupported;
|
||||
bool m_nodeAlive;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Capabilities
|
||||
//-----------------------------------------------------------------------------
|
||||
public:
|
||||
// Security flags
|
||||
enum
|
||||
{
|
||||
SecurityFlag_Security = 0x01,
|
||||
SecurityFlag_Controller = 0x02,
|
||||
SecurityFlag_SpecificDevice = 0x04,
|
||||
SecurityFlag_RoutingSlave = 0x08,
|
||||
SecurityFlag_BeamCapability = 0x10,
|
||||
SecurityFlag_Sensor250ms = 0x20,
|
||||
SecurityFlag_Sensor1000ms = 0x40,
|
||||
SecurityFlag_OptionalFunctionality = 0x80
|
||||
};
|
||||
|
||||
// Node Ids
|
||||
enum
|
||||
{
|
||||
NodeBroadcast = 0xff
|
||||
};
|
||||
|
||||
bool IsListeningDevice()const{ return m_listening; }
|
||||
bool IsFrequentListeningDevice()const{ return m_frequentListening; }
|
||||
bool IsBeamingDevice()const{ return m_beaming; }
|
||||
bool IsRoutingDevice()const{ return m_routing; }
|
||||
bool IsSecurityDevice()const{ return m_security; }
|
||||
uint32 GetMaxBaudRate()const{ return m_maxBaudRate; }
|
||||
uint8 GetVersion()const{ return m_version; }
|
||||
uint8 GetSecurity()const{ return m_security; }
|
||||
|
||||
uint8 GetNodeId()const{ return m_nodeId; }
|
||||
|
||||
uint8 GetBasic()const{ return m_basic; }
|
||||
uint8 GetGeneric()const{ return m_generic; }
|
||||
uint8 GetSpecific()const{ return m_specific; }
|
||||
string const& GetType()const{ return m_type; }
|
||||
uint32 GetNeighbors( uint8** o_associations );
|
||||
bool IsController()const{ return ( m_basic == 0x01 || m_basic == 0x02 ) && ( m_generic == 0x01 || m_generic == 0x02 ); }
|
||||
bool IsAddingNode() const { return m_addingNode; } /* These three *AddingNode functions are used to tell if we this node is just being discovered. Currently used by the Security CC to initiate the Network Key Exchange */
|
||||
void SetAddingNode() { m_addingNode = true; }
|
||||
void ClearAddingNode() { m_addingNode = false; }
|
||||
|
||||
private:
|
||||
bool m_listening;
|
||||
bool m_frequentListening;
|
||||
bool m_beaming;
|
||||
bool m_routing;
|
||||
uint32 m_maxBaudRate;
|
||||
uint8 m_version;
|
||||
bool m_security;
|
||||
uint32 m_homeId;
|
||||
uint8 m_nodeId;
|
||||
uint8 m_basic; //*< Basic device class (0x01-Controller, 0x02-Static Controller, 0x03-Slave, 0x04-Routing Slave
|
||||
uint8 m_generic;
|
||||
uint8 m_specific;
|
||||
string m_type; // Label representing the specific/generic/basic value
|
||||
uint8 m_neighbors[29]; // Bitmask containing the neighbouring nodes
|
||||
uint8 m_numRouteNodes; // number of node routes
|
||||
uint8 m_routeNodes[5]; // nodes to route to
|
||||
map<uint8,uint8> m_buttonMap; // Map button IDs into virtual node numbers
|
||||
bool m_addingNode;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Device Naming
|
||||
//-----------------------------------------------------------------------------
|
||||
private:
|
||||
// Manufacturer, Product and Name are stored here so they can be set by the
|
||||
// user even if the device does not support the relevant command classes.
|
||||
string GetManufacturerName()const{ return m_manufacturerName; }
|
||||
string GetProductName()const{ return m_productName; }
|
||||
string GetNodeName()const{ return m_nodeName; }
|
||||
string GetLocation()const{ return m_location; }
|
||||
|
||||
string GetManufacturerId()const{ return m_manufacturerId; }
|
||||
string GetProductType()const{ return m_productType; }
|
||||
string GetProductId()const{ return m_productId; }
|
||||
|
||||
void SetManufacturerName( string const& _manufacturerName ){ m_manufacturerName = _manufacturerName; }
|
||||
void SetProductName( string const& _productName ){ m_productName = _productName; }
|
||||
void SetNodeName( string const& _nodeName );
|
||||
void SetLocation( string const& _location );
|
||||
|
||||
void SetManufacturerId( string const& _manufacturerId ){ m_manufacturerId = _manufacturerId; }
|
||||
void SetProductType( string const& _productType ){ m_productType = _productType; }
|
||||
void SetProductId( string const& _productId ){ m_productId = _productId; }
|
||||
|
||||
string m_manufacturerName;
|
||||
string m_productName;
|
||||
string m_nodeName;
|
||||
string m_location;
|
||||
|
||||
string m_manufacturerId;
|
||||
string m_productType;
|
||||
string m_productId;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Command Classes
|
||||
//-----------------------------------------------------------------------------
|
||||
public:
|
||||
/**
|
||||
* This function retrieves a pointer to the requested command class object (if supported by this node).
|
||||
* \param _commandClassId Class ID (a single byte value) identifying the command class requested.
|
||||
* \return Pointer to the requested CommandClass object if supported, otherwise NULL.
|
||||
* \see CommandClass, m_commandClassMap
|
||||
*/
|
||||
CommandClass* GetCommandClass( uint8 const _commandClassId )const;
|
||||
void ApplicationCommandHandler( uint8 const* _data );
|
||||
|
||||
/**
|
||||
* This function sets up Secured Command Classes. It iterates over the existing command classes marking them
|
||||
* as Secured if they exist, and if they don't, it creates new Command Classes and sets them up as Secured
|
||||
* @param _data a list of Command Classes that are Secured by the Device
|
||||
* @param _length the length of the _data string
|
||||
*/
|
||||
void SetSecuredClasses( uint8 const* _data, uint8 const _length );
|
||||
|
||||
private:
|
||||
/**
|
||||
* Creates the specified command class object and adds it to the node (via the
|
||||
* m_commandClassMap) if it doesn't exist.
|
||||
* No new object is created if it already exists for this node.
|
||||
* \param _commandClassId Class ID (a single byte value) identifying the command class requested.
|
||||
* \return Pointer to the CommandClass object just added to the map (NULL if the object
|
||||
* was already there or if the CommandClass object creation failed).
|
||||
* \see CommandClass, CommandClasses::CreateCommandClass, m_commandClassMap
|
||||
*/
|
||||
CommandClass* AddCommandClass( uint8 const _commandClassId );
|
||||
/**
|
||||
* Removes a command class object from the node (via the m_commandClassMap). Before removing the
|
||||
* object, this function also removes any values stored in the object's ValueStore.
|
||||
* \param _commandClassId Class ID (a single byte value) identifying the command class to be removed.
|
||||
* \see m_commandClassMap, ValueStore, GetValueStore, ValueStore::RemoveCommandClassValues
|
||||
*/
|
||||
void RemoveCommandClass( uint8 const _commandClassId );
|
||||
void ReadXML( TiXmlElement const* _nodeElement );
|
||||
void ReadDeviceProtocolXML( TiXmlElement const* _ccsElement );
|
||||
void ReadCommandClassesXML( TiXmlElement const* _ccsElement );
|
||||
void WriteXML( TiXmlElement* _nodeElement );
|
||||
|
||||
map<uint8,CommandClass*> m_commandClassMap; /**< Map of command class ids and pointers to associated command class objects */
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Basic commands (helpers that go through the basic command class)
|
||||
//-----------------------------------------------------------------------------
|
||||
public:
|
||||
void SetLevel( uint8 const _level );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// On/Off commands (helpers that go through the basic or switchall command class)
|
||||
//-----------------------------------------------------------------------------
|
||||
public:
|
||||
void SetNodeOn();
|
||||
void SetNodeOff();
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Values (handled by the command classes)
|
||||
//-----------------------------------------------------------------------------
|
||||
public:
|
||||
ValueID CreateValueID( ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint8 const _valueIndex, ValueID::ValueType const _type );
|
||||
|
||||
Value* GetValue( ValueID const& _id );
|
||||
Value* GetValue( uint8 const _commandClassId, uint8 const _instance, uint8 const _valueIndex );
|
||||
bool RemoveValue( uint8 const _commandClassId, uint8 const _instance, uint8 const _valueIndex );
|
||||
|
||||
// Helpers for creating values
|
||||
bool CreateValueBool( ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint8 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, bool const _default, uint8 const _pollIntensity );
|
||||
bool CreateValueButton( ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint8 const _valueIndex, string const& _label, uint8 const _pollIntensity );
|
||||
bool CreateValueByte( ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint8 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, uint8 const _default, uint8 const _pollIntensity );
|
||||
bool CreateValueDecimal( ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint8 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, string const& _default, uint8 const _pollIntensity );
|
||||
bool CreateValueInt( ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint8 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, int32 const _default, uint8 const _pollIntensity );
|
||||
bool CreateValueList( ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint8 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, uint8 const _size, vector<ValueList::Item> const& _items, int32 const _default, uint8 const _pollIntensity );
|
||||
bool CreateValueRaw( ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint8 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, uint8 const* _default, uint8 const _length, uint8 const _pollIntensity );
|
||||
bool CreateValueSchedule( ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint8 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, uint8 const _pollIntensity );
|
||||
bool CreateValueShort( ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint8 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, int16 const _default, uint8 const _pollIntensity );
|
||||
bool CreateValueString( ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint8 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, string const& _default, uint8 const _pollIntensity );
|
||||
|
||||
// helpers for removing values
|
||||
void RemoveValueList( ValueList* _value );
|
||||
|
||||
void ReadValueFromXML( uint8 const _commandClassId, TiXmlElement const* _valueElement );
|
||||
bool CreateValueFromXML( uint8 const _commandClassId, TiXmlElement const* _valueElement );
|
||||
|
||||
private:
|
||||
ValueStore* GetValueStore()const{ return m_values; }
|
||||
|
||||
ValueStore* m_values; // Values reported via command classes
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Configuration Parameters (handled by the Configuration command class)
|
||||
//-----------------------------------------------------------------------------
|
||||
private:
|
||||
bool SetConfigParam( uint8 const _param, int32 _value, uint8 const _size );
|
||||
void RequestConfigParam( uint8 const _param );
|
||||
bool RequestAllConfigParams( uint32 const _requestFlags );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Dynamic Values (used by query and other command classes for updating)
|
||||
//-----------------------------------------------------------------------------
|
||||
private:
|
||||
bool RequestDynamicValues();
|
||||
//-----------------------------------------------------------------------------
|
||||
// Groups
|
||||
//-----------------------------------------------------------------------------
|
||||
private:
|
||||
// The public interface is provided via the wrappers in the Manager class
|
||||
uint8 GetNumGroups();
|
||||
uint32 GetAssociations( uint8 const _groupIdx, uint8** o_associations );
|
||||
uint8 GetMaxAssociations( uint8 const _groupIdx );
|
||||
string GetGroupLabel( uint8 const _groupIdx );
|
||||
void AddAssociation( uint8 const _groupIdx, uint8 const _targetNodeId );
|
||||
void RemoveAssociation( uint8 const _groupIdx, uint8 const _targetNodeId );
|
||||
void AutoAssociate();
|
||||
|
||||
// The following methods are not exposed
|
||||
Group* GetGroup( uint8 const _groupIdx ); // Get a pointer to a Group object. This must only be called while holding the node Lock.
|
||||
void AddGroup( Group* _group ); // The groups are fixed properties of a device, so there is no need for a matching RemoveGroup.
|
||||
void WriteGroups( TiXmlElement* _associationsElement ); // Write the group data out to XNL
|
||||
|
||||
map<uint8,Group*> m_groups; // Maps group indices to Group objects.
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Device Classes (static data read from the device_classes.xml file)
|
||||
//-----------------------------------------------------------------------------
|
||||
private:
|
||||
// Container for device class info
|
||||
class DeviceClass
|
||||
{
|
||||
public:
|
||||
DeviceClass( TiXmlElement const* _el );
|
||||
~DeviceClass(){ delete [] m_mandatoryCommandClasses; }
|
||||
|
||||
uint8 const* GetMandatoryCommandClasses(){ return m_mandatoryCommandClasses; }
|
||||
uint8 GetBasicMapping(){ return m_basicMapping; }
|
||||
string const& GetLabel(){ return m_label; }
|
||||
|
||||
private:
|
||||
uint8* m_mandatoryCommandClasses; // Zero terminated array of mandatory command classes for this device type.
|
||||
uint8 m_basicMapping; // Command class that COMMAND_CLASS_BASIC maps on to, or zero if there is no mapping.
|
||||
string m_label; // Descriptive label for the device.
|
||||
};
|
||||
|
||||
// Container for generic device class info
|
||||
class GenericDeviceClass : public DeviceClass
|
||||
{
|
||||
public:
|
||||
GenericDeviceClass( TiXmlElement const* _el );
|
||||
~GenericDeviceClass();
|
||||
|
||||
DeviceClass* GetSpecificDeviceClass( uint8 const& _specific );
|
||||
|
||||
private:
|
||||
map<uint8,DeviceClass*> m_specificDeviceClasses;
|
||||
};
|
||||
|
||||
|
||||
bool SetDeviceClasses( uint8 const _basic, uint8 const _generic, uint8 const _specific ); // Set the device class data for the node
|
||||
bool AddMandatoryCommandClasses( uint8 const* _commandClasses ); // Add mandatory command classes as specified in the device_classes.xml to the node.
|
||||
void ReadDeviceClasses(); // Read the static device class data from the device_classes.xml file
|
||||
string GetEndPointDeviceClassLabel( uint8 const _generic, uint8 const _specific );
|
||||
|
||||
static bool s_deviceClassesLoaded; // True if the xml file has alreayd been loaded
|
||||
static map<uint8,string> s_basicDeviceClasses; // Map of basic device classes.
|
||||
static map<uint8,GenericDeviceClass*> s_genericDeviceClasses; // Map of generic device classes.
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Statistics
|
||||
//-----------------------------------------------------------------------------
|
||||
public:
|
||||
struct CommandClassData
|
||||
{
|
||||
uint8 m_commandClassId;
|
||||
uint32 m_sentCnt;
|
||||
uint32 m_receivedCnt;
|
||||
};
|
||||
|
||||
struct NodeData
|
||||
{
|
||||
uint32 m_sentCnt;
|
||||
uint32 m_sentFailed;
|
||||
uint32 m_retries;
|
||||
uint32 m_receivedCnt;
|
||||
uint32 m_receivedDups;
|
||||
uint32 m_receivedUnsolicited;
|
||||
string m_sentTS;
|
||||
string m_receivedTS;
|
||||
uint32 m_lastRequestRTT;
|
||||
uint32 m_averageRequestRTT; // ms
|
||||
uint32 m_lastResponseRTT;
|
||||
uint32 m_averageResponseRTT;
|
||||
uint8 m_quality; // Node quality measure
|
||||
uint8 m_lastReceivedMessage[254];
|
||||
list<CommandClassData> m_ccData;
|
||||
};
|
||||
|
||||
private:
|
||||
void GetNodeStatistics( NodeData* _data );
|
||||
|
||||
uint32 m_sentCnt; // Number of messages sent from this node.
|
||||
uint32 m_sentFailed; // Number of sent messages failed
|
||||
uint32 m_retries; // Number of message retries
|
||||
uint32 m_receivedCnt; // Number of messages received from this node.
|
||||
uint32 m_receivedDups; // Number of duplicated messages received;
|
||||
uint32 m_receivedUnsolicited; // Number of messages received unsolicited
|
||||
uint32 m_lastRequestRTT; // Last message request RTT
|
||||
uint32 m_lastResponseRTT; // Last message response RTT
|
||||
TimeStamp m_sentTS; // Last message sent time
|
||||
TimeStamp m_receivedTS; // Last message received time
|
||||
uint32 m_averageRequestRTT; // Average Request round trip time.
|
||||
uint32 m_averageResponseRTT; // Average Reponse round trip time.
|
||||
uint8 m_quality; // Node quality measure
|
||||
uint8 m_lastReceivedMessage[254]; // Place to hold last received message
|
||||
uint8 m_errors; // Count errors for dead node detection
|
||||
};
|
||||
|
||||
} //namespace OpenZWave
|
||||
|
||||
#endif //_Node_H
|
||||
@@ -0,0 +1,195 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Notification.h
|
||||
//
|
||||
// Contains details of a Z-Wave event reported to the user
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _Notification_H
|
||||
#define _Notification_H
|
||||
|
||||
#include "Defs.h"
|
||||
#include "value_classes/ValueID.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
/** \brief Provides a container for data sent via the notification callback
|
||||
* handler installed by a call to Manager::AddWatcher.
|
||||
*
|
||||
* A notification object is only ever created or deleted internally by
|
||||
* OpenZWave.
|
||||
*/
|
||||
class OPENZWAVE_EXPORT Notification
|
||||
{
|
||||
friend class Manager;
|
||||
friend class Driver;
|
||||
friend class Node;
|
||||
friend class Group;
|
||||
friend class Value;
|
||||
friend class ValueStore;
|
||||
friend class Basic;
|
||||
friend class ManufacturerSpecific;
|
||||
friend class NodeNaming;
|
||||
friend class NoOperation;
|
||||
friend class SceneActivation;
|
||||
friend class WakeUp;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Notification types.
|
||||
* Notifications of various Z-Wave events sent to the watchers
|
||||
* registered with the Manager::AddWatcher method.
|
||||
* \see Manager::AddWatcher
|
||||
*/
|
||||
enum NotificationType
|
||||
{
|
||||
Type_ValueAdded = 0, /**< A new node value has been added to OpenZWave's list. These notifications occur after a node has been discovered, and details of its command classes have been received. Each command class may generate one or more values depending on the complexity of the item being represented. */
|
||||
Type_ValueRemoved, /**< A node value has been removed from OpenZWave's list. This only occurs when a node is removed. */
|
||||
Type_ValueChanged, /**< A node value has been updated from the Z-Wave network and it is different from the previous value. */
|
||||
Type_ValueRefreshed, /**< A node value has been updated from the Z-Wave network. */
|
||||
Type_Group, /**< The associations for the node have changed. The application should rebuild any group information it holds about the node. */
|
||||
Type_NodeNew, /**< A new node has been found (not already stored in zwcfg*.xml file) */
|
||||
Type_NodeAdded, /**< A new node has been added to OpenZWave's list. This may be due to a device being added to the Z-Wave network, or because the application is initializing itself. */
|
||||
Type_NodeRemoved, /**< A node has been removed from OpenZWave's list. This may be due to a device being removed from the Z-Wave network, or because the application is closing. */
|
||||
Type_NodeProtocolInfo, /**< Basic node information has been receievd, such as whether the node is a listening device, a routing device and its baud rate and basic, generic and specific types. It is after this notification that you can call Manager::GetNodeType to obtain a label containing the device description. */
|
||||
Type_NodeNaming, /**< One of the node names has changed (name, manufacturer, product). */
|
||||
Type_NodeEvent, /**< A node has triggered an event. This is commonly caused when a node sends a Basic_Set command to the controller. The event value is stored in the notification. */
|
||||
Type_PollingDisabled, /**< Polling of a node has been successfully turned off by a call to Manager::DisablePoll */
|
||||
Type_PollingEnabled, /**< Polling of a node has been successfully turned on by a call to Manager::EnablePoll */
|
||||
Type_SceneEvent, /**< Scene Activation Set received */
|
||||
Type_CreateButton, /**< Handheld controller button event created */
|
||||
Type_DeleteButton, /**< Handheld controller button event deleted */
|
||||
Type_ButtonOn, /**< Handheld controller button on pressed event */
|
||||
Type_ButtonOff, /**< Handheld controller button off pressed event */
|
||||
Type_DriverReady, /**< A driver for a PC Z-Wave controller has been added and is ready to use. The notification will contain the controller's Home ID, which is needed to call most of the Manager methods. */
|
||||
Type_DriverFailed, /**< Driver failed to load */
|
||||
Type_DriverReset, /**< All nodes and values for this driver have been removed. This is sent instead of potentially hundreds of individual node and value notifications. */
|
||||
Type_EssentialNodeQueriesComplete, /**< The queries on a node that are essential to its operation have been completed. The node can now handle incoming messages. */
|
||||
Type_NodeQueriesComplete, /**< All the initialisation queries on a node have been completed. */
|
||||
Type_AwakeNodesQueried, /**< All awake nodes have been queried, so client application can expected complete data for these nodes. */
|
||||
Type_AllNodesQueriedSomeDead, /**< All nodes have been queried but some dead nodes found. */
|
||||
Type_AllNodesQueried, /**< All nodes have been queried, so client application can expected complete data. */
|
||||
Type_Notification, /**< An error has occured that we need to report. */
|
||||
Type_DriverRemoved /**< The Driver is being removed. (either due to Error or by request) Do Not Call Any Driver Related Methods after recieving this call */
|
||||
};
|
||||
|
||||
/**
|
||||
* Notification codes.
|
||||
* Notifications of the type Type_Notification convey some
|
||||
* extra information defined here.
|
||||
*/
|
||||
enum NotificationCode
|
||||
{
|
||||
Code_MsgComplete = 0, /**< Completed messages */
|
||||
Code_Timeout, /**< Messages that timeout will send a Notification with this code. */
|
||||
Code_NoOperation, /**< Report on NoOperation message sent completion */
|
||||
Code_Awake, /**< Report when a sleeping node wakes up */
|
||||
Code_Sleep, /**< Report when a node goes to sleep */
|
||||
Code_Dead, /**< Report when a node is presumed dead */
|
||||
Code_Alive /**< Report when a node is revived */
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the type of this notification.
|
||||
* \return the notification type.
|
||||
* \see NotificationType
|
||||
*/
|
||||
NotificationType GetType()const{ return m_type; }
|
||||
|
||||
/**
|
||||
* Get the Home ID of the driver sending this notification.
|
||||
* \return the driver Home ID
|
||||
*/
|
||||
uint32 GetHomeId()const{ return m_valueId.GetHomeId(); }
|
||||
|
||||
/**
|
||||
* Get the ID of any node involved in this notification.
|
||||
* \return the node's ID
|
||||
*/
|
||||
uint8 GetNodeId()const{ return m_valueId.GetNodeId(); }
|
||||
|
||||
/**
|
||||
* Get the unique ValueID of any value involved in this notification.
|
||||
* \return the value's ValueID
|
||||
*/
|
||||
ValueID const& GetValueID()const{ return m_valueId; }
|
||||
|
||||
/**
|
||||
* Get the index of the association group that has been changed. Only valid in NotificationType::Type_Group notifications.
|
||||
* \return the group index.
|
||||
*/
|
||||
uint8 GetGroupIdx()const{ assert(Type_Group==m_type); return m_byte; }
|
||||
|
||||
/**
|
||||
* Get the event value of a notification. Only valid in NotificationType::Type_NodeEvent notifications.
|
||||
* \return the event value.
|
||||
*/
|
||||
uint8 GetEvent()const{ assert(Type_NodeEvent==m_type); return m_byte; }
|
||||
|
||||
/**
|
||||
* Get the button id of a notification. Only valid in NotificationType::Type_CreateButton, DeleteButton,
|
||||
* ButtonOn and ButtonOff notifications.
|
||||
* \return the button id.
|
||||
*/
|
||||
uint8 GetButtonId()const{ assert(Type_CreateButton==m_type || Type_DeleteButton==m_type || Type_ButtonOn==m_type || Type_ButtonOff==m_type); return m_byte; }
|
||||
|
||||
/**
|
||||
* Get the scene Id of a notification. Only valid in NotificationType::Type_SceneEvent notifications.
|
||||
* \return the event value.
|
||||
*/
|
||||
uint8 GetSceneId()const{ assert(Type_SceneEvent==m_type); return m_byte; }
|
||||
|
||||
/**
|
||||
* Get the notification code from a notification. Only valid for NotificationType::Type_Notification notifications.
|
||||
* \return the notification code.
|
||||
*/
|
||||
uint8 GetNotification()const{ assert(Type_Notification==m_type); return m_byte; }
|
||||
|
||||
/**
|
||||
* Helper function to simplify wrapping the notification class. Should not normally need to be called.
|
||||
* \return the internal byte value of the notification.
|
||||
*/
|
||||
uint8 GetByte()const{ return m_byte; }
|
||||
|
||||
private:
|
||||
Notification( NotificationType _type ): m_type( _type ), m_byte(0){}
|
||||
~Notification(){}
|
||||
|
||||
void SetHomeAndNodeIds( uint32 const _homeId, uint8 const _nodeId ){ m_valueId = ValueID( _homeId, _nodeId ); }
|
||||
void SetHomeNodeIdAndInstance ( uint32 const _homeId, uint8 const _nodeId, uint32 const _instance ){ m_valueId = ValueID( _homeId, _nodeId, _instance ); }
|
||||
void SetValueId( ValueID const& _valueId ){ m_valueId = _valueId; }
|
||||
void SetGroupIdx( uint8 const _groupIdx ){ assert(Type_Group==m_type); m_byte = _groupIdx; }
|
||||
void SetEvent( uint8 const _event ){ assert(Type_NodeEvent==m_type); m_byte = _event; }
|
||||
void SetSceneId( uint8 const _sceneId ){ assert(Type_SceneEvent==m_type); m_byte = _sceneId; }
|
||||
void SetButtonId( uint8 const _buttonId ){ assert(Type_CreateButton==m_type||Type_DeleteButton==m_type||Type_ButtonOn==m_type||Type_ButtonOff==m_type); m_byte = _buttonId; }
|
||||
void SetNotification( uint8 const _noteId ){ assert(Type_Notification==m_type); m_byte = _noteId; }
|
||||
|
||||
NotificationType m_type;
|
||||
ValueID m_valueId;
|
||||
uint8 m_byte;
|
||||
};
|
||||
|
||||
} //namespace OpenZWave
|
||||
|
||||
#endif //_Notification_H
|
||||
|
||||
@@ -0,0 +1,603 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Options.h
|
||||
//
|
||||
// Program options read from XML files or the command line.
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "Defs.h"
|
||||
#include "Options.h"
|
||||
#include "Utils.h"
|
||||
#include "Manager.h"
|
||||
#include "platform/Log.h"
|
||||
#include "platform/FileOps.h"
|
||||
#include "tinyxml.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
Options* Options::s_instance = NULL;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Options::Create>
|
||||
// Static method to create an Options object
|
||||
//-----------------------------------------------------------------------------
|
||||
Options* Options::Create
|
||||
(
|
||||
string const& _configPath,
|
||||
string const& _userPath,
|
||||
string const& _commandLine
|
||||
)
|
||||
{
|
||||
if( s_instance == NULL )
|
||||
{
|
||||
string configPath = _configPath;
|
||||
string userPath = _userPath;
|
||||
|
||||
// Make sure a trailing path delimiter is present
|
||||
if( configPath.size() > 0 && configPath[configPath.size() - 1] != '/' )
|
||||
{
|
||||
configPath += "/";
|
||||
}
|
||||
if( userPath.size() > 0 && userPath[userPath.size() - 1] != '/' )
|
||||
{
|
||||
userPath += "/";
|
||||
}
|
||||
|
||||
FileOps::Create();
|
||||
if( !FileOps::FolderExists( configPath ) )
|
||||
{
|
||||
Log::Create( "", false, true, LogLevel_Debug, LogLevel_Debug, LogLevel_None );
|
||||
/* Try some default directories */
|
||||
if ( FileOps::FolderExists( "config/" ) )
|
||||
{
|
||||
Log::Write( LogLevel_Error, "Cannot find a path to the configuration files at %s, Using config/ instead...", configPath.c_str() );
|
||||
configPath = "config/";
|
||||
} else if (FileOps::FolderExists("/etc/openzwave/" ) )
|
||||
{
|
||||
Log::Write( LogLevel_Error, "Cannot find a path to the configuration files at %s, Using /etc/openzwave/ instead...", configPath.c_str() );
|
||||
configPath = "/etc/openzwave/";
|
||||
#ifdef SYSCONFDIR
|
||||
} else if ( FileOps::FolderExists(SYSCONFDIR ) )
|
||||
{
|
||||
Log::Write( LogLevel_Error, "Cannot find a path to the configuration files at %s, Using %s instead...", configPath.c_str(), SYSCONFDIR);
|
||||
configPath = SYSCONFDIR;
|
||||
#endif
|
||||
} else {
|
||||
Log::Write( LogLevel_Error, "Cannot find a path to the configuration files at %s. Exiting...", configPath.c_str() );
|
||||
exit( 1 );
|
||||
}
|
||||
}
|
||||
FileOps::Destroy();
|
||||
s_instance = new Options( configPath, userPath, _commandLine );
|
||||
|
||||
// Add the default options
|
||||
s_instance->AddOptionString( "ConfigPath", configPath, false ); // Path to the OpenZWave config folder.
|
||||
s_instance->AddOptionString( "UserPath", userPath, false ); // Path to the user's data folder.
|
||||
|
||||
s_instance->AddOptionBool( "Logging", true ); // Enable logging of library activity.
|
||||
s_instance->AddOptionString( "LogFileName", "OZW_Log.txt", false ); // Name of the log file (can be changed via Log::SetLogFileName)
|
||||
s_instance->AddOptionBool( "AppendLogFile", false ); // Append new session logs to existing log file (false = overwrite)
|
||||
s_instance->AddOptionBool( "ConsoleOutput", true ); // Display log information on console (as well as save to disk)
|
||||
s_instance->AddOptionInt( "SaveLogLevel", LogLevel_Detail ); // Save (to file) log messages equal to or above LogLevel_Detail
|
||||
s_instance->AddOptionInt( "QueueLogLevel", LogLevel_Debug ); // Save (in RAM) log messages equal to or above LogLevel_Debug
|
||||
s_instance->AddOptionInt( "DumpTriggerLevel", LogLevel_None ); // Default is to never dump RAM-stored log messages
|
||||
|
||||
s_instance->AddOptionBool( "Associate", true ); // Enable automatic association of the controller with group one of every device.
|
||||
s_instance->AddOptionString( "Exclude", string(""), true ); // Remove support for the listed command classes.
|
||||
s_instance->AddOptionString( "Include", string(""), true ); // Only handle the specified command classes. The Exclude option is ignored if anything is listed here.
|
||||
s_instance->AddOptionBool( "NotifyTransactions", false ); // Notifications when transaction complete is reported.
|
||||
s_instance->AddOptionString( "Interface", string(""), true ); // Identify the serial port to be accessed (TODO: change the code so more than one serial port can be specified and HID)
|
||||
s_instance->AddOptionBool( "SaveConfiguration", true ); // Save the XML configuration upon driver close.
|
||||
s_instance->AddOptionInt( "DriverMaxAttempts", 0);
|
||||
|
||||
s_instance->AddOptionInt( "PollInterval", 30000); // 30 seconds (can easily poll 30 values in this time; ~120 values is the effective limit for 30 seconds)
|
||||
s_instance->AddOptionBool( "IntervalBetweenPolls", false ); // if false, try to execute the entire poll list within the PollInterval time frame
|
||||
// if true, wait for PollInterval milliseconds between polls
|
||||
s_instance->AddOptionBool( "SuppressValueRefresh", false ); // if true, notifications for refreshed (but unchanged) values will not be sent
|
||||
s_instance->AddOptionBool( "PerformReturnRoutes", true ); // if true, return routes will be updated
|
||||
s_instance->AddOptionString( "NetworkKey", string(""), false);
|
||||
s_instance->AddOptionBool( "RefreshAllUserCodes", false ); // if true, during startup, we refresh all the UserCodes the device reports it supports. If False, we stop after we get the first "Available" slot (Some devices have 250+ usercode slots! - That makes our Session Stage Very Long )
|
||||
s_instance->AddOptionInt( "RetryTimeout", RETRY_TIMEOUT); // How long do we wait to timeout messages sent
|
||||
s_instance->AddOptionBool( "EnableSIS", true); // Automatically become a SUC if there is no SUC on the network.
|
||||
s_instance->AddOptionBool( "AssumeAwake", true); // Assume Devices that Support the Wakeup CC are awake when we first query them....
|
||||
s_instance->AddOptionBool( "NotifyOnDriverUnload", false); // Should we send the Node/Value Notifications on Driver Unloading - Read comments in Driver::~Driver() method about possible race conditions
|
||||
}
|
||||
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Options::Destroy>
|
||||
// Static method to destroy an Options object
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Options::Destroy
|
||||
(
|
||||
)
|
||||
{
|
||||
if( Manager::Get() )
|
||||
{
|
||||
// Cannot delete Options because Manager object still exists
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
delete s_instance;
|
||||
s_instance = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Options::Options>
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
Options::Options
|
||||
(
|
||||
string const& _configPath,
|
||||
string const& _userPath,
|
||||
string const& _commandLine
|
||||
):
|
||||
m_xml ("options.xml"),
|
||||
m_commandLine( _commandLine ),
|
||||
m_SystemPath (_configPath),
|
||||
m_LocalPath (_userPath),
|
||||
m_locked( false )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Options::~Options>
|
||||
// Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
Options::~Options
|
||||
(
|
||||
)
|
||||
{
|
||||
// Clear the options map
|
||||
while( !m_options.empty() )
|
||||
{
|
||||
map<string,Option*>::iterator it = m_options.begin();
|
||||
delete it->second;
|
||||
m_options.erase( it );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Options::AddOptionBool>
|
||||
// Add a boolean option.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Options::AddOptionBool
|
||||
(
|
||||
string const& _name,
|
||||
bool const _value
|
||||
)
|
||||
{
|
||||
// get (or create) option
|
||||
Option* option = AddOption( _name );
|
||||
|
||||
if (option == NULL) return false;
|
||||
|
||||
// set unique option members
|
||||
option->m_type = Options::OptionType_Bool;
|
||||
option->m_valueBool = _value;
|
||||
|
||||
// save in m_options map
|
||||
string lowerName = ToLower( _name );
|
||||
m_options[lowerName] = option;
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Options::AddOptionInt>
|
||||
// Add an integer option.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Options::AddOptionInt
|
||||
(
|
||||
string const& _name,
|
||||
int32 const _value
|
||||
)
|
||||
{
|
||||
// get (or create) option
|
||||
Option* option = AddOption( _name );
|
||||
|
||||
if (option == NULL) return false;
|
||||
|
||||
// set unique option members
|
||||
option->m_type = Options::OptionType_Int;
|
||||
option->m_valueInt = _value;
|
||||
|
||||
// save in m_options map
|
||||
string lowerName = ToLower( _name );
|
||||
m_options[lowerName] = option;
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Options::AddOptionString>
|
||||
// Add a string option.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Options::AddOptionString
|
||||
(
|
||||
string const& _name,
|
||||
string const& _value,
|
||||
bool const _append
|
||||
)
|
||||
{
|
||||
// get (or create) option
|
||||
Option* option = AddOption( _name );
|
||||
|
||||
if (option == NULL) return false;
|
||||
|
||||
// set unique option members
|
||||
option->m_type = Options::OptionType_String;
|
||||
option->m_valueString = _value;
|
||||
option->m_append = _append;
|
||||
|
||||
// save in m_options map
|
||||
string lowerName = ToLower( _name );
|
||||
m_options[lowerName] = option;
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Options::GetOptionAsBool>
|
||||
// Get the value of a boolean option.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Options::GetOptionAsBool
|
||||
(
|
||||
string const& _name,
|
||||
bool* o_value
|
||||
)
|
||||
{
|
||||
Option* option = Find( _name );
|
||||
if( o_value && option && ( OptionType_Bool == option->m_type ) )
|
||||
{
|
||||
*o_value = option->m_valueBool;
|
||||
return true;
|
||||
}
|
||||
|
||||
Log::Write( LogLevel_Warning, "Specified option [%s] was not found.", _name.c_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Options::GetOptionAsInt>
|
||||
// Get the value of an integer option.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Options::GetOptionAsInt
|
||||
(
|
||||
string const& _name,
|
||||
int32* o_value
|
||||
)
|
||||
{
|
||||
Option* option = Find( _name );
|
||||
if( o_value && option && ( OptionType_Int == option->m_type ) )
|
||||
{
|
||||
*o_value = option->m_valueInt;
|
||||
return true;
|
||||
}
|
||||
|
||||
Log::Write( LogLevel_Warning, "Specified option [%s] was not found.", _name.c_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Options::GetOptionAsString>
|
||||
// Get the value of a string option.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Options::GetOptionAsString
|
||||
(
|
||||
string const& _name,
|
||||
string* o_value
|
||||
)
|
||||
{
|
||||
Option* option = Find( _name );
|
||||
if( o_value && option && ( OptionType_String == option->m_type ) )
|
||||
{
|
||||
*o_value = option->m_valueString;
|
||||
return true;
|
||||
}
|
||||
|
||||
Log::Write( LogLevel_Warning, "Specified option [%s] was not found.", _name.c_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Options::GetOptionType>
|
||||
// Get the type of value stored in an option.
|
||||
//-----------------------------------------------------------------------------
|
||||
Options::OptionType Options::GetOptionType
|
||||
(
|
||||
string const& _name
|
||||
)
|
||||
{
|
||||
Option* option = Find( _name );
|
||||
if( option )
|
||||
{
|
||||
return option->m_type;
|
||||
}
|
||||
|
||||
// Option not found
|
||||
Log::Write( LogLevel_Warning, "Specified option [%s] was not found.", _name.c_str() );
|
||||
return OptionType_Invalid;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Options::Lock>
|
||||
// Read all the option XMLs and Command Lines, and lock their values.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Options::Lock
|
||||
(
|
||||
)
|
||||
{
|
||||
if( m_locked )
|
||||
{
|
||||
Log::Write( LogLevel_Error, "Options are already final (locked)." );
|
||||
return false;
|
||||
}
|
||||
|
||||
ParseOptionsXML( m_SystemPath + m_xml );
|
||||
ParseOptionsXML( m_LocalPath + m_xml);
|
||||
ParseOptionsString( m_commandLine );
|
||||
m_locked = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Options::ParseOptionsString>
|
||||
// Parse a string containing program options, such as a command line
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Options::ParseOptionsString
|
||||
(
|
||||
string const& _commandLine
|
||||
)
|
||||
{
|
||||
bool res = true;
|
||||
|
||||
size_t pos = 0;
|
||||
size_t start = 0;
|
||||
while( 1 )
|
||||
{
|
||||
// find start of first option name
|
||||
pos = _commandLine.find_first_of( "--", start );
|
||||
if( string::npos == pos )
|
||||
{
|
||||
break;
|
||||
}
|
||||
start = pos + 2;
|
||||
|
||||
// found an option. Get the name.
|
||||
string optionName;
|
||||
pos = _commandLine.find( " ", start );
|
||||
if( string::npos == pos )
|
||||
{
|
||||
optionName = _commandLine.substr( start );
|
||||
start = pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
optionName = _commandLine.substr( start, pos-start );
|
||||
start = pos + 1;
|
||||
}
|
||||
|
||||
// Find the matching option object
|
||||
Option* option = Find( optionName );
|
||||
if( option )
|
||||
{
|
||||
// Read the values
|
||||
int numValues = 0;
|
||||
bool parsing = true;
|
||||
while( parsing )
|
||||
{
|
||||
string value;
|
||||
size_t back = start;
|
||||
pos = _commandLine.find( " ", start );
|
||||
if( string::npos == pos )
|
||||
{
|
||||
// Last value in string
|
||||
value = _commandLine.substr( start );
|
||||
parsing = false;
|
||||
start = pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = _commandLine.substr( start, pos-start );
|
||||
start = pos+1;
|
||||
}
|
||||
|
||||
if( !value.compare( 0, 2, "--" ) )
|
||||
{
|
||||
// Value is actually the next option.
|
||||
if( !numValues )
|
||||
{
|
||||
// No values were read for this option
|
||||
// This is ok only for bool options, where we assume no value means "true".
|
||||
if( OptionType_Bool == option->m_type )
|
||||
{
|
||||
option->m_valueBool = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = false;
|
||||
}
|
||||
}
|
||||
start = back; // back up to the beginning of the next option
|
||||
break;
|
||||
}
|
||||
else if( value.size() > 0 )
|
||||
{
|
||||
// Set the value
|
||||
option->SetValueFromString( value );
|
||||
numValues++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Options::ParseOptionsXML>
|
||||
// Parse an XML file containing program options
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Options::ParseOptionsXML
|
||||
(
|
||||
string const& _filename
|
||||
)
|
||||
{
|
||||
TiXmlDocument doc;
|
||||
if( !doc.LoadFile( _filename.c_str(), TIXML_ENCODING_UTF8 ) )
|
||||
{
|
||||
Log::Write(LogLevel_Warning, "Failed to Parse %s: %s", _filename.c_str(), doc.ErrorDesc());
|
||||
return false;
|
||||
}
|
||||
Log::Write(LogLevel_Info, "Reading %s for Options", _filename.c_str());
|
||||
|
||||
TiXmlElement const* optionsElement = doc.RootElement();
|
||||
|
||||
// Read the options
|
||||
TiXmlElement const* optionElement = optionsElement->FirstChildElement();
|
||||
while( optionElement )
|
||||
{
|
||||
char const* str = optionElement->Value();
|
||||
if( str && !strcmp( str, "Option" ) )
|
||||
{
|
||||
char const* name = optionElement->Attribute( "name" );
|
||||
if( name )
|
||||
{
|
||||
Option* option = Find( name );
|
||||
if( option )
|
||||
{
|
||||
char const* value = optionElement->Attribute( "value" );
|
||||
if( value )
|
||||
{
|
||||
// Set the value
|
||||
option->SetValueFromString( value );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
optionElement = optionElement->NextSiblingElement();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Options::AddOption>
|
||||
// General setup for adding a specific option
|
||||
//-----------------------------------------------------------------------------
|
||||
Options::Option* Options::AddOption
|
||||
(
|
||||
string const& _name
|
||||
)
|
||||
{
|
||||
if( m_locked )
|
||||
{
|
||||
Log::Write( LogLevel_Error, "Options have been locked. No more may be added." );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// get a pointer to the option (and create a new Option if it doesn't already exist)
|
||||
Option* option = Find( _name );
|
||||
if( option == NULL )
|
||||
{
|
||||
option = new Option( _name );
|
||||
}
|
||||
|
||||
return option;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Options::Find>
|
||||
// Find an option by name
|
||||
//-----------------------------------------------------------------------------
|
||||
Options::Option* Options::Find
|
||||
(
|
||||
string const& _name
|
||||
)
|
||||
{
|
||||
string lowername = ToLower( _name );
|
||||
map<string,Option*>::iterator it = m_options.find( lowername );
|
||||
if( it != m_options.end() )
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Options::Option::SetValueFromString>
|
||||
// Find an option by name
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Options::Option::SetValueFromString
|
||||
(
|
||||
string const& _value
|
||||
)
|
||||
{
|
||||
if( OptionType_Bool == m_type )
|
||||
{
|
||||
string lowerValue = ToLower( _value );
|
||||
if( ( lowerValue == "true" ) || ( lowerValue == "1" ) )
|
||||
{
|
||||
m_valueBool = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if( ( lowerValue == "false" ) || ( lowerValue == "0" ) )
|
||||
{
|
||||
m_valueBool = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( OptionType_Int == m_type )
|
||||
{
|
||||
m_valueInt = (int32)atol( _value.c_str() );
|
||||
return true;
|
||||
}
|
||||
|
||||
if( OptionType_String == m_type )
|
||||
{
|
||||
if( m_append && ( m_valueString.size() > 0 ) )
|
||||
{
|
||||
m_valueString += ( string(",") + _value );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_valueString = _value;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Options.h
|
||||
//
|
||||
// Program options read from XML files or the command line.
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _Options_H
|
||||
#define _Options_H
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
|
||||
#include "Defs.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
/** \brief Manages library options read from XML files or the command line.
|
||||
*
|
||||
* A class that manages program options read from XML files or the command line.
|
||||
* The OpenZWave Manager class requires a complete and locked Options
|
||||
* object when created. The Options are therefore one of the first things that
|
||||
* any OpenZWave application must deal with.
|
||||
* Options are first read from an XML file called options.xml located in the
|
||||
* User data folder (the path to which is supplied to the Options::Create method).
|
||||
* This is the same folder that will be used by the Manager to save the state of
|
||||
* each controller in the Z-Wave network, to avoid querying them for their entire
|
||||
* state every time the application starts up.
|
||||
* The second source of program options is a string, which will normally be the
|
||||
* command line used to launch the application.
|
||||
* In this way, common options can be specified in the XML, but over-ridden if
|
||||
* necessary by the command line.
|
||||
* The Options process is as follows:
|
||||
* 1) Create an Options object, providing paths to the OpenZWave config folder,
|
||||
* the User data folder and any command line string containing program options.
|
||||
* 2) Call Options::AddOptionBool, Options::AddOptionInt or Options::AddOptionString
|
||||
* to add any application-specific configurable options. In this way, the Options
|
||||
* class can be used for non-OpenZWave options as well. (OpenZWave options must
|
||||
* be specified in step #1 above (either via xml file or a command line string).
|
||||
* 3) Call Options::Lock. This will cause the option values to be read from
|
||||
* the options.xml file and the command line string, and will lock the options
|
||||
* so that no more calls aside from GetOptionAs may be made.
|
||||
* 4) Create the OpenZWave Manager object.
|
||||
*/
|
||||
class OPENZWAVE_EXPORT Options
|
||||
{
|
||||
public:
|
||||
enum OptionType
|
||||
{
|
||||
OptionType_Invalid = 0,
|
||||
OptionType_Bool,
|
||||
OptionType_Int,
|
||||
OptionType_String
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an object to manage the program options.
|
||||
* \param _configPath a string containing the path to the OpenZWave library config
|
||||
* folder, which contains XML descriptions of Z-Wave manufacturers and products.
|
||||
* \param _userPath a string containing the path to the application's user data
|
||||
* folder where the OpenZWave should store the Z-Wave network configuration and state.
|
||||
* The _userPath is also the folder where OpenZWave will look for the file Options.xml
|
||||
* which contains program option values. The file should be in the form outlined below,
|
||||
* with one or more Option elements containing a name and value attribute. Multiple
|
||||
* values with the same option name should be listed separately. Note that option names
|
||||
* are case insensitive.
|
||||
* \code
|
||||
* <?xml version="1.0" encoding="utf-8"?>
|
||||
* <Options>
|
||||
* <Option name="logging" value="true" />
|
||||
* <Option name="ignore" value="COMMAND_CLASS_BASIC" />
|
||||
* <Option name="ignore" value="COMMAND_CLASS_VERSION" />
|
||||
* </Options>
|
||||
* \endcode
|
||||
* \param _commandLine a string containing the program's command line options.
|
||||
* Command line options are parsed after the options.xml file, and so take precedence.
|
||||
* Options are identified by a leading -- (two minus signs). The following items
|
||||
* in the string are treated as values for this option, until the next -- is
|
||||
* reached. For boolean options only, it is possible to omit the value, in which case
|
||||
* the value is assumed to be "true". Note that option names are case insensitive, and
|
||||
* that option values should be separated by a space.
|
||||
* \return Pointer to the newly created Options object.
|
||||
* \see Get, Destroy, AddOption, GetOptionAs, Lock
|
||||
*/
|
||||
static Options* Create( string const& _configPath, string const& _userPath, string const& _commandLine );
|
||||
|
||||
/**
|
||||
* Deletes the Options and cleans up any associated objects.
|
||||
* The application is responsible for destroying the Options object,
|
||||
* but this must not be done until after the Manager object has been
|
||||
* destroyed.
|
||||
* \param _options Pointer to the Options object to be destroyed.
|
||||
* \return true if the Options object was destroyed. If the manager
|
||||
* object still exists, this call will return false.
|
||||
* \see Create, Get
|
||||
*/
|
||||
static bool Destroy();
|
||||
|
||||
/**
|
||||
* Gets a pointer to the Options singleton object.
|
||||
* \return a pointer to the Options singleton object.
|
||||
* \see Create, Destroy
|
||||
*/
|
||||
static Options* Get(){ return s_instance; }
|
||||
|
||||
/**
|
||||
* Locks the options.
|
||||
* Reads in option values from the XML options file and command line string and
|
||||
* marks the options as locked. Once locked, no more calls to AddOption
|
||||
* can be made.
|
||||
* The options must be locked before the Manager::Create method is called.
|
||||
* \see AddOption
|
||||
*/
|
||||
bool Lock();
|
||||
|
||||
/**
|
||||
* Add a boolean option to the program.
|
||||
* Adds an option to the program whose value can then be read from a file or command line.
|
||||
* All calls to AddOptionInt must be made before Lock.
|
||||
* \param _name the name of the option. Option names are case insensitive and must be unique.
|
||||
* \param _default the default value for this option.
|
||||
* \see GetOptionAsBool
|
||||
*/
|
||||
bool AddOptionBool( string const& _name, bool const _default );
|
||||
|
||||
/**
|
||||
* Add an integer option to the program.
|
||||
* Adds an option to the program whose value can then be read from a file or command line.
|
||||
* All calls to AddOptionInt must be made before Lock.
|
||||
* \param _name the name of the option. Option names are case insensitive and must be unique.
|
||||
* \param _default the default value for this option.
|
||||
* \see GetOptionAsInt
|
||||
*/
|
||||
bool AddOptionInt( string const& _name, int32 const _default );
|
||||
|
||||
/**
|
||||
* Add a string option to the program.
|
||||
* Adds an option to the program whose value can then be read from a file or command line.
|
||||
* All calls to AddOptionString must be made before Lock.
|
||||
* \param _name the name of the option. Option names are case insensitive and must be unique.
|
||||
* \param _default the default value for this option.
|
||||
* \param _append Setting append to true will cause values read from the command line
|
||||
* or XML file to be concatenated into a comma delimited list. If _append is false,
|
||||
* newer values will overwrite older ones.
|
||||
* \see GetOptionAsString
|
||||
*/
|
||||
bool AddOptionString( string const& _name, string const& _default, bool const _append );
|
||||
|
||||
/**
|
||||
* Get the value of a boolean option.
|
||||
* \param _name the name of the option. Option names are case insensitive.
|
||||
* \param o_value a pointer to the item that will be filled with the option value.
|
||||
* \return true if the option value was fetched successfully, false if the
|
||||
* option does not exist, or does not contain a boolean value
|
||||
* \see AddOptionBool, GetOptionType
|
||||
*/
|
||||
bool GetOptionAsBool( string const& _name, bool* o_value );
|
||||
|
||||
/**
|
||||
* Get the value of an integer option.
|
||||
* \param _name the name of the option. Option names are case insensitive.
|
||||
* \param o_value a pointer to the item that will be filled with the option value.
|
||||
* \return true if the option value was fetched successfully, false if the
|
||||
* option does not exist, or does not contain an integer value
|
||||
* \see AddOptionInt, GetOptionType
|
||||
*/
|
||||
bool GetOptionAsInt( string const& _name, int32* o_value );
|
||||
|
||||
/**
|
||||
* Get the value of a string option.
|
||||
* \param _name the name of the option. Option names are case insensitive.
|
||||
* \param o_value a pointer to the item that will be filled with the option value.
|
||||
* \return true if the option value was fetched successfully, false if the
|
||||
* option does not exist, or does not contain a string value
|
||||
* \see AddOptionString, GetOptionType
|
||||
*/
|
||||
bool GetOptionAsString( string const& _name, string* o_value );
|
||||
|
||||
/**
|
||||
* Get the type of value stored in an option.
|
||||
* \param _name the name of the option. Option names are case insensitive.
|
||||
* \return An enum value representing the type of the option value. If the
|
||||
* option does not exist, OptionType_Invalid is returned.
|
||||
* \see GetOptionAsBool, GetOptionAsInt, GetOptionAsString
|
||||
*/
|
||||
OptionType GetOptionType( string const& _name );
|
||||
|
||||
/**
|
||||
* Test whether the options have been locked.
|
||||
* \return true if the options have been locked.
|
||||
* \see Lock
|
||||
*/
|
||||
bool AreLocked()const{ return m_locked; }
|
||||
|
||||
|
||||
private:
|
||||
class Option
|
||||
{
|
||||
friend class Options;
|
||||
|
||||
public:
|
||||
Option( string const& _name ): m_name( _name ), m_append( false ){}
|
||||
bool SetValueFromString( string const& _value );
|
||||
|
||||
Options::OptionType m_type;
|
||||
string m_name;
|
||||
bool m_valueBool;
|
||||
int32 m_valueInt;
|
||||
string m_valueString;
|
||||
bool m_append;
|
||||
};
|
||||
|
||||
Options( string const& _configPath, string const& _userPath, string const& _commandLine ); // Constructor, to be called only via the static Create method.
|
||||
~Options(); // Destructor, to be called only via the static Destroy method.
|
||||
|
||||
bool ParseOptionsString( string const& _options ); // Parse a string containing program options, such as a command line.
|
||||
bool ParseOptionsXML( string const& _filename ); // Parse an XML file containing program options.
|
||||
Option* AddOption( string const& _name ); // check lock and create (or open existing) option
|
||||
Option* Find( string const& _name );
|
||||
|
||||
OPENZWAVE_EXPORT_WARNINGS_OFF
|
||||
map<string,Option*> m_options; // Map of option names to values.
|
||||
OPENZWAVE_EXPORT_WARNINGS_ON
|
||||
string m_xml; // Path to XML options file.
|
||||
string m_commandLine; // String containing command line options.
|
||||
string m_SystemPath;
|
||||
string m_LocalPath;
|
||||
bool m_locked; // If true, the options are final and AddOption can no longer be called.
|
||||
static Options* s_instance;
|
||||
};
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif // _Options_H
|
||||
@@ -0,0 +1,481 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Scene.cpp
|
||||
//
|
||||
// A collection of ValueIDs to be used together.
|
||||
//
|
||||
// Copyright (c) 2011 Greg Satz <satz@iranger.com>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <cstring>
|
||||
#include "Manager.h"
|
||||
#include "platform/Log.h"
|
||||
#include "value_classes/Value.h"
|
||||
#include "value_classes/ValueID.h"
|
||||
#include "Scene.h"
|
||||
#include "Options.h"
|
||||
|
||||
#include "tinyxml.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
uint32 const c_sceneVersion = 1;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Statics
|
||||
//-----------------------------------------------------------------------------
|
||||
uint8 Scene::s_sceneCnt = 0;
|
||||
Scene* Scene::s_scenes[256] = { 0 };
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Scene::Scene>
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
Scene::Scene
|
||||
(
|
||||
uint8 const _sceneId
|
||||
):
|
||||
m_sceneId( _sceneId ),
|
||||
m_label( "" )
|
||||
{
|
||||
s_scenes[_sceneId] = this;
|
||||
s_sceneCnt++;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Scene::~Scene>
|
||||
// Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
Scene::~Scene
|
||||
(
|
||||
)
|
||||
{
|
||||
while( !m_values.empty() )
|
||||
{
|
||||
SceneStorage* ss = m_values.back();
|
||||
m_values.pop_back();
|
||||
delete ss;
|
||||
}
|
||||
|
||||
s_sceneCnt--;
|
||||
s_scenes[m_sceneId] = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Scene::WriteXML>
|
||||
// Write ourselves to an XML document
|
||||
//-----------------------------------------------------------------------------
|
||||
void Scene::WriteXML
|
||||
(
|
||||
string const& _name
|
||||
)
|
||||
{
|
||||
char str[16];
|
||||
|
||||
// Create a new XML document to contain the driver configuration
|
||||
TiXmlDocument doc;
|
||||
TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "utf-8", "" );
|
||||
TiXmlElement* scenesElement = new TiXmlElement( "Scenes" );
|
||||
doc.LinkEndChild( decl );
|
||||
doc.LinkEndChild( scenesElement );
|
||||
|
||||
scenesElement->SetAttribute( "xmlns", "http://code.google.com/p/open-zwave/" );
|
||||
|
||||
snprintf( str, sizeof(str), "%d", c_sceneVersion );
|
||||
scenesElement->SetAttribute( "version", str);
|
||||
|
||||
for( int i = 1; i < 256; i++ )
|
||||
{
|
||||
if( s_scenes[i] == NULL )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
TiXmlElement* sceneElement = new TiXmlElement( "Scene" );
|
||||
|
||||
snprintf( str, sizeof(str), "%d", i );
|
||||
sceneElement->SetAttribute( "id", str );
|
||||
sceneElement->SetAttribute( "label", s_scenes[i]->m_label.c_str() );
|
||||
|
||||
for( vector<SceneStorage*>::iterator vt = s_scenes[i]->m_values.begin(); vt != s_scenes[i]->m_values.end(); ++vt )
|
||||
{
|
||||
TiXmlElement* valueElement = new TiXmlElement( "Value" );
|
||||
|
||||
snprintf( str, sizeof(str), "0x%.8x", (*vt)->m_id.GetHomeId() );
|
||||
valueElement->SetAttribute( "homeId", str );
|
||||
|
||||
snprintf( str, sizeof(str), "%d", (*vt)->m_id.GetNodeId() );
|
||||
valueElement->SetAttribute( "nodeId", str );
|
||||
|
||||
valueElement->SetAttribute( "genre", Value::GetGenreNameFromEnum((*vt)->m_id.GetGenre()) );
|
||||
|
||||
snprintf( str, sizeof(str), "%d", (*vt)->m_id.GetCommandClassId() );
|
||||
valueElement->SetAttribute( "commandClassId", str );
|
||||
|
||||
snprintf( str, sizeof(str), "%d", (*vt)->m_id.GetInstance() );
|
||||
valueElement->SetAttribute( "instance", str );
|
||||
|
||||
snprintf( str, sizeof(str), "%d", (*vt)->m_id.GetIndex() );
|
||||
valueElement->SetAttribute( "index", str );
|
||||
|
||||
valueElement->SetAttribute( "type", Value::GetTypeNameFromEnum((*vt)->m_id.GetType()) );
|
||||
|
||||
TiXmlText* textElement = new TiXmlText( (*vt)->m_value.c_str() );
|
||||
valueElement->LinkEndChild( textElement );
|
||||
|
||||
sceneElement->LinkEndChild( valueElement );
|
||||
}
|
||||
|
||||
scenesElement->LinkEndChild( sceneElement );
|
||||
}
|
||||
|
||||
string userPath;
|
||||
Options::Get()->GetOptionAsString( "UserPath", &userPath );
|
||||
|
||||
string filename = userPath + _name;
|
||||
|
||||
doc.SaveFile( filename.c_str() );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Scene::ReadScene>
|
||||
// Read scene configuration from an XML document
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Scene::ReadScenes
|
||||
(
|
||||
)
|
||||
{
|
||||
int32 intVal;
|
||||
char const* str;
|
||||
|
||||
// Load the XML document that contains the driver configuration
|
||||
string userPath;
|
||||
Options::Get()->GetOptionAsString( "UserPath", &userPath );
|
||||
|
||||
string filename = userPath + "zwscene.xml";
|
||||
|
||||
TiXmlDocument doc;
|
||||
if( !doc.LoadFile( filename.c_str(), TIXML_ENCODING_UTF8 ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TiXmlElement const* scenesElement = doc.RootElement();
|
||||
|
||||
// Version
|
||||
if( TIXML_SUCCESS == scenesElement->QueryIntAttribute( "version", &intVal ) )
|
||||
{
|
||||
if( (uint32)intVal != c_sceneVersion )
|
||||
{
|
||||
Log::Write( LogLevel_Alert, "Driver::ReadScenes - %s is from an older version of OpenZWave and cannot be loaded.", filename.c_str() );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Write( LogLevel_Alert, "Driver::ReadScenes - %s is from an older version of OpenZWave and cannot be loaded.", filename.c_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
TiXmlElement const* sceneElement = scenesElement->FirstChildElement();
|
||||
while( sceneElement )
|
||||
{
|
||||
Scene* scene = NULL;
|
||||
|
||||
if( TIXML_SUCCESS == sceneElement->QueryIntAttribute( "id", &intVal ) )
|
||||
{
|
||||
scene = new Scene( (uint8)intVal );
|
||||
}
|
||||
|
||||
if( scene == NULL )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
str = sceneElement->Attribute( "label" );
|
||||
if( str )
|
||||
{
|
||||
scene->m_label = str;
|
||||
}
|
||||
|
||||
// Read the ValueId for this scene
|
||||
TiXmlElement const* valueElement = sceneElement->FirstChildElement();
|
||||
while( valueElement )
|
||||
{
|
||||
char const* elementName = valueElement->Value();
|
||||
if( elementName && !strcmp( elementName, "Value" ) )
|
||||
{
|
||||
uint32 homeId = 0;
|
||||
str = valueElement->Attribute( "homeId" );
|
||||
if( str )
|
||||
{
|
||||
char *p;
|
||||
homeId = (uint32)strtol( str, &p, 0 );
|
||||
}
|
||||
uint8 nodeId = 0;
|
||||
if (TIXML_SUCCESS == valueElement->QueryIntAttribute( "nodeId", &intVal ) )
|
||||
{
|
||||
nodeId = intVal;
|
||||
}
|
||||
ValueID::ValueGenre genre = Value::GetGenreEnumFromName( valueElement->Attribute( "genre" ) );
|
||||
uint8 commandClassId = 0;
|
||||
if (TIXML_SUCCESS == valueElement->QueryIntAttribute( "commandClassId", &intVal ) )
|
||||
{
|
||||
commandClassId = intVal;
|
||||
}
|
||||
uint8 instance = 0;
|
||||
if (TIXML_SUCCESS == valueElement->QueryIntAttribute( "instance", &intVal ) )
|
||||
{
|
||||
instance = intVal;
|
||||
}
|
||||
uint8 index = 0;
|
||||
if (TIXML_SUCCESS == valueElement->QueryIntAttribute( "index", &intVal ) )
|
||||
{
|
||||
index = intVal;
|
||||
}
|
||||
ValueID::ValueType type = Value::GetTypeEnumFromName( valueElement->Attribute( "type" ) );
|
||||
char const* data = valueElement->GetText();
|
||||
|
||||
scene->m_values.push_back( new SceneStorage( ValueID(homeId, nodeId, genre, commandClassId, instance, index, type), data ) );
|
||||
}
|
||||
|
||||
valueElement = valueElement->NextSiblingElement();
|
||||
}
|
||||
sceneElement = sceneElement->NextSiblingElement();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Scene::Get>
|
||||
// Return the Scene object given the Scene Id
|
||||
//-----------------------------------------------------------------------------
|
||||
Scene* Scene::Get
|
||||
(
|
||||
uint8 const _sceneId
|
||||
)
|
||||
{
|
||||
if ( s_scenes[_sceneId] != NULL )
|
||||
{
|
||||
return s_scenes[_sceneId];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Scene::GetAllScenes>
|
||||
// Return an array of uint8 of used Scene IDs and the count
|
||||
//-----------------------------------------------------------------------------
|
||||
uint8 Scene::GetAllScenes
|
||||
(
|
||||
uint8** _sceneIds
|
||||
)
|
||||
{
|
||||
if( s_sceneCnt > 0 )
|
||||
{
|
||||
*_sceneIds = new uint8[s_sceneCnt];
|
||||
int j = 0;
|
||||
for( int i = 1; i < 256; i++ )
|
||||
{
|
||||
if (s_scenes[i] != NULL)
|
||||
{
|
||||
(*_sceneIds)[j++] = s_scenes[i]->m_sceneId;
|
||||
}
|
||||
}
|
||||
}
|
||||
return s_sceneCnt;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Scene::AddValue>
|
||||
// Add a ValueID and a string to the scene.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Scene::AddValue
|
||||
(
|
||||
ValueID const& _valueId,
|
||||
string const& _value
|
||||
)
|
||||
{
|
||||
m_values.push_back( new SceneStorage( _valueId, _value ) );
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Scene::RemoveValue>
|
||||
// Remove the first ValueID found
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Scene::RemoveValue
|
||||
(
|
||||
ValueID const& _valueId
|
||||
)
|
||||
{
|
||||
for( vector<SceneStorage*>::iterator it = m_values.begin(); it != m_values.end(); ++it )
|
||||
{
|
||||
if( (*it)->m_id == _valueId )
|
||||
{
|
||||
delete *it;
|
||||
m_values.erase( it );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Scene::RemoveValues>
|
||||
// Remove all ValueIDs from given Home ID
|
||||
//-----------------------------------------------------------------------------
|
||||
void Scene::RemoveValues
|
||||
(
|
||||
uint32 const _homeId
|
||||
)
|
||||
{
|
||||
again:
|
||||
for( vector<SceneStorage*>::iterator it = m_values.begin(); it != m_values.end(); ++it )
|
||||
{
|
||||
if( (*it)->m_id.GetHomeId() == _homeId )
|
||||
{
|
||||
delete *it;
|
||||
m_values.erase( it );
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
// If the scene is now empty, delete it.
|
||||
if( m_values.empty() )
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Scene::RemoveValues>
|
||||
// Remove all ValueIDs from given Home ID and node ID
|
||||
//-----------------------------------------------------------------------------
|
||||
void Scene::RemoveValues
|
||||
(
|
||||
uint32 const _homeId,
|
||||
uint8 const _nodeId
|
||||
)
|
||||
{
|
||||
for( int i = 1; i < 256; i++ )
|
||||
{
|
||||
Scene *scene = Scene::Get( i );
|
||||
if( scene != NULL )
|
||||
{
|
||||
again:
|
||||
for( vector<SceneStorage*>::iterator it = scene->m_values.begin(); it != scene->m_values.end(); ++it )
|
||||
{
|
||||
if( (*it)->m_id.GetHomeId() == _homeId && (*it)->m_id.GetNodeId() == _nodeId )
|
||||
{
|
||||
delete *it;
|
||||
scene->m_values.erase( it );
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
// If the scene is now empty, delete it.
|
||||
if( scene->m_values.empty() )
|
||||
{
|
||||
delete scene;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Scene::GetValues>
|
||||
// Return all ValueIDs for the given scene.
|
||||
//-----------------------------------------------------------------------------
|
||||
int Scene::GetValues
|
||||
(
|
||||
vector<ValueID>* o_value
|
||||
)
|
||||
{
|
||||
int size = (int) m_values.size();
|
||||
if( size > 0 )
|
||||
{
|
||||
for( vector<SceneStorage*>::iterator it = m_values.begin(); it != m_values.end(); ++it )
|
||||
{
|
||||
o_value->push_back( (*it)->m_id );
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Scene::GetValue>
|
||||
// Return a ValueID's value as string
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Scene::GetValue
|
||||
(
|
||||
ValueID const& _valueId,
|
||||
string* o_value
|
||||
)
|
||||
{
|
||||
for( vector<SceneStorage*>::iterator it = m_values.begin(); it != m_values.end(); ++it )
|
||||
{
|
||||
if( (*it)->m_id == _valueId )
|
||||
{
|
||||
*o_value = (*it)->m_value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Scene::SetValue>
|
||||
// Set a ValueID's value as string
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Scene::SetValue
|
||||
(
|
||||
ValueID const& _valueId,
|
||||
string const& _value
|
||||
)
|
||||
{
|
||||
for( vector<SceneStorage*>::iterator it = m_values.begin(); it != m_values.end(); ++it )
|
||||
{
|
||||
if( (*it)->m_id == _valueId )
|
||||
{
|
||||
(*it)->m_value = _value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Scene::Activate>
|
||||
// Execute scene activation by running each ValueId/value
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Scene::Activate
|
||||
(
|
||||
)
|
||||
{
|
||||
bool res = true;
|
||||
for( vector<SceneStorage*>::iterator it = m_values.begin(); it != m_values.end(); ++it )
|
||||
{
|
||||
if ( !Manager::Get()->SetValue( (*it)->m_id, (*it)->m_value ) )
|
||||
{
|
||||
res = false;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Scene.h
|
||||
//
|
||||
// A collection of ValueIDs to be used together.
|
||||
//
|
||||
// Copyright (c) 2011 Greg Satz <satz@iranger.com>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _Scene_H
|
||||
#define _Scene_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Defs.h"
|
||||
|
||||
class TiXmlElement;
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class ValueID;
|
||||
|
||||
/** \brief Collection of ValueIDs to be treated as a unit.
|
||||
*/
|
||||
class Scene
|
||||
{
|
||||
friend class Manager;
|
||||
friend class Driver;
|
||||
friend class Node;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Construction
|
||||
//-----------------------------------------------------------------------------
|
||||
private:
|
||||
Scene( uint8 const _sceneId );
|
||||
~Scene();
|
||||
|
||||
static void WriteXML( string const& _name );
|
||||
static bool ReadScenes();
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Scene functions
|
||||
//-----------------------------------------------------------------------------
|
||||
private:
|
||||
static Scene* Get( uint8 const _sceneId );
|
||||
static uint8 GetAllScenes( uint8** _sceneIds );
|
||||
|
||||
string const& GetLabel()const{ return m_label; }
|
||||
void SetLabel( string const &_label ){ m_label = _label; }
|
||||
|
||||
bool AddValue( ValueID const& _valueId, string const& _value );
|
||||
bool RemoveValue( ValueID const& _valueId );
|
||||
void RemoveValues( uint32 const _homeId );
|
||||
static void RemoveValues( uint32 const _homeId, uint8 const _nodeId );
|
||||
int GetValues( vector<ValueID>* o_value );
|
||||
bool GetValue( ValueID const& _valueId, string* o_value );
|
||||
bool SetValue( ValueID const& _valueId, string const& _value );
|
||||
bool Activate();
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ValueID/value storage
|
||||
//-----------------------------------------------------------------------------
|
||||
private:
|
||||
class SceneStorage
|
||||
{
|
||||
public:
|
||||
SceneStorage( ValueID const& _id, string const& _value ): m_id( _id ), m_value( _value ) {};
|
||||
~SceneStorage() {};
|
||||
|
||||
ValueID const m_id;
|
||||
string m_value;
|
||||
};
|
||||
//-----------------------------------------------------------------------------
|
||||
// Member variables
|
||||
//-----------------------------------------------------------------------------
|
||||
private:
|
||||
uint8 m_sceneId;
|
||||
string m_label;
|
||||
vector<SceneStorage*> m_values;
|
||||
static uint8 s_sceneCnt;
|
||||
static Scene* s_scenes[256];
|
||||
};
|
||||
|
||||
} //namespace OpenZWave
|
||||
|
||||
#endif //_Scene_H
|
||||
@@ -0,0 +1,116 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Utils.h
|
||||
//
|
||||
// Miscellaneous helper functions
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "Defs.h"
|
||||
#include "Utils.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <OpenZWave::ToUpper>
|
||||
// Convert a string to all upper-case.
|
||||
//-----------------------------------------------------------------------------
|
||||
string OpenZWave::ToUpper
|
||||
(
|
||||
string const& _str
|
||||
)
|
||||
{
|
||||
string upper = _str;
|
||||
transform( upper.begin(), upper.end(), upper.begin(), ::toupper );
|
||||
return upper;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <OpenZWave::ToLower>
|
||||
// Convert a string to all lower-case.
|
||||
//-----------------------------------------------------------------------------
|
||||
string OpenZWave::ToLower
|
||||
(
|
||||
string const& _str
|
||||
)
|
||||
{
|
||||
string lower = _str;
|
||||
transform( lower.begin(), lower.end(), lower.begin(), ::tolower );
|
||||
return lower;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <OpenZWave::trim>
|
||||
// Remove WhiteSpaces from the begining and end of a string
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
std::string &OpenZWave::trim
|
||||
(
|
||||
std::string &s
|
||||
)
|
||||
{
|
||||
if(s.size() == 0)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
int val = 0;
|
||||
for (size_t cur = 0; cur < s.size(); cur++)
|
||||
{
|
||||
if(s[cur] != ' ' && isalnum(s[cur]))
|
||||
{
|
||||
s[val] = s[cur];
|
||||
val++;
|
||||
}
|
||||
}
|
||||
s.resize(val);
|
||||
return s;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <OpenZWave::split>
|
||||
// Split a String into a vector, seperated by anything specified in seperators.
|
||||
//-----------------------------------------------------------------------------
|
||||
void OpenZWave::split
|
||||
(
|
||||
std::vector<std::string>& lst,
|
||||
const std::string& input,
|
||||
const std::string& separators,
|
||||
bool remove_empty
|
||||
)
|
||||
{
|
||||
std::ostringstream word;
|
||||
for (size_t n = 0; n < input.size(); ++n)
|
||||
{
|
||||
if (std::string::npos == separators.find(input[n]))
|
||||
word << input[n];
|
||||
else
|
||||
{
|
||||
if (!word.str().empty() || !remove_empty)
|
||||
lst.push_back(word.str());
|
||||
word.str("");
|
||||
}
|
||||
}
|
||||
if (!word.str().empty() || !remove_empty)
|
||||
lst.push_back(word.str());
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Utils.h
|
||||
//
|
||||
// Miscellaneous helper functions
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _Utils_H
|
||||
#define _Utils_H
|
||||
|
||||
#include <string>
|
||||
#include <locale>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
/**
|
||||
* Convert a string to all upper-case.
|
||||
* \param _str the string to be converted.
|
||||
* \return the upper-case string.
|
||||
* \see ToLower, Trim
|
||||
*/
|
||||
string ToUpper( string const& _str );
|
||||
|
||||
/**
|
||||
* Convert a string to all lower-case.
|
||||
* \param _str the string to be converted.
|
||||
* \return the lower-case string.
|
||||
* \see ToUpper, Trim
|
||||
*/
|
||||
string ToLower( string const& _str );
|
||||
|
||||
/**
|
||||
* Split a String into a Vector, seperated by seperators
|
||||
* \param lst the vector to store the results in
|
||||
* \param input the input string to split
|
||||
* \param seperators a string containing a list of valid seperators
|
||||
* \param remove_empty if after spliting a string, the any of the results are a empty string, should we preseve them or not
|
||||
*/
|
||||
void split (std::vector<std::string>& lst, const std::string& input, const std::string& separators, bool remove_empty = true);
|
||||
|
||||
/**
|
||||
* Trim Whitespace from the start and end of a string.
|
||||
* \param s the string to trim
|
||||
* \return the trimmed string
|
||||
*/
|
||||
std::string &trim ( std::string &s );
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
#ifndef _ZWAVE_COMMAND_CLASSES_H_
|
||||
#define _ZWAVE_COMMAND_CLASSES_H_
|
||||
|
||||
#define COMMAND_CLASS_NO_OPERATION 0x00
|
||||
#define COMMAND_CLASS_BASIC 0x20
|
||||
#define COMMAND_CLASS_CONTROLLER_REPLICATION 0x21
|
||||
#define COMMAND_CLASS_APPLICATION_STATUS 0x22
|
||||
#define COMMAND_CLASS_ZIP_SERVICES 0x23
|
||||
#define COMMAND_CLASS_ZIP_SERVER 0x24
|
||||
#define COMMAND_CLASS_SWITCH_BINARY 0x25
|
||||
#define COMMAND_CLASS_SWITCH_MULTILEVEL 0x26
|
||||
#define COMMAND_CLASS_SWITCH_ALL 0x27
|
||||
#define COMMAND_CLASS_SWITCH_TOGGLE_BINARY 0x28
|
||||
#define COMMAND_CLASS_SWITCH_TOGGLE_MULTILEVEL 0x29
|
||||
#define COMMAND_CLASS_CHIMNEY_FAN 0x2A
|
||||
#define COMMAND_CLASS_SCENE_ACTIVATION 0x2B
|
||||
#define COMMAND_CLASS_SCENE_ACTUATOR_CONF 0x2C
|
||||
#define COMMAND_CLASS_SCENE_CONTROLLER_CONF 0x2D
|
||||
#define COMMAND_CLASS_ZIP_CLIENT 0x2E
|
||||
#define COMMAND_CLASS_ZIP_ADV_SERVICES 0x2F
|
||||
#define COMMAND_CLASS_SENSOR_BINARY 0x30
|
||||
#define COMMAND_CLASS_SENSOR_MULTILEVEL 0x31
|
||||
#define COMMAND_CLASS_METER 0x32
|
||||
#define COMMAND_CLASS_COLOR_CONTROL 0x33
|
||||
#define COMMAND_CLASS_ZIP_ADV_CLIENT 0x34
|
||||
#define COMMAND_CLASS_METER_PULSE 0x35
|
||||
#define COMMAND_CLASS_THERMOSTAT_HEATING 0x38
|
||||
#define COMMAND_CLASS_THERMOSTAT_MODE 0x40
|
||||
#define COMMAND_CLASS_THERMOSTAT_OPERATING_STATE 0x42
|
||||
#define COMMAND_CLASS_THERMOSTAT_SETPOINT 0x43
|
||||
#define COMMAND_CLASS_THERMOSTAT_FAN_MODE 0x44
|
||||
#define COMMAND_CLASS_THERMOSTAT_FAN_STATE 0x45
|
||||
#define COMMAND_CLASS_CLIMATE_CONTROL_SCHEDULE 0x46
|
||||
#define COMMAND_CLASS_THERMOSTAT_SETBACK 0x47
|
||||
#define COMMAND_CLASS_BASIC_WINDOW_COVERING 0x50
|
||||
#define COMMAND_CLASS_MTP_WINDOW_COVERING 0x51
|
||||
#define COMMAND_CLASS_MULTI_INSTANCE 0x60
|
||||
#define COMMAND_CLASS_DOOR_LOCK 0x62
|
||||
#define COMMAND_CLASS_USER_CODE 0x63
|
||||
#define COMMAND_CLASS_CONFIGURATION 0x70
|
||||
#define COMMAND_CLASS_ALARM 0x71
|
||||
#define COMMAND_CLASS_MANUFACTURER_SPECIFIC 0x72
|
||||
#define COMMAND_CLASS_POWERLEVEL 0x73
|
||||
#define COMMAND_CLASS_PROTECTION 0x75
|
||||
#define COMMAND_CLASS_LOCK 0x76
|
||||
#define COMMAND_CLASS_NODE_NAMING 0x77
|
||||
#define COMMAND_CLASS_FIRMWARE_UPDATE_MD 0x7A
|
||||
#define COMMAND_CLASS_GROUPING_NAME 0x7B
|
||||
#define COMMAND_CLASS_REMOTE_ASSOCIATION_ACTIVATE 0x7C
|
||||
#define COMMAND_CLASS_REMOTE_ASSOCIATION 0x7D
|
||||
#define COMMAND_CLASS_BATTERY 0x80
|
||||
#define COMMAND_CLASS_CLOCK 0x81
|
||||
#define COMMAND_CLASS_HAIL 0x82
|
||||
#define COMMAND_CLASS_WAKE_UP 0x84
|
||||
#define COMMAND_CLASS_ASSOCIATION 0x85
|
||||
#define COMMAND_CLASS_VERSION 0x86
|
||||
#define COMMAND_CLASS_INDICATOR 0x87
|
||||
#define COMMAND_CLASS_PROPRIETARY 0x88
|
||||
#define COMMAND_CLASS_LANGUAGE 0x89
|
||||
#define COMMAND_CLASS_TIME 0x8A
|
||||
#define COMMAND_CLASS_TIME_PARAMETERS 0x8B
|
||||
#define COMMAND_CLASS_GEOGRAPHIC_LOCATION 0x8C
|
||||
#define COMMAND_CLASS_COMPOSITE 0x8D
|
||||
#define COMMAND_CLASS_MULTI_INSTANCE_ASSOCIATION 0x8E
|
||||
#define COMMAND_CLASS_MULTI_CMD 0x8F
|
||||
#define COMMAND_CLASS_ENERGY_PRODUCTION 0x90
|
||||
#define COMMAND_CLASS_MANUFACTURER_PROPRIETARY 0x91
|
||||
#define COMMAND_CLASS_SCREEN_MD 0x92
|
||||
#define COMMAND_CLASS_SCREEN_ATTRIBUTES 0x93
|
||||
#define COMMAND_CLASS_SIMPLE_AV_CONTROL 0x94
|
||||
#define COMMAND_CLASS_AV_CONTENT_DIRECTORY_MD 0x95
|
||||
#define COMMAND_CLASS_AV_RENDERER_STATUS 0x96
|
||||
#define COMMAND_CLASS_AV_CONTENT_SEARCH_MD 0x97
|
||||
#define COMMAND_CLASS_SECURITY 0x98
|
||||
#define COMMAND_CLASS_AV_TAGGING_MD 0x99
|
||||
#define COMMAND_CLASS_IP_CONFIGURATION 0x9A
|
||||
#define COMMAND_CLASS_ASSOCIATION_COMMAND_CONFIGURATION 0x9B
|
||||
#define COMMAND_CLASS_SENSOR_ALARM 0x9C
|
||||
#define COMMAND_CLASS_SILENCE_ALARM 0x9D
|
||||
#define COMMAND_CLASS_SENSOR_CONFIGURATION 0x9E
|
||||
#define COMMAND_CLASS_NON_INTEROPERABLE 0xF0
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,6 @@
|
||||
project(openzwave_aes)
|
||||
|
||||
file(GLOB ${PROJECT_NAME}_sources "${PROJECT_SOURCE_DIR}/*.c")
|
||||
file(GLOB ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/*.h")
|
||||
|
||||
set(${PROJECT_NAME}_files ${${PROJECT_NAME}_sources} ${${PROJECT_NAME}_headers} CACHE INTERNAL "")
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
|
||||
This file contains the definitions required to use AES in C. See aesopt.h
|
||||
for optimisation details.
|
||||
*/
|
||||
|
||||
#ifndef _AES_H
|
||||
#define _AES_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* This include is used to find 8 & 32 bit unsigned integer types */
|
||||
#include "brg_types.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#define AES_128 /* if a fast 128 bit key scheduler is needed */
|
||||
#define AES_192 /* if a fast 192 bit key scheduler is needed */
|
||||
#define AES_256 /* if a fast 256 bit key scheduler is needed */
|
||||
#define AES_VAR /* if variable key size scheduler is needed */
|
||||
#define AES_MODES /* if support is needed for modes */
|
||||
|
||||
/* The following must also be set in assembler files if being used */
|
||||
|
||||
#define AES_ENCRYPT /* if support for encryption is needed */
|
||||
#define AES_DECRYPT /* if support for decryption is needed */
|
||||
|
||||
#define AES_BLOCK_SIZE 16 /* the AES block size in bytes */
|
||||
#define N_COLS 4 /* the number of columns in the state */
|
||||
|
||||
/* The key schedule length is 11, 13 or 15 16-byte blocks for 128, */
|
||||
/* 192 or 256-bit keys respectively. That is 176, 208 or 240 bytes */
|
||||
/* or 44, 52 or 60 32-bit words. */
|
||||
|
||||
#if defined( AES_VAR ) || defined( AES_256 )
|
||||
#define KS_LENGTH 60
|
||||
#elif defined( AES_192 )
|
||||
#define KS_LENGTH 52
|
||||
#else
|
||||
#define KS_LENGTH 44
|
||||
#endif
|
||||
|
||||
#define AES_RETURN INT_RETURN
|
||||
|
||||
/* the character array 'inf' in the following structures is used */
|
||||
/* to hold AES context information. This AES code uses cx->inf.b[0] */
|
||||
/* to hold the number of rounds multiplied by 16. The other three */
|
||||
/* elements can be used by code that implements additional modes */
|
||||
|
||||
typedef union
|
||||
{ uint32_t l;
|
||||
uint8_t b[4];
|
||||
} aes_inf;
|
||||
|
||||
#ifdef _WIN64
|
||||
__declspec(align(16))
|
||||
#endif
|
||||
typedef struct
|
||||
{ uint32_t ks[KS_LENGTH];
|
||||
aes_inf inf;
|
||||
} aes_encrypt_ctx;
|
||||
|
||||
#ifdef _WIN64
|
||||
__declspec(align(16))
|
||||
#endif
|
||||
typedef struct
|
||||
{ uint32_t ks[KS_LENGTH];
|
||||
aes_inf inf;
|
||||
} aes_decrypt_ctx;
|
||||
|
||||
/* This routine must be called before first use if non-static */
|
||||
/* tables are being used */
|
||||
|
||||
AES_RETURN aes_init1(void);
|
||||
|
||||
/* Key lengths in the range 16 <= key_len <= 32 are given in bytes, */
|
||||
/* those in the range 128 <= key_len <= 256 are given in bits */
|
||||
|
||||
#if defined( AES_ENCRYPT )
|
||||
|
||||
#if defined( AES_128 ) || defined( AES_VAR)
|
||||
AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
#if defined( AES_192 ) || defined( AES_VAR)
|
||||
AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
#if defined( AES_256 ) || defined( AES_VAR)
|
||||
AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
#if defined( AES_VAR )
|
||||
AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined( AES_DECRYPT )
|
||||
|
||||
#if defined( AES_128 ) || defined( AES_VAR)
|
||||
AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
#if defined( AES_192 ) || defined( AES_VAR)
|
||||
AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
#if defined( AES_256 ) || defined( AES_VAR)
|
||||
AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
#if defined( AES_VAR )
|
||||
AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]);
|
||||
#endif
|
||||
|
||||
AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined( AES_MODES )
|
||||
|
||||
/* Multiple calls to the following subroutines for multiple block */
|
||||
/* ECB, CBC, CFB, OFB and CTR mode encryption can be used to handle */
|
||||
/* long messages incrementally provided that the context AND the iv */
|
||||
/* are preserved between all such calls. For the ECB and CBC modes */
|
||||
/* each individual call within a series of incremental calls must */
|
||||
/* process only full blocks (i.e. len must be a multiple of 16) but */
|
||||
/* the CFB, OFB and CTR mode calls can handle multiple incremental */
|
||||
/* calls of any length. Each mode is reset when a new AES key is */
|
||||
/* set but ECB and CBC operations can be reset without setting a */
|
||||
/* new key by setting a new IV value. To reset CFB, OFB and CTR */
|
||||
/* without setting the key, aes_mode_reset() must be called and the */
|
||||
/* IV must be set. NOTE: All these calls update the IV on exit so */
|
||||
/* this has to be reset if a new operation with the same IV as the */
|
||||
/* previous one is required (or decryption follows encryption with */
|
||||
/* the same IV array). */
|
||||
|
||||
AES_RETURN aes_test_alignment_detection(unsigned int n);
|
||||
|
||||
AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, const aes_encrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, const aes_decrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, const aes_encrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, const aes_decrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN aes_mode_reset(aes_encrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, aes_encrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, aes_encrypt_ctx cx[1]);
|
||||
|
||||
#define aes_ofb_encrypt aes_ofb_crypt
|
||||
#define aes_ofb_decrypt aes_ofb_crypt
|
||||
|
||||
AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, aes_encrypt_ctx cx[1]);
|
||||
|
||||
typedef void cbuf_inc(unsigned char *cbuf);
|
||||
|
||||
#define aes_ctr_encrypt aes_ctr_crypt
|
||||
#define aes_ctr_decrypt aes_ctr_crypt
|
||||
|
||||
AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx cx[1]);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,947 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
|
||||
These subroutines implement multiple block AES modes for ECB, CBC, CFB,
|
||||
OFB and CTR encryption, The code provides support for the VIA Advanced
|
||||
Cryptography Engine (ACE).
|
||||
|
||||
NOTE: In the following subroutines, the AES contexts (ctx) must be
|
||||
16 byte aligned if VIA ACE is being used
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "aesopt.h"
|
||||
|
||||
#if defined( AES_MODES )
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if defined( _WIN32 ) && ( _WIN32 > 800 )
|
||||
#pragma intrinsic(memcpy)
|
||||
#endif
|
||||
|
||||
#define BFR_BLOCKS 8
|
||||
|
||||
/* These values are used to detect long word alignment in order to */
|
||||
/* speed up some buffer operations. This facility may not work on */
|
||||
/* some machines so this define can be commented out if necessary */
|
||||
|
||||
#define FAST_BUFFER_OPERATIONS
|
||||
|
||||
#define lp32(x) ((uint32_t*)(x))
|
||||
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
|
||||
#include "aes_via_ace.h"
|
||||
|
||||
#pragma pack(16)
|
||||
|
||||
aligned_array(unsigned long, enc_gen_table, 12, 16) = NEH_ENC_GEN_DATA;
|
||||
aligned_array(unsigned long, enc_load_table, 12, 16) = NEH_ENC_LOAD_DATA;
|
||||
aligned_array(unsigned long, enc_hybrid_table, 12, 16) = NEH_ENC_HYBRID_DATA;
|
||||
aligned_array(unsigned long, dec_gen_table, 12, 16) = NEH_DEC_GEN_DATA;
|
||||
aligned_array(unsigned long, dec_load_table, 12, 16) = NEH_DEC_LOAD_DATA;
|
||||
aligned_array(unsigned long, dec_hybrid_table, 12, 16) = NEH_DEC_HYBRID_DATA;
|
||||
|
||||
/* NOTE: These control word macros must only be used after */
|
||||
/* a key has been set up because they depend on key size */
|
||||
/* See the VIA ACE documentation for key type information */
|
||||
/* and aes_via_ace.h for non-default NEH_KEY_TYPE values */
|
||||
|
||||
#ifndef NEH_KEY_TYPE
|
||||
# define NEH_KEY_TYPE NEH_HYBRID
|
||||
#endif
|
||||
|
||||
#if NEH_KEY_TYPE == NEH_LOAD
|
||||
#define kd_adr(c) ((uint8_t*)(c)->ks)
|
||||
#elif NEH_KEY_TYPE == NEH_GENERATE
|
||||
#define kd_adr(c) ((uint8_t*)(c)->ks + (c)->inf.b[0])
|
||||
#elif NEH_KEY_TYPE == NEH_HYBRID
|
||||
#define kd_adr(c) ((uint8_t*)(c)->ks + ((c)->inf.b[0] == 160 ? 160 : 0))
|
||||
#else
|
||||
#error no key type defined for VIA ACE
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define aligned_array(type, name, no, stride) type name[no]
|
||||
#define aligned_auto(type, name, no, stride) type name[no]
|
||||
|
||||
#endif
|
||||
|
||||
#if defined( _WIN32 ) && _WIN32 > 1200
|
||||
|
||||
#define via_cwd(cwd, ty, dir, len) \
|
||||
unsigned long* cwd = (dir##_##ty##_table + ((len - 128) >> 4))
|
||||
|
||||
#else
|
||||
|
||||
#define via_cwd(cwd, ty, dir, len) \
|
||||
aligned_auto(unsigned long, cwd, 4, 16); \
|
||||
cwd[1] = cwd[2] = cwd[3] = 0; \
|
||||
cwd[0] = neh_##dir##_##ty##_key(len)
|
||||
|
||||
#endif
|
||||
|
||||
/* test the code for detecting and setting pointer alignment */
|
||||
|
||||
AES_RETURN aes_test_alignment_detection(unsigned int n) /* 4 <= n <= 16 */
|
||||
{ uint8_t p[16];
|
||||
uint32_t i, count_eq = 0, count_neq = 0;
|
||||
|
||||
if(n < 4 || n > 16)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
for(i = 0; i < n; ++i)
|
||||
{
|
||||
uint8_t *qf = ALIGN_FLOOR(p + i, n),
|
||||
*qh = ALIGN_CEIL(p + i, n);
|
||||
|
||||
if(qh == qf)
|
||||
++count_eq;
|
||||
else if(qh == qf + n)
|
||||
++count_neq;
|
||||
else
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return (count_eq != 1 || count_neq != n - 1 ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
AES_RETURN aes_mode_reset(aes_encrypt_ctx ctx[1])
|
||||
{
|
||||
ctx->inf.b[2] = 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, const aes_encrypt_ctx ctx[1])
|
||||
{ int nb = len >> 4;
|
||||
|
||||
if(len & (AES_BLOCK_SIZE - 1))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
|
||||
if(ctx->inf.b[1] == 0xff)
|
||||
{ uint8_t *ksp = (uint8_t*)(ctx->ks);
|
||||
via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(ALIGN_OFFSET( ctx, 16 ))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ))
|
||||
{
|
||||
via_ecb_op5(ksp, cwd, ibuf, obuf, nb);
|
||||
}
|
||||
else
|
||||
{ aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint8_t *ip, *op;
|
||||
|
||||
while(nb)
|
||||
{
|
||||
int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb);
|
||||
|
||||
ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);
|
||||
op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf)
|
||||
memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_ecb_op5(ksp, cwd, ip, op, m);
|
||||
|
||||
if(op != obuf)
|
||||
memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
nb -= m;
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined( ASSUME_VIA_ACE_PRESENT )
|
||||
while(nb--)
|
||||
{
|
||||
if(aes_encrypt(ibuf, obuf, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, const aes_decrypt_ctx ctx[1])
|
||||
{ int nb = len >> 4;
|
||||
|
||||
if(len & (AES_BLOCK_SIZE - 1))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
|
||||
if(ctx->inf.b[1] == 0xff)
|
||||
{ uint8_t *ksp = kd_adr(ctx);
|
||||
via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(ALIGN_OFFSET( ctx, 16 ))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ))
|
||||
{
|
||||
via_ecb_op5(ksp, cwd, ibuf, obuf, nb);
|
||||
}
|
||||
else
|
||||
{ aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint8_t *ip, *op;
|
||||
|
||||
while(nb)
|
||||
{
|
||||
int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb);
|
||||
|
||||
ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);
|
||||
op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf)
|
||||
memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_ecb_op5(ksp, cwd, ip, op, m);
|
||||
|
||||
if(op != obuf)
|
||||
memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
nb -= m;
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined( ASSUME_VIA_ACE_PRESENT )
|
||||
while(nb--)
|
||||
{
|
||||
if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, const aes_encrypt_ctx ctx[1])
|
||||
{ int nb = len >> 4;
|
||||
|
||||
if(len & (AES_BLOCK_SIZE - 1))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
|
||||
if(ctx->inf.b[1] == 0xff)
|
||||
{ uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv;
|
||||
aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16);
|
||||
via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(ALIGN_OFFSET( ctx, 16 ))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */
|
||||
{
|
||||
ivp = liv;
|
||||
memcpy(liv, iv, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ) && !ALIGN_OFFSET( iv, 16 ))
|
||||
{
|
||||
via_cbc_op7(ksp, cwd, ibuf, obuf, nb, ivp, ivp);
|
||||
}
|
||||
else
|
||||
{ aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint8_t *ip, *op;
|
||||
|
||||
while(nb)
|
||||
{
|
||||
int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb);
|
||||
|
||||
ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);
|
||||
op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf)
|
||||
memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_cbc_op7(ksp, cwd, ip, op, m, ivp, ivp);
|
||||
|
||||
if(op != obuf)
|
||||
memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
nb -= m;
|
||||
}
|
||||
}
|
||||
|
||||
if(iv != ivp)
|
||||
memcpy(iv, ivp, AES_BLOCK_SIZE);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined( ASSUME_VIA_ACE_PRESENT )
|
||||
# ifdef FAST_BUFFER_OPERATIONS
|
||||
if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( iv, 4 ))
|
||||
while(nb--)
|
||||
{
|
||||
lp32(iv)[0] ^= lp32(ibuf)[0];
|
||||
lp32(iv)[1] ^= lp32(ibuf)[1];
|
||||
lp32(iv)[2] ^= lp32(ibuf)[2];
|
||||
lp32(iv)[3] ^= lp32(ibuf)[3];
|
||||
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
memcpy(obuf, iv, AES_BLOCK_SIZE);
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
# endif
|
||||
while(nb--)
|
||||
{
|
||||
iv[ 0] ^= ibuf[ 0]; iv[ 1] ^= ibuf[ 1];
|
||||
iv[ 2] ^= ibuf[ 2]; iv[ 3] ^= ibuf[ 3];
|
||||
iv[ 4] ^= ibuf[ 4]; iv[ 5] ^= ibuf[ 5];
|
||||
iv[ 6] ^= ibuf[ 6]; iv[ 7] ^= ibuf[ 7];
|
||||
iv[ 8] ^= ibuf[ 8]; iv[ 9] ^= ibuf[ 9];
|
||||
iv[10] ^= ibuf[10]; iv[11] ^= ibuf[11];
|
||||
iv[12] ^= ibuf[12]; iv[13] ^= ibuf[13];
|
||||
iv[14] ^= ibuf[14]; iv[15] ^= ibuf[15];
|
||||
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
memcpy(obuf, iv, AES_BLOCK_SIZE);
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, const aes_decrypt_ctx ctx[1])
|
||||
{ unsigned char tmp[AES_BLOCK_SIZE];
|
||||
int nb = len >> 4;
|
||||
|
||||
if(len & (AES_BLOCK_SIZE - 1))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
|
||||
if(ctx->inf.b[1] == 0xff)
|
||||
{ uint8_t *ksp = kd_adr(ctx), *ivp = iv;
|
||||
aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16);
|
||||
via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(ALIGN_OFFSET( ctx, 16 ))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */
|
||||
{
|
||||
ivp = liv;
|
||||
memcpy(liv, iv, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ) && !ALIGN_OFFSET( iv, 16 ))
|
||||
{
|
||||
via_cbc_op6(ksp, cwd, ibuf, obuf, nb, ivp);
|
||||
}
|
||||
else
|
||||
{ aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint8_t *ip, *op;
|
||||
|
||||
while(nb)
|
||||
{
|
||||
int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb);
|
||||
|
||||
ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);
|
||||
op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf)
|
||||
memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_cbc_op6(ksp, cwd, ip, op, m, ivp);
|
||||
|
||||
if(op != obuf)
|
||||
memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
nb -= m;
|
||||
}
|
||||
}
|
||||
|
||||
if(iv != ivp)
|
||||
memcpy(iv, ivp, AES_BLOCK_SIZE);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined( ASSUME_VIA_ACE_PRESENT )
|
||||
# ifdef FAST_BUFFER_OPERATIONS
|
||||
if(!ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 ))
|
||||
while(nb--)
|
||||
{
|
||||
memcpy(tmp, ibuf, AES_BLOCK_SIZE);
|
||||
if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
lp32(obuf)[0] ^= lp32(iv)[0];
|
||||
lp32(obuf)[1] ^= lp32(iv)[1];
|
||||
lp32(obuf)[2] ^= lp32(iv)[2];
|
||||
lp32(obuf)[3] ^= lp32(iv)[3];
|
||||
memcpy(iv, tmp, AES_BLOCK_SIZE);
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
# endif
|
||||
while(nb--)
|
||||
{
|
||||
memcpy(tmp, ibuf, AES_BLOCK_SIZE);
|
||||
if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
obuf[ 0] ^= iv[ 0]; obuf[ 1] ^= iv[ 1];
|
||||
obuf[ 2] ^= iv[ 2]; obuf[ 3] ^= iv[ 3];
|
||||
obuf[ 4] ^= iv[ 4]; obuf[ 5] ^= iv[ 5];
|
||||
obuf[ 6] ^= iv[ 6]; obuf[ 7] ^= iv[ 7];
|
||||
obuf[ 8] ^= iv[ 8]; obuf[ 9] ^= iv[ 9];
|
||||
obuf[10] ^= iv[10]; obuf[11] ^= iv[11];
|
||||
obuf[12] ^= iv[12]; obuf[13] ^= iv[13];
|
||||
obuf[14] ^= iv[14]; obuf[15] ^= iv[15];
|
||||
memcpy(iv, tmp, AES_BLOCK_SIZE);
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, aes_encrypt_ctx ctx[1])
|
||||
{ int cnt = 0, b_pos = (int)ctx->inf.b[2], nb;
|
||||
|
||||
if(b_pos) /* complete any partial block */
|
||||
{
|
||||
while(b_pos < AES_BLOCK_SIZE && cnt < len)
|
||||
{
|
||||
*obuf++ = (iv[b_pos++] ^= *ibuf++);
|
||||
cnt++;
|
||||
}
|
||||
|
||||
b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
|
||||
}
|
||||
|
||||
if((nb = (len - cnt) >> 4) != 0) /* process whole blocks */
|
||||
{
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
|
||||
if(ctx->inf.b[1] == 0xff)
|
||||
{ int m;
|
||||
uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv;
|
||||
aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16);
|
||||
via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(ALIGN_OFFSET( ctx, 16 ))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */
|
||||
{
|
||||
ivp = liv;
|
||||
memcpy(liv, iv, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ))
|
||||
{
|
||||
via_cfb_op7(ksp, cwd, ibuf, obuf, nb, ivp, ivp);
|
||||
ibuf += nb * AES_BLOCK_SIZE;
|
||||
obuf += nb * AES_BLOCK_SIZE;
|
||||
cnt += nb * AES_BLOCK_SIZE;
|
||||
}
|
||||
else /* input, output or both are unaligned */
|
||||
{ aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint8_t *ip, *op;
|
||||
|
||||
while(nb)
|
||||
{
|
||||
m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m;
|
||||
|
||||
ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);
|
||||
op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf)
|
||||
memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_cfb_op7(ksp, cwd, ip, op, m, ivp, ivp);
|
||||
|
||||
if(op != obuf)
|
||||
memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
cnt += m * AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
if(ivp != iv)
|
||||
memcpy(iv, ivp, AES_BLOCK_SIZE);
|
||||
}
|
||||
#else
|
||||
# ifdef FAST_BUFFER_OPERATIONS
|
||||
if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 ))
|
||||
while(cnt + AES_BLOCK_SIZE <= len)
|
||||
{
|
||||
assert(b_pos == 0);
|
||||
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
lp32(obuf)[0] = lp32(iv)[0] ^= lp32(ibuf)[0];
|
||||
lp32(obuf)[1] = lp32(iv)[1] ^= lp32(ibuf)[1];
|
||||
lp32(obuf)[2] = lp32(iv)[2] ^= lp32(ibuf)[2];
|
||||
lp32(obuf)[3] = lp32(iv)[3] ^= lp32(ibuf)[3];
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
cnt += AES_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
# endif
|
||||
while(cnt + AES_BLOCK_SIZE <= len)
|
||||
{
|
||||
assert(b_pos == 0);
|
||||
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
obuf[ 0] = iv[ 0] ^= ibuf[ 0]; obuf[ 1] = iv[ 1] ^= ibuf[ 1];
|
||||
obuf[ 2] = iv[ 2] ^= ibuf[ 2]; obuf[ 3] = iv[ 3] ^= ibuf[ 3];
|
||||
obuf[ 4] = iv[ 4] ^= ibuf[ 4]; obuf[ 5] = iv[ 5] ^= ibuf[ 5];
|
||||
obuf[ 6] = iv[ 6] ^= ibuf[ 6]; obuf[ 7] = iv[ 7] ^= ibuf[ 7];
|
||||
obuf[ 8] = iv[ 8] ^= ibuf[ 8]; obuf[ 9] = iv[ 9] ^= ibuf[ 9];
|
||||
obuf[10] = iv[10] ^= ibuf[10]; obuf[11] = iv[11] ^= ibuf[11];
|
||||
obuf[12] = iv[12] ^= ibuf[12]; obuf[13] = iv[13] ^= ibuf[13];
|
||||
obuf[14] = iv[14] ^= ibuf[14]; obuf[15] = iv[15] ^= ibuf[15];
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
cnt += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
while(cnt < len)
|
||||
{
|
||||
if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
while(cnt < len && b_pos < AES_BLOCK_SIZE)
|
||||
{
|
||||
*obuf++ = (iv[b_pos++] ^= *ibuf++);
|
||||
cnt++;
|
||||
}
|
||||
|
||||
b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
|
||||
}
|
||||
|
||||
ctx->inf.b[2] = (uint8_t)b_pos;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, aes_encrypt_ctx ctx[1])
|
||||
{ int cnt = 0, b_pos = (int)ctx->inf.b[2], nb;
|
||||
|
||||
if(b_pos) /* complete any partial block */
|
||||
{ uint8_t t;
|
||||
|
||||
while(b_pos < AES_BLOCK_SIZE && cnt < len)
|
||||
{
|
||||
t = *ibuf++;
|
||||
*obuf++ = t ^ iv[b_pos];
|
||||
iv[b_pos++] = t;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
|
||||
}
|
||||
|
||||
if((nb = (len - cnt) >> 4) != 0) /* process whole blocks */
|
||||
{
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
|
||||
if(ctx->inf.b[1] == 0xff)
|
||||
{ int m;
|
||||
uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv;
|
||||
aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16);
|
||||
via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(ALIGN_OFFSET( ctx, 16 ))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */
|
||||
{
|
||||
ivp = liv;
|
||||
memcpy(liv, iv, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ))
|
||||
{
|
||||
via_cfb_op6(ksp, cwd, ibuf, obuf, nb, ivp);
|
||||
ibuf += nb * AES_BLOCK_SIZE;
|
||||
obuf += nb * AES_BLOCK_SIZE;
|
||||
cnt += nb * AES_BLOCK_SIZE;
|
||||
}
|
||||
else /* input, output or both are unaligned */
|
||||
{ aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint8_t *ip, *op;
|
||||
|
||||
while(nb)
|
||||
{
|
||||
m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m;
|
||||
|
||||
ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);
|
||||
op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf) /* input buffer is not aligned */
|
||||
memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_cfb_op6(ksp, cwd, ip, op, m, ivp);
|
||||
|
||||
if(op != obuf) /* output buffer is not aligned */
|
||||
memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
cnt += m * AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
if(ivp != iv)
|
||||
memcpy(iv, ivp, AES_BLOCK_SIZE);
|
||||
}
|
||||
#else
|
||||
# ifdef FAST_BUFFER_OPERATIONS
|
||||
if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) &&!ALIGN_OFFSET( iv, 4 ))
|
||||
while(cnt + AES_BLOCK_SIZE <= len)
|
||||
{ uint32_t t;
|
||||
|
||||
assert(b_pos == 0);
|
||||
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
t = lp32(ibuf)[0], lp32(obuf)[0] = t ^ lp32(iv)[0], lp32(iv)[0] = t;
|
||||
t = lp32(ibuf)[1], lp32(obuf)[1] = t ^ lp32(iv)[1], lp32(iv)[1] = t;
|
||||
t = lp32(ibuf)[2], lp32(obuf)[2] = t ^ lp32(iv)[2], lp32(iv)[2] = t;
|
||||
t = lp32(ibuf)[3], lp32(obuf)[3] = t ^ lp32(iv)[3], lp32(iv)[3] = t;
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
cnt += AES_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
# endif
|
||||
while(cnt + AES_BLOCK_SIZE <= len)
|
||||
{ uint8_t t;
|
||||
|
||||
assert(b_pos == 0);
|
||||
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
t = ibuf[ 0], obuf[ 0] = t ^ iv[ 0], iv[ 0] = t;
|
||||
t = ibuf[ 1], obuf[ 1] = t ^ iv[ 1], iv[ 1] = t;
|
||||
t = ibuf[ 2], obuf[ 2] = t ^ iv[ 2], iv[ 2] = t;
|
||||
t = ibuf[ 3], obuf[ 3] = t ^ iv[ 3], iv[ 3] = t;
|
||||
t = ibuf[ 4], obuf[ 4] = t ^ iv[ 4], iv[ 4] = t;
|
||||
t = ibuf[ 5], obuf[ 5] = t ^ iv[ 5], iv[ 5] = t;
|
||||
t = ibuf[ 6], obuf[ 6] = t ^ iv[ 6], iv[ 6] = t;
|
||||
t = ibuf[ 7], obuf[ 7] = t ^ iv[ 7], iv[ 7] = t;
|
||||
t = ibuf[ 8], obuf[ 8] = t ^ iv[ 8], iv[ 8] = t;
|
||||
t = ibuf[ 9], obuf[ 9] = t ^ iv[ 9], iv[ 9] = t;
|
||||
t = ibuf[10], obuf[10] = t ^ iv[10], iv[10] = t;
|
||||
t = ibuf[11], obuf[11] = t ^ iv[11], iv[11] = t;
|
||||
t = ibuf[12], obuf[12] = t ^ iv[12], iv[12] = t;
|
||||
t = ibuf[13], obuf[13] = t ^ iv[13], iv[13] = t;
|
||||
t = ibuf[14], obuf[14] = t ^ iv[14], iv[14] = t;
|
||||
t = ibuf[15], obuf[15] = t ^ iv[15], iv[15] = t;
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
cnt += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
while(cnt < len)
|
||||
{ uint8_t t;
|
||||
|
||||
if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
while(cnt < len && b_pos < AES_BLOCK_SIZE)
|
||||
{
|
||||
t = *ibuf++;
|
||||
*obuf++ = t ^ iv[b_pos];
|
||||
iv[b_pos++] = t;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
|
||||
}
|
||||
|
||||
ctx->inf.b[2] = (uint8_t)b_pos;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *iv, aes_encrypt_ctx ctx[1])
|
||||
{ int cnt = 0, b_pos = (int)ctx->inf.b[2], nb;
|
||||
|
||||
if(b_pos) /* complete any partial block */
|
||||
{
|
||||
while(b_pos < AES_BLOCK_SIZE && cnt < len)
|
||||
{
|
||||
*obuf++ = iv[b_pos++] ^ *ibuf++;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
|
||||
}
|
||||
|
||||
if((nb = (len - cnt) >> 4) != 0) /* process whole blocks */
|
||||
{
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
|
||||
if(ctx->inf.b[1] == 0xff)
|
||||
{ int m;
|
||||
uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv;
|
||||
aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16);
|
||||
via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
|
||||
|
||||
if(ALIGN_OFFSET( ctx, 16 ))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */
|
||||
{
|
||||
ivp = liv;
|
||||
memcpy(liv, iv, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ))
|
||||
{
|
||||
via_ofb_op6(ksp, cwd, ibuf, obuf, nb, ivp);
|
||||
ibuf += nb * AES_BLOCK_SIZE;
|
||||
obuf += nb * AES_BLOCK_SIZE;
|
||||
cnt += nb * AES_BLOCK_SIZE;
|
||||
}
|
||||
else /* input, output or both are unaligned */
|
||||
{ aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);
|
||||
uint8_t *ip, *op;
|
||||
|
||||
while(nb)
|
||||
{
|
||||
m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m;
|
||||
|
||||
ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);
|
||||
op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);
|
||||
|
||||
if(ip != ibuf)
|
||||
memcpy(buf, ibuf, m * AES_BLOCK_SIZE);
|
||||
|
||||
via_ofb_op6(ksp, cwd, ip, op, m, ivp);
|
||||
|
||||
if(op != obuf)
|
||||
memcpy(obuf, buf, m * AES_BLOCK_SIZE);
|
||||
|
||||
ibuf += m * AES_BLOCK_SIZE;
|
||||
obuf += m * AES_BLOCK_SIZE;
|
||||
cnt += m * AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
if(ivp != iv)
|
||||
memcpy(iv, ivp, AES_BLOCK_SIZE);
|
||||
}
|
||||
#else
|
||||
# ifdef FAST_BUFFER_OPERATIONS
|
||||
if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 ))
|
||||
while(cnt + AES_BLOCK_SIZE <= len)
|
||||
{
|
||||
assert(b_pos == 0);
|
||||
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
lp32(obuf)[0] = lp32(iv)[0] ^ lp32(ibuf)[0];
|
||||
lp32(obuf)[1] = lp32(iv)[1] ^ lp32(ibuf)[1];
|
||||
lp32(obuf)[2] = lp32(iv)[2] ^ lp32(ibuf)[2];
|
||||
lp32(obuf)[3] = lp32(iv)[3] ^ lp32(ibuf)[3];
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
cnt += AES_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
# endif
|
||||
while(cnt + AES_BLOCK_SIZE <= len)
|
||||
{
|
||||
assert(b_pos == 0);
|
||||
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
obuf[ 0] = iv[ 0] ^ ibuf[ 0]; obuf[ 1] = iv[ 1] ^ ibuf[ 1];
|
||||
obuf[ 2] = iv[ 2] ^ ibuf[ 2]; obuf[ 3] = iv[ 3] ^ ibuf[ 3];
|
||||
obuf[ 4] = iv[ 4] ^ ibuf[ 4]; obuf[ 5] = iv[ 5] ^ ibuf[ 5];
|
||||
obuf[ 6] = iv[ 6] ^ ibuf[ 6]; obuf[ 7] = iv[ 7] ^ ibuf[ 7];
|
||||
obuf[ 8] = iv[ 8] ^ ibuf[ 8]; obuf[ 9] = iv[ 9] ^ ibuf[ 9];
|
||||
obuf[10] = iv[10] ^ ibuf[10]; obuf[11] = iv[11] ^ ibuf[11];
|
||||
obuf[12] = iv[12] ^ ibuf[12]; obuf[13] = iv[13] ^ ibuf[13];
|
||||
obuf[14] = iv[14] ^ ibuf[14]; obuf[15] = iv[15] ^ ibuf[15];
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
cnt += AES_BLOCK_SIZE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
while(cnt < len)
|
||||
{
|
||||
if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
while(cnt < len && b_pos < AES_BLOCK_SIZE)
|
||||
{
|
||||
*obuf++ = iv[b_pos++] ^ *ibuf++;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);
|
||||
}
|
||||
|
||||
ctx->inf.b[2] = (uint8_t)b_pos;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#define BFR_LENGTH (BFR_BLOCKS * AES_BLOCK_SIZE)
|
||||
|
||||
AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf,
|
||||
int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx ctx[1])
|
||||
{ unsigned char *ip;
|
||||
int i, blen, b_pos = (int)(ctx->inf.b[2]);
|
||||
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
aligned_auto(uint8_t, buf, BFR_LENGTH, 16);
|
||||
if(ctx->inf.b[1] == 0xff && ALIGN_OFFSET( ctx, 16 ))
|
||||
return EXIT_FAILURE;
|
||||
#else
|
||||
uint8_t buf[BFR_LENGTH];
|
||||
#endif
|
||||
|
||||
if(b_pos)
|
||||
{
|
||||
memcpy(buf, cbuf, AES_BLOCK_SIZE);
|
||||
if(aes_ecb_encrypt(buf, buf, AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
while(b_pos < AES_BLOCK_SIZE && len)
|
||||
{
|
||||
*obuf++ = *ibuf++ ^ buf[b_pos++];
|
||||
--len;
|
||||
}
|
||||
|
||||
if(len)
|
||||
ctr_inc(cbuf), b_pos = 0;
|
||||
}
|
||||
|
||||
while(len)
|
||||
{
|
||||
blen = (len > BFR_LENGTH ? BFR_LENGTH : len), len -= blen;
|
||||
|
||||
for(i = 0, ip = buf; i < (blen >> 4); ++i)
|
||||
{
|
||||
memcpy(ip, cbuf, AES_BLOCK_SIZE);
|
||||
ctr_inc(cbuf);
|
||||
ip += AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
if(blen & (AES_BLOCK_SIZE - 1))
|
||||
memcpy(ip, cbuf, AES_BLOCK_SIZE), i++;
|
||||
|
||||
#if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
if(ctx->inf.b[1] == 0xff)
|
||||
{
|
||||
via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);
|
||||
via_ecb_op5((ctx->ks), cwd, buf, buf, i);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if(aes_ecb_encrypt(buf, buf, i * AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
i = 0; ip = buf;
|
||||
# ifdef FAST_BUFFER_OPERATIONS
|
||||
if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( ip, 4 ))
|
||||
while(i + AES_BLOCK_SIZE <= blen)
|
||||
{
|
||||
lp32(obuf)[0] = lp32(ibuf)[0] ^ lp32(ip)[0];
|
||||
lp32(obuf)[1] = lp32(ibuf)[1] ^ lp32(ip)[1];
|
||||
lp32(obuf)[2] = lp32(ibuf)[2] ^ lp32(ip)[2];
|
||||
lp32(obuf)[3] = lp32(ibuf)[3] ^ lp32(ip)[3];
|
||||
i += AES_BLOCK_SIZE;
|
||||
ip += AES_BLOCK_SIZE;
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
while(i + AES_BLOCK_SIZE <= blen)
|
||||
{
|
||||
obuf[ 0] = ibuf[ 0] ^ ip[ 0]; obuf[ 1] = ibuf[ 1] ^ ip[ 1];
|
||||
obuf[ 2] = ibuf[ 2] ^ ip[ 2]; obuf[ 3] = ibuf[ 3] ^ ip[ 3];
|
||||
obuf[ 4] = ibuf[ 4] ^ ip[ 4]; obuf[ 5] = ibuf[ 5] ^ ip[ 5];
|
||||
obuf[ 6] = ibuf[ 6] ^ ip[ 6]; obuf[ 7] = ibuf[ 7] ^ ip[ 7];
|
||||
obuf[ 8] = ibuf[ 8] ^ ip[ 8]; obuf[ 9] = ibuf[ 9] ^ ip[ 9];
|
||||
obuf[10] = ibuf[10] ^ ip[10]; obuf[11] = ibuf[11] ^ ip[11];
|
||||
obuf[12] = ibuf[12] ^ ip[12]; obuf[13] = ibuf[13] ^ ip[13];
|
||||
obuf[14] = ibuf[14] ^ ip[14]; obuf[15] = ibuf[15] ^ ip[15];
|
||||
i += AES_BLOCK_SIZE;
|
||||
ip += AES_BLOCK_SIZE;
|
||||
ibuf += AES_BLOCK_SIZE;
|
||||
obuf += AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
while(i++ < blen)
|
||||
*obuf++ = *ibuf++ ^ ip[b_pos++];
|
||||
}
|
||||
|
||||
ctx->inf.b[2] = (uint8_t)b_pos;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
|
||||
This file contains the definitions required to use AES (Rijndael) in C++.
|
||||
*/
|
||||
|
||||
#ifndef _AESCPP_H
|
||||
#define _AESCPP_H
|
||||
|
||||
#include "aes.h"
|
||||
|
||||
#if defined( AES_ENCRYPT )
|
||||
|
||||
class AESencrypt
|
||||
{
|
||||
public:
|
||||
aes_encrypt_ctx cx[1];
|
||||
AESencrypt(void) { aes_init1(); };
|
||||
#if defined(AES_128)
|
||||
AESencrypt(const unsigned char key[])
|
||||
{ aes_encrypt_key128(key, cx); }
|
||||
AES_RETURN key128(const unsigned char key[])
|
||||
{ return aes_encrypt_key128(key, cx); }
|
||||
#endif
|
||||
#if defined(AES_192)
|
||||
AES_RETURN key192(const unsigned char key[])
|
||||
{ return aes_encrypt_key192(key, cx); }
|
||||
#endif
|
||||
#if defined(AES_256)
|
||||
AES_RETURN key256(const unsigned char key[])
|
||||
{ return aes_encrypt_key256(key, cx); }
|
||||
#endif
|
||||
#if defined(AES_VAR)
|
||||
AES_RETURN key(const unsigned char key[], int key_len)
|
||||
{ return aes_encrypt_key(key, key_len, cx); }
|
||||
#endif
|
||||
AES_RETURN encrypt(const unsigned char in[], unsigned char out[]) const
|
||||
{ return aes_encrypt(in, out, cx); }
|
||||
#ifndef AES_MODES
|
||||
AES_RETURN ecb_encrypt(const unsigned char in[], unsigned char out[], int nb) const
|
||||
{ while(nb--)
|
||||
{ aes_encrypt(in, out, cx), in += AES_BLOCK_SIZE, out += AES_BLOCK_SIZE; }
|
||||
}
|
||||
#endif
|
||||
#ifdef AES_MODES
|
||||
AES_RETURN mode_reset(void) { return aes_mode_reset(cx); }
|
||||
|
||||
AES_RETURN ecb_encrypt(const unsigned char in[], unsigned char out[], int nb) const
|
||||
{ return aes_ecb_encrypt(in, out, nb, cx); }
|
||||
|
||||
AES_RETURN cbc_encrypt(const unsigned char in[], unsigned char out[], int nb,
|
||||
unsigned char iv[]) const
|
||||
{ return aes_cbc_encrypt(in, out, nb, iv, cx); }
|
||||
|
||||
AES_RETURN cfb_encrypt(const unsigned char in[], unsigned char out[], int nb,
|
||||
unsigned char iv[])
|
||||
{ return aes_cfb_encrypt(in, out, nb, iv, cx); }
|
||||
|
||||
AES_RETURN cfb_decrypt(const unsigned char in[], unsigned char out[], int nb,
|
||||
unsigned char iv[])
|
||||
{ return aes_cfb_decrypt(in, out, nb, iv, cx); }
|
||||
|
||||
AES_RETURN ofb_crypt(const unsigned char in[], unsigned char out[], int nb,
|
||||
unsigned char iv[])
|
||||
{ return aes_ofb_crypt(in, out, nb, iv, cx); }
|
||||
|
||||
typedef void ctr_fn(unsigned char ctr[]);
|
||||
|
||||
AES_RETURN ctr_crypt(const unsigned char in[], unsigned char out[], int nb,
|
||||
unsigned char iv[], ctr_fn cf)
|
||||
{ return aes_ctr_crypt(in, out, nb, iv, cf, cx); }
|
||||
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if defined( AES_DECRYPT )
|
||||
|
||||
class AESdecrypt
|
||||
{
|
||||
public:
|
||||
aes_decrypt_ctx cx[1];
|
||||
AESdecrypt(void) { aes_init1(); };
|
||||
#if defined(AES_128)
|
||||
AESdecrypt(const unsigned char key[])
|
||||
{ aes_decrypt_key128(key, cx); }
|
||||
AES_RETURN key128(const unsigned char key[])
|
||||
{ return aes_decrypt_key128(key, cx); }
|
||||
#endif
|
||||
#if defined(AES_192)
|
||||
AES_RETURN key192(const unsigned char key[])
|
||||
{ return aes_decrypt_key192(key, cx); }
|
||||
#endif
|
||||
#if defined(AES_256)
|
||||
AES_RETURN key256(const unsigned char key[])
|
||||
{ return aes_decrypt_key256(key, cx); }
|
||||
#endif
|
||||
#if defined(AES_VAR)
|
||||
AES_RETURN key(const unsigned char key[], int key_len)
|
||||
{ return aes_decrypt_key(key, key_len, cx); }
|
||||
#endif
|
||||
AES_RETURN decrypt(const unsigned char in[], unsigned char out[]) const
|
||||
{ return aes_decrypt(in, out, cx); }
|
||||
#ifndef AES_MODES
|
||||
AES_RETURN ecb_decrypt(const unsigned char in[], unsigned char out[], int nb) const
|
||||
{ while(nb--)
|
||||
{ aes_decrypt(in, out, cx), in += AES_BLOCK_SIZE, out += AES_BLOCK_SIZE; }
|
||||
}
|
||||
#endif
|
||||
#ifdef AES_MODES
|
||||
|
||||
AES_RETURN ecb_decrypt(const unsigned char in[], unsigned char out[], int nb) const
|
||||
{ return aes_ecb_decrypt(in, out, nb, cx); }
|
||||
|
||||
AES_RETURN cbc_decrypt(const unsigned char in[], unsigned char out[], int nb,
|
||||
unsigned char iv[]) const
|
||||
{ return aes_cbc_decrypt(in, out, nb, iv, cx); }
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
*/
|
||||
|
||||
#include "aesopt.h"
|
||||
#include "aestab.h"
|
||||
|
||||
#if defined( USE_INTEL_AES_IF_PRESENT )
|
||||
#include <aes/aesaes_ni.h>
|
||||
#else
|
||||
/* map names here to provide the external API ('name' -> 'aes_name') */
|
||||
# define aes_xi(x) aes_ ## x
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#define si(y,x,k,c) (s(y,c) = word_in(x, c) ^ (k)[c])
|
||||
#define so(y,x,c) word_out(y, c, s(x,c))
|
||||
|
||||
#if defined(ARRAYS)
|
||||
#define locals(y,x) x[4],y[4]
|
||||
#else
|
||||
#define locals(y,x) x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3
|
||||
#endif
|
||||
|
||||
#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \
|
||||
s(y,2) = s(x,2); s(y,3) = s(x,3);
|
||||
#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3)
|
||||
#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3)
|
||||
#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3)
|
||||
|
||||
#if ( FUNCS_IN_C & ENCRYPTION_IN_C )
|
||||
|
||||
/* Visual C++ .Net v7.1 provides the fastest encryption code when using
|
||||
Pentium optimiation with small code but this is poor for decryption
|
||||
so we need to control this with the following VC++ pragmas
|
||||
*/
|
||||
|
||||
#if defined( _WIN32 ) && !defined( _WIN64 )
|
||||
#pragma optimize( "s", on )
|
||||
#endif
|
||||
|
||||
/* Given the column (c) of the output state variable, the following
|
||||
macros give the input state variables which are needed in its
|
||||
computation for each row (r) of the state. All the alternative
|
||||
macros give the same end values but expand into different ways
|
||||
of calculating these values. In particular the complex macro
|
||||
used for dynamically variable block sizes is designed to expand
|
||||
to a compile time constant whenever possible but will expand to
|
||||
conditional clauses on some branches (I am grateful to Frank
|
||||
Yellin for this construction)
|
||||
*/
|
||||
|
||||
#define fwd_var(x,r,c)\
|
||||
( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\
|
||||
: r == 1 ? ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))\
|
||||
: r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\
|
||||
: ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2)))
|
||||
|
||||
#if defined(FT4_SET)
|
||||
#undef dec_fmvars
|
||||
#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,n),fwd_var,rf1,c))
|
||||
#elif defined(FT1_SET)
|
||||
#undef dec_fmvars
|
||||
#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(f,n),fwd_var,rf1,c))
|
||||
#else
|
||||
#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ fwd_mcol(no_table(x,t_use(s,box),fwd_var,rf1,c)))
|
||||
#endif
|
||||
|
||||
#if defined(FL4_SET)
|
||||
#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,l),fwd_var,rf1,c))
|
||||
#elif defined(FL1_SET)
|
||||
#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(f,l),fwd_var,rf1,c))
|
||||
#else
|
||||
#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(s,box),fwd_var,rf1,c))
|
||||
#endif
|
||||
|
||||
AES_RETURN aes_xi(encrypt)(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1])
|
||||
{ uint32_t locals(b0, b1);
|
||||
const uint32_t *kp;
|
||||
#if defined( dec_fmvars )
|
||||
dec_fmvars; /* declare variables for fwd_mcol() if needed */
|
||||
#endif
|
||||
|
||||
if(cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
kp = cx->ks;
|
||||
state_in(b0, in, kp);
|
||||
|
||||
#if (ENC_UNROLL == FULL)
|
||||
|
||||
switch(cx->inf.b[0])
|
||||
{
|
||||
case 14 * 16:
|
||||
round(fwd_rnd, b1, b0, kp + 1 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 2 * N_COLS);
|
||||
kp += 2 * N_COLS;
|
||||
case 12 * 16:
|
||||
round(fwd_rnd, b1, b0, kp + 1 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 2 * N_COLS);
|
||||
kp += 2 * N_COLS;
|
||||
case 10 * 16:
|
||||
round(fwd_rnd, b1, b0, kp + 1 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 2 * N_COLS);
|
||||
round(fwd_rnd, b1, b0, kp + 3 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 4 * N_COLS);
|
||||
round(fwd_rnd, b1, b0, kp + 5 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 6 * N_COLS);
|
||||
round(fwd_rnd, b1, b0, kp + 7 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 8 * N_COLS);
|
||||
round(fwd_rnd, b1, b0, kp + 9 * N_COLS);
|
||||
round(fwd_lrnd, b0, b1, kp +10 * N_COLS);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#if (ENC_UNROLL == PARTIAL)
|
||||
{ uint32_t rnd;
|
||||
for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd)
|
||||
{
|
||||
kp += N_COLS;
|
||||
round(fwd_rnd, b1, b0, kp);
|
||||
kp += N_COLS;
|
||||
round(fwd_rnd, b0, b1, kp);
|
||||
}
|
||||
kp += N_COLS;
|
||||
round(fwd_rnd, b1, b0, kp);
|
||||
#else
|
||||
{ uint32_t rnd;
|
||||
for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd)
|
||||
{
|
||||
kp += N_COLS;
|
||||
round(fwd_rnd, b1, b0, kp);
|
||||
l_copy(b0, b1);
|
||||
}
|
||||
#endif
|
||||
kp += N_COLS;
|
||||
round(fwd_lrnd, b0, b1, kp);
|
||||
}
|
||||
#endif
|
||||
|
||||
state_out(out, b0);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if ( FUNCS_IN_C & DECRYPTION_IN_C)
|
||||
|
||||
/* Visual C++ .Net v7.1 provides the fastest encryption code when using
|
||||
Pentium optimiation with small code but this is poor for decryption
|
||||
so we need to control this with the following VC++ pragmas
|
||||
*/
|
||||
|
||||
#if defined( _WIN32 ) && !defined( _WIN64 )
|
||||
#pragma optimize( "t", on )
|
||||
#endif
|
||||
|
||||
/* Given the column (c) of the output state variable, the following
|
||||
macros give the input state variables which are needed in its
|
||||
computation for each row (r) of the state. All the alternative
|
||||
macros give the same end values but expand into different ways
|
||||
of calculating these values. In particular the complex macro
|
||||
used for dynamically variable block sizes is designed to expand
|
||||
to a compile time constant whenever possible but will expand to
|
||||
conditional clauses on some branches (I am grateful to Frank
|
||||
Yellin for this construction)
|
||||
*/
|
||||
|
||||
#define inv_var(x,r,c)\
|
||||
( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\
|
||||
: r == 1 ? ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))\
|
||||
: r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\
|
||||
: ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0)))
|
||||
|
||||
#if defined(IT4_SET)
|
||||
#undef dec_imvars
|
||||
#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,n),inv_var,rf1,c))
|
||||
#elif defined(IT1_SET)
|
||||
#undef dec_imvars
|
||||
#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(i,n),inv_var,rf1,c))
|
||||
#else
|
||||
#define inv_rnd(y,x,k,c) (s(y,c) = inv_mcol((k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c)))
|
||||
#endif
|
||||
|
||||
#if defined(IL4_SET)
|
||||
#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,l),inv_var,rf1,c))
|
||||
#elif defined(IL1_SET)
|
||||
#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(i,l),inv_var,rf1,c))
|
||||
#else
|
||||
#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c))
|
||||
#endif
|
||||
|
||||
/* This code can work with the decryption key schedule in the */
|
||||
/* order that is used for encrytpion (where the 1st decryption */
|
||||
/* round key is at the high end ot the schedule) or with a key */
|
||||
/* schedule that has been reversed to put the 1st decryption */
|
||||
/* round key at the low end of the schedule in memory (when */
|
||||
/* AES_REV_DKS is defined) */
|
||||
|
||||
#ifdef AES_REV_DKS
|
||||
#define key_ofs 0
|
||||
#define rnd_key(n) (kp + n * N_COLS)
|
||||
#else
|
||||
#define key_ofs 1
|
||||
#define rnd_key(n) (kp - n * N_COLS)
|
||||
#endif
|
||||
|
||||
AES_RETURN aes_xi(decrypt)(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1])
|
||||
{ uint32_t locals(b0, b1);
|
||||
#if defined( dec_imvars )
|
||||
dec_imvars; /* declare variables for inv_mcol() if needed */
|
||||
#endif
|
||||
const uint32_t *kp;
|
||||
|
||||
if(cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
kp = cx->ks + (key_ofs ? (cx->inf.b[0] >> 2) : 0);
|
||||
state_in(b0, in, kp);
|
||||
|
||||
#if (DEC_UNROLL == FULL)
|
||||
|
||||
kp = cx->ks + (key_ofs ? 0 : (cx->inf.b[0] >> 2));
|
||||
switch(cx->inf.b[0])
|
||||
{
|
||||
case 14 * 16:
|
||||
round(inv_rnd, b1, b0, rnd_key(-13));
|
||||
round(inv_rnd, b0, b1, rnd_key(-12));
|
||||
case 12 * 16:
|
||||
round(inv_rnd, b1, b0, rnd_key(-11));
|
||||
round(inv_rnd, b0, b1, rnd_key(-10));
|
||||
case 10 * 16:
|
||||
round(inv_rnd, b1, b0, rnd_key(-9));
|
||||
round(inv_rnd, b0, b1, rnd_key(-8));
|
||||
round(inv_rnd, b1, b0, rnd_key(-7));
|
||||
round(inv_rnd, b0, b1, rnd_key(-6));
|
||||
round(inv_rnd, b1, b0, rnd_key(-5));
|
||||
round(inv_rnd, b0, b1, rnd_key(-4));
|
||||
round(inv_rnd, b1, b0, rnd_key(-3));
|
||||
round(inv_rnd, b0, b1, rnd_key(-2));
|
||||
round(inv_rnd, b1, b0, rnd_key(-1));
|
||||
round(inv_lrnd, b0, b1, rnd_key( 0));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#if (DEC_UNROLL == PARTIAL)
|
||||
{ uint32_t rnd;
|
||||
for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd)
|
||||
{
|
||||
kp = rnd_key(1);
|
||||
round(inv_rnd, b1, b0, kp);
|
||||
kp = rnd_key(1);
|
||||
round(inv_rnd, b0, b1, kp);
|
||||
}
|
||||
kp = rnd_key(1);
|
||||
round(inv_rnd, b1, b0, kp);
|
||||
#else
|
||||
{ uint32_t rnd;
|
||||
for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd)
|
||||
{
|
||||
kp = rnd_key(1);
|
||||
round(inv_rnd, b1, b0, kp);
|
||||
l_copy(b0, b1);
|
||||
}
|
||||
#endif
|
||||
kp = rnd_key(1);
|
||||
round(inv_lrnd, b0, b1, kp);
|
||||
}
|
||||
#endif
|
||||
|
||||
state_out(out, b0);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,554 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
*/
|
||||
|
||||
#include "aesopt.h"
|
||||
#include "aestab.h"
|
||||
|
||||
#if defined( USE_INTEL_AES_IF_PRESENT )
|
||||
# include "aes_ni.h"
|
||||
#else
|
||||
/* map names here to provide the external API ('name' -> 'aes_name') */
|
||||
# define aes_xi(x) aes_ ## x
|
||||
#endif
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
# include "aes_via_ace.h"
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* Initialise the key schedule from the user supplied key. The key
|
||||
length can be specified in bytes, with legal values of 16, 24
|
||||
and 32, or in bits, with legal values of 128, 192 and 256. These
|
||||
values correspond with Nk values of 4, 6 and 8 respectively.
|
||||
|
||||
The following macros implement a single cycle in the key
|
||||
schedule generation process. The number of cycles needed
|
||||
for each cx->n_col and nk value is:
|
||||
|
||||
nk = 4 5 6 7 8
|
||||
------------------------------
|
||||
cx->n_col = 4 10 9 8 7 7
|
||||
cx->n_col = 5 14 11 10 9 9
|
||||
cx->n_col = 6 19 15 12 11 11
|
||||
cx->n_col = 7 21 19 16 13 14
|
||||
cx->n_col = 8 29 23 19 17 14
|
||||
*/
|
||||
|
||||
#if defined( REDUCE_CODE_SIZE )
|
||||
# define ls_box ls_sub
|
||||
uint32_t ls_sub(const uint32_t t, const uint32_t n);
|
||||
# define inv_mcol im_sub
|
||||
uint32_t im_sub(const uint32_t x);
|
||||
# ifdef ENC_KS_UNROLL
|
||||
# undef ENC_KS_UNROLL
|
||||
# endif
|
||||
# ifdef DEC_KS_UNROLL
|
||||
# undef DEC_KS_UNROLL
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if (FUNCS_IN_C & ENC_KEYING_IN_C)
|
||||
|
||||
#if defined(AES_128) || defined( AES_VAR )
|
||||
|
||||
#define ke4(k,i) \
|
||||
{ k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \
|
||||
k[4*(i)+5] = ss[1] ^= ss[0]; \
|
||||
k[4*(i)+6] = ss[2] ^= ss[1]; \
|
||||
k[4*(i)+7] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
AES_RETURN aes_xi(encrypt_key128)(const unsigned char *key, aes_encrypt_ctx cx[1])
|
||||
{ uint32_t ss[4];
|
||||
|
||||
cx->ks[0] = ss[0] = word_in(key, 0);
|
||||
cx->ks[1] = ss[1] = word_in(key, 1);
|
||||
cx->ks[2] = ss[2] = word_in(key, 2);
|
||||
cx->ks[3] = ss[3] = word_in(key, 3);
|
||||
|
||||
#ifdef ENC_KS_UNROLL
|
||||
ke4(cx->ks, 0); ke4(cx->ks, 1);
|
||||
ke4(cx->ks, 2); ke4(cx->ks, 3);
|
||||
ke4(cx->ks, 4); ke4(cx->ks, 5);
|
||||
ke4(cx->ks, 6); ke4(cx->ks, 7);
|
||||
ke4(cx->ks, 8);
|
||||
#else
|
||||
{ uint32_t i;
|
||||
for(i = 0; i < 9; ++i)
|
||||
ke4(cx->ks, i);
|
||||
}
|
||||
#endif
|
||||
ke4(cx->ks, 9);
|
||||
cx->inf.l = 0;
|
||||
cx->inf.b[0] = 10 * 16;
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
if(VIA_ACE_AVAILABLE)
|
||||
cx->inf.b[1] = 0xff;
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_192) || defined( AES_VAR )
|
||||
|
||||
#define kef6(k,i) \
|
||||
{ k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \
|
||||
k[6*(i)+ 7] = ss[1] ^= ss[0]; \
|
||||
k[6*(i)+ 8] = ss[2] ^= ss[1]; \
|
||||
k[6*(i)+ 9] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#define ke6(k,i) \
|
||||
{ kef6(k,i); \
|
||||
k[6*(i)+10] = ss[4] ^= ss[3]; \
|
||||
k[6*(i)+11] = ss[5] ^= ss[4]; \
|
||||
}
|
||||
|
||||
AES_RETURN aes_xi(encrypt_key192)(const unsigned char *key, aes_encrypt_ctx cx[1])
|
||||
{ uint32_t ss[6];
|
||||
|
||||
cx->ks[0] = ss[0] = word_in(key, 0);
|
||||
cx->ks[1] = ss[1] = word_in(key, 1);
|
||||
cx->ks[2] = ss[2] = word_in(key, 2);
|
||||
cx->ks[3] = ss[3] = word_in(key, 3);
|
||||
cx->ks[4] = ss[4] = word_in(key, 4);
|
||||
cx->ks[5] = ss[5] = word_in(key, 5);
|
||||
|
||||
#ifdef ENC_KS_UNROLL
|
||||
ke6(cx->ks, 0); ke6(cx->ks, 1);
|
||||
ke6(cx->ks, 2); ke6(cx->ks, 3);
|
||||
ke6(cx->ks, 4); ke6(cx->ks, 5);
|
||||
ke6(cx->ks, 6);
|
||||
#else
|
||||
{ uint32_t i;
|
||||
for(i = 0; i < 7; ++i)
|
||||
ke6(cx->ks, i);
|
||||
}
|
||||
#endif
|
||||
kef6(cx->ks, 7);
|
||||
cx->inf.l = 0;
|
||||
cx->inf.b[0] = 12 * 16;
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
if(VIA_ACE_AVAILABLE)
|
||||
cx->inf.b[1] = 0xff;
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_256) || defined( AES_VAR )
|
||||
|
||||
#define kef8(k,i) \
|
||||
{ k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \
|
||||
k[8*(i)+ 9] = ss[1] ^= ss[0]; \
|
||||
k[8*(i)+10] = ss[2] ^= ss[1]; \
|
||||
k[8*(i)+11] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#define ke8(k,i) \
|
||||
{ kef8(k,i); \
|
||||
k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0); \
|
||||
k[8*(i)+13] = ss[5] ^= ss[4]; \
|
||||
k[8*(i)+14] = ss[6] ^= ss[5]; \
|
||||
k[8*(i)+15] = ss[7] ^= ss[6]; \
|
||||
}
|
||||
|
||||
AES_RETURN aes_xi(encrypt_key256)(const unsigned char *key, aes_encrypt_ctx cx[1])
|
||||
{ uint32_t ss[8];
|
||||
|
||||
cx->ks[0] = ss[0] = word_in(key, 0);
|
||||
cx->ks[1] = ss[1] = word_in(key, 1);
|
||||
cx->ks[2] = ss[2] = word_in(key, 2);
|
||||
cx->ks[3] = ss[3] = word_in(key, 3);
|
||||
cx->ks[4] = ss[4] = word_in(key, 4);
|
||||
cx->ks[5] = ss[5] = word_in(key, 5);
|
||||
cx->ks[6] = ss[6] = word_in(key, 6);
|
||||
cx->ks[7] = ss[7] = word_in(key, 7);
|
||||
|
||||
#ifdef ENC_KS_UNROLL
|
||||
ke8(cx->ks, 0); ke8(cx->ks, 1);
|
||||
ke8(cx->ks, 2); ke8(cx->ks, 3);
|
||||
ke8(cx->ks, 4); ke8(cx->ks, 5);
|
||||
#else
|
||||
{ uint32_t i;
|
||||
for(i = 0; i < 6; ++i)
|
||||
ke8(cx->ks, i);
|
||||
}
|
||||
#endif
|
||||
kef8(cx->ks, 6);
|
||||
cx->inf.l = 0;
|
||||
cx->inf.b[0] = 14 * 16;
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
if(VIA_ACE_AVAILABLE)
|
||||
cx->inf.b[1] = 0xff;
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if (FUNCS_IN_C & DEC_KEYING_IN_C)
|
||||
|
||||
/* this is used to store the decryption round keys */
|
||||
/* in forward or reverse order */
|
||||
|
||||
#ifdef AES_REV_DKS
|
||||
#define v(n,i) ((n) - (i) + 2 * ((i) & 3))
|
||||
#else
|
||||
#define v(n,i) (i)
|
||||
#endif
|
||||
|
||||
#if DEC_ROUND == NO_TABLES
|
||||
#define ff(x) (x)
|
||||
#else
|
||||
#define ff(x) inv_mcol(x)
|
||||
#if defined( dec_imvars )
|
||||
#define d_vars dec_imvars
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(AES_128) || defined( AES_VAR )
|
||||
|
||||
#define k4e(k,i) \
|
||||
{ k[v(40,(4*(i))+4)] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \
|
||||
k[v(40,(4*(i))+5)] = ss[1] ^= ss[0]; \
|
||||
k[v(40,(4*(i))+6)] = ss[2] ^= ss[1]; \
|
||||
k[v(40,(4*(i))+7)] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#if 1
|
||||
|
||||
#define kdf4(k,i) \
|
||||
{ ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; \
|
||||
ss[1] = ss[1] ^ ss[3]; \
|
||||
ss[2] = ss[2] ^ ss[3]; \
|
||||
ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \
|
||||
ss[i % 4] ^= ss[4]; \
|
||||
ss[4] ^= k[v(40,(4*(i)))]; k[v(40,(4*(i))+4)] = ff(ss[4]); \
|
||||
ss[4] ^= k[v(40,(4*(i))+1)]; k[v(40,(4*(i))+5)] = ff(ss[4]); \
|
||||
ss[4] ^= k[v(40,(4*(i))+2)]; k[v(40,(4*(i))+6)] = ff(ss[4]); \
|
||||
ss[4] ^= k[v(40,(4*(i))+3)]; k[v(40,(4*(i))+7)] = ff(ss[4]); \
|
||||
}
|
||||
|
||||
#define kd4(k,i) \
|
||||
{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \
|
||||
ss[i % 4] ^= ss[4]; ss[4] = ff(ss[4]); \
|
||||
k[v(40,(4*(i))+4)] = ss[4] ^= k[v(40,(4*(i)))]; \
|
||||
k[v(40,(4*(i))+5)] = ss[4] ^= k[v(40,(4*(i))+1)]; \
|
||||
k[v(40,(4*(i))+6)] = ss[4] ^= k[v(40,(4*(i))+2)]; \
|
||||
k[v(40,(4*(i))+7)] = ss[4] ^= k[v(40,(4*(i))+3)]; \
|
||||
}
|
||||
|
||||
#define kdl4(k,i) \
|
||||
{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; ss[i % 4] ^= ss[4]; \
|
||||
k[v(40,(4*(i))+4)] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; \
|
||||
k[v(40,(4*(i))+5)] = ss[1] ^ ss[3]; \
|
||||
k[v(40,(4*(i))+6)] = ss[0]; \
|
||||
k[v(40,(4*(i))+7)] = ss[1]; \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define kdf4(k,i) \
|
||||
{ ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ff(ss[0]); \
|
||||
ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ff(ss[1]); \
|
||||
ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ff(ss[2]); \
|
||||
ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ff(ss[3]); \
|
||||
}
|
||||
|
||||
#define kd4(k,i) \
|
||||
{ ss[4] = ls_box(ss[3],3) ^ t_use(r,c)[i]; \
|
||||
ss[0] ^= ss[4]; ss[4] = ff(ss[4]); k[v(40,(4*(i))+ 4)] = ss[4] ^= k[v(40,(4*(i)))]; \
|
||||
ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[4] ^= k[v(40,(4*(i))+ 1)]; \
|
||||
ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[4] ^= k[v(40,(4*(i))+ 2)]; \
|
||||
ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[4] ^= k[v(40,(4*(i))+ 3)]; \
|
||||
}
|
||||
|
||||
#define kdl4(k,i) \
|
||||
{ ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ss[0]; \
|
||||
ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[1]; \
|
||||
ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[2]; \
|
||||
ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[3]; \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
AES_RETURN aes_xi(decrypt_key128)(const unsigned char *key, aes_decrypt_ctx cx[1])
|
||||
{ uint32_t ss[5];
|
||||
#if defined( d_vars )
|
||||
d_vars;
|
||||
#endif
|
||||
|
||||
cx->ks[v(40,(0))] = ss[0] = word_in(key, 0);
|
||||
cx->ks[v(40,(1))] = ss[1] = word_in(key, 1);
|
||||
cx->ks[v(40,(2))] = ss[2] = word_in(key, 2);
|
||||
cx->ks[v(40,(3))] = ss[3] = word_in(key, 3);
|
||||
|
||||
#ifdef DEC_KS_UNROLL
|
||||
kdf4(cx->ks, 0); kd4(cx->ks, 1);
|
||||
kd4(cx->ks, 2); kd4(cx->ks, 3);
|
||||
kd4(cx->ks, 4); kd4(cx->ks, 5);
|
||||
kd4(cx->ks, 6); kd4(cx->ks, 7);
|
||||
kd4(cx->ks, 8); kdl4(cx->ks, 9);
|
||||
#else
|
||||
{ uint32_t i;
|
||||
for(i = 0; i < 10; ++i)
|
||||
k4e(cx->ks, i);
|
||||
#if !(DEC_ROUND == NO_TABLES)
|
||||
for(i = N_COLS; i < 10 * N_COLS; ++i)
|
||||
cx->ks[i] = inv_mcol(cx->ks[i]);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
cx->inf.l = 0;
|
||||
cx->inf.b[0] = 10 * 16;
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
if(VIA_ACE_AVAILABLE)
|
||||
cx->inf.b[1] = 0xff;
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_192) || defined( AES_VAR )
|
||||
|
||||
#define k6ef(k,i) \
|
||||
{ k[v(48,(6*(i))+ 6)] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \
|
||||
k[v(48,(6*(i))+ 7)] = ss[1] ^= ss[0]; \
|
||||
k[v(48,(6*(i))+ 8)] = ss[2] ^= ss[1]; \
|
||||
k[v(48,(6*(i))+ 9)] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#define k6e(k,i) \
|
||||
{ k6ef(k,i); \
|
||||
k[v(48,(6*(i))+10)] = ss[4] ^= ss[3]; \
|
||||
k[v(48,(6*(i))+11)] = ss[5] ^= ss[4]; \
|
||||
}
|
||||
|
||||
#define kdf6(k,i) \
|
||||
{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ff(ss[0]); \
|
||||
ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ff(ss[1]); \
|
||||
ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ff(ss[2]); \
|
||||
ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ff(ss[3]); \
|
||||
ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ff(ss[4]); \
|
||||
ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ff(ss[5]); \
|
||||
}
|
||||
|
||||
#define kd6(k,i) \
|
||||
{ ss[6] = ls_box(ss[5],3) ^ t_use(r,c)[i]; \
|
||||
ss[0] ^= ss[6]; ss[6] = ff(ss[6]); k[v(48,(6*(i))+ 6)] = ss[6] ^= k[v(48,(6*(i)))]; \
|
||||
ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[6] ^= k[v(48,(6*(i))+ 1)]; \
|
||||
ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[6] ^= k[v(48,(6*(i))+ 2)]; \
|
||||
ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[6] ^= k[v(48,(6*(i))+ 3)]; \
|
||||
ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ss[6] ^= k[v(48,(6*(i))+ 4)]; \
|
||||
ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ss[6] ^= k[v(48,(6*(i))+ 5)]; \
|
||||
}
|
||||
|
||||
#define kdl6(k,i) \
|
||||
{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ss[0]; \
|
||||
ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[1]; \
|
||||
ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[2]; \
|
||||
ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[3]; \
|
||||
}
|
||||
|
||||
AES_RETURN aes_xi(decrypt_key192)(const unsigned char *key, aes_decrypt_ctx cx[1])
|
||||
{ uint32_t ss[7];
|
||||
#if defined( d_vars )
|
||||
d_vars;
|
||||
#endif
|
||||
|
||||
cx->ks[v(48,(0))] = ss[0] = word_in(key, 0);
|
||||
cx->ks[v(48,(1))] = ss[1] = word_in(key, 1);
|
||||
cx->ks[v(48,(2))] = ss[2] = word_in(key, 2);
|
||||
cx->ks[v(48,(3))] = ss[3] = word_in(key, 3);
|
||||
|
||||
#ifdef DEC_KS_UNROLL
|
||||
cx->ks[v(48,(4))] = ff(ss[4] = word_in(key, 4));
|
||||
cx->ks[v(48,(5))] = ff(ss[5] = word_in(key, 5));
|
||||
kdf6(cx->ks, 0); kd6(cx->ks, 1);
|
||||
kd6(cx->ks, 2); kd6(cx->ks, 3);
|
||||
kd6(cx->ks, 4); kd6(cx->ks, 5);
|
||||
kd6(cx->ks, 6); kdl6(cx->ks, 7);
|
||||
#else
|
||||
cx->ks[v(48,(4))] = ss[4] = word_in(key, 4);
|
||||
cx->ks[v(48,(5))] = ss[5] = word_in(key, 5);
|
||||
{ uint32_t i;
|
||||
|
||||
for(i = 0; i < 7; ++i)
|
||||
k6e(cx->ks, i);
|
||||
k6ef(cx->ks, 7);
|
||||
#if !(DEC_ROUND == NO_TABLES)
|
||||
for(i = N_COLS; i < 12 * N_COLS; ++i)
|
||||
cx->ks[i] = inv_mcol(cx->ks[i]);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
cx->inf.l = 0;
|
||||
cx->inf.b[0] = 12 * 16;
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
if(VIA_ACE_AVAILABLE)
|
||||
cx->inf.b[1] = 0xff;
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_256) || defined( AES_VAR )
|
||||
|
||||
#define k8ef(k,i) \
|
||||
{ k[v(56,(8*(i))+ 8)] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \
|
||||
k[v(56,(8*(i))+ 9)] = ss[1] ^= ss[0]; \
|
||||
k[v(56,(8*(i))+10)] = ss[2] ^= ss[1]; \
|
||||
k[v(56,(8*(i))+11)] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#define k8e(k,i) \
|
||||
{ k8ef(k,i); \
|
||||
k[v(56,(8*(i))+12)] = ss[4] ^= ls_box(ss[3],0); \
|
||||
k[v(56,(8*(i))+13)] = ss[5] ^= ss[4]; \
|
||||
k[v(56,(8*(i))+14)] = ss[6] ^= ss[5]; \
|
||||
k[v(56,(8*(i))+15)] = ss[7] ^= ss[6]; \
|
||||
}
|
||||
|
||||
#define kdf8(k,i) \
|
||||
{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ff(ss[0]); \
|
||||
ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ff(ss[1]); \
|
||||
ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ff(ss[2]); \
|
||||
ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ff(ss[3]); \
|
||||
ss[4] ^= ls_box(ss[3],0); k[v(56,(8*(i))+12)] = ff(ss[4]); \
|
||||
ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ff(ss[5]); \
|
||||
ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ff(ss[6]); \
|
||||
ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ff(ss[7]); \
|
||||
}
|
||||
|
||||
#define kd8(k,i) \
|
||||
{ ss[8] = ls_box(ss[7],3) ^ t_use(r,c)[i]; \
|
||||
ss[0] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+ 8)] = ss[8] ^= k[v(56,(8*(i)))]; \
|
||||
ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[8] ^= k[v(56,(8*(i))+ 1)]; \
|
||||
ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[8] ^= k[v(56,(8*(i))+ 2)]; \
|
||||
ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[8] ^= k[v(56,(8*(i))+ 3)]; \
|
||||
ss[8] = ls_box(ss[3],0); \
|
||||
ss[4] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+12)] = ss[8] ^= k[v(56,(8*(i))+ 4)]; \
|
||||
ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ss[8] ^= k[v(56,(8*(i))+ 5)]; \
|
||||
ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ss[8] ^= k[v(56,(8*(i))+ 6)]; \
|
||||
ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ss[8] ^= k[v(56,(8*(i))+ 7)]; \
|
||||
}
|
||||
|
||||
#define kdl8(k,i) \
|
||||
{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ss[0]; \
|
||||
ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[1]; \
|
||||
ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[2]; \
|
||||
ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[3]; \
|
||||
}
|
||||
|
||||
AES_RETURN aes_xi(decrypt_key256)(const unsigned char *key, aes_decrypt_ctx cx[1])
|
||||
{ uint32_t ss[9];
|
||||
#if defined( d_vars )
|
||||
d_vars;
|
||||
#endif
|
||||
|
||||
cx->ks[v(56,(0))] = ss[0] = word_in(key, 0);
|
||||
cx->ks[v(56,(1))] = ss[1] = word_in(key, 1);
|
||||
cx->ks[v(56,(2))] = ss[2] = word_in(key, 2);
|
||||
cx->ks[v(56,(3))] = ss[3] = word_in(key, 3);
|
||||
|
||||
#ifdef DEC_KS_UNROLL
|
||||
cx->ks[v(56,(4))] = ff(ss[4] = word_in(key, 4));
|
||||
cx->ks[v(56,(5))] = ff(ss[5] = word_in(key, 5));
|
||||
cx->ks[v(56,(6))] = ff(ss[6] = word_in(key, 6));
|
||||
cx->ks[v(56,(7))] = ff(ss[7] = word_in(key, 7));
|
||||
kdf8(cx->ks, 0); kd8(cx->ks, 1);
|
||||
kd8(cx->ks, 2); kd8(cx->ks, 3);
|
||||
kd8(cx->ks, 4); kd8(cx->ks, 5);
|
||||
kdl8(cx->ks, 6);
|
||||
#else
|
||||
cx->ks[v(56,(4))] = ss[4] = word_in(key, 4);
|
||||
cx->ks[v(56,(5))] = ss[5] = word_in(key, 5);
|
||||
cx->ks[v(56,(6))] = ss[6] = word_in(key, 6);
|
||||
cx->ks[v(56,(7))] = ss[7] = word_in(key, 7);
|
||||
{ uint32_t i;
|
||||
|
||||
for(i = 0; i < 6; ++i)
|
||||
k8e(cx->ks, i);
|
||||
k8ef(cx->ks, 6);
|
||||
#if !(DEC_ROUND == NO_TABLES)
|
||||
for(i = N_COLS; i < 14 * N_COLS; ++i)
|
||||
cx->ks[i] = inv_mcol(cx->ks[i]);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
cx->inf.l = 0;
|
||||
cx->inf.b[0] = 14 * 16;
|
||||
|
||||
#ifdef USE_VIA_ACE_IF_PRESENT
|
||||
if(VIA_ACE_AVAILABLE)
|
||||
cx->inf.b[1] = 0xff;
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined( AES_VAR )
|
||||
|
||||
AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1])
|
||||
{
|
||||
switch(key_len)
|
||||
{
|
||||
case 16: case 128: return aes_encrypt_key128(key, cx);
|
||||
case 24: case 192: return aes_encrypt_key192(key, cx);
|
||||
case 32: case 256: return aes_encrypt_key256(key, cx);
|
||||
default: return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1])
|
||||
{
|
||||
switch(key_len)
|
||||
{
|
||||
case 16: case 128: return aes_decrypt_key128(key, cx);
|
||||
case 24: case 192: return aes_decrypt_key192(key, cx);
|
||||
case 32: case 256: return aes_decrypt_key256(key, cx);
|
||||
default: return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,769 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
|
||||
This file contains the compilation options for AES (Rijndael) and code
|
||||
that is common across encryption, key scheduling and table generation.
|
||||
|
||||
OPERATION
|
||||
|
||||
These source code files implement the AES algorithm Rijndael designed by
|
||||
Joan Daemen and Vincent Rijmen. This version is designed for the standard
|
||||
block size of 16 bytes and for key sizes of 128, 192 and 256 bits (16, 24
|
||||
and 32 bytes).
|
||||
|
||||
This version is designed for flexibility and speed using operations on
|
||||
32-bit words rather than operations on bytes. It can be compiled with
|
||||
either big or little endian internal byte order but is faster when the
|
||||
native byte order for the processor is used.
|
||||
|
||||
THE CIPHER INTERFACE
|
||||
|
||||
The cipher interface is implemented as an array of bytes in which lower
|
||||
AES bit sequence indexes map to higher numeric significance within bytes.
|
||||
|
||||
uint8_t (an unsigned 8-bit type)
|
||||
uint32_t (an unsigned 32-bit type)
|
||||
struct aes_encrypt_ctx (structure for the cipher encryption context)
|
||||
struct aes_decrypt_ctx (structure for the cipher decryption context)
|
||||
AES_RETURN the function return type
|
||||
|
||||
C subroutine calls:
|
||||
|
||||
AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]);
|
||||
AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]);
|
||||
AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]);
|
||||
AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out,
|
||||
const aes_encrypt_ctx cx[1]);
|
||||
|
||||
AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]);
|
||||
AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]);
|
||||
AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]);
|
||||
AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out,
|
||||
const aes_decrypt_ctx cx[1]);
|
||||
|
||||
IMPORTANT NOTE: If you are using this C interface with dynamic tables make sure that
|
||||
you call aes_init() before AES is used so that the tables are initialised.
|
||||
|
||||
C++ aes class subroutines:
|
||||
|
||||
Class AESencrypt for encryption
|
||||
|
||||
Construtors:
|
||||
AESencrypt(void)
|
||||
AESencrypt(const unsigned char *key) - 128 bit key
|
||||
Members:
|
||||
AES_RETURN key128(const unsigned char *key)
|
||||
AES_RETURN key192(const unsigned char *key)
|
||||
AES_RETURN key256(const unsigned char *key)
|
||||
AES_RETURN encrypt(const unsigned char *in, unsigned char *out) const
|
||||
|
||||
Class AESdecrypt for encryption
|
||||
Construtors:
|
||||
AESdecrypt(void)
|
||||
AESdecrypt(const unsigned char *key) - 128 bit key
|
||||
Members:
|
||||
AES_RETURN key128(const unsigned char *key)
|
||||
AES_RETURN key192(const unsigned char *key)
|
||||
AES_RETURN key256(const unsigned char *key)
|
||||
AES_RETURN decrypt(const unsigned char *in, unsigned char *out) const
|
||||
*/
|
||||
|
||||
#if !defined( _AESOPT_H )
|
||||
#define _AESOPT_H
|
||||
|
||||
#if defined( __cplusplus )
|
||||
#include "aescpp.h"
|
||||
#else
|
||||
#include "aes.h"
|
||||
#endif
|
||||
|
||||
/* PLATFORM SPECIFIC INCLUDES */
|
||||
|
||||
#include "brg_endian.h"
|
||||
|
||||
/* CONFIGURATION - THE USE OF DEFINES
|
||||
|
||||
Later in this section there are a number of defines that control the
|
||||
operation of the code. In each section, the purpose of each define is
|
||||
explained so that the relevant form can be included or excluded by
|
||||
setting either 1's or 0's respectively on the branches of the related
|
||||
#if clauses. The following local defines should not be changed.
|
||||
*/
|
||||
|
||||
#define ENCRYPTION_IN_C 1
|
||||
#define DECRYPTION_IN_C 2
|
||||
#define ENC_KEYING_IN_C 4
|
||||
#define DEC_KEYING_IN_C 8
|
||||
|
||||
#define NO_TABLES 0
|
||||
#define ONE_TABLE 1
|
||||
#define FOUR_TABLES 4
|
||||
#define NONE 0
|
||||
#define PARTIAL 1
|
||||
#define FULL 2
|
||||
|
||||
/* --- START OF USER CONFIGURED OPTIONS --- */
|
||||
|
||||
/* 1. BYTE ORDER WITHIN 32 BIT WORDS
|
||||
|
||||
The fundamental data processing units in Rijndael are 8-bit bytes. The
|
||||
input, output and key input are all enumerated arrays of bytes in which
|
||||
bytes are numbered starting at zero and increasing to one less than the
|
||||
number of bytes in the array in question. This enumeration is only used
|
||||
for naming bytes and does not imply any adjacency or order relationship
|
||||
from one byte to another. When these inputs and outputs are considered
|
||||
as bit sequences, bits 8*n to 8*n+7 of the bit sequence are mapped to
|
||||
byte[n] with bit 8n+i in the sequence mapped to bit 7-i within the byte.
|
||||
In this implementation bits are numbered from 0 to 7 starting at the
|
||||
numerically least significant end of each byte (bit n represents 2^n).
|
||||
|
||||
However, Rijndael can be implemented more efficiently using 32-bit
|
||||
words by packing bytes into words so that bytes 4*n to 4*n+3 are placed
|
||||
into word[n]. While in principle these bytes can be assembled into words
|
||||
in any positions, this implementation only supports the two formats in
|
||||
which bytes in adjacent positions within words also have adjacent byte
|
||||
numbers. This order is called big-endian if the lowest numbered bytes
|
||||
in words have the highest numeric significance and little-endian if the
|
||||
opposite applies.
|
||||
|
||||
This code can work in either order irrespective of the order used by the
|
||||
machine on which it runs. Normally the internal byte order will be set
|
||||
to the order of the processor on which the code is to be run but this
|
||||
define can be used to reverse this in special situations
|
||||
|
||||
WARNING: Assembler code versions rely on PLATFORM_BYTE_ORDER being set.
|
||||
This define will hence be redefined later (in section 4) if necessary
|
||||
*/
|
||||
|
||||
#if 1
|
||||
# define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER
|
||||
#elif 0
|
||||
# define ALGORITHM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
#elif 0
|
||||
# define ALGORITHM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
#else
|
||||
# error The algorithm byte order is not defined
|
||||
#endif
|
||||
|
||||
/* 2. Intel AES AND VIA ACE SUPPORT */
|
||||
|
||||
#if defined( __GNUC__ ) && defined( __i386__ ) \
|
||||
|| defined(_WIN32) && defined(_M_IX86) \
|
||||
&& !(defined(_WIN64) || defined(_WIN32_WCE) || defined(_WIN32) && (_WIN32 <= 800))
|
||||
# define VIA_ACE_POSSIBLE
|
||||
#endif
|
||||
|
||||
/* Define this option if support for the Intel AESNI is required (not
|
||||
currently available with GCC). If AESNI is known to be present, then
|
||||
defining ASSUME_INTEL_AES_VIA_PRESENT will replace the ordinary
|
||||
encryption/decryption. If USE_INTEL_AES_IF_PRESENT is defined then
|
||||
AESNI will be used if it is detected (both present and enabled).
|
||||
|
||||
AESNI uses a decryption key schedule with the first decryption
|
||||
round key at the high end of the key scedule with the following
|
||||
round keys at lower positions in memory. So AES_REV_DKS must NOT
|
||||
be defined when AESNI will be used. ALthough it is unlikely that
|
||||
assembler code will be used with an AESNI build, if it is then
|
||||
AES_REV_DKS must NOT be defined when such assembler files are
|
||||
built
|
||||
*/
|
||||
#if 0 && defined( _WIN64 ) && defined( _WIN32 )
|
||||
# define INTEL_AES_POSSIBLE
|
||||
#endif
|
||||
|
||||
#if defined( INTEL_AES_POSSIBLE ) && !defined( USE_INTEL_AES_IF_PRESENT )
|
||||
# define USE_INTEL_AES_IF_PRESENT
|
||||
#endif
|
||||
|
||||
/* Define this option if support for the VIA ACE is required. This uses
|
||||
inline assembler instructions and is only implemented for the Microsoft,
|
||||
Intel and GCC compilers. If VIA ACE is known to be present, then defining
|
||||
ASSUME_VIA_ACE_PRESENT will remove the ordinary encryption/decryption
|
||||
code. If USE_VIA_ACE_IF_PRESENT is defined then VIA ACE will be used if
|
||||
it is detected (both present and enabled) but the normal AES code will
|
||||
also be present.
|
||||
|
||||
When VIA ACE is to be used, all AES encryption contexts MUST be 16 byte
|
||||
aligned; other input/output buffers do not need to be 16 byte aligned
|
||||
but there are very large performance gains if this can be arranged.
|
||||
VIA ACE also requires the decryption key schedule to be in reverse
|
||||
order (which later checks below ensure).
|
||||
|
||||
AES_REV_DKS must be set for assembler code used with a VIA ACE build
|
||||
*/
|
||||
|
||||
#if 0 && defined( VIA_ACE_POSSIBLE ) && !defined( USE_VIA_ACE_IF_PRESENT )
|
||||
# define USE_VIA_ACE_IF_PRESENT
|
||||
#endif
|
||||
|
||||
#if 0 && defined( VIA_ACE_POSSIBLE ) && !defined( ASSUME_VIA_ACE_PRESENT )
|
||||
# define ASSUME_VIA_ACE_PRESENT
|
||||
# endif
|
||||
|
||||
/* 3. ASSEMBLER SUPPORT
|
||||
|
||||
This define (which can be on the command line) enables the use of the
|
||||
assembler code routines for encryption, decryption and key scheduling
|
||||
as follows:
|
||||
|
||||
ASM_X86_V1C uses the assembler (aes_x86_v1.asm) with large tables for
|
||||
encryption and decryption and but with key scheduling in C
|
||||
ASM_X86_V2 uses assembler (aes_x86_v2.asm) with compressed tables for
|
||||
encryption, decryption and key scheduling
|
||||
ASM_X86_V2C uses assembler (aes_x86_v2.asm) with compressed tables for
|
||||
encryption and decryption and but with key scheduling in C
|
||||
ASM_AMD64_C uses assembler (aes_amd64.asm) with compressed tables for
|
||||
encryption and decryption and but with key scheduling in C
|
||||
|
||||
Change one 'if 0' below to 'if 1' to select the version or define
|
||||
as a compilation option.
|
||||
*/
|
||||
|
||||
#if 0 && !defined( ASM_X86_V1C )
|
||||
# define ASM_X86_V1C
|
||||
#elif 0 && !defined( ASM_X86_V2 )
|
||||
# define ASM_X86_V2
|
||||
#elif 0 && !defined( ASM_X86_V2C )
|
||||
# define ASM_X86_V2C
|
||||
#elif 0 && !defined( ASM_AMD64_C )
|
||||
# define ASM_AMD64_C
|
||||
#endif
|
||||
|
||||
#if (defined ( ASM_X86_V1C ) || defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )) \
|
||||
&& !defined( _M_IX86 ) || defined( ASM_AMD64_C ) && !defined( _M_X64 )
|
||||
# error Assembler code is only available for x86 and AMD64 systems
|
||||
#endif
|
||||
|
||||
/* 4. FAST INPUT/OUTPUT OPERATIONS.
|
||||
|
||||
On some machines it is possible to improve speed by transferring the
|
||||
bytes in the input and output arrays to and from the internal 32-bit
|
||||
variables by addressing these arrays as if they are arrays of 32-bit
|
||||
words. On some machines this will always be possible but there may
|
||||
be a large performance penalty if the byte arrays are not aligned on
|
||||
the normal word boundaries. On other machines this technique will
|
||||
lead to memory access errors when such 32-bit word accesses are not
|
||||
properly aligned. The option SAFE_IO avoids such problems but will
|
||||
often be slower on those machines that support misaligned access
|
||||
(especially so if care is taken to align the input and output byte
|
||||
arrays on 32-bit word boundaries). If SAFE_IO is not defined it is
|
||||
assumed that access to byte arrays as if they are arrays of 32-bit
|
||||
words will not cause problems when such accesses are misaligned.
|
||||
*/
|
||||
#if 1 && !defined( _WIN32 )
|
||||
# define SAFE_IO
|
||||
#endif
|
||||
|
||||
/* 5. LOOP UNROLLING
|
||||
|
||||
The code for encryption and decrytpion cycles through a number of rounds
|
||||
that can be implemented either in a loop or by expanding the code into a
|
||||
long sequence of instructions, the latter producing a larger program but
|
||||
one that will often be much faster. The latter is called loop unrolling.
|
||||
There are also potential speed advantages in expanding two iterations in
|
||||
a loop with half the number of iterations, which is called partial loop
|
||||
unrolling. The following options allow partial or full loop unrolling
|
||||
to be set independently for encryption and decryption
|
||||
*/
|
||||
#if 1
|
||||
# define ENC_UNROLL FULL
|
||||
#elif 0
|
||||
# define ENC_UNROLL PARTIAL
|
||||
#else
|
||||
# define ENC_UNROLL NONE
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
# define DEC_UNROLL FULL
|
||||
#elif 0
|
||||
# define DEC_UNROLL PARTIAL
|
||||
#else
|
||||
# define DEC_UNROLL NONE
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
# define ENC_KS_UNROLL
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
# define DEC_KS_UNROLL
|
||||
#endif
|
||||
|
||||
/* 6. FAST FINITE FIELD OPERATIONS
|
||||
|
||||
If this section is included, tables are used to provide faster finite
|
||||
field arithmetic (this has no effect if FIXED_TABLES is defined).
|
||||
*/
|
||||
#if 1
|
||||
# define FF_TABLES
|
||||
#endif
|
||||
|
||||
/* 7. INTERNAL STATE VARIABLE FORMAT
|
||||
|
||||
The internal state of Rijndael is stored in a number of local 32-bit
|
||||
word varaibles which can be defined either as an array or as individual
|
||||
names variables. Include this section if you want to store these local
|
||||
varaibles in arrays. Otherwise individual local variables will be used.
|
||||
*/
|
||||
#if 1
|
||||
# define ARRAYS
|
||||
#endif
|
||||
|
||||
/* 8. FIXED OR DYNAMIC TABLES
|
||||
|
||||
When this section is included the tables used by the code are compiled
|
||||
statically into the binary file. Otherwise the subroutine aes_init()
|
||||
must be called to compute them before the code is first used.
|
||||
*/
|
||||
#if 1 && !(defined( _WIN32 ) && ( _WIN32 <= 800 ))
|
||||
# define FIXED_TABLES
|
||||
#endif
|
||||
|
||||
/* 9. MASKING OR CASTING FROM LONGER VALUES TO BYTES
|
||||
|
||||
In some systems it is better to mask longer values to extract bytes
|
||||
rather than using a cast. This option allows this choice.
|
||||
*/
|
||||
#if 0
|
||||
# define to_byte(x) ((uint8_t)(x))
|
||||
#else
|
||||
# define to_byte(x) ((x) & 0xff)
|
||||
#endif
|
||||
|
||||
/* 10. TABLE ALIGNMENT
|
||||
|
||||
On some sytsems speed will be improved by aligning the AES large lookup
|
||||
tables on particular boundaries. This define should be set to a power of
|
||||
two giving the desired alignment. It can be left undefined if alignment
|
||||
is not needed. This option is specific to the Microsft VC++ compiler -
|
||||
it seems to sometimes cause trouble for the VC++ version 6 compiler.
|
||||
*/
|
||||
|
||||
#if 1 && defined( _WIN32 ) && ( _WIN32 >= 1300 )
|
||||
# define TABLE_ALIGN 32
|
||||
#endif
|
||||
|
||||
/* 11. REDUCE CODE AND TABLE SIZE
|
||||
|
||||
This replaces some expanded macros with function calls if AES_ASM_V2 or
|
||||
AES_ASM_V2C are defined
|
||||
*/
|
||||
|
||||
#if 0 && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))
|
||||
# define REDUCE_CODE_SIZE
|
||||
#endif
|
||||
|
||||
/* 12. TABLE OPTIONS
|
||||
|
||||
This cipher proceeds by repeating in a number of cycles known as 'rounds'
|
||||
which are implemented by a round function which can optionally be speeded
|
||||
up using tables. The basic tables are each 256 32-bit words, with either
|
||||
one or four tables being required for each round function depending on
|
||||
how much speed is required. The encryption and decryption round functions
|
||||
are different and the last encryption and decrytpion round functions are
|
||||
different again making four different round functions in all.
|
||||
|
||||
This means that:
|
||||
1. Normal encryption and decryption rounds can each use either 0, 1
|
||||
or 4 tables and table spaces of 0, 1024 or 4096 bytes each.
|
||||
2. The last encryption and decryption rounds can also use either 0, 1
|
||||
or 4 tables and table spaces of 0, 1024 or 4096 bytes each.
|
||||
|
||||
Include or exclude the appropriate definitions below to set the number
|
||||
of tables used by this implementation.
|
||||
*/
|
||||
|
||||
#if 1 /* set tables for the normal encryption round */
|
||||
# define ENC_ROUND FOUR_TABLES
|
||||
#elif 0
|
||||
# define ENC_ROUND ONE_TABLE
|
||||
#else
|
||||
# define ENC_ROUND NO_TABLES
|
||||
#endif
|
||||
|
||||
#if 1 /* set tables for the last encryption round */
|
||||
# define LAST_ENC_ROUND FOUR_TABLES
|
||||
#elif 0
|
||||
# define LAST_ENC_ROUND ONE_TABLE
|
||||
#else
|
||||
# define LAST_ENC_ROUND NO_TABLES
|
||||
#endif
|
||||
|
||||
#if 1 /* set tables for the normal decryption round */
|
||||
# define DEC_ROUND FOUR_TABLES
|
||||
#elif 0
|
||||
# define DEC_ROUND ONE_TABLE
|
||||
#else
|
||||
# define DEC_ROUND NO_TABLES
|
||||
#endif
|
||||
|
||||
#if 1 /* set tables for the last decryption round */
|
||||
# define LAST_DEC_ROUND FOUR_TABLES
|
||||
#elif 0
|
||||
# define LAST_DEC_ROUND ONE_TABLE
|
||||
#else
|
||||
# define LAST_DEC_ROUND NO_TABLES
|
||||
#endif
|
||||
|
||||
/* The decryption key schedule can be speeded up with tables in the same
|
||||
way that the round functions can. Include or exclude the following
|
||||
defines to set this requirement.
|
||||
*/
|
||||
#if 1
|
||||
# define KEY_SCHED FOUR_TABLES
|
||||
#elif 0
|
||||
# define KEY_SCHED ONE_TABLE
|
||||
#else
|
||||
# define KEY_SCHED NO_TABLES
|
||||
#endif
|
||||
|
||||
/* ---- END OF USER CONFIGURED OPTIONS ---- */
|
||||
|
||||
/* VIA ACE support is only available for VC++ and GCC */
|
||||
|
||||
#if !defined( _WIN32 ) && !defined( __GNUC__ )
|
||||
# if defined( ASSUME_VIA_ACE_PRESENT )
|
||||
# undef ASSUME_VIA_ACE_PRESENT
|
||||
# endif
|
||||
# if defined( USE_VIA_ACE_IF_PRESENT )
|
||||
# undef USE_VIA_ACE_IF_PRESENT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined( ASSUME_VIA_ACE_PRESENT ) && !defined( USE_VIA_ACE_IF_PRESENT )
|
||||
# define USE_VIA_ACE_IF_PRESENT
|
||||
#endif
|
||||
|
||||
/* define to reverse decryption key schedule */
|
||||
#if 1 || defined( USE_VIA_ACE_IF_PRESENT ) && !defined ( AES_REV_DKS )
|
||||
# define AES_REV_DKS
|
||||
#endif
|
||||
|
||||
/* Intel AESNI uses a decryption key schedule in the encryption order */
|
||||
#if defined( USE_INTEL_AES_IF_PRESENT ) && defined ( AES_REV_DKS )
|
||||
# undef AES_REV_DKS
|
||||
#endif
|
||||
|
||||
/* Assembler support requires the use of platform byte order */
|
||||
|
||||
#if ( defined( ASM_X86_V1C ) || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) ) \
|
||||
&& (ALGORITHM_BYTE_ORDER != PLATFORM_BYTE_ORDER)
|
||||
# undef ALGORITHM_BYTE_ORDER
|
||||
# define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER
|
||||
#endif
|
||||
|
||||
/* In this implementation the columns of the state array are each held in
|
||||
32-bit words. The state array can be held in various ways: in an array
|
||||
of words, in a number of individual word variables or in a number of
|
||||
processor registers. The following define maps a variable name x and
|
||||
a column number c to the way the state array variable is to be held.
|
||||
The first define below maps the state into an array x[c] whereas the
|
||||
second form maps the state into a number of individual variables x0,
|
||||
x1, etc. Another form could map individual state colums to machine
|
||||
register names.
|
||||
*/
|
||||
|
||||
#if defined( ARRAYS )
|
||||
# define s(x,c) x[c]
|
||||
#else
|
||||
# define s(x,c) x##c
|
||||
#endif
|
||||
|
||||
/* This implementation provides subroutines for encryption, decryption
|
||||
and for setting the three key lengths (separately) for encryption
|
||||
and decryption. Since not all functions are needed, masks are set
|
||||
up here to determine which will be implemented in C
|
||||
*/
|
||||
|
||||
#if !defined( AES_ENCRYPT )
|
||||
# define EFUNCS_IN_C 0
|
||||
#elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \
|
||||
|| defined( ASM_X86_V2C ) || defined( ASM_AMD64_C )
|
||||
# define EFUNCS_IN_C ENC_KEYING_IN_C
|
||||
#elif !defined( ASM_X86_V2 )
|
||||
# define EFUNCS_IN_C ( ENCRYPTION_IN_C | ENC_KEYING_IN_C )
|
||||
#else
|
||||
# define EFUNCS_IN_C 0
|
||||
#endif
|
||||
|
||||
#if !defined( AES_DECRYPT )
|
||||
# define DFUNCS_IN_C 0
|
||||
#elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \
|
||||
|| defined( ASM_X86_V2C ) || defined( ASM_AMD64_C )
|
||||
# define DFUNCS_IN_C DEC_KEYING_IN_C
|
||||
#elif !defined( ASM_X86_V2 )
|
||||
# define DFUNCS_IN_C ( DECRYPTION_IN_C | DEC_KEYING_IN_C )
|
||||
#else
|
||||
# define DFUNCS_IN_C 0
|
||||
#endif
|
||||
|
||||
#define FUNCS_IN_C ( EFUNCS_IN_C | DFUNCS_IN_C )
|
||||
|
||||
/* END OF CONFIGURATION OPTIONS */
|
||||
|
||||
#define RC_LENGTH (5 * (AES_BLOCK_SIZE / 4 - 2))
|
||||
|
||||
/* Disable or report errors on some combinations of options */
|
||||
|
||||
#if ENC_ROUND == NO_TABLES && LAST_ENC_ROUND != NO_TABLES
|
||||
# undef LAST_ENC_ROUND
|
||||
# define LAST_ENC_ROUND NO_TABLES
|
||||
#elif ENC_ROUND == ONE_TABLE && LAST_ENC_ROUND == FOUR_TABLES
|
||||
# undef LAST_ENC_ROUND
|
||||
# define LAST_ENC_ROUND ONE_TABLE
|
||||
#endif
|
||||
|
||||
#if ENC_ROUND == NO_TABLES && ENC_UNROLL != NONE
|
||||
# undef ENC_UNROLL
|
||||
# define ENC_UNROLL NONE
|
||||
#endif
|
||||
|
||||
#if DEC_ROUND == NO_TABLES && LAST_DEC_ROUND != NO_TABLES
|
||||
# undef LAST_DEC_ROUND
|
||||
# define LAST_DEC_ROUND NO_TABLES
|
||||
#elif DEC_ROUND == ONE_TABLE && LAST_DEC_ROUND == FOUR_TABLES
|
||||
# undef LAST_DEC_ROUND
|
||||
# define LAST_DEC_ROUND ONE_TABLE
|
||||
#endif
|
||||
|
||||
#if DEC_ROUND == NO_TABLES && DEC_UNROLL != NONE
|
||||
# undef DEC_UNROLL
|
||||
# define DEC_UNROLL NONE
|
||||
#endif
|
||||
|
||||
#if defined( bswap32 )
|
||||
# define aes_sw32 bswap32
|
||||
#elif defined( bswap_32 )
|
||||
# define aes_sw32 bswap_32
|
||||
#else
|
||||
# define brot(x,n) (((uint32_t)(x) << n) | ((uint32_t)(x) >> (32 - n)))
|
||||
# define aes_sw32(x) ((brot((x),8) & 0x00ff00ff) | (brot((x),24) & 0xff00ff00))
|
||||
#endif
|
||||
|
||||
/* upr(x,n): rotates bytes within words by n positions, moving bytes to
|
||||
higher index positions with wrap around into low positions
|
||||
ups(x,n): moves bytes by n positions to higher index positions in
|
||||
words but without wrap around
|
||||
bval(x,n): extracts a byte from a word
|
||||
|
||||
WARNING: The definitions given here are intended only for use with
|
||||
unsigned variables and with shift counts that are compile
|
||||
time constants
|
||||
*/
|
||||
|
||||
#if ( ALGORITHM_BYTE_ORDER == IS_LITTLE_ENDIAN )
|
||||
# define upr(x,n) (((uint32_t)(x) << (8 * (n))) | ((uint32_t)(x) >> (32 - 8 * (n))))
|
||||
# define ups(x,n) ((uint32_t) (x) << (8 * (n)))
|
||||
# define bval(x,n) to_byte((x) >> (8 * (n)))
|
||||
# define bytes2word(b0, b1, b2, b3) \
|
||||
(((uint32_t)(b3) << 24) | ((uint32_t)(b2) << 16) | ((uint32_t)(b1) << 8) | (b0))
|
||||
#endif
|
||||
|
||||
#if ( ALGORITHM_BYTE_ORDER == IS_BIG_ENDIAN )
|
||||
# define upr(x,n) (((uint32_t)(x) >> (8 * (n))) | ((uint32_t)(x) << (32 - 8 * (n))))
|
||||
# define ups(x,n) ((uint32_t) (x) >> (8 * (n)))
|
||||
# define bval(x,n) to_byte((x) >> (24 - 8 * (n)))
|
||||
# define bytes2word(b0, b1, b2, b3) \
|
||||
(((uint32_t)(b0) << 24) | ((uint32_t)(b1) << 16) | ((uint32_t)(b2) << 8) | (b3))
|
||||
#endif
|
||||
|
||||
#if defined( SAFE_IO )
|
||||
# define word_in(x,c) bytes2word(((const uint8_t*)(x)+4*c)[0], ((const uint8_t*)(x)+4*c)[1], \
|
||||
((const uint8_t*)(x)+4*c)[2], ((const uint8_t*)(x)+4*c)[3])
|
||||
# define word_out(x,c,v) { ((uint8_t*)(x)+4*c)[0] = bval(v,0); ((uint8_t*)(x)+4*c)[1] = bval(v,1); \
|
||||
((uint8_t*)(x)+4*c)[2] = bval(v,2); ((uint8_t*)(x)+4*c)[3] = bval(v,3); }
|
||||
#elif ( ALGORITHM_BYTE_ORDER == PLATFORM_BYTE_ORDER )
|
||||
# define word_in(x,c) (*((uint32_t*)(x)+(c)))
|
||||
# define word_out(x,c,v) (*((uint32_t*)(x)+(c)) = (v))
|
||||
#else
|
||||
# define word_in(x,c) aes_sw32(*((uint32_t*)(x)+(c)))
|
||||
# define word_out(x,c,v) (*((uint32_t*)(x)+(c)) = aes_sw32(v))
|
||||
#endif
|
||||
|
||||
/* the finite field modular polynomial and elements */
|
||||
|
||||
#define WPOLY 0x011b
|
||||
#define BPOLY 0x1b
|
||||
|
||||
/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
|
||||
|
||||
#define gf_c1 0x80808080
|
||||
#define gf_c2 0x7f7f7f7f
|
||||
#define gf_mulx(x) ((((x) & gf_c2) << 1) ^ ((((x) & gf_c1) >> 7) * BPOLY))
|
||||
|
||||
/* The following defines provide alternative definitions of gf_mulx that might
|
||||
give improved performance if a fast 32-bit multiply is not available. Note
|
||||
that a temporary variable u needs to be defined where gf_mulx is used.
|
||||
|
||||
#define gf_mulx(x) (u = (x) & gf_c1, u |= (u >> 1), ((x) & gf_c2) << 1) ^ ((u >> 3) | (u >> 6))
|
||||
#define gf_c4 (0x01010101 * BPOLY)
|
||||
#define gf_mulx(x) (u = (x) & gf_c1, ((x) & gf_c2) << 1) ^ ((u - (u >> 7)) & gf_c4)
|
||||
*/
|
||||
|
||||
/* Work out which tables are needed for the different options */
|
||||
|
||||
#if defined( ASM_X86_V1C )
|
||||
# if defined( ENC_ROUND )
|
||||
# undef ENC_ROUND
|
||||
# endif
|
||||
# define ENC_ROUND FOUR_TABLES
|
||||
# if defined( LAST_ENC_ROUND )
|
||||
# undef LAST_ENC_ROUND
|
||||
# endif
|
||||
# define LAST_ENC_ROUND FOUR_TABLES
|
||||
# if defined( DEC_ROUND )
|
||||
# undef DEC_ROUND
|
||||
# endif
|
||||
# define DEC_ROUND FOUR_TABLES
|
||||
# if defined( LAST_DEC_ROUND )
|
||||
# undef LAST_DEC_ROUND
|
||||
# endif
|
||||
# define LAST_DEC_ROUND FOUR_TABLES
|
||||
# if defined( KEY_SCHED )
|
||||
# undef KEY_SCHED
|
||||
# define KEY_SCHED FOUR_TABLES
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if ( FUNCS_IN_C & ENCRYPTION_IN_C ) || defined( ASM_X86_V1C )
|
||||
# if ENC_ROUND == ONE_TABLE
|
||||
# define FT1_SET
|
||||
# elif ENC_ROUND == FOUR_TABLES
|
||||
# define FT4_SET
|
||||
# else
|
||||
# define SBX_SET
|
||||
# endif
|
||||
# if LAST_ENC_ROUND == ONE_TABLE
|
||||
# define FL1_SET
|
||||
# elif LAST_ENC_ROUND == FOUR_TABLES
|
||||
# define FL4_SET
|
||||
# elif !defined( SBX_SET )
|
||||
# define SBX_SET
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if ( FUNCS_IN_C & DECRYPTION_IN_C ) || defined( ASM_X86_V1C )
|
||||
# if DEC_ROUND == ONE_TABLE
|
||||
# define IT1_SET
|
||||
# elif DEC_ROUND == FOUR_TABLES
|
||||
# define IT4_SET
|
||||
# else
|
||||
# define ISB_SET
|
||||
# endif
|
||||
# if LAST_DEC_ROUND == ONE_TABLE
|
||||
# define IL1_SET
|
||||
# elif LAST_DEC_ROUND == FOUR_TABLES
|
||||
# define IL4_SET
|
||||
# elif !defined(ISB_SET)
|
||||
# define ISB_SET
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )))
|
||||
# if ((FUNCS_IN_C & ENC_KEYING_IN_C) || (FUNCS_IN_C & DEC_KEYING_IN_C))
|
||||
# if KEY_SCHED == ONE_TABLE
|
||||
# if !defined( FL1_SET ) && !defined( FL4_SET )
|
||||
# define LS1_SET
|
||||
# endif
|
||||
# elif KEY_SCHED == FOUR_TABLES
|
||||
# if !defined( FL4_SET )
|
||||
# define LS4_SET
|
||||
# endif
|
||||
# elif !defined( SBX_SET )
|
||||
# define SBX_SET
|
||||
# endif
|
||||
# endif
|
||||
# if (FUNCS_IN_C & DEC_KEYING_IN_C)
|
||||
# if KEY_SCHED == ONE_TABLE
|
||||
# define IM1_SET
|
||||
# elif KEY_SCHED == FOUR_TABLES
|
||||
# define IM4_SET
|
||||
# elif !defined( SBX_SET )
|
||||
# define SBX_SET
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* generic definitions of Rijndael macros that use tables */
|
||||
|
||||
#define no_table(x,box,vf,rf,c) bytes2word( \
|
||||
box[bval(vf(x,0,c),rf(0,c))], \
|
||||
box[bval(vf(x,1,c),rf(1,c))], \
|
||||
box[bval(vf(x,2,c),rf(2,c))], \
|
||||
box[bval(vf(x,3,c),rf(3,c))])
|
||||
|
||||
#define one_table(x,op,tab,vf,rf,c) \
|
||||
( tab[bval(vf(x,0,c),rf(0,c))] \
|
||||
^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \
|
||||
^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \
|
||||
^ op(tab[bval(vf(x,3,c),rf(3,c))],3))
|
||||
|
||||
#define four_tables(x,tab,vf,rf,c) \
|
||||
( tab[0][bval(vf(x,0,c),rf(0,c))] \
|
||||
^ tab[1][bval(vf(x,1,c),rf(1,c))] \
|
||||
^ tab[2][bval(vf(x,2,c),rf(2,c))] \
|
||||
^ tab[3][bval(vf(x,3,c),rf(3,c))])
|
||||
|
||||
#define vf1(x,r,c) (x)
|
||||
#define rf1(r,c) (r)
|
||||
#define rf2(r,c) ((8+r-c)&3)
|
||||
|
||||
/* perform forward and inverse column mix operation on four bytes in long word x in */
|
||||
/* parallel. NOTE: x must be a simple variable, NOT an expression in these macros. */
|
||||
|
||||
#if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )))
|
||||
|
||||
#if defined( FM4_SET ) /* not currently used */
|
||||
# define fwd_mcol(x) four_tables(x,t_use(f,m),vf1,rf1,0)
|
||||
#elif defined( FM1_SET ) /* not currently used */
|
||||
# define fwd_mcol(x) one_table(x,upr,t_use(f,m),vf1,rf1,0)
|
||||
#else
|
||||
# define dec_fmvars uint32_t g2
|
||||
# define fwd_mcol(x) (g2 = gf_mulx(x), g2 ^ upr((x) ^ g2, 3) ^ upr((x), 2) ^ upr((x), 1))
|
||||
#endif
|
||||
|
||||
#if defined( IM4_SET )
|
||||
# define inv_mcol(x) four_tables(x,t_use(i,m),vf1,rf1,0)
|
||||
#elif defined( IM1_SET )
|
||||
# define inv_mcol(x) one_table(x,upr,t_use(i,m),vf1,rf1,0)
|
||||
#else
|
||||
# define dec_imvars uint32_t g2, g4, g9
|
||||
# define inv_mcol(x) (g2 = gf_mulx(x), g4 = gf_mulx(g2), g9 = (x) ^ gf_mulx(g4), g4 ^= g9, \
|
||||
(x) ^ g2 ^ g4 ^ upr(g2 ^ g9, 3) ^ upr(g4, 2) ^ upr(g9, 1))
|
||||
#endif
|
||||
|
||||
#if defined( FL4_SET )
|
||||
# define ls_box(x,c) four_tables(x,t_use(f,l),vf1,rf2,c)
|
||||
#elif defined( LS4_SET )
|
||||
# define ls_box(x,c) four_tables(x,t_use(l,s),vf1,rf2,c)
|
||||
#elif defined( FL1_SET )
|
||||
# define ls_box(x,c) one_table(x,upr,t_use(f,l),vf1,rf2,c)
|
||||
#elif defined( LS1_SET )
|
||||
# define ls_box(x,c) one_table(x,upr,t_use(l,s),vf1,rf2,c)
|
||||
#else
|
||||
# define ls_box(x,c) no_table(x,t_use(s,box),vf1,rf2,c)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined( ASM_X86_V1C ) && defined( AES_DECRYPT ) && !defined( ISB_SET )
|
||||
# define ISB_SET
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,391 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
*/
|
||||
|
||||
#define DO_TABLES
|
||||
|
||||
#include "aes.h"
|
||||
#include "aesopt.h"
|
||||
|
||||
#if defined(FIXED_TABLES)
|
||||
|
||||
#define sb_data(w) {\
|
||||
w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\
|
||||
w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\
|
||||
w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\
|
||||
w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\
|
||||
w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\
|
||||
w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\
|
||||
w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\
|
||||
w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\
|
||||
w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\
|
||||
w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\
|
||||
w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\
|
||||
w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\
|
||||
w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\
|
||||
w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\
|
||||
w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\
|
||||
w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\
|
||||
w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\
|
||||
w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\
|
||||
w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\
|
||||
w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\
|
||||
w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\
|
||||
w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\
|
||||
w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\
|
||||
w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\
|
||||
w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\
|
||||
w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\
|
||||
w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\
|
||||
w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\
|
||||
w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\
|
||||
w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\
|
||||
w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\
|
||||
w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) }
|
||||
|
||||
#define isb_data(w) {\
|
||||
w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\
|
||||
w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\
|
||||
w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\
|
||||
w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\
|
||||
w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\
|
||||
w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\
|
||||
w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\
|
||||
w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\
|
||||
w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\
|
||||
w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\
|
||||
w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\
|
||||
w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\
|
||||
w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\
|
||||
w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\
|
||||
w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\
|
||||
w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\
|
||||
w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\
|
||||
w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\
|
||||
w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\
|
||||
w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\
|
||||
w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\
|
||||
w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\
|
||||
w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\
|
||||
w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\
|
||||
w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\
|
||||
w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\
|
||||
w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\
|
||||
w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\
|
||||
w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\
|
||||
w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\
|
||||
w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\
|
||||
w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) }
|
||||
|
||||
#define mm_data(w) {\
|
||||
w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\
|
||||
w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\
|
||||
w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\
|
||||
w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\
|
||||
w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\
|
||||
w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\
|
||||
w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\
|
||||
w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\
|
||||
w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\
|
||||
w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\
|
||||
w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\
|
||||
w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\
|
||||
w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\
|
||||
w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\
|
||||
w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\
|
||||
w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\
|
||||
w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\
|
||||
w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\
|
||||
w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\
|
||||
w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\
|
||||
w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\
|
||||
w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\
|
||||
w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\
|
||||
w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\
|
||||
w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\
|
||||
w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\
|
||||
w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\
|
||||
w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\
|
||||
w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\
|
||||
w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\
|
||||
w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\
|
||||
w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) }
|
||||
|
||||
#define rc_data(w) {\
|
||||
w(0x01), w(0x02), w(0x04), w(0x08), w(0x10),w(0x20), w(0x40), w(0x80),\
|
||||
w(0x1b), w(0x36) }
|
||||
|
||||
#define h0(x) (x)
|
||||
|
||||
#define w0(p) bytes2word(p, 0, 0, 0)
|
||||
#define w1(p) bytes2word(0, p, 0, 0)
|
||||
#define w2(p) bytes2word(0, 0, p, 0)
|
||||
#define w3(p) bytes2word(0, 0, 0, p)
|
||||
|
||||
#define u0(p) bytes2word(f2(p), p, p, f3(p))
|
||||
#define u1(p) bytes2word(f3(p), f2(p), p, p)
|
||||
#define u2(p) bytes2word(p, f3(p), f2(p), p)
|
||||
#define u3(p) bytes2word(p, p, f3(p), f2(p))
|
||||
|
||||
#define v0(p) bytes2word(fe(p), f9(p), fd(p), fb(p))
|
||||
#define v1(p) bytes2word(fb(p), fe(p), f9(p), fd(p))
|
||||
#define v2(p) bytes2word(fd(p), fb(p), fe(p), f9(p))
|
||||
#define v3(p) bytes2word(f9(p), fd(p), fb(p), fe(p))
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(FIXED_TABLES) || !defined(FF_TABLES)
|
||||
|
||||
#define f2(x) ((x<<1) ^ (((x>>7) & 1) * WPOLY))
|
||||
#define f4(x) ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY))
|
||||
#define f8(x) ((x<<3) ^ (((x>>5) & 1) * WPOLY) ^ (((x>>5) & 2) * WPOLY) \
|
||||
^ (((x>>5) & 4) * WPOLY))
|
||||
#define f3(x) (f2(x) ^ x)
|
||||
#define f9(x) (f8(x) ^ x)
|
||||
#define fb(x) (f8(x) ^ f2(x) ^ x)
|
||||
#define fd(x) (f8(x) ^ f4(x) ^ x)
|
||||
#define fe(x) (f8(x) ^ f4(x) ^ f2(x))
|
||||
|
||||
#else
|
||||
|
||||
#define f2(x) ((x) ? pow[log[x] + 0x19] : 0)
|
||||
#define f3(x) ((x) ? pow[log[x] + 0x01] : 0)
|
||||
#define f9(x) ((x) ? pow[log[x] + 0xc7] : 0)
|
||||
#define fb(x) ((x) ? pow[log[x] + 0x68] : 0)
|
||||
#define fd(x) ((x) ? pow[log[x] + 0xee] : 0)
|
||||
#define fe(x) ((x) ? pow[log[x] + 0xdf] : 0)
|
||||
|
||||
#endif
|
||||
|
||||
#include "aestab.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if defined(FIXED_TABLES)
|
||||
|
||||
/* implemented in case of wrong call for fixed tables */
|
||||
|
||||
AES_RETURN aes_init1(void)
|
||||
{
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#else /* Generate the tables for the dynamic table option */
|
||||
|
||||
#if defined(FF_TABLES)
|
||||
|
||||
#define gf_inv(x) ((x) ? pow[ 255 - log[x]] : 0)
|
||||
|
||||
#else
|
||||
|
||||
/* It will generally be sensible to use tables to compute finite
|
||||
field multiplies and inverses but where memory is scarse this
|
||||
code might sometimes be better. But it only has effect during
|
||||
initialisation so its pretty unimportant in overall terms.
|
||||
*/
|
||||
|
||||
/* return 2 ^ (n - 1) where n is the bit number of the highest bit
|
||||
set in x with x in the range 1 < x < 0x00000200. This form is
|
||||
used so that locals within fi can be bytes rather than words
|
||||
*/
|
||||
|
||||
static uint8_t hibit(const uint32_t x)
|
||||
{ uint8_t r = (uint8_t)((x >> 1) | (x >> 2));
|
||||
|
||||
r |= (r >> 2);
|
||||
r |= (r >> 4);
|
||||
return (r + 1) >> 1;
|
||||
}
|
||||
|
||||
/* return the inverse of the finite field element x */
|
||||
|
||||
static uint8_t gf_inv(const uint8_t x)
|
||||
{ uint8_t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0;
|
||||
|
||||
if(x < 2)
|
||||
return x;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
if(n1)
|
||||
while(n2 >= n1) /* divide polynomial p2 by p1 */
|
||||
{
|
||||
n2 /= n1; /* shift smaller polynomial left */
|
||||
p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */
|
||||
v2 ^= v1 * n2; /* shift accumulated value and */
|
||||
n2 = hibit(p2); /* add into result */
|
||||
}
|
||||
else
|
||||
return v1;
|
||||
|
||||
if(n2) /* repeat with values swapped */
|
||||
while(n1 >= n2)
|
||||
{
|
||||
n1 /= n2;
|
||||
p1 ^= p2 * n1;
|
||||
v1 ^= v2 * n1;
|
||||
n1 = hibit(p1);
|
||||
}
|
||||
else
|
||||
return v2;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* The forward and inverse affine transformations used in the S-box */
|
||||
uint8_t fwd_affine(const uint8_t x)
|
||||
{ uint32_t w = x;
|
||||
w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4);
|
||||
return 0x63 ^ ((w ^ (w >> 8)) & 0xff);
|
||||
}
|
||||
|
||||
uint8_t inv_affine(const uint8_t x)
|
||||
{ uint32_t w = x;
|
||||
w = (w << 1) ^ (w << 3) ^ (w << 6);
|
||||
return 0x05 ^ ((w ^ (w >> 8)) & 0xff);
|
||||
}
|
||||
|
||||
static int init = 0;
|
||||
|
||||
AES_RETURN aes_init1(void)
|
||||
{ uint32_t i, w;
|
||||
|
||||
#if defined(FF_TABLES)
|
||||
|
||||
uint8_t pow[512], log[256];
|
||||
|
||||
if(init)
|
||||
return EXIT_SUCCESS;
|
||||
/* log and power tables for GF(2^8) finite field with
|
||||
WPOLY as modular polynomial - the simplest primitive
|
||||
root is 0x03, used here to generate the tables
|
||||
*/
|
||||
|
||||
i = 0; w = 1;
|
||||
do
|
||||
{
|
||||
pow[i] = (uint8_t)w;
|
||||
pow[i + 255] = (uint8_t)w;
|
||||
log[w] = (uint8_t)i++;
|
||||
w ^= (w << 1) ^ (w & 0x80 ? WPOLY : 0);
|
||||
}
|
||||
while (w != 1);
|
||||
|
||||
#else
|
||||
if(init)
|
||||
return EXIT_SUCCESS;
|
||||
#endif
|
||||
|
||||
for(i = 0, w = 1; i < RC_LENGTH; ++i)
|
||||
{
|
||||
t_set(r,c)[i] = bytes2word(w, 0, 0, 0);
|
||||
w = f2(w);
|
||||
}
|
||||
|
||||
for(i = 0; i < 256; ++i)
|
||||
{ uint8_t b;
|
||||
|
||||
b = fwd_affine(gf_inv((uint8_t)i));
|
||||
w = bytes2word(f2(b), b, b, f3(b));
|
||||
|
||||
#if defined( SBX_SET )
|
||||
t_set(s,box)[i] = b;
|
||||
#endif
|
||||
|
||||
#if defined( FT1_SET ) /* tables for a normal encryption round */
|
||||
t_set(f,n)[i] = w;
|
||||
#endif
|
||||
#if defined( FT4_SET )
|
||||
t_set(f,n)[0][i] = w;
|
||||
t_set(f,n)[1][i] = upr(w,1);
|
||||
t_set(f,n)[2][i] = upr(w,2);
|
||||
t_set(f,n)[3][i] = upr(w,3);
|
||||
#endif
|
||||
w = bytes2word(b, 0, 0, 0);
|
||||
|
||||
#if defined( FL1_SET ) /* tables for last encryption round (may also */
|
||||
t_set(f,l)[i] = w; /* be used in the key schedule) */
|
||||
#endif
|
||||
#if defined( FL4_SET )
|
||||
t_set(f,l)[0][i] = w;
|
||||
t_set(f,l)[1][i] = upr(w,1);
|
||||
t_set(f,l)[2][i] = upr(w,2);
|
||||
t_set(f,l)[3][i] = upr(w,3);
|
||||
#endif
|
||||
|
||||
#if defined( LS1_SET ) /* table for key schedule if t_set(f,l) above is*/
|
||||
t_set(l,s)[i] = w; /* not of the required form */
|
||||
#endif
|
||||
#if defined( LS4_SET )
|
||||
t_set(l,s)[0][i] = w;
|
||||
t_set(l,s)[1][i] = upr(w,1);
|
||||
t_set(l,s)[2][i] = upr(w,2);
|
||||
t_set(l,s)[3][i] = upr(w,3);
|
||||
#endif
|
||||
|
||||
b = gf_inv(inv_affine((uint8_t)i));
|
||||
w = bytes2word(fe(b), f9(b), fd(b), fb(b));
|
||||
|
||||
#if defined( IM1_SET ) /* tables for the inverse mix column operation */
|
||||
t_set(i,m)[b] = w;
|
||||
#endif
|
||||
#if defined( IM4_SET )
|
||||
t_set(i,m)[0][b] = w;
|
||||
t_set(i,m)[1][b] = upr(w,1);
|
||||
t_set(i,m)[2][b] = upr(w,2);
|
||||
t_set(i,m)[3][b] = upr(w,3);
|
||||
#endif
|
||||
|
||||
#if defined( ISB_SET )
|
||||
t_set(i,box)[i] = b;
|
||||
#endif
|
||||
#if defined( IT1_SET ) /* tables for a normal decryption round */
|
||||
t_set(i,n)[i] = w;
|
||||
#endif
|
||||
#if defined( IT4_SET )
|
||||
t_set(i,n)[0][i] = w;
|
||||
t_set(i,n)[1][i] = upr(w,1);
|
||||
t_set(i,n)[2][i] = upr(w,2);
|
||||
t_set(i,n)[3][i] = upr(w,3);
|
||||
#endif
|
||||
w = bytes2word(b, 0, 0, 0);
|
||||
#if defined( IL1_SET ) /* tables for last decryption round */
|
||||
t_set(i,l)[i] = w;
|
||||
#endif
|
||||
#if defined( IL4_SET )
|
||||
t_set(i,l)[0][i] = w;
|
||||
t_set(i,l)[1][i] = upr(w,1);
|
||||
t_set(i,l)[2][i] = upr(w,2);
|
||||
t_set(i,l)[3][i] = upr(w,3);
|
||||
#endif
|
||||
}
|
||||
init = 1;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
|
||||
This file contains the code for declaring the tables needed to implement
|
||||
AES. The file aesopt.h is assumed to be included before this header file.
|
||||
If there are no global variables, the definitions here can be used to put
|
||||
the AES tables in a structure so that a pointer can then be added to the
|
||||
AES context to pass them to the AES routines that need them. If this
|
||||
facility is used, the calling program has to ensure that this pointer is
|
||||
managed appropriately. In particular, the value of the t_dec(in,it) item
|
||||
in the table structure must be set to zero in order to ensure that the
|
||||
tables are initialised. In practice the three code sequences in aeskey.c
|
||||
that control the calls to aes_init() and the aes_init() routine itself will
|
||||
have to be changed for a specific implementation. If global variables are
|
||||
available it will generally be preferable to use them with the precomputed
|
||||
FIXED_TABLES option that uses static global tables.
|
||||
|
||||
The following defines can be used to control the way the tables
|
||||
are defined, initialised and used in embedded environments that
|
||||
require special features for these purposes
|
||||
|
||||
the 't_dec' construction is used to declare fixed table arrays
|
||||
the 't_set' construction is used to set fixed table values
|
||||
the 't_use' construction is used to access fixed table values
|
||||
|
||||
256 byte tables:
|
||||
|
||||
t_xxx(s,box) => forward S box
|
||||
t_xxx(i,box) => inverse S box
|
||||
|
||||
256 32-bit word OR 4 x 256 32-bit word tables:
|
||||
|
||||
t_xxx(f,n) => forward normal round
|
||||
t_xxx(f,l) => forward last round
|
||||
t_xxx(i,n) => inverse normal round
|
||||
t_xxx(i,l) => inverse last round
|
||||
t_xxx(l,s) => key schedule table
|
||||
t_xxx(i,m) => key schedule table
|
||||
|
||||
Other variables and tables:
|
||||
|
||||
t_xxx(r,c) => the rcon table
|
||||
*/
|
||||
|
||||
#if !defined( _AESTAB_H )
|
||||
#define _AESTAB_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define t_dec(m,n) t_##m##n
|
||||
#define t_set(m,n) t_##m##n
|
||||
#define t_use(m,n) t_##m##n
|
||||
|
||||
#if defined(FIXED_TABLES)
|
||||
# if !defined( __GNUC__ ) && (defined( __MSDOS__ ) || defined( __WIN16__ ))
|
||||
/* make tables far data to avoid using too much DGROUP space (PG) */
|
||||
# define CONST const far
|
||||
# else
|
||||
# define CONST const
|
||||
# endif
|
||||
#else
|
||||
# define CONST
|
||||
#endif
|
||||
|
||||
#if defined(DO_TABLES)
|
||||
# define EXTERN
|
||||
#else
|
||||
# define EXTERN extern
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && defined(TABLE_ALIGN)
|
||||
#define ALIGN __declspec(align(TABLE_ALIGN))
|
||||
#else
|
||||
#define ALIGN
|
||||
#endif
|
||||
|
||||
#if defined( __WATCOMC__ ) && ( __WATCOMC__ >= 1100 )
|
||||
# define XP_DIR __cdecl
|
||||
#else
|
||||
# define XP_DIR
|
||||
#endif
|
||||
|
||||
#if defined(DO_TABLES) && defined(FIXED_TABLES)
|
||||
#define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256] = b(e)
|
||||
#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] = { b(e), b(f), b(g), b(h) }
|
||||
EXTERN ALIGN CONST uint32_t t_dec(r,c)[RC_LENGTH] = rc_data(w0);
|
||||
#else
|
||||
#define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256]
|
||||
#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256]
|
||||
EXTERN ALIGN CONST uint32_t t_dec(r,c)[RC_LENGTH];
|
||||
#endif
|
||||
|
||||
#if defined( SBX_SET )
|
||||
d_1(uint8_t, t_dec(s,box), sb_data, h0);
|
||||
#endif
|
||||
#if defined( ISB_SET )
|
||||
d_1(uint8_t, t_dec(i,box), isb_data, h0);
|
||||
#endif
|
||||
|
||||
#if defined( FT1_SET )
|
||||
d_1(uint32_t, t_dec(f,n), sb_data, u0);
|
||||
#endif
|
||||
#if defined( FT4_SET )
|
||||
d_4(uint32_t, t_dec(f,n), sb_data, u0, u1, u2, u3);
|
||||
#endif
|
||||
|
||||
#if defined( FL1_SET )
|
||||
d_1(uint32_t, t_dec(f,l), sb_data, w0);
|
||||
#endif
|
||||
#if defined( FL4_SET )
|
||||
d_4(uint32_t, t_dec(f,l), sb_data, w0, w1, w2, w3);
|
||||
#endif
|
||||
|
||||
#if defined( IT1_SET )
|
||||
d_1(uint32_t, t_dec(i,n), isb_data, v0);
|
||||
#endif
|
||||
#if defined( IT4_SET )
|
||||
d_4(uint32_t, t_dec(i,n), isb_data, v0, v1, v2, v3);
|
||||
#endif
|
||||
|
||||
#if defined( IL1_SET )
|
||||
d_1(uint32_t, t_dec(i,l), isb_data, w0);
|
||||
#endif
|
||||
#if defined( IL4_SET )
|
||||
d_4(uint32_t, t_dec(i,l), isb_data, w0, w1, w2, w3);
|
||||
#endif
|
||||
|
||||
#if defined( LS1_SET )
|
||||
#if defined( FL1_SET )
|
||||
#undef LS1_SET
|
||||
#else
|
||||
d_1(uint32_t, t_dec(l,s), sb_data, w0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined( LS4_SET )
|
||||
#if defined( FL4_SET )
|
||||
#undef LS4_SET
|
||||
#else
|
||||
d_4(uint32_t, t_dec(l,s), sb_data, w0, w1, w2, w3);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined( IM1_SET )
|
||||
d_1(uint32_t, t_dec(i,m), mm_data, v0);
|
||||
#endif
|
||||
#if defined( IM4_SET )
|
||||
d_4(uint32_t, t_dec(i,m), mm_data, v0, v1, v2, v3);
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
*/
|
||||
|
||||
#ifndef _BRG_ENDIAN_H
|
||||
#define _BRG_ENDIAN_H
|
||||
|
||||
#define IS_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */
|
||||
#define IS_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */
|
||||
|
||||
/* Include files where endian defines and byteswap functions may reside */
|
||||
#if defined( __sun )
|
||||
# include <sys/isa_defs.h>
|
||||
#elif defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ )
|
||||
# include <sys/endian.h>
|
||||
#elif defined( BSD ) && ( BSD >= 199103 ) || defined( __APPLE__ ) || \
|
||||
defined( __CYGWIN32__ ) || defined( __DJGPP__ ) || defined( __osf__ )
|
||||
# include <machine/endian.h>
|
||||
#elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ )
|
||||
# if !defined( __MINGW32__ ) && !defined( _AIX )
|
||||
# include <endian.h>
|
||||
# if !defined( __BEOS__ )
|
||||
# include <byteswap.h>
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Now attempt to set the define for platform byte order using any */
|
||||
/* of the four forms SYMBOL, _SYMBOL, __SYMBOL & __SYMBOL__, which */
|
||||
/* seem to encompass most endian symbol definitions */
|
||||
|
||||
#if defined( BIG_ENDIAN ) && defined( LITTLE_ENDIAN )
|
||||
# if defined( BYTE_ORDER ) && BYTE_ORDER == BIG_ENDIAN
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
# elif defined( BYTE_ORDER ) && BYTE_ORDER == LITTLE_ENDIAN
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
# endif
|
||||
#elif defined( BIG_ENDIAN )
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
#elif defined( LITTLE_ENDIAN )
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
#if defined( _BIG_ENDIAN ) && defined( _LITTLE_ENDIAN )
|
||||
# if defined( _BYTE_ORDER ) && _BYTE_ORDER == _BIG_ENDIAN
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
# elif defined( _BYTE_ORDER ) && _BYTE_ORDER == _LITTLE_ENDIAN
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
# endif
|
||||
#elif defined( _BIG_ENDIAN )
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
#elif defined( _LITTLE_ENDIAN )
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
#if defined( __BIG_ENDIAN ) && defined( __LITTLE_ENDIAN )
|
||||
# if defined( __BYTE_ORDER ) && __BYTE_ORDER == __BIG_ENDIAN
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
# elif defined( __BYTE_ORDER ) && __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
# endif
|
||||
#elif defined( __BIG_ENDIAN )
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
#elif defined( __LITTLE_ENDIAN )
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
#if defined( __BIG_ENDIAN__ ) && defined( __LITTLE_ENDIAN__ )
|
||||
# if defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __BIG_ENDIAN__
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
# elif defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __LITTLE_ENDIAN__
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
# endif
|
||||
#elif defined( __BIG_ENDIAN__ )
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
#elif defined( __LITTLE_ENDIAN__ )
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
/* if the platform byte order could not be determined, then try to */
|
||||
/* set this define using common machine defines */
|
||||
#if !defined(PLATFORM_BYTE_ORDER)
|
||||
|
||||
#if defined( __alpha__ ) || defined( __alpha ) || defined( i386 ) || \
|
||||
defined( __i386__ ) || defined( _M_I86 ) || defined( _M_IX86 ) || \
|
||||
defined( __OS2__ ) || defined( sun386 ) || defined( __TURBOC__ ) || \
|
||||
defined( vax ) || defined( vms ) || defined( VMS ) || \
|
||||
defined( __VMS ) || defined( _M_X64 )
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
|
||||
#elif defined( AMIGA ) || defined( applec ) || defined( __AS400__ ) || \
|
||||
defined( _CRAY ) || defined( __hppa ) || defined( __hp9000 ) || \
|
||||
defined( ibm370 ) || defined( mc68000 ) || defined( m68k ) || \
|
||||
defined( __MRC__ ) || defined( __MVS__ ) || defined( __MWERKS__ ) || \
|
||||
defined( sparc ) || defined( __sparc) || defined( SYMANTEC_C ) || \
|
||||
defined( __VOS__ ) || defined( __TIGCC__ ) || defined( __TANDEM ) || \
|
||||
defined( THINK_C ) || defined( __VMCMS__ ) || defined( _AIX )
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
|
||||
#elif 0 /* **** EDIT HERE IF NECESSARY **** */
|
||||
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
#elif 0 /* **** EDIT HERE IF NECESSARY **** */
|
||||
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
#else
|
||||
# error Please edit lines 126 or 128 in brg_endian.h to set the platform byte order
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved.
|
||||
|
||||
The redistribution and use of this software (with or without changes)
|
||||
is allowed without the payment of fees or royalties provided that:
|
||||
|
||||
source code distributions include the above copyright notice, this
|
||||
list of conditions and the following disclaimer;
|
||||
|
||||
binary distributions include the above copyright notice, this list
|
||||
of conditions and the following disclaimer in their documentation.
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its operation, including, but not limited to, correctness
|
||||
and fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 20/12/2007
|
||||
|
||||
The unsigned integer types defined here are of the form uint_<nn>t where
|
||||
<nn> is the length of the type; for example, the unsigned 32-bit type is
|
||||
'uint32_t'. These are NOT the same as the 'C99 integer types' that are
|
||||
defined in the inttypes.h and stdint.h headers since attempts to use these
|
||||
types have shown that support for them is still highly variable. However,
|
||||
since the latter are of the form uint<nn>_t, a regular expression search
|
||||
and replace (in VC++ search on 'uint_{:z}t' and replace with 'uint\1_t')
|
||||
can be used to convert the types used here to the C99 standard types.
|
||||
*/
|
||||
|
||||
#ifndef _BRG_TYPES_H
|
||||
#define _BRG_TYPES_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined( _WIN32 ) && ( _WIN32 >= 1300 )
|
||||
# include <stddef.h>
|
||||
# define ptrint_t intptr_t
|
||||
#elif defined( __ECOS__ )
|
||||
# define intptr_t unsigned int
|
||||
# define ptrint_t intptr_t
|
||||
#elif defined( __GNUC__ ) && ( __GNUC__ >= 3 )
|
||||
# define ptrint_t intptr_t
|
||||
#else
|
||||
# define ptrint_t int
|
||||
#endif
|
||||
|
||||
#ifndef BRG_UI32
|
||||
# define BRG_UI32
|
||||
# if UINT_MAX == 4294967295u
|
||||
# define li_32(h) 0x##h##u
|
||||
# elif ULONG_MAX == 4294967295u
|
||||
# define li_32(h) 0x##h##ul
|
||||
# elif defined( _CRAY )
|
||||
# error This code needs 32-bit data types, which Cray machines do not provide
|
||||
# else
|
||||
# error Please define uint32_t as a 32-bit unsigned integer type in brg_types.h
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BRG_UI64
|
||||
# if defined( __BORLANDC__ ) && !defined( __MSDOS__ )
|
||||
# define BRG_UI64
|
||||
# define li_64(h) 0x##h##ui64
|
||||
# elif defined( _WIN32 ) && ( _WIN32 < 1300 ) /* 1300 == VC++ 7.0 */
|
||||
# define BRG_UI64
|
||||
# define li_64(h) 0x##h##ui64
|
||||
# elif defined( __sun ) && defined( ULONG_MAX ) && ULONG_MAX == 0xfffffffful
|
||||
# define BRG_UI64
|
||||
# define li_64(h) 0x##h##ull
|
||||
# elif defined( __MVS__ )
|
||||
# define BRG_UI64
|
||||
# define li_64(h) 0x##h##ull
|
||||
# elif defined( UINT_MAX ) && UINT_MAX > 4294967295u
|
||||
# if UINT_MAX == 18446744073709551615u
|
||||
# define BRG_UI64
|
||||
# define li_64(h) 0x##h##u
|
||||
# endif
|
||||
# elif defined( ULONG_MAX ) && ULONG_MAX > 4294967295u
|
||||
# if ULONG_MAX == 18446744073709551615ul
|
||||
# define BRG_UI64
|
||||
# define li_64(h) 0x##h##ul
|
||||
# endif
|
||||
# elif defined( ULLONG_MAX ) && ULLONG_MAX > 4294967295u
|
||||
# if ULLONG_MAX == 18446744073709551615ull
|
||||
# define BRG_UI64
|
||||
# define li_64(h) 0x##h##ull
|
||||
# endif
|
||||
# elif defined( ULONG_LONG_MAX ) && ULONG_LONG_MAX > 4294967295u
|
||||
# if ULONG_LONG_MAX == 18446744073709551615ull
|
||||
# define BRG_UI64
|
||||
# define li_64(h) 0x##h##ull
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined( BRG_UI64 )
|
||||
# if defined( NEED_UINT_64T )
|
||||
# error Please define uint64_t as an unsigned 64 bit type in brg_types.h
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef RETURN_VALUES
|
||||
# define RETURN_VALUES
|
||||
# if defined( DLL_EXPORT )
|
||||
# if defined( _WIN32 ) || defined ( __INTEL_COMPILER )
|
||||
# define VOID_RETURN __declspec( dllexport ) void __stdcall
|
||||
# define INT_RETURN __declspec( dllexport ) int __stdcall
|
||||
# elif defined( __GNUC__ )
|
||||
# define VOID_RETURN __declspec( __dllexport__ ) void
|
||||
# define INT_RETURN __declspec( __dllexport__ ) int
|
||||
# else
|
||||
# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers
|
||||
# endif
|
||||
# elif defined( DLL_IMPORT )
|
||||
# if defined( _WIN32 ) || defined ( __INTEL_COMPILER )
|
||||
# define VOID_RETURN __declspec( dllimport ) void __stdcall
|
||||
# define INT_RETURN __declspec( dllimport ) int __stdcall
|
||||
# elif defined( __GNUC__ )
|
||||
# define VOID_RETURN __declspec( __dllimport__ ) void
|
||||
# define INT_RETURN __declspec( __dllimport__ ) int
|
||||
# else
|
||||
# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers
|
||||
# endif
|
||||
# elif defined( __WATCOMC__ )
|
||||
# define VOID_RETURN void __cdecl
|
||||
# define INT_RETURN int __cdecl
|
||||
# else
|
||||
# define VOID_RETURN void
|
||||
# define INT_RETURN int
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* These defines are used to detect and set the memory alignment of pointers.
|
||||
Note that offsets are in bytes.
|
||||
|
||||
ALIGN_OFFSET(x,n) return the positive or zero offset of
|
||||
the memory addressed by the pointer 'x'
|
||||
from an address that is aligned on an
|
||||
'n' byte boundary ('n' is a power of 2)
|
||||
|
||||
ALIGN_FLOOR(x,n) return a pointer that points to memory
|
||||
that is aligned on an 'n' byte boundary
|
||||
and is not higher than the memory address
|
||||
pointed to by 'x' ('n' is a power of 2)
|
||||
|
||||
ALIGN_CEIL(x,n) return a pointer that points to memory
|
||||
that is aligned on an 'n' byte boundary
|
||||
and is not lower than the memory address
|
||||
pointed to by 'x' ('n' is a power of 2)
|
||||
*/
|
||||
|
||||
#define ALIGN_OFFSET(x,n) (((ptrint_t)(x)) & ((n) - 1))
|
||||
#define ALIGN_FLOOR(x,n) ((uint8_t*)(x) - ( ((ptrint_t)(x)) & ((n) - 1)))
|
||||
#define ALIGN_CEIL(x,n) ((uint8_t*)(x) + (-((ptrint_t)(x)) & ((n) - 1)))
|
||||
|
||||
/* These defines are used to declare buffers in a way that allows
|
||||
faster operations on longer variables to be used. In all these
|
||||
defines 'size' must be a power of 2 and >= 8. NOTE that the
|
||||
buffer size is in bytes but the type length is in bits
|
||||
|
||||
UNIT_TYPEDEF(x,size) declares a variable 'x' of length
|
||||
'size' bits
|
||||
|
||||
BUFR_TYPEDEF(x,size,bsize) declares a buffer 'x' of length 'bsize'
|
||||
bytes defined as an array of variables
|
||||
each of 'size' bits (bsize must be a
|
||||
multiple of size / 8)
|
||||
|
||||
UNIT_CAST(x,size) casts a variable to a type of
|
||||
length 'size' bits
|
||||
|
||||
UPTR_CAST(x,size) casts a pointer to a pointer to a
|
||||
varaiable of length 'size' bits
|
||||
*/
|
||||
|
||||
#define UI_TYPE(size) uint##size##_t
|
||||
#define UNIT_TYPEDEF(x,size) typedef UI_TYPE(size) x
|
||||
#define BUFR_TYPEDEF(x,size,bsize) typedef UI_TYPE(size) x[bsize / (size >> 3)]
|
||||
#define UNIT_CAST(x,size) ((UI_TYPE(size) )(x))
|
||||
#define UPTR_CAST(x,size) ((UI_TYPE(size)*)(x))
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,148 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Alarm.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_ALARM
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "Alarm.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Node.h"
|
||||
#include "../Driver.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
#include "../value_classes/ValueByte.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum AlarmCmd
|
||||
{
|
||||
AlarmCmd_Get = 0x04,
|
||||
AlarmCmd_Report = 0x05
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
AlarmIndex_Type = 0,
|
||||
AlarmIndex_Level
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Alarm::RequestState>
|
||||
// Request current state from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Alarm::RequestState
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( _requestFlags & RequestFlag_Dynamic )
|
||||
{
|
||||
return RequestValue( _requestFlags, 0, _instance, _queue );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Alarm::RequestValue>
|
||||
// Request current value from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Alarm::RequestValue
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _dummy1, // = 0 (not used)
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( IsGetSupported() )
|
||||
{
|
||||
Msg* msg = new Msg( "AlarmCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, _instance );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( AlarmCmd_Get );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
return true;
|
||||
} else {
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "AlarmCmd_Get Not Supported on this node");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Alarm::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Alarm::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
if (AlarmCmd_Report == (AlarmCmd)_data[0])
|
||||
{
|
||||
// We have received a report from the Z-Wave device
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received Alarm report: type=%d, level=%d", _data[1], _data[2] );
|
||||
|
||||
ValueByte* value;
|
||||
if( (value = static_cast<ValueByte*>( GetValue( _instance, AlarmIndex_Type ) )) )
|
||||
{
|
||||
value->OnValueRefreshed( _data[1] );
|
||||
value->Release();
|
||||
}
|
||||
if( (value = static_cast<ValueByte*>( GetValue( _instance, AlarmIndex_Level ) )) )
|
||||
{
|
||||
value->OnValueRefreshed( _data[2] );
|
||||
value->Release();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Alarm::CreateVars>
|
||||
// Create the values managed by this command class
|
||||
//-----------------------------------------------------------------------------
|
||||
void Alarm::CreateVars
|
||||
(
|
||||
uint8 const _instance
|
||||
)
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
node->CreateValueByte( ValueID::ValueGenre_User, GetCommandClassId(), _instance, AlarmIndex_Type, "Alarm Type", "", true, false, 0, 0 );
|
||||
node->CreateValueByte( ValueID::ValueGenre_User, GetCommandClassId(), _instance, AlarmIndex_Level, "Alarm Level", "", true, false, 0, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Alarm.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_ALARM
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _Alarm_H
|
||||
#define _Alarm_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class ValueByte;
|
||||
|
||||
/** \brief Implements COMMAND_CLASS_ALARM (0x71), a Z-Wave device command class.
|
||||
*/
|
||||
class Alarm: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new Alarm( _homeId, _nodeId ); }
|
||||
virtual ~Alarm(){}
|
||||
|
||||
/** \brief Get command class ID (1 byte) identifying this command class. */
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x71; }
|
||||
/** \brief Get a string containing the name of this command class. */
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_ALARM"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual bool RequestState( uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual bool RequestValue( uint32 const _requestFlags, uint8 const _index, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
/** \brief Get command class ID (1 byte) identifying this command class. (Inherited from CommandClass) */
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
/** \brief Get a string containing the name of this command class. (Inherited from CommandClass) */
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
/** \brief Handle a response to a message associated with this command class. (Inherited from CommandClass) */
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
|
||||
virtual uint8 GetMaxVersion(){ return 2; }
|
||||
|
||||
protected:
|
||||
virtual void CreateVars( uint8 const _instance );
|
||||
|
||||
private:
|
||||
Alarm( uint32 const _homeId, uint8 const _nodeId ): CommandClass( _homeId, _nodeId ){}
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,93 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ApplicationStatus.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_APPLICATION_STATUS
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "ApplicationStatus.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Driver.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum ApplicationStatusCmd
|
||||
{
|
||||
ApplicationStatusCmd_Busy = 0x01,
|
||||
ApplicationStatusCmd_RejectedRequest = 0x02
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ApplicationStatus::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ApplicationStatus::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
if( ApplicationStatusCmd_Busy == (ApplicationStatusCmd)_data[0] )
|
||||
{
|
||||
char msg[64];
|
||||
switch( _data[1] )
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
snprintf( msg, sizeof(msg), "Try again later" );
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
snprintf( msg, sizeof(msg), "Try again in %d seconds", _data[2] );
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
snprintf( msg, sizeof(msg), "Request queued, will be executed later" );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
// Invalid status
|
||||
snprintf( msg, sizeof(msg), "Unknown status %d", _data[1] );
|
||||
}
|
||||
}
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received Application Status Busy: %s", msg );
|
||||
return true;
|
||||
}
|
||||
|
||||
if( ApplicationStatusCmd_RejectedRequest == (ApplicationStatusCmd)_data[0] )
|
||||
{
|
||||
Log::Write( LogLevel_Info, "Received Application Rejected Request: Status=%d", _data[1] );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ApplicationStatus.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_APPLICATION_STATUS
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _ApplicationStatus_H
|
||||
#define _ApplicationStatus_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
/** \brief Implements COMMAND_CLASS_APPLICATION_STATUS (0x22), a Z-Wave device command class.
|
||||
*/
|
||||
class ApplicationStatus: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new ApplicationStatus( _homeId, _nodeId ); }
|
||||
virtual ~ApplicationStatus(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x22; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_APPLICATION_STATUS"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
|
||||
private:
|
||||
ApplicationStatus( uint32 const _homeId, uint8 const _nodeId ): CommandClass( _homeId, _nodeId ){}
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,390 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Association.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_ASSOCIATION
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "../tinyxml.h"
|
||||
#include "CommandClasses.h"
|
||||
#include "Association.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Driver.h"
|
||||
#include "../Node.h"
|
||||
#include "../Group.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum AssociationCmd
|
||||
{
|
||||
AssociationCmd_Set = 0x01,
|
||||
AssociationCmd_Get = 0x02,
|
||||
AssociationCmd_Report = 0x03,
|
||||
AssociationCmd_Remove = 0x04,
|
||||
AssociationCmd_GroupingsGet = 0x05,
|
||||
AssociationCmd_GroupingsReport = 0x06
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Association::Association>
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
Association::Association
|
||||
(
|
||||
uint32 const _homeId,
|
||||
uint8 const _nodeId
|
||||
):
|
||||
CommandClass( _homeId, _nodeId ),
|
||||
m_queryAll(false),
|
||||
m_numGroups(0)
|
||||
{
|
||||
SetStaticRequest( StaticRequest_Values );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Association::ReadXML>
|
||||
// Read the saved association data
|
||||
//-----------------------------------------------------------------------------
|
||||
void Association::ReadXML
|
||||
(
|
||||
TiXmlElement const* _ccElement
|
||||
)
|
||||
{
|
||||
CommandClass::ReadXML( _ccElement );
|
||||
|
||||
TiXmlElement const* associationsElement = _ccElement->FirstChildElement();
|
||||
while( associationsElement )
|
||||
{
|
||||
char const* str = associationsElement->Value();
|
||||
if( str && !strcmp( str, "Associations" ) )
|
||||
{
|
||||
int intVal;
|
||||
if( TIXML_SUCCESS == associationsElement->QueryIntAttribute( "num_groups", &intVal ) )
|
||||
{
|
||||
m_numGroups = (uint8)intVal;
|
||||
}
|
||||
|
||||
TiXmlElement const* groupElement = associationsElement->FirstChildElement();
|
||||
while( groupElement )
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
Group* group = new Group( GetHomeId(), GetNodeId(), groupElement );
|
||||
node->AddGroup( group );
|
||||
}
|
||||
|
||||
groupElement = groupElement->NextSiblingElement();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
associationsElement = associationsElement->NextSiblingElement();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Association::WriteXML>
|
||||
// Save the association data
|
||||
//-----------------------------------------------------------------------------
|
||||
void Association::WriteXML
|
||||
(
|
||||
TiXmlElement* _ccElement
|
||||
)
|
||||
{
|
||||
CommandClass::WriteXML( _ccElement );
|
||||
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
TiXmlElement* associationsElement = new TiXmlElement( "Associations" );
|
||||
|
||||
char str[8];
|
||||
snprintf( str, 8, "%d", m_numGroups );
|
||||
associationsElement->SetAttribute( "num_groups", str );
|
||||
|
||||
_ccElement->LinkEndChild( associationsElement );
|
||||
node->WriteGroups( associationsElement );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Association::RequestState>
|
||||
// Nothing to do for Association
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Association::RequestState
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( ( _requestFlags & RequestFlag_Static ) && HasStaticRequest( StaticRequest_Values ) )
|
||||
{
|
||||
// Request the supported group info
|
||||
return RequestValue( _requestFlags, 0, _instance, _queue );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Association::RequestValue>
|
||||
// Nothing to do for Association
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Association::RequestValue
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _dummy1, // = 0 (not used)
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( _instance != 1 )
|
||||
{
|
||||
// This command class doesn't work with multiple instances
|
||||
return false;
|
||||
}
|
||||
// Request the supported group info
|
||||
Msg* msg = new Msg( "Get Association Groupings", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( AssociationCmd_GroupingsGet );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Association::RequestAllGroups>
|
||||
// Request the contents of each group in turn
|
||||
//-----------------------------------------------------------------------------
|
||||
void Association::RequestAllGroups
|
||||
(
|
||||
uint32 const _requestFlags
|
||||
)
|
||||
{
|
||||
m_queryAll = true;
|
||||
|
||||
// Request the contents of the individual groups in turn.
|
||||
if( m_numGroups == 0xff )
|
||||
{
|
||||
// We start with group 255, and will then move to group 1, 2 etc and stop when we find a group with a maxAssociations of zero.
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Number of association groups reported for node %d is 255, which requires special case handling.", GetNodeId() );
|
||||
QueryGroup( 0xff, _requestFlags );
|
||||
}
|
||||
else
|
||||
{
|
||||
// We start with group 1, and will then move to group 2, 3 etc and stop when the group index is greater than m_numGroups.
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Number of association groups reported for node %d is %d.", GetNodeId(), m_numGroups );
|
||||
QueryGroup( 1, _requestFlags );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Association::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Association::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
bool handled = false;
|
||||
uint32 i;
|
||||
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
if( AssociationCmd_GroupingsReport == (AssociationCmd)_data[0] )
|
||||
{
|
||||
// Retrieve the number of groups this device supports.
|
||||
// The groups will be queried with the session data.
|
||||
m_numGroups = _data[1];
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received Association Groupings report from node %d. Number of groups is %d", GetNodeId(), m_numGroups );
|
||||
ClearStaticRequest( StaticRequest_Values );
|
||||
handled = true;
|
||||
}
|
||||
else if( AssociationCmd_Report == (AssociationCmd)_data[0] )
|
||||
{
|
||||
// Get the group info
|
||||
uint8 groupIdx = _data[1];
|
||||
uint8 maxAssociations = _data[2]; // If the maxAssociations is zero, this is not a supported group.
|
||||
uint8 numReportsToFollow = _data[3]; // If a device supports a lot of associations, they may come in more than one message.
|
||||
|
||||
if( maxAssociations )
|
||||
{
|
||||
if( _length >= 5 )
|
||||
{
|
||||
uint8 numAssociations = _length - 5;
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received Association report from node %d, group %d, containing %d associations", GetNodeId(), groupIdx, numAssociations );
|
||||
if( numAssociations )
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), " The group contains:" );
|
||||
for( i=0; i<numAssociations; ++i )
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), " Node %d", _data[i+4] );
|
||||
m_pendingMembers.push_back( _data[i+4] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( numReportsToFollow )
|
||||
{
|
||||
// We're expecting more reports for this group
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "%d more association reports expected for node %d, group %d", numReportsToFollow, GetNodeId(), groupIdx );
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No more reports to come for this group, so we can apply the pending list
|
||||
Group* group = node->GetGroup( groupIdx );
|
||||
if( NULL == group )
|
||||
{
|
||||
// Group has not been created yet
|
||||
group = new Group( GetHomeId(), GetNodeId(), groupIdx, maxAssociations );
|
||||
node->AddGroup( group );
|
||||
}
|
||||
|
||||
// Update the group with its new contents
|
||||
group->OnGroupChanged( m_pendingMembers );
|
||||
m_pendingMembers.clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// maxAssociations is zero, so we've reached the end of the query process
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Max associations for node %d, group %d is zero. Querying associations for this node is complete.", GetNodeId(), groupIdx );
|
||||
node->AutoAssociate();
|
||||
m_queryAll = false;
|
||||
}
|
||||
|
||||
if( m_queryAll )
|
||||
{
|
||||
// Work out which is the next group we will query.
|
||||
// If we are currently on group 255, the next group will be 1.
|
||||
uint8 nextGroup = groupIdx + 1;
|
||||
if( !nextGroup )
|
||||
{
|
||||
nextGroup = 1;
|
||||
}
|
||||
|
||||
if( nextGroup <= m_numGroups )
|
||||
{
|
||||
// Query the next group
|
||||
QueryGroup( nextGroup, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
// We're all done
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Querying associations for node %d is complete.", GetNodeId() );
|
||||
node->AutoAssociate();
|
||||
m_queryAll = false;
|
||||
}
|
||||
}
|
||||
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Association::QueryGroup>
|
||||
// Request details of an association group
|
||||
//-----------------------------------------------------------------------------
|
||||
void Association::QueryGroup
|
||||
(
|
||||
uint8 _groupIdx,
|
||||
uint32 const _requestFlags
|
||||
)
|
||||
{
|
||||
if ( IsGetSupported() )
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Get Associations for group %d of node %d", _groupIdx, GetNodeId() );
|
||||
Msg* msg = new Msg( "Get Associations", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 3 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( AssociationCmd_Get );
|
||||
msg->Append( _groupIdx );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
return;
|
||||
} else {
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "AssociationCmd_Get Not Supported on this node");
|
||||
}
|
||||
return;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Association::Set>
|
||||
// Add an association between devices
|
||||
//-----------------------------------------------------------------------------
|
||||
void Association::Set
|
||||
(
|
||||
uint8 _groupIdx,
|
||||
uint8 _targetNodeId
|
||||
)
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Association::Set - Adding node %d to group %d of node %d", _targetNodeId, _groupIdx, GetNodeId() );
|
||||
|
||||
Msg* msg = new Msg( "Association Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 4 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( AssociationCmd_Set );
|
||||
msg->Append( _groupIdx );
|
||||
msg->Append( _targetNodeId );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Association::Remove>
|
||||
// Remove an association between devices
|
||||
//-----------------------------------------------------------------------------
|
||||
void Association::Remove
|
||||
(
|
||||
uint8 _groupIdx,
|
||||
uint8 _targetNodeId
|
||||
)
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Association::Remove - Removing node %d from group %d of node %d", _targetNodeId, _groupIdx, GetNodeId() );
|
||||
|
||||
Msg* msg = new Msg( "Association Remove", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 4 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( AssociationCmd_Remove );
|
||||
msg->Append( _groupIdx );
|
||||
msg->Append( _targetNodeId );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Association.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_ASSOCIATION
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _Association_H
|
||||
#define _Association_H
|
||||
|
||||
#include <vector>
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
/** \brief Implements COMMAND_CLASS_ASSOCIATION (0x85), a Z-Wave device command class.
|
||||
*/
|
||||
class Association: public CommandClass
|
||||
{
|
||||
friend class Group;
|
||||
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new Association( _homeId, _nodeId ); }
|
||||
virtual ~Association(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x85; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_ASSOCIATION"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual void ReadXML( TiXmlElement const* _ccElement );
|
||||
virtual void WriteXML( TiXmlElement* _ccElement );
|
||||
virtual bool RequestState( uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual bool RequestValue( uint32 const _requestFlags, uint8 const _index, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
|
||||
void RequestAllGroups( uint32 const _requestFlags );
|
||||
void Set( uint8 const _group, uint8 const _nodeId );
|
||||
void Remove( uint8 const _group, uint8 const _nodeId );
|
||||
|
||||
private:
|
||||
Association( uint32 const _homeId, uint8 const _nodeId );
|
||||
void QueryGroup( uint8 _groupIdx, uint32 const _requestFlags );
|
||||
void AutoAssociate();
|
||||
|
||||
bool m_queryAll; // When true, once a group has been queried, we request the next one.
|
||||
uint8 m_numGroups; // Number of groups supported by the device. 255 is reported by certain manufacturers and requires special handling.
|
||||
vector<uint8> m_pendingMembers; // Used to build a list of group members from multiple reports
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
+281
@@ -0,0 +1,281 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// AssociationCommandConfiguration.cpp
|
||||
//
|
||||
// Implementation of the COMMAND_CLASS_ASSOCIATION_COMMAND_CONFIGURATION
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "AssociationCommandConfiguration.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Node.h"
|
||||
#include "../Group.h"
|
||||
#include "../Driver.h"
|
||||
#include "../platform/Log.h"
|
||||
#include "../value_classes/ValueBool.h"
|
||||
#include "../value_classes/ValueByte.h"
|
||||
#include "../value_classes/ValueShort.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum AssociationCommandConfigurationCmd
|
||||
{
|
||||
AssociationCommandConfigurationCmd_SupportedRecordsGet = 0x01,
|
||||
AssociationCommandConfigurationCmd_SupportedRecordsReport = 0x02,
|
||||
AssociationCommandConfigurationCmd_Set = 0x03,
|
||||
AssociationCommandConfigurationCmd_Get = 0x04,
|
||||
AssociationCommandConfigurationCmd_Report = 0x05
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
AssociationCommandConfigurationIndex_MaxCommandLength = 0,
|
||||
AssociationCommandConfigurationIndex_CommandsAreValues,
|
||||
AssociationCommandConfigurationIndex_CommandsAreConfigurable,
|
||||
AssociationCommandConfigurationIndex_NumFreeCommands,
|
||||
AssociationCommandConfigurationIndex_MaxCommands
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <AssociationCommandConfiguration::RequestState>
|
||||
// Request current state from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool AssociationCommandConfiguration::RequestState
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( _requestFlags & RequestFlag_Session )
|
||||
{
|
||||
return RequestValue( _requestFlags, 0, _instance, _queue );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <AssociationCommandConfiguration::RequestValue>
|
||||
// Request current value from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool AssociationCommandConfiguration::RequestValue
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _dummy1, // = 0 (not used)
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( _instance != 1 )
|
||||
{
|
||||
// This command class doesn't work with multiple instances
|
||||
return false;
|
||||
}
|
||||
|
||||
Msg* msg = new Msg( "AssociationCommandConfigurationCmd_SupportedRecordsGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( AssociationCommandConfigurationCmd_SupportedRecordsGet );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <AssociationCommandConfiguration::RequestCommands>
|
||||
// Request the command data
|
||||
//-----------------------------------------------------------------------------
|
||||
void AssociationCommandConfiguration::RequestCommands
|
||||
(
|
||||
uint8 const _groupIdx,
|
||||
uint8 const _nodeId
|
||||
)
|
||||
{
|
||||
if ( IsGetSupported() )
|
||||
{
|
||||
Msg* msg = new Msg( "AssociationCommandConfigurationCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 4 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( AssociationCommandConfigurationCmd_Get );
|
||||
msg->Append( _groupIdx );
|
||||
msg->Append( _nodeId );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
} else {
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "AssociationCommandConfigurationCmd_Get Not Supported on this node");
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// <AssociationCommandConfiguration::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool AssociationCommandConfiguration::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
if (AssociationCommandConfigurationCmd_SupportedRecordsReport == (AssociationCommandConfigurationCmd)_data[0])
|
||||
{
|
||||
uint8 maxCommandLength = _data[1] >> 2;
|
||||
bool commandsAreValues = ( (_data[1] & 0x02) != 0 );
|
||||
bool commandsAreConfigurable = ( (_data[1] & 0x01) != 0 );
|
||||
int16 numFreeCommands = (((int16)_data[2])<<16) | (int16)_data[3];
|
||||
int16 maxCommands = (((int16)_data[4])<<16) | (int16)_data[5];
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received AssociationCommandConfiguration Supported Records Report:" );
|
||||
Log::Write( LogLevel_Info, GetNodeId(), " Maximum command length = %d bytes", maxCommandLength );
|
||||
Log::Write( LogLevel_Info, GetNodeId(), " Maximum number of commands = %d", maxCommands );
|
||||
Log::Write( LogLevel_Info, GetNodeId(), " Number of free commands = %d", numFreeCommands );
|
||||
Log::Write( LogLevel_Info, GetNodeId(), " Commands are %s and are %s", commandsAreValues ? "values" : "not values", commandsAreConfigurable ? "configurable" : "not configurable" );
|
||||
|
||||
ValueBool* valueBool;
|
||||
ValueByte* valueByte;
|
||||
ValueShort* valueShort;
|
||||
|
||||
if( (valueByte = static_cast<ValueByte*>( GetValue( _instance, AssociationCommandConfigurationIndex_MaxCommandLength ) )) )
|
||||
{
|
||||
valueByte->OnValueRefreshed( maxCommandLength );
|
||||
valueByte->Release();
|
||||
}
|
||||
|
||||
if( (valueBool = static_cast<ValueBool*>( GetValue( _instance, AssociationCommandConfigurationIndex_CommandsAreValues ) )) )
|
||||
{
|
||||
valueBool->OnValueRefreshed( commandsAreValues );
|
||||
valueBool->Release();
|
||||
}
|
||||
|
||||
if( (valueBool = static_cast<ValueBool*>( GetValue( _instance, AssociationCommandConfigurationIndex_CommandsAreConfigurable ) )) )
|
||||
{
|
||||
valueBool->OnValueRefreshed( commandsAreConfigurable );
|
||||
valueBool->Release();
|
||||
}
|
||||
|
||||
if( (valueShort = static_cast<ValueShort*>( GetValue( _instance, AssociationCommandConfigurationIndex_NumFreeCommands ) )) )
|
||||
{
|
||||
valueShort->OnValueRefreshed( numFreeCommands );
|
||||
valueShort->Release();
|
||||
}
|
||||
|
||||
if( (valueShort = static_cast<ValueShort*>( GetValue( _instance, AssociationCommandConfigurationIndex_MaxCommands ) )) )
|
||||
{
|
||||
valueShort->OnValueRefreshed( maxCommands );
|
||||
valueShort->Release();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (AssociationCommandConfigurationCmd_Report == (AssociationCommandConfigurationCmd)_data[0])
|
||||
{
|
||||
uint8 groupIdx = _data[1];
|
||||
uint8 nodeIdx = _data[2];
|
||||
bool firstReports = ( ( _data[3] & 0x80 ) != 0 ); // True if this is the first message containing commands for this group and node.
|
||||
uint8 numReports = _data[3] & 0x0f;
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received AssociationCommandConfiguration Report from:" );
|
||||
Log::Write( LogLevel_Info, GetNodeId(), " Commands for node %d in group %d,", nodeIdx, groupIdx );
|
||||
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
Group* group = node->GetGroup( groupIdx );
|
||||
if( NULL == group )
|
||||
{
|
||||
if( firstReports )
|
||||
{
|
||||
// This is the first report message, so we should clear any existing command data
|
||||
group->ClearCommands( nodeIdx );
|
||||
}
|
||||
|
||||
uint8 const* start = &_data[4];
|
||||
|
||||
for( uint8 i=0; i<numReports; ++i )
|
||||
{
|
||||
uint8 length = start[0];
|
||||
group->AddCommand( nodeIdx, length, start+1 );
|
||||
start += length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <AssociationCommandConfiguration::CreateVars>
|
||||
// Create the values managed by this command class
|
||||
//-----------------------------------------------------------------------------
|
||||
void AssociationCommandConfiguration::CreateVars
|
||||
(
|
||||
uint8 const _instance
|
||||
)
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
node->CreateValueByte ( ValueID::ValueGenre_System, GetCommandClassId(), _instance, AssociationCommandConfigurationIndex_MaxCommandLength, "Max Command Length", "", true, false, 0, 0 );
|
||||
node->CreateValueBool ( ValueID::ValueGenre_System, GetCommandClassId(), _instance, AssociationCommandConfigurationIndex_CommandsAreValues, "Commands are Values", "", true, false, false, 0 );
|
||||
node->CreateValueBool ( ValueID::ValueGenre_System, GetCommandClassId(), _instance, AssociationCommandConfigurationIndex_CommandsAreConfigurable, "Commands are Configurable", "", true, false, false, 0 );
|
||||
node->CreateValueShort( ValueID::ValueGenre_System, GetCommandClassId(), _instance, AssociationCommandConfigurationIndex_NumFreeCommands, "Free Commands", "", true, false, 0, 0 );
|
||||
node->CreateValueShort( ValueID::ValueGenre_System, GetCommandClassId(), _instance, AssociationCommandConfigurationIndex_MaxCommands, "Max Commands", "", true, false, 0, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <AssociationCommandConfiguration::SetCommand>
|
||||
// Set a command for the association
|
||||
//-----------------------------------------------------------------------------
|
||||
void AssociationCommandConfiguration::SetCommand
|
||||
(
|
||||
uint8 const _groupIdx,
|
||||
uint8 const _nodeId,
|
||||
uint8 const _length,
|
||||
uint8 const* _data
|
||||
)
|
||||
{
|
||||
Msg* msg = new Msg( "AssociationCommandConfigurationCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( _length + 5 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( AssociationCommandConfigurationCmd_Set );
|
||||
msg->Append( _groupIdx );
|
||||
msg->Append( _nodeId );
|
||||
msg->Append( _length );
|
||||
|
||||
for( uint8 i=0; i<_length; ++i )
|
||||
{
|
||||
msg->Append( _data[i] );
|
||||
}
|
||||
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
}
|
||||
|
||||
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// AssociationCommandConfiguration.h
|
||||
//
|
||||
// Implementation of the COMMAND_CLASS_ASSOCIATION_COMMAND_CONFIGURATION
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _AssociationCommandConfiguration_H
|
||||
#define _AssociationCommandConfiguration_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
#include "../value_classes/ValueBool.h"
|
||||
#include "../value_classes/ValueByte.h"
|
||||
#include "../value_classes/ValueShort.h"
|
||||
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
/** \brief Implements COMMAND_CLASS_ASSOCIATION_COMMAND_CONFIGURATION (0x9b), a Z-Wave device command class.
|
||||
*/
|
||||
|
||||
class AssociationCommandConfiguration: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new AssociationCommandConfiguration( _homeId, _nodeId ); }
|
||||
virtual ~AssociationCommandConfiguration(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x9b; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_ASSOCIATION_COMMAND_CONFIGURATION"; }
|
||||
|
||||
void RequestCommands( uint8 const _groupIdx, uint8 const _nodeId );
|
||||
void SetCommand( uint8 const _groupIdx, uint8 const _nodeId, uint8 const _length, uint8 const* _data );
|
||||
|
||||
// From CommandClass
|
||||
virtual bool RequestState( uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual bool RequestValue( uint32 const _requestFlags, uint8 const _index, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
|
||||
protected:
|
||||
virtual void CreateVars( uint8 const _instance );
|
||||
|
||||
private:
|
||||
AssociationCommandConfiguration( uint32 const _homeId, uint8 const _nodeId ): CommandClass( _homeId, _nodeId ){}
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,345 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Basic.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_BASIC
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "Basic.h"
|
||||
#include "Association.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Node.h"
|
||||
#include "../Driver.h"
|
||||
#include "../Notification.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
#include "../value_classes/ValueByte.h"
|
||||
#include "NoOperation.h"
|
||||
|
||||
#include "../tinyxml.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum BasicCmd
|
||||
{
|
||||
BasicCmd_Set = 0x01,
|
||||
BasicCmd_Get = 0x02,
|
||||
BasicCmd_Report = 0x03
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Basic::Basic>
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
Basic::Basic
|
||||
(
|
||||
uint32 const _homeId,
|
||||
uint8 const _nodeId
|
||||
):
|
||||
CommandClass( _homeId, _nodeId ),
|
||||
m_mapping( 0 ),
|
||||
m_ignoreMapping( false ),
|
||||
m_setAsReport( false )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Basic::ReadXML>
|
||||
// Read configuration.
|
||||
//-----------------------------------------------------------------------------
|
||||
void Basic::ReadXML
|
||||
(
|
||||
TiXmlElement const* _ccElement
|
||||
)
|
||||
{
|
||||
CommandClass::ReadXML( _ccElement );
|
||||
|
||||
char const* str = _ccElement->Attribute("ignoremapping");
|
||||
if( str )
|
||||
{
|
||||
m_ignoreMapping = !strcmp( str, "true");
|
||||
}
|
||||
|
||||
int32 intVal;
|
||||
if( TIXML_SUCCESS == _ccElement->QueryIntAttribute( "mapping", &intVal ) )
|
||||
{
|
||||
if( intVal < 256 && intVal != 0 )
|
||||
{
|
||||
SetMapping( (uint8)intVal, false );
|
||||
}
|
||||
}
|
||||
|
||||
str = _ccElement->Attribute("setasreport");
|
||||
if( str )
|
||||
{
|
||||
m_setAsReport = !strcmp( str, "true");
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Basic::WriteXML>
|
||||
// Save changed configuration
|
||||
//-----------------------------------------------------------------------------
|
||||
void Basic::WriteXML
|
||||
(
|
||||
TiXmlElement* _ccElement
|
||||
)
|
||||
{
|
||||
CommandClass::WriteXML( _ccElement );
|
||||
|
||||
if( m_ignoreMapping )
|
||||
{
|
||||
_ccElement->SetAttribute( "ignoremapping", "true" );
|
||||
}
|
||||
|
||||
char str[32];
|
||||
if( m_mapping != 0 )
|
||||
{
|
||||
snprintf( str, sizeof(str), "%d", m_mapping );
|
||||
_ccElement->SetAttribute( "mapping", str );
|
||||
}
|
||||
|
||||
if( m_setAsReport )
|
||||
{
|
||||
_ccElement->SetAttribute( "setasreport", "true" );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Basic::RequestState>
|
||||
// Request current state from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Basic::RequestState
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( _requestFlags & RequestFlag_Dynamic )
|
||||
{
|
||||
return RequestValue( _requestFlags, 0, _instance, _queue );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Basic::RequestValue>
|
||||
// Request current state from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Basic::RequestValue
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _dummy1, // = 0 (not used)
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if ( IsGetSupported() )
|
||||
{
|
||||
Msg* msg = new Msg( "BasicCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, _instance );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( BasicCmd_Get );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
return true;
|
||||
} else {
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "BasicCmd_Get Not Supported on this node");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Basic::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Basic::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
if( BasicCmd_Report == (BasicCmd)_data[0] )
|
||||
{
|
||||
// Level
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received Basic report from node %d: level=%d", GetNodeId(), _data[1] );
|
||||
if( !m_ignoreMapping && m_mapping != 0 )
|
||||
{
|
||||
UpdateMappedClass( _instance, m_mapping, _data[1] );
|
||||
}
|
||||
else if( ValueByte* value = static_cast<ValueByte*>( GetValue( _instance, 0 ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( _data[1] );
|
||||
value->Release();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if( BasicCmd_Set == (BasicCmd)_data[0] )
|
||||
{
|
||||
if( m_setAsReport )
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received Basic set from node %d: level=%d. Treating it as a Basic report.", GetNodeId(), _data[1] );
|
||||
if( !m_ignoreMapping && m_mapping != 0 )
|
||||
{
|
||||
UpdateMappedClass( _instance, m_mapping, _data[1] );
|
||||
}
|
||||
else if( ValueByte* value = static_cast<ValueByte*>( GetValue( _instance, 0 ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( _data[1] );
|
||||
value->Release();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Commmand received from the node. Handle as a notification event
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received Basic set from node %d: level=%d. Sending event notification.", GetNodeId(), _data[1] );
|
||||
|
||||
Notification* notification = new Notification( Notification::Type_NodeEvent );
|
||||
notification->SetHomeNodeIdAndInstance( GetHomeId(), GetNodeId(), _instance );
|
||||
notification->SetEvent( _data[1] );
|
||||
GetDriver()->QueueNotification( notification );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Basic::SetValue>
|
||||
// Set a value on the Z-Wave device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Basic::SetValue
|
||||
(
|
||||
Value const& _value
|
||||
)
|
||||
{
|
||||
if( ValueID::ValueType_Byte == _value.GetID().GetType() )
|
||||
{
|
||||
ValueByte const* value = static_cast<ValueByte const*>(&_value);
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Basic::Set - Setting node %d to level %d", GetNodeId(), value->GetValue() );
|
||||
Msg* msg = new Msg( "Basic Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true );
|
||||
msg->SetInstance( this, _value.GetID().GetInstance() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 3 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( BasicCmd_Set );
|
||||
msg->Append( value->GetValue() );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Basic::CreateVars>
|
||||
// Create the values managed by this command class
|
||||
//-----------------------------------------------------------------------------
|
||||
void Basic::CreateVars
|
||||
(
|
||||
uint8 const _instance
|
||||
)
|
||||
{
|
||||
if( m_mapping == 0 )
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
node->CreateValueByte( ValueID::ValueGenre_Basic, GetCommandClassId(), _instance, 0, "Basic", "", false, false, 0, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Basic::Set>
|
||||
// Helper method to set the level
|
||||
//-----------------------------------------------------------------------------
|
||||
void Basic::Set
|
||||
(
|
||||
uint8 const _level
|
||||
)
|
||||
{
|
||||
// This may look like a long winded way to do this, but
|
||||
// it ensures that all the proper notifications get sent.
|
||||
if( ValueByte* value = static_cast<ValueByte*>( GetValue( 1, 0 ) ) )
|
||||
{
|
||||
value->Set( _level );
|
||||
value->Release();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Basic::SetMapping>
|
||||
// Map COMMAND_CLASS_BASIC messages to another command class
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Basic::SetMapping
|
||||
(
|
||||
uint8 const _commandClassId,
|
||||
bool const _doLog
|
||||
)
|
||||
{
|
||||
bool res = false;
|
||||
|
||||
if( _commandClassId != NoOperation::StaticGetCommandClassId() )
|
||||
{
|
||||
if( _doLog )
|
||||
{
|
||||
char str[16];
|
||||
snprintf( str, sizeof(str), "0x%02x", _commandClassId );
|
||||
string ccstr = str;
|
||||
if( Node const* node = GetNodeUnsafe() )
|
||||
{
|
||||
if( CommandClass* cc = node->GetCommandClass( _commandClassId ) )
|
||||
{
|
||||
ccstr = cc->GetCommandClassName();
|
||||
}
|
||||
}
|
||||
if( m_ignoreMapping )
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), " COMMAND_CLASS_BASIC will not be mapped to %s (ignored)", ccstr.c_str() );
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), " COMMAND_CLASS_BASIC will be mapped to %s", ccstr.c_str() );
|
||||
}
|
||||
}
|
||||
m_mapping = _commandClassId;
|
||||
RemoveValue( 1, 0 );
|
||||
res = true;
|
||||
}
|
||||
|
||||
if( m_mapping == 0 && _doLog )
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), " COMMAND_CLASS_BASIC is not mapped" );
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Basic.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_BASIC
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _Basic_H
|
||||
#define _Basic_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class ValueByte;
|
||||
|
||||
/** \brief Implements COMMAND_CLASS_BASIC (0x20), a Z-Wave device command class.
|
||||
*/
|
||||
class Basic: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new Basic( _homeId, _nodeId ); }
|
||||
virtual ~Basic(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x20; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_BASIC"; }
|
||||
|
||||
bool SetMapping( uint8 const _commandClassId, bool const _doLog = true ); // Map COMMAND_CLASS_BASIC messages to another command class
|
||||
uint8 GetMapping(){ return m_mapping; }
|
||||
|
||||
// From CommandClass
|
||||
virtual void ReadXML( TiXmlElement const* _ccElement );
|
||||
virtual void WriteXML( TiXmlElement* _ccElement );
|
||||
virtual bool RequestState( uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual bool RequestValue( uint32 const _requestFlags, uint8 const _index, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
virtual bool SetValue( Value const& _value );
|
||||
|
||||
void Set( uint8 const _level );
|
||||
|
||||
protected:
|
||||
virtual void CreateVars( uint8 const _instance );
|
||||
|
||||
private:
|
||||
Basic( uint32 const _homeId, uint8 const _nodeId );
|
||||
|
||||
uint8 m_mapping;
|
||||
bool m_ignoreMapping;
|
||||
bool m_setAsReport;
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// BasicWindowCovering.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_BASIC_WINDOW_COVERING
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "BasicWindowCovering.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Driver.h"
|
||||
#include "../Node.h"
|
||||
#include "../platform/Log.h"
|
||||
#include "../value_classes/ValueButton.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum BasicWindowCoveringCmd
|
||||
{
|
||||
BasicWindowCoveringCmd_StartLevelChange = 0x01,
|
||||
BasicWindowCoveringCmd_StopLevelChange = 0x02
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
BasicWindowCoveringIndex_Open = 0,
|
||||
BasicWindowCoveringIndex_Close
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <BasicWindowCovering::SetValue>
|
||||
// Set a value on the Z-Wave device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool BasicWindowCovering::SetValue
|
||||
(
|
||||
Value const& _value
|
||||
)
|
||||
{
|
||||
if( ValueID::ValueType_Button == _value.GetID().GetType() )
|
||||
{
|
||||
ValueButton const* button = static_cast<ValueButton const*>(&_value);
|
||||
|
||||
uint8 action = 0x40;
|
||||
if( button->GetID().GetIndex() ) // Open is index zero, so non-zero is close.
|
||||
{
|
||||
// Close
|
||||
action = 0;
|
||||
}
|
||||
|
||||
if( button && button->IsPressed() )
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "BasicWindowCovering - Start Level Change (%s)", action ? "Open" : "Close" );
|
||||
Msg* msg = new Msg( "Basic Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true );
|
||||
msg->SetInstance( this, _value.GetID().GetInstance() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 3 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( BasicWindowCoveringCmd_StartLevelChange );
|
||||
msg->Append( action );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "BasicWindowCovering - Stop Level Change" );
|
||||
Msg* msg = new Msg( "Basic Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true );
|
||||
msg->SetInstance( this, _value.GetID().GetInstance() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( BasicWindowCoveringCmd_StopLevelChange );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <BasicWindowCovering::CreateVars>
|
||||
// Create the values managed by this command class
|
||||
//-----------------------------------------------------------------------------
|
||||
void BasicWindowCovering::CreateVars
|
||||
(
|
||||
uint8 const _instance
|
||||
)
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
node->CreateValueButton( ValueID::ValueGenre_User, GetCommandClassId(), _instance, BasicWindowCoveringIndex_Open, "Open", 0 );
|
||||
node->CreateValueButton( ValueID::ValueGenre_User, GetCommandClassId(), _instance, BasicWindowCoveringIndex_Close, "Close", 0 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// BasicWindowCovering.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_BASIC_WINDOW_COVERING
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _BasicWindowCovering_H
|
||||
#define _BasicWindowCovering_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class ValueButton;
|
||||
|
||||
/** \brief Implements COMMAND_CLASS_BASIC_WINDOW_COVERING (0x50), a Z-Wave device command class.
|
||||
*/
|
||||
class BasicWindowCovering: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new BasicWindowCovering( _homeId, _nodeId ); }
|
||||
virtual ~BasicWindowCovering(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x50; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_BASIC_WINDOW_COVERING"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 ){ return false; }
|
||||
virtual bool SetValue( Value const& _value );
|
||||
|
||||
protected:
|
||||
virtual void CreateVars( uint8 const _instance );
|
||||
|
||||
private:
|
||||
BasicWindowCovering( uint32 const _homeId, uint8 const _nodeId ): CommandClass( _homeId, _nodeId ){}
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Battery.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_BATTERY
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "Battery.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Node.h"
|
||||
#include "../Driver.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
#include "../value_classes/ValueByte.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum BatteryCmd
|
||||
{
|
||||
BatteryCmd_Get = 0x02,
|
||||
BatteryCmd_Report = 0x03
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Battery::RequestState>
|
||||
// Request current state from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Battery::RequestState
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( _requestFlags & RequestFlag_Dynamic )
|
||||
{
|
||||
return RequestValue( _requestFlags, 0, _instance, _queue );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Battery::RequestValue>
|
||||
// Request current value from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Battery::RequestValue
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _dummy1, // = 0 (not used)
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( _instance != 1 )
|
||||
{
|
||||
// This command class doesn't work with multiple instances
|
||||
return false;
|
||||
}
|
||||
if ( IsGetSupported() )
|
||||
{
|
||||
Msg* msg = new Msg( "BatteryCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( BatteryCmd_Get );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
return true;
|
||||
} else {
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "BatteryCmd_Get Not Supported on this node");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Battery::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Battery::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
if (BatteryCmd_Report == (BatteryCmd)_data[0])
|
||||
{
|
||||
// We have received a battery level report from the Z-Wave device.
|
||||
// Devices send 0xff instead of zero for a low battery warning.
|
||||
uint8 batteryLevel = _data[1];
|
||||
if( batteryLevel == 0xff )
|
||||
{
|
||||
batteryLevel = 0;
|
||||
}
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received Battery report from node %d: level=%d", GetNodeId(), batteryLevel );
|
||||
|
||||
if( ValueByte* value = static_cast<ValueByte*>( GetValue( _instance, 0 ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( batteryLevel );
|
||||
value->Release();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Battery::CreateVars>
|
||||
// Create the values managed by this command class
|
||||
//-----------------------------------------------------------------------------
|
||||
void Battery::CreateVars
|
||||
(
|
||||
uint8 const _instance
|
||||
)
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
node->CreateValueByte( ValueID::ValueGenre_User, GetCommandClassId(), _instance, 0, "Battery Level", "%", true, false, 100, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Battery.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_BATTERY
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _Battery_H
|
||||
#define _Battery_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class ValueByte;
|
||||
|
||||
/** \brief Implements COMMAND_CLASS_BATTERY (0x80), a Z-Wave device command class.
|
||||
*/
|
||||
class Battery: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new Battery( _homeId, _nodeId ); }
|
||||
virtual ~Battery(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x80; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_BATTERY"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual bool RequestState( uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual bool RequestValue( uint32 const _requestFlags, uint8 const _index, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
|
||||
protected:
|
||||
virtual void CreateVars( uint8 const _instance );
|
||||
|
||||
private:
|
||||
Battery( uint32 const _homeId, uint8 const _nodeId ): CommandClass( _homeId, _nodeId ){}
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
project(openzwave_command_classes)
|
||||
|
||||
file(GLOB ${PROJECT_NAME}_sources "${PROJECT_SOURCE_DIR}/*.cpp")
|
||||
file(GLOB ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/*.h")
|
||||
|
||||
set(${PROJECT_NAME}_files ${${PROJECT_NAME}_sources} ${${PROJECT_NAME}_headers} CACHE INTERNAL "")
|
||||
@@ -0,0 +1,50 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// CRC16Encap.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_CRC_16_ENCAP
|
||||
//
|
||||
// Copyright (c) 2012 Greg Satz <satz@iranger.com>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "CRC16Encap.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Node.h"
|
||||
#include "../Driver.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Hail::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CRC16Encap::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// CRC16Encap.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_CRC_16_ENCAP
|
||||
//
|
||||
// Copyright (c) 2012 Greg Satz <satz@iranger.com>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _CRC16_ENCAP_H
|
||||
#define _CRC16_ENCAP_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
/** \brief Implements COMMAND_CLASS_CRC_16_ENCAP (0x56), a Z-Wave device command class.
|
||||
*/
|
||||
class CRC16Encap: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new CRC16Encap( _homeId, _nodeId ); }
|
||||
virtual ~CRC16Encap(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x56; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_CRC_16_ENCAP"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
|
||||
private:
|
||||
CRC16Encap( uint32 const _homeId, uint8 const _nodeId ): CommandClass( _homeId, _nodeId ){}
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,428 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ClimateControlSchedule.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_CLIMATE_CONTROL_SCHEDULE
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "ClimateControlSchedule.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Driver.h"
|
||||
#include "../Node.h"
|
||||
#include "../platform/Log.h"
|
||||
#include "../value_classes/ValueByte.h"
|
||||
#include "../value_classes/ValueList.h"
|
||||
#include "../value_classes/ValueSchedule.h"
|
||||
|
||||
#include "../tinyxml.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum ClimateControlScheduleCmd
|
||||
{
|
||||
ClimateControlScheduleCmd_Set = 0x01,
|
||||
ClimateControlScheduleCmd_Get,
|
||||
ClimateControlScheduleCmd_Report,
|
||||
ClimateControlScheduleCmd_ChangedGet,
|
||||
ClimateControlScheduleCmd_ChangedReport,
|
||||
ClimateControlScheduleCmd_OverrideSet,
|
||||
ClimateControlScheduleCmd_OverrideGet,
|
||||
ClimateControlScheduleCmd_OverrideReport
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ClimateControlScheduleIndex_OverrideState = 8,
|
||||
ClimateControlScheduleIndex_OverrideSetback = 9
|
||||
};
|
||||
|
||||
static char const* c_dayNames[] =
|
||||
{
|
||||
"Invalid",
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday",
|
||||
"Saturday",
|
||||
"Sunday"
|
||||
};
|
||||
|
||||
static char const* c_overrideStateNames[] =
|
||||
{
|
||||
"None",
|
||||
"Temporary",
|
||||
"Permanent",
|
||||
"Invalid"
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ClimateControlSchedule::ReadXML>
|
||||
// Read the saved change-counter value
|
||||
//-----------------------------------------------------------------------------
|
||||
void ClimateControlSchedule::ReadXML
|
||||
(
|
||||
TiXmlElement const* _ccElement
|
||||
)
|
||||
{
|
||||
CommandClass::ReadXML( _ccElement );
|
||||
|
||||
int intVal;
|
||||
if( TIXML_SUCCESS == _ccElement->QueryIntAttribute( "change_counter", &intVal ) )
|
||||
{
|
||||
m_changeCounter = (uint8)intVal;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ClimateControlSchedule::WriteXML>
|
||||
// Write the change-counter value
|
||||
//-----------------------------------------------------------------------------
|
||||
void ClimateControlSchedule::WriteXML
|
||||
(
|
||||
TiXmlElement* _ccElement
|
||||
)
|
||||
{
|
||||
CommandClass::WriteXML( _ccElement );
|
||||
|
||||
char str[8];
|
||||
snprintf( str, 8, "%d", m_changeCounter );
|
||||
_ccElement->SetAttribute( "change_counter", str );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ClimateControlSchedule::RequestState>
|
||||
// Request current state from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ClimateControlSchedule::RequestState
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( _requestFlags & RequestFlag_Session )
|
||||
{
|
||||
// See if the schedule has changed since last time
|
||||
return RequestValue( _requestFlags, 0, _instance, _queue );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ClimateControlSchedule::RequestValue>
|
||||
// Request current value from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ClimateControlSchedule::RequestValue
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _dummy1, // = 0 (not used)
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
// See if the schedule has changed since last time
|
||||
Msg* msg = new Msg( "ClimateControlScheduleCmd_ChangedGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, _instance );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( ClimateControlScheduleCmd_ChangedGet );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ClimateControlSchedule::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ClimateControlSchedule::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
if( ClimateControlScheduleCmd_Report == (ClimateControlScheduleCmd)_data[0] )
|
||||
{
|
||||
uint8 day = _data[1] & 0x07;
|
||||
|
||||
if (day > 7) /* size of c_dayNames */
|
||||
{
|
||||
Log::Write (LogLevel_Warning, GetNodeId(), "Day Value was greater than range. Setting to Invalid");
|
||||
day = 0;
|
||||
}
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received climate control schedule report for %s", c_dayNames[day] );
|
||||
|
||||
if( ValueSchedule* value = static_cast<ValueSchedule*>( GetValue( _instance, day ) ) )
|
||||
{
|
||||
// Remove any existing data
|
||||
value->ClearSwitchPoints();
|
||||
|
||||
// Parse the switch point data
|
||||
for( uint8 i=2; i<29; i+=3 )
|
||||
{
|
||||
uint8 setback = _data[i+2];
|
||||
if( setback == 0x7f )
|
||||
{
|
||||
// Switch point is unused, so we stop parsing here
|
||||
break;
|
||||
}
|
||||
|
||||
uint8 hours = _data[i] & 0x1f;
|
||||
uint8 minutes = _data[i+1] & 0x3f;
|
||||
|
||||
if( setback == 0x79 )
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), " Switch point at %02d:%02d, Frost Protection Mode", hours, minutes, c_dayNames[day] );
|
||||
}
|
||||
else if( setback == 0x7a )
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), " Switch point at %02d:%02d, Energy Saving Mode", hours, minutes, c_dayNames[day] );
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), " Switch point at %02d:%02d, Setback %+.1fC", hours, minutes, ((float)setback)*0.1f );
|
||||
}
|
||||
|
||||
value->SetSwitchPoint( hours, minutes, setback );
|
||||
}
|
||||
|
||||
if( !value->GetNumSwitchPoints() )
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), " No Switch points have been set" );
|
||||
}
|
||||
|
||||
// Notify the user
|
||||
value->OnValueRefreshed();
|
||||
value->Release();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( ClimateControlScheduleCmd_ChangedReport == (ClimateControlScheduleCmd)_data[0] )
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received climate control schedule changed report:" );
|
||||
|
||||
if( _data[1] )
|
||||
{
|
||||
if( _data[1] != m_changeCounter )
|
||||
{
|
||||
m_changeCounter = _data[1];
|
||||
|
||||
// The schedule has changed and is not in override mode, so request reports for each day
|
||||
for( int i=1; i<=7; ++i )
|
||||
{
|
||||
char str[64];
|
||||
snprintf( str, 64, "Get climate control schedule for %s", c_dayNames[i] );
|
||||
|
||||
Msg* msg = new Msg( str, GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 3 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( ClimateControlScheduleCmd_Get );
|
||||
msg->Append( i );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Device is in override mode, so we request details of that instead
|
||||
Msg* msg = new Msg( "Get climate control schedule override state", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( ClimateControlScheduleCmd_OverrideGet );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if( ClimateControlScheduleCmd_OverrideReport == (ClimateControlScheduleCmd)_data[0] )
|
||||
{
|
||||
uint8 overrideState = _data[1] & 0x03;
|
||||
if (overrideState > 3) /* size of c_overrideStateNames */
|
||||
{
|
||||
Log::Write (LogLevel_Warning, GetNodeId(), "overrideState Value was greater than range. Setting to Invalid");
|
||||
overrideState = 3;
|
||||
}
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received climate control schedule override report:" );
|
||||
Log::Write( LogLevel_Info, GetNodeId(), " Override State: %s:", c_overrideStateNames[overrideState] );
|
||||
|
||||
if( ValueList* valueList = static_cast<ValueList*>( GetValue( _instance, ClimateControlScheduleIndex_OverrideState ) ) )
|
||||
{
|
||||
valueList->OnValueRefreshed( (int)overrideState );
|
||||
valueList->Release();
|
||||
}
|
||||
|
||||
uint8 setback = _data[2];
|
||||
if( overrideState )
|
||||
{
|
||||
if( setback == 0x79 )
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), " Override Setback: Frost Protection Mode" );
|
||||
}
|
||||
else if( setback == 0x7a )
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), " Override Setback: Energy Saving Mode" );
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), " Override Setback: %+.1fC", ((float)setback)*0.1f );
|
||||
}
|
||||
}
|
||||
|
||||
if( ValueByte* valueByte = static_cast<ValueByte*>( GetValue( _instance, ClimateControlScheduleIndex_OverrideSetback ) ) )
|
||||
{
|
||||
valueByte->OnValueRefreshed( setback );
|
||||
valueByte->Release();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ClimateControlSchedule::SetValue>
|
||||
// Set a value in the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ClimateControlSchedule::SetValue
|
||||
(
|
||||
Value const& _value
|
||||
)
|
||||
{
|
||||
// bool res = false;
|
||||
uint8 instance = _value.GetID().GetInstance();
|
||||
uint8 idx = _value.GetID().GetIndex();
|
||||
|
||||
if( idx < 8 )
|
||||
{
|
||||
// Set a schedule
|
||||
ValueSchedule const* value = static_cast<ValueSchedule const*>(&_value);
|
||||
|
||||
char str[64];
|
||||
snprintf( str, 64, "Set the climate control schedule for %s on node %d", c_dayNames[idx], GetNodeId() );
|
||||
|
||||
Msg* msg = new Msg( str, GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, instance );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 30 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( ClimateControlScheduleCmd_Set );
|
||||
msg->Append( idx ); // Day of week
|
||||
|
||||
for( uint8 i=0; i<9; ++i )
|
||||
{
|
||||
uint8 hours;
|
||||
uint8 minutes;
|
||||
int8 setback;
|
||||
if( value->GetSwitchPoint( i, &hours, &minutes, &setback ) )
|
||||
{
|
||||
msg->Append( hours );
|
||||
msg->Append( minutes );
|
||||
msg->Append( setback );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unused switch point
|
||||
msg->Append( 0 );
|
||||
msg->Append( 0 );
|
||||
msg->Append( 0x7f );
|
||||
}
|
||||
}
|
||||
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set an override
|
||||
ValueList* state = static_cast<ValueList*>( GetValue( instance, ClimateControlScheduleIndex_OverrideState ) );
|
||||
ValueByte* setback = static_cast<ValueByte*>( GetValue( instance, ClimateControlScheduleIndex_OverrideSetback ) );
|
||||
|
||||
if( state && setback )
|
||||
{
|
||||
ValueList::Item const& item = state->GetItem();
|
||||
|
||||
Msg* msg = new Msg( "Set climate control schedule override state", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, instance );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 4 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( ClimateControlScheduleCmd_OverrideSet );
|
||||
msg->Append( (uint8)item.m_value );
|
||||
msg->Append( setback->GetValue() );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ClimateControlSchedule::CreateVars>
|
||||
// Create the values managed by this command class
|
||||
//-----------------------------------------------------------------------------
|
||||
void ClimateControlSchedule::CreateVars
|
||||
(
|
||||
uint8 const _instance
|
||||
)
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
// Add a ValueSchedule for each day of the week.
|
||||
for( uint8 i=0; i<7; ++i )
|
||||
{
|
||||
node->CreateValueSchedule( ValueID::ValueGenre_User, GetCommandClassId(), _instance, i+1, c_dayNames[i+1], "", false, false, 0 );
|
||||
}
|
||||
|
||||
// Add values for the override state and setback
|
||||
vector<ValueList::Item> items;
|
||||
|
||||
ValueList::Item item;
|
||||
for( uint8 i=0; i<3; ++i )
|
||||
{
|
||||
item.m_label = c_overrideStateNames[i];
|
||||
item.m_value = i;
|
||||
items.push_back( item );
|
||||
}
|
||||
|
||||
node->CreateValueList( ValueID::ValueGenre_User, GetCommandClassId(), _instance, ClimateControlScheduleIndex_OverrideState, "Override State", "", false, false, 1, items, 0, 0 );
|
||||
node->CreateValueByte( ValueID::ValueGenre_User, GetCommandClassId(), _instance, ClimateControlScheduleIndex_OverrideSetback, "Override Setback", "", false, false, 0, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ClimateControlSchedule.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_CLIMATE_CONTROL_SCHEDULE
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _ClimateControlSchedule_H
|
||||
#define _ClimateControlSchedule_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class ValueSchedule;
|
||||
class ValueList;
|
||||
class ValueByte;
|
||||
|
||||
/** \brief Implements COMMAND_CLASS_CLIMATE_CONTROL_SCHEDULE (0x46), a Z-Wave device command class.
|
||||
*/
|
||||
class ClimateControlSchedule: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new ClimateControlSchedule( _homeId, _nodeId ); }
|
||||
virtual ~ClimateControlSchedule(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x46; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_CLIMATE_CONTROL_SCHEDULE"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual void ReadXML( TiXmlElement const* _ccElement );
|
||||
virtual void WriteXML( TiXmlElement* _ccElement );
|
||||
virtual bool RequestState( uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual bool RequestValue( uint32 const _requestFlags, uint8 const _index, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
virtual bool SetValue( Value const& _value );
|
||||
|
||||
protected:
|
||||
virtual void CreateVars( uint8 const _instance );
|
||||
|
||||
private:
|
||||
ClimateControlSchedule( uint32 const _homeId, uint8 const _nodeId ): CommandClass( _homeId, _nodeId ), m_changeCounter( 0 ){}
|
||||
uint8 m_changeCounter;
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Clock.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_CLOCK
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "Clock.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Node.h"
|
||||
#include "../Driver.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
#include "../value_classes/ValueByte.h"
|
||||
#include "../value_classes/ValueList.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum ClockCmd
|
||||
{
|
||||
ClockCmd_Set = 0x04,
|
||||
ClockCmd_Get = 0x05,
|
||||
ClockCmd_Report = 0x06
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ClockIndex_Day = 0,
|
||||
ClockIndex_Hour,
|
||||
ClockIndex_Minute
|
||||
};
|
||||
|
||||
static char const* c_dayNames[] =
|
||||
{
|
||||
"Invalid",
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday",
|
||||
"Saturday",
|
||||
"Sunday"
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Clock::RequestState>
|
||||
// Request current state from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Clock::RequestState
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( _requestFlags & RequestFlag_Dynamic )
|
||||
{
|
||||
return RequestValue( _requestFlags, 0, _instance, _queue );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Clock::RequestValue>
|
||||
// Request current value from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Clock::RequestValue
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _dummy1, // = 0 (not used)
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if ( IsGetSupported() )
|
||||
{
|
||||
Msg* msg = new Msg( "ClockCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, _instance );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( ClockCmd_Get );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
return true;
|
||||
} else {
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "ClockCmd_Get Not Supported on this node");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Clock::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Clock::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
if (ClockCmd_Report == (ClockCmd)_data[0])
|
||||
{
|
||||
uint8 day = _data[1] >> 5;
|
||||
uint8 hour = _data[1] & 0x1f;
|
||||
uint8 minute = _data[2];
|
||||
|
||||
if (day > 7) /* size of c_dayNames */
|
||||
{
|
||||
Log::Write (LogLevel_Warning, GetNodeId(), "Day Value was greater than range. Setting to Invalid");
|
||||
day = 0;
|
||||
}
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received Clock report: %s %.2d:%.2d", c_dayNames[day], hour, minute );
|
||||
|
||||
|
||||
if( ValueList* dayValue = static_cast<ValueList*>( GetValue( _instance, ClockIndex_Day ) ) )
|
||||
{
|
||||
dayValue->OnValueRefreshed( day );
|
||||
dayValue->Release();
|
||||
}
|
||||
if( ValueByte* hourValue = static_cast<ValueByte*>( GetValue( _instance, ClockIndex_Hour ) ) )
|
||||
{
|
||||
hourValue->OnValueRefreshed( hour );
|
||||
hourValue->Release();
|
||||
}
|
||||
if( ValueByte* minuteValue = static_cast<ValueByte*>( GetValue( _instance, ClockIndex_Minute ) ) )
|
||||
{
|
||||
minuteValue->OnValueRefreshed( minute );
|
||||
minuteValue->Release();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Clock::SetValue>
|
||||
// Set a value in the Z-Wave device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Clock::SetValue
|
||||
(
|
||||
Value const& _value
|
||||
)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
uint8 instance = _value.GetID().GetInstance();
|
||||
|
||||
ValueList* dayValue = static_cast<ValueList*>( GetValue( instance, ClockIndex_Day ) );
|
||||
ValueByte* hourValue = static_cast<ValueByte*>( GetValue( instance, ClockIndex_Hour ) );
|
||||
ValueByte* minuteValue = static_cast<ValueByte*>( GetValue( instance, ClockIndex_Minute ) );
|
||||
|
||||
if( dayValue && hourValue && minuteValue )
|
||||
{
|
||||
uint8 day = dayValue->GetItem().m_value;
|
||||
uint8 hour = hourValue->GetValue();
|
||||
uint8 minute = minuteValue->GetValue();
|
||||
|
||||
Msg* msg = new Msg( "ClockCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true );
|
||||
msg->SetInstance( this, instance );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 4 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( ClockCmd_Set );
|
||||
msg->Append( ( day << 5 ) | hour );
|
||||
msg->Append( minute );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
ret = true;
|
||||
}
|
||||
|
||||
if( dayValue != NULL )
|
||||
{
|
||||
dayValue->Release();
|
||||
}
|
||||
if( hourValue != NULL )
|
||||
{
|
||||
hourValue->Release();
|
||||
}
|
||||
if( minuteValue != NULL )
|
||||
{
|
||||
minuteValue->Release();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Clock::CreateVars>
|
||||
// Create the values managed by this command class
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clock::CreateVars
|
||||
(
|
||||
uint8 const _instance
|
||||
)
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
vector<ValueList::Item> items;
|
||||
for( int i=1; i<=7; ++i )
|
||||
{
|
||||
ValueList::Item item;
|
||||
item.m_label = c_dayNames[i];
|
||||
item.m_value = i;
|
||||
items.push_back( item );
|
||||
}
|
||||
|
||||
node->CreateValueList( ValueID::ValueGenre_User, GetCommandClassId(), _instance, ClockIndex_Day, "Day", "", false, false, 1, items, 0, 0 );
|
||||
node->CreateValueByte( ValueID::ValueGenre_User, GetCommandClassId(), _instance, ClockIndex_Hour, "Hour", "", false, false, 12, 0 );
|
||||
node->CreateValueByte( ValueID::ValueGenre_User, GetCommandClassId(), _instance, ClockIndex_Minute, "Minute", "", false, false, 0, 0 );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Clock.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_CLOCK
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _Clock_H
|
||||
#define _Clock_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class ValueByte;
|
||||
class ValueList;
|
||||
|
||||
/** \brief Implements COMMAND_CLASS_CLOCK (0x81), a Z-Wave device command class.
|
||||
*/
|
||||
class Clock: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new Clock( _homeId, _nodeId ); }
|
||||
virtual ~Clock(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x81; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_CLOCK"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual bool RequestState( uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual bool RequestValue( uint32 const _requestFlags, uint8 const _index, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
virtual bool SetValue( Value const& _value );
|
||||
|
||||
protected:
|
||||
virtual void CreateVars( uint8 const _instance );
|
||||
|
||||
private:
|
||||
Clock( uint32 const _homeId, uint8 const _nodeId ): CommandClass( _homeId, _nodeId ){}
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,805 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// CommandClass.cpp
|
||||
//
|
||||
// Base class for all Z-Wave Command Classes
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <math.h>
|
||||
#include <locale.h>
|
||||
#include "../tinyxml.h"
|
||||
#include "CommandClass.h"
|
||||
#include "Basic.h"
|
||||
#include "MultiInstance.h"
|
||||
#include "CommandClasses.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Node.h"
|
||||
#include "../Driver.h"
|
||||
#include "../Manager.h"
|
||||
#include "../platform/Log.h"
|
||||
#include "../value_classes/ValueStore.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
static uint8 const c_sizeMask = 0x07;
|
||||
static uint8 const c_scaleMask = 0x18;
|
||||
static uint8 const c_scaleShift = 0x03;
|
||||
static uint8 const c_precisionMask = 0xe0;
|
||||
static uint8 const c_precisionShift = 0x05;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClass::CommandClass>
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CommandClass::CommandClass
|
||||
(
|
||||
uint32 const _homeId,
|
||||
uint8 const _nodeId
|
||||
):
|
||||
m_homeId( _homeId ),
|
||||
m_nodeId( _nodeId ),
|
||||
m_version( 1 ),
|
||||
m_afterMark( false ),
|
||||
m_createVars( true ),
|
||||
m_overridePrecision( -1 ),
|
||||
m_getSupported( true ),
|
||||
m_isSecured( false ),
|
||||
m_SecureSupport( true ),
|
||||
m_staticRequests( 0 ),
|
||||
m_sentCnt( 0 ),
|
||||
m_receivedCnt( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClass::~CommandClass>
|
||||
// Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CommandClass::~CommandClass
|
||||
(
|
||||
)
|
||||
{
|
||||
while( !m_endPointMap.empty() )
|
||||
{
|
||||
map<uint8,uint8>::iterator it = m_endPointMap.begin();
|
||||
m_endPointMap.erase( it );
|
||||
}
|
||||
while ( !m_RefreshClassValues.empty() )
|
||||
{
|
||||
for (unsigned int i = 0; i < m_RefreshClassValues.size(); i++)
|
||||
{
|
||||
RefreshValue *rcc = m_RefreshClassValues.at(i);
|
||||
while(!rcc->RefreshClasses.empty()) {
|
||||
delete rcc->RefreshClasses.back();
|
||||
rcc->RefreshClasses.pop_back();
|
||||
}
|
||||
// for (unsigned int j = 0; j < rcc->RefreshClasses.size(); i++)
|
||||
// {
|
||||
// delete rcc->RefreshClasses[j];
|
||||
// }
|
||||
rcc->RefreshClasses.clear();
|
||||
delete rcc;
|
||||
}
|
||||
m_RefreshClassValues.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClass::GetDriver>
|
||||
// Get a pointer to our driver
|
||||
//-----------------------------------------------------------------------------
|
||||
Driver* CommandClass::GetDriver
|
||||
(
|
||||
)const
|
||||
{
|
||||
return( Manager::Get()->GetDriver( m_homeId ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClass::GetNode>
|
||||
// Get a pointer to our node without locking the mutex
|
||||
//-----------------------------------------------------------------------------
|
||||
Node* CommandClass::GetNodeUnsafe
|
||||
(
|
||||
)const
|
||||
{
|
||||
return( GetDriver()->GetNodeUnsafe( m_nodeId ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClass::GetValue>
|
||||
// Get a pointer to a value by its instance and index
|
||||
//-----------------------------------------------------------------------------
|
||||
Value* CommandClass::GetValue
|
||||
(
|
||||
uint8 const _instance,
|
||||
uint8 const _index
|
||||
)
|
||||
{
|
||||
Value* value = NULL;
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
value = node->GetValue( GetCommandClassId(), _instance, _index );
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClass::RemoveValue>
|
||||
// Remove a value by its instance and index
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CommandClass::RemoveValue
|
||||
(
|
||||
uint8 const _instance,
|
||||
uint8 const _index
|
||||
)
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
return node->RemoveValue( GetCommandClassId(), _instance, _index );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClass::SetInstances>
|
||||
// Instances as set by the MultiInstance V1 command class
|
||||
//-----------------------------------------------------------------------------
|
||||
void CommandClass::SetInstances
|
||||
(
|
||||
uint8 const _instances
|
||||
)
|
||||
{
|
||||
// Ensure we have a set of reported variables for each new instance
|
||||
if( !m_afterMark )
|
||||
{
|
||||
for( uint8 i=0; i<_instances; ++i )
|
||||
{
|
||||
SetInstance( i+1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClass::SetInstance>
|
||||
// Instances as set by the MultiChannel (i.e. MultiInstance V2) command class
|
||||
//-----------------------------------------------------------------------------
|
||||
void CommandClass::SetInstance
|
||||
(
|
||||
uint8 const _endPoint
|
||||
)
|
||||
{
|
||||
if( !m_instances.IsSet( _endPoint ) )
|
||||
{
|
||||
m_instances.Set( _endPoint );
|
||||
if( IsCreateVars() )
|
||||
{
|
||||
CreateVars( _endPoint );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClass::ReadXML>
|
||||
// Read the saved command class data
|
||||
//-----------------------------------------------------------------------------
|
||||
void CommandClass::ReadXML
|
||||
(
|
||||
TiXmlElement const* _ccElement
|
||||
)
|
||||
{
|
||||
int32 intVal;
|
||||
char const* str;
|
||||
|
||||
if( TIXML_SUCCESS == _ccElement->QueryIntAttribute( "version", &intVal ) )
|
||||
{
|
||||
m_version = (uint8)intVal;
|
||||
}
|
||||
|
||||
uint8 instances = 1;
|
||||
if( TIXML_SUCCESS == _ccElement->QueryIntAttribute( "instances", &intVal ) )
|
||||
{
|
||||
instances = (uint8)intVal;
|
||||
}
|
||||
|
||||
if( TIXML_SUCCESS == _ccElement->QueryIntAttribute( "request_flags", &intVal ) )
|
||||
{
|
||||
m_staticRequests = (uint8)intVal;
|
||||
}
|
||||
|
||||
if( TIXML_SUCCESS == _ccElement->QueryIntAttribute( "override_precision", &intVal ) )
|
||||
{
|
||||
m_overridePrecision = (int8)intVal;
|
||||
}
|
||||
|
||||
str = _ccElement->Attribute( "after_mark" );
|
||||
if( str )
|
||||
{
|
||||
m_afterMark = !strcmp( str, "true" );
|
||||
}
|
||||
|
||||
str = _ccElement->Attribute( "create_vars" );
|
||||
if( str )
|
||||
{
|
||||
m_createVars = !strcmp( str, "true" );
|
||||
}
|
||||
|
||||
// Make sure previously created values are removed if create_vars=false
|
||||
if( !m_createVars )
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
node->GetValueStore()->RemoveCommandClassValues( GetCommandClassId() );
|
||||
}
|
||||
}
|
||||
|
||||
str = _ccElement->Attribute( "getsupported" );
|
||||
if( str )
|
||||
{
|
||||
m_getSupported = !strcmp( str, "true" );
|
||||
}
|
||||
|
||||
str = _ccElement->Attribute( "issecured" );
|
||||
if( str )
|
||||
{
|
||||
m_isSecured = !strcmp( str, "true" );
|
||||
}
|
||||
// Setting the instance count will create all the values.
|
||||
SetInstances( instances );
|
||||
|
||||
// Apply any differences from the saved XML to the values
|
||||
TiXmlElement const* child = _ccElement->FirstChildElement();
|
||||
while( child )
|
||||
{
|
||||
str = child->Value();
|
||||
if( str )
|
||||
{
|
||||
if( !strcmp( str, "Instance" ) )
|
||||
{
|
||||
uint8 instance = 0;
|
||||
// Add an instance to the command class
|
||||
if( TIXML_SUCCESS == child->QueryIntAttribute( "index", &intVal ) )
|
||||
{
|
||||
instance = (uint8)intVal;
|
||||
SetInstance( instance );
|
||||
}
|
||||
// See if its associated endpoint is present
|
||||
if( TIXML_SUCCESS == child->QueryIntAttribute( "endpoint", &intVal ) )
|
||||
{
|
||||
uint8 endpoint = (uint8)intVal;
|
||||
SetEndPoint( instance, endpoint );
|
||||
}
|
||||
}
|
||||
else if( !strcmp( str, "Value" ) )
|
||||
{
|
||||
// Apply any differences from the saved XML to the value
|
||||
GetNodeUnsafe()->ReadValueFromXML( GetCommandClassId(), child );
|
||||
}
|
||||
else if (!strcmp( str, "TriggerRefreshValue" ) )
|
||||
{
|
||||
ReadValueRefreshXML(child);
|
||||
}
|
||||
}
|
||||
|
||||
child = child->NextSiblingElement();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClass::ReadValueRefreshXML>
|
||||
// Read the config that contains a list of Values that should be refreshed when
|
||||
// we recieve u updated Value from a device. (This helps Yale Door Locks, which send a
|
||||
// Alarm Report instead of DoorLock Report when the status of the Door Lock is changed
|
||||
//-----------------------------------------------------------------------------
|
||||
void CommandClass::ReadValueRefreshXML
|
||||
(
|
||||
TiXmlElement const* _ccElement
|
||||
)
|
||||
{
|
||||
|
||||
char const* str;
|
||||
bool ok = false;
|
||||
const char *genre;
|
||||
RefreshValue *rcc = new RefreshValue();
|
||||
rcc->cc = GetCommandClassId();
|
||||
genre = _ccElement->Attribute( "Genre" );
|
||||
rcc->genre = Value::GetGenreEnumFromName(genre);
|
||||
_ccElement->QueryIntAttribute( "Instance", (int*)&rcc->instance);
|
||||
_ccElement->QueryIntAttribute( "Index", (int*)&rcc->index);
|
||||
Log::Write(LogLevel_Info, GetNodeId(), "Value Refresh triggered by CommandClass: %s, Genre: %d, Instance: %d, Index: %d for:", GetCommandClassName().c_str(), rcc->genre, rcc->instance, rcc->index);
|
||||
TiXmlElement const* child = _ccElement->FirstChildElement();
|
||||
while( child )
|
||||
{
|
||||
str = child->Value();
|
||||
if( str )
|
||||
{
|
||||
if ( !strcmp(str, "RefreshClassValue"))
|
||||
{
|
||||
RefreshValue *arcc = new RefreshValue();
|
||||
if (child->QueryIntAttribute( "CommandClass", (int*)&arcc->cc) != TIXML_SUCCESS) {
|
||||
Log::Write(LogLevel_Warning, GetNodeId(), " Invalid XML - CommandClass Attribute is wrong type or missing");
|
||||
continue;
|
||||
}
|
||||
if (child->QueryIntAttribute( "RequestFlags", (int*)&arcc->genre) != TIXML_SUCCESS) {
|
||||
Log::Write(LogLevel_Warning, GetNodeId(), " Invalid XML - RequestFlags Attribute is wrong type or missing");
|
||||
continue;
|
||||
}
|
||||
if (child->QueryIntAttribute( "Instance", (int*)&arcc->instance) != TIXML_SUCCESS) {
|
||||
Log::Write(LogLevel_Warning, GetNodeId(), " Invalid XML - Instance Attribute is wrong type or missing");
|
||||
continue;
|
||||
}
|
||||
if (child->QueryIntAttribute( "Index", (int*)&arcc->index) != TIXML_SUCCESS) {
|
||||
Log::Write(LogLevel_Warning, GetNodeId(), " Invalid XML - Index Attribute is wrong type or missing");
|
||||
continue;
|
||||
}
|
||||
Log::Write(LogLevel_Info, GetNodeId(), " CommandClass: %s, RequestFlags: %d, Instance: %d, Index: %d", CommandClasses::GetName(arcc->cc).c_str(), arcc->genre, arcc->instance, arcc->index);
|
||||
rcc->RefreshClasses.push_back(arcc);
|
||||
ok = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Write(LogLevel_Warning, GetNodeId(), "Got Unhandled Child Entry in TriggerRefreshValue XML Config: %s", str);
|
||||
}
|
||||
}
|
||||
child = child->NextSiblingElement();
|
||||
}
|
||||
if (ok == true) {
|
||||
m_RefreshClassValues.push_back( rcc );
|
||||
} else {
|
||||
Log::Write(LogLevel_Warning, GetNodeId(), "Failed to add a RefreshClassValue from XML");
|
||||
delete rcc;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClass::CheckForRefreshValues>
|
||||
// Scan our m_RefreshClassValues vector to see if we should call any other
|
||||
// Command Classes to refresh their value
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool CommandClass::CheckForRefreshValues (
|
||||
Value const* _value
|
||||
)
|
||||
{
|
||||
if (m_RefreshClassValues.empty())
|
||||
{
|
||||
//Log::Write(LogLevel_Debug, GetNodeId(), "Bailing out of CheckForRefreshValues");
|
||||
return false;
|
||||
}
|
||||
Node* node = GetNodeUnsafe();
|
||||
if( node != NULL )
|
||||
{
|
||||
for (uint32 i = 0; i < m_RefreshClassValues.size(); i++)
|
||||
{
|
||||
RefreshValue *rcc = m_RefreshClassValues.at(i);
|
||||
//Log::Write(LogLevel_Debug, GetNodeId(), "Checking Value Against RefreshClassList: CommandClass %s = %s, Genre %d = %d, Instance %d = %d, Index %d = %d", CommandClasses::GetName(rcc->cc).c_str(), CommandClasses::GetName(_value->GetID().GetCommandClassId()).c_str(), rcc->genre, _value->GetID().GetGenre(), rcc->instance, _value->GetID().GetInstance(), rcc->index, _value->GetID().GetIndex());
|
||||
if ((rcc->genre == _value->GetID().GetGenre()) && (rcc->instance == _value->GetID().GetInstance()) && (rcc->index == _value->GetID().GetIndex()) )
|
||||
{
|
||||
/* we got a match..... */
|
||||
for (uint32 j = 0; j < rcc->RefreshClasses.size(); j++)
|
||||
{
|
||||
RefreshValue *arcc = rcc->RefreshClasses.at(j);
|
||||
Log::Write(LogLevel_Debug, GetNodeId(), "Requesting Refresh of Value: CommandClass: %s Genre %d, Instance %d, Index %d", CommandClasses::GetName(arcc->cc).c_str(), arcc->genre, arcc->instance, arcc->index);
|
||||
if( CommandClass* cc = node->GetCommandClass( arcc->cc ) )
|
||||
{
|
||||
cc->RequestValue(arcc->genre, arcc->index, arcc->instance, Driver::MsgQueue_Send);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* Driver */
|
||||
{
|
||||
Log::Write(LogLevel_Warning, GetNodeId(), "Can't get Node");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClass::WriteXML>
|
||||
// Save the static node configuration data
|
||||
//-----------------------------------------------------------------------------
|
||||
void CommandClass::WriteXML
|
||||
(
|
||||
TiXmlElement* _ccElement
|
||||
)
|
||||
{
|
||||
char str[32];
|
||||
|
||||
snprintf( str, sizeof(str), "%d", GetCommandClassId() );
|
||||
_ccElement->SetAttribute( "id", str );
|
||||
_ccElement->SetAttribute( "name", GetCommandClassName().c_str() );
|
||||
|
||||
snprintf( str, sizeof(str), "%d", GetVersion() );
|
||||
_ccElement->SetAttribute( "version", str );
|
||||
|
||||
if( m_staticRequests )
|
||||
{
|
||||
snprintf( str, sizeof(str), "%d", m_staticRequests );
|
||||
_ccElement->SetAttribute( "request_flags", str );
|
||||
}
|
||||
|
||||
if( m_overridePrecision >= 0 )
|
||||
{
|
||||
snprintf( str, sizeof(str), "%d", m_overridePrecision );
|
||||
_ccElement->SetAttribute( "override_precision", str );
|
||||
}
|
||||
|
||||
if( m_afterMark )
|
||||
{
|
||||
_ccElement->SetAttribute( "after_mark", "true" );
|
||||
}
|
||||
|
||||
if( !m_createVars )
|
||||
{
|
||||
_ccElement->SetAttribute( "create_vars", "false" );
|
||||
}
|
||||
|
||||
if( !m_getSupported )
|
||||
{
|
||||
_ccElement->SetAttribute( "getsupported", "false" );
|
||||
}
|
||||
if ( m_isSecured )
|
||||
{
|
||||
_ccElement->SetAttribute( "issecured", "true" );
|
||||
}
|
||||
|
||||
|
||||
// Write out the instances
|
||||
for( Bitfield::Iterator it = m_instances.Begin(); it != m_instances.End(); ++ it )
|
||||
{
|
||||
TiXmlElement* instanceElement = new TiXmlElement( "Instance" );
|
||||
_ccElement->LinkEndChild( instanceElement );
|
||||
|
||||
snprintf( str, sizeof(str), "%d", *it );
|
||||
instanceElement->SetAttribute( "index", str );
|
||||
|
||||
map<uint8,uint8>::iterator eit = m_endPointMap.find( *it );
|
||||
if( eit != m_endPointMap.end() )
|
||||
{
|
||||
snprintf( str, sizeof(str), "%d", eit->second );
|
||||
instanceElement->SetAttribute( "endpoint", str );
|
||||
}
|
||||
}
|
||||
|
||||
// Write out the values for this command class
|
||||
ValueStore* store = GetNodeUnsafe()->GetValueStore();
|
||||
for( ValueStore::Iterator it = store->Begin(); it != store->End(); ++it )
|
||||
{
|
||||
Value* value = it->second;
|
||||
if( value->GetID().GetCommandClassId() == GetCommandClassId() )
|
||||
{
|
||||
TiXmlElement* valueElement = new TiXmlElement( "Value" );
|
||||
_ccElement->LinkEndChild( valueElement );
|
||||
value->WriteXML( valueElement );
|
||||
}
|
||||
}
|
||||
// Write out the TriggerRefreshValue if it exists
|
||||
for (uint32 i = 0; i < m_RefreshClassValues.size(); i++)
|
||||
{
|
||||
RefreshValue *rcc = m_RefreshClassValues.at(i);
|
||||
TiXmlElement* RefreshElement = new TiXmlElement("TriggerRefreshValue");
|
||||
_ccElement->LinkEndChild( RefreshElement );
|
||||
RefreshElement->SetAttribute("Genre", Value::GetGenreNameFromEnum((ValueID::ValueGenre)rcc->genre));
|
||||
RefreshElement->SetAttribute("Instance", rcc->instance);
|
||||
RefreshElement->SetAttribute("Index", rcc->index);
|
||||
for (uint32 j = 0; j < rcc->RefreshClasses.size(); j++)
|
||||
{
|
||||
RefreshValue *arcc = rcc->RefreshClasses.at(j);
|
||||
TiXmlElement *ClassElement = new TiXmlElement("RefreshClassValue");
|
||||
RefreshElement->LinkEndChild(ClassElement);
|
||||
ClassElement->SetAttribute("CommandClass", arcc->cc);
|
||||
ClassElement->SetAttribute("RequestFlags", arcc->genre);
|
||||
ClassElement->SetAttribute("Instance", arcc->instance);
|
||||
ClassElement->SetAttribute("Index", arcc->index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClass::ExtractValue>
|
||||
// Read a value from a variable length sequence of bytes
|
||||
//-----------------------------------------------------------------------------
|
||||
string CommandClass::ExtractValue
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint8* _scale,
|
||||
uint8* _precision,
|
||||
uint8 _valueOffset // = 1
|
||||
)const
|
||||
{
|
||||
uint8 const size = _data[0] & c_sizeMask;
|
||||
uint8 const precision = (_data[0] & c_precisionMask) >> c_precisionShift;
|
||||
|
||||
if( _scale )
|
||||
{
|
||||
*_scale = (_data[0] & c_scaleMask) >> c_scaleShift;
|
||||
}
|
||||
|
||||
if( _precision )
|
||||
{
|
||||
*_precision = precision;
|
||||
}
|
||||
|
||||
uint32 value = 0;
|
||||
uint8 i;
|
||||
for( i=0; i<size; ++i )
|
||||
{
|
||||
value <<= 8;
|
||||
value |= (uint32)_data[i+(uint32)_valueOffset];
|
||||
}
|
||||
|
||||
// Deal with sign extension. All values are signed
|
||||
string res;
|
||||
if( _data[_valueOffset] & 0x80 )
|
||||
{
|
||||
res = "-";
|
||||
|
||||
// MSB is signed
|
||||
if( size == 1 )
|
||||
{
|
||||
value |= 0xffffff00;
|
||||
}
|
||||
else if( size == 2 )
|
||||
{
|
||||
value |= 0xffff0000;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the integer to a decimal string. We avoid
|
||||
// using floats to prevent accuracy issues.
|
||||
char numBuf[12] = {0};
|
||||
|
||||
if( precision == 0 )
|
||||
{
|
||||
// The precision is zero, so we can just print the number directly into the string.
|
||||
snprintf( numBuf, 12, "%d", (signed int)value );
|
||||
res = numBuf;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We'll need to insert a decimal point and include any necessary leading zeros.
|
||||
|
||||
// Fill the buffer with the value padded with leading zeros.
|
||||
snprintf( numBuf, 12, "%011d", (signed int)value );
|
||||
|
||||
// Calculate the position of the decimal point in the buffer
|
||||
int32 decimal = 10-precision;
|
||||
|
||||
// Shift the characters to make space for the decimal point.
|
||||
// We don't worry about overwriting any minus sign since that is
|
||||
// already written into the res string. While we're shifting, we
|
||||
// also look for the real starting position of the number so we
|
||||
// can copy it into the res string later.
|
||||
int32 start = -1;
|
||||
for( int32 i=0; i<decimal; ++i )
|
||||
{
|
||||
numBuf[i] = numBuf[i+1];
|
||||
if( ( start<0 ) && ( numBuf[i] != '0' ) )
|
||||
{
|
||||
start = i;
|
||||
}
|
||||
}
|
||||
if( start<0 )
|
||||
{
|
||||
start = decimal-1;
|
||||
}
|
||||
|
||||
// Insert the decimal point
|
||||
struct lconv const* locale = localeconv();
|
||||
numBuf[decimal] = *(locale->decimal_point);
|
||||
|
||||
// Copy the buffer into res
|
||||
res += &numBuf[start];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClass::AppendValue>
|
||||
// Add a value to a message as a sequence of bytes
|
||||
//-----------------------------------------------------------------------------
|
||||
void CommandClass::AppendValue
|
||||
(
|
||||
Msg* _msg,
|
||||
string const& _value,
|
||||
uint8 const _scale
|
||||
)const
|
||||
{
|
||||
uint8 precision;
|
||||
uint8 size;
|
||||
int32 val = ValueToInteger( _value, &precision, &size );
|
||||
|
||||
_msg->Append( (precision<<c_precisionShift) | (_scale<<c_scaleShift) | size );
|
||||
|
||||
int32 shift = (size-1)<<3;
|
||||
for( int32 i=size; i>0; --i, shift-=8 )
|
||||
{
|
||||
_msg->Append( (uint8)(val >> shift) );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClass::GetAppendValueSize>
|
||||
// Get the number of bytes that would be added by a call to AppendValue
|
||||
//-----------------------------------------------------------------------------
|
||||
uint8 const CommandClass::GetAppendValueSize
|
||||
(
|
||||
string const& _value
|
||||
)const
|
||||
{
|
||||
uint8 size;
|
||||
ValueToInteger( _value, NULL, &size );
|
||||
return size;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClass::ValueToInteger>
|
||||
// Convert a decimal string to an integer and report the precision and
|
||||
// number of bytes required to store the value.
|
||||
//-----------------------------------------------------------------------------
|
||||
int32 CommandClass::ValueToInteger
|
||||
(
|
||||
string const& _value,
|
||||
uint8* o_precision,
|
||||
uint8* o_size
|
||||
)const
|
||||
{
|
||||
int32 val;
|
||||
uint8 precision;
|
||||
|
||||
// Find the decimal point
|
||||
size_t pos = _value.find_first_of( "." );
|
||||
if( pos == string::npos )
|
||||
pos = _value.find_first_of( "," );
|
||||
|
||||
if( pos == string::npos )
|
||||
{
|
||||
// No decimal point
|
||||
precision = 0;
|
||||
|
||||
// Convert the string to an integer
|
||||
val = atol( _value.c_str() );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove the decimal point and convert to an integer
|
||||
precision = (uint8) ((_value.size()-pos)-1);
|
||||
|
||||
string str = _value.substr( 0, pos ) + _value.substr( pos+1 );
|
||||
val = atol( str.c_str() );
|
||||
}
|
||||
|
||||
if ( m_overridePrecision > 0 )
|
||||
{
|
||||
while ( precision < m_overridePrecision ) {
|
||||
precision++;
|
||||
val *= 10;
|
||||
}
|
||||
}
|
||||
|
||||
if ( o_precision ) *o_precision = precision;
|
||||
|
||||
if( o_size )
|
||||
{
|
||||
// Work out the size as either 1, 2 or 4 bytes
|
||||
*o_size = 4;
|
||||
if( val < 0 )
|
||||
{
|
||||
if( ( val & 0xffffff80 ) == 0xffffff80 )
|
||||
{
|
||||
*o_size = 1;
|
||||
}
|
||||
else if( ( val & 0xffff8000 ) == 0xffff8000 )
|
||||
{
|
||||
*o_size = 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( ( val & 0xffffff00 ) == 0 )
|
||||
{
|
||||
*o_size = 1;
|
||||
}
|
||||
else if( ( val & 0xffff0000 ) == 0 )
|
||||
{
|
||||
*o_size = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClass::UpdateMappedClass>
|
||||
// Update the mapped class if there is one with BASIC level
|
||||
//-----------------------------------------------------------------------------
|
||||
void CommandClass::UpdateMappedClass
|
||||
(
|
||||
uint8 const _instance,
|
||||
uint8 const _classId,
|
||||
uint8 const _level
|
||||
)
|
||||
{
|
||||
if( _classId )
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
CommandClass* cc = node->GetCommandClass( _classId );
|
||||
if( node->GetCurrentQueryStage() == Node::QueryStage_Complete && cc != NULL )
|
||||
{
|
||||
cc->SetValueBasic( _instance, _level );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClass::ClearStaticRequest>
|
||||
// The static data for this command class has been read from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
void CommandClass::ClearStaticRequest
|
||||
(
|
||||
uint8 _request
|
||||
)
|
||||
{
|
||||
m_staticRequests &= ~_request;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClass::RequestStateForAllInstances>
|
||||
// Request current state from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CommandClass::RequestStateForAllInstances
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
bool res = false;
|
||||
if( m_createVars )
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
MultiInstance* multiInstance = static_cast<MultiInstance*>( node->GetCommandClass( MultiInstance::StaticGetCommandClassId() ) );
|
||||
if( multiInstance != NULL )
|
||||
{
|
||||
for( Bitfield::Iterator it = m_instances.Begin(); it != m_instances.End(); ++it )
|
||||
{
|
||||
res |= RequestState( _requestFlags, (uint8)*it, _queue );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
res = RequestState( _requestFlags, 1, _queue );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// CommandClass.h
|
||||
//
|
||||
// Base class for all Z-Wave Command Classes
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _CommandClass_H
|
||||
#define _CommandClass_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "../Defs.h"
|
||||
#include "../Bitfield.h"
|
||||
#include "../Driver.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class Msg;
|
||||
class Node;
|
||||
class Value;
|
||||
|
||||
/** \brief Base class for all Z-Wave command classes.
|
||||
*/
|
||||
class OPENZWAVE_EXPORT CommandClass
|
||||
{
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
RequestFlag_Static = 0x00000001, /**< Values that never change. */
|
||||
RequestFlag_Session = 0x00000002, /**< Values that change infrequently, and so only need to be requested at start up, or via a manual refresh. */
|
||||
RequestFlag_Dynamic = 0x00000004, /**< Values that change and will be requested if polling is enabled on the node. */
|
||||
};
|
||||
|
||||
CommandClass( uint32 const _homeId, uint8 const _nodeId );
|
||||
virtual ~CommandClass();
|
||||
|
||||
virtual void ReadXML( TiXmlElement const* _ccElement );
|
||||
virtual void WriteXML( TiXmlElement* _ccElement );
|
||||
virtual bool RequestState( uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue ){ return false; }
|
||||
virtual bool RequestValue( uint32 const _requestFlags, uint8 const _index, uint8 const _instance, Driver::MsgQueue const _queue ) { return false; }
|
||||
|
||||
virtual uint8 const GetCommandClassId()const = 0;
|
||||
virtual string const GetCommandClassName()const = 0;
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 ) = 0;
|
||||
virtual bool SetValue( Value const& _value ){ return false; }
|
||||
virtual void SetValueBasic( uint8 const _instance, uint8 const _level ){} // Class specific handling of BASIC value mapping
|
||||
virtual void SetVersion( uint8 const _version ){ m_version = _version; }
|
||||
|
||||
bool RequestStateForAllInstances( uint32 const _requestFlags, Driver::MsgQueue const _queue );
|
||||
bool CheckForRefreshValues(Value const* _value );
|
||||
|
||||
// The highest version number of the command class implemented by OpenZWave. We only need
|
||||
// to do version gets on command classes that override this with a number greater than one.
|
||||
virtual uint8 GetMaxVersion(){ return 1; }
|
||||
|
||||
uint8 GetVersion()const{ return m_version; }
|
||||
Bitfield const* GetInstances()const{ return &m_instances; }
|
||||
uint32 GetHomeId()const{ return m_homeId; }
|
||||
uint8 GetNodeId()const{ return m_nodeId; }
|
||||
Driver* GetDriver()const;
|
||||
Node* GetNodeUnsafe()const;
|
||||
Value* GetValue( uint8 const _instance, uint8 const _index );
|
||||
bool RemoveValue( uint8 const _instance, uint8 const _index );
|
||||
uint8 GetEndPoint( uint8 const _instance )
|
||||
{
|
||||
map<uint8,uint8>::iterator it = m_endPointMap.find( _instance );
|
||||
return( it == m_endPointMap.end() ? 0 : it->second );
|
||||
}
|
||||
uint8 GetInstance( uint8 const _endPoint )
|
||||
{
|
||||
for( map<uint8,uint8>::iterator it = m_endPointMap.begin(); it != m_endPointMap.end(); ++it )
|
||||
{
|
||||
if( _endPoint == it->second )
|
||||
{
|
||||
return it->first;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SetInstances( uint8 const _instances );
|
||||
void SetInstance( uint8 const _endPoint );
|
||||
void SetAfterMark(){ m_afterMark = true; }
|
||||
void SetEndPoint( uint8 const _instance, uint8 const _endpoint){ m_endPointMap[_instance] = _endpoint; }
|
||||
bool IsAfterMark()const{ return m_afterMark; }
|
||||
bool IsCreateVars()const{ return m_createVars; }
|
||||
bool IsGetSupported()const{ return m_getSupported; }
|
||||
bool IsSecured()const{ return m_isSecured; }
|
||||
void SetSecured(){ m_isSecured = true; }
|
||||
bool IsSecureSupported()const { return m_SecureSupport; }
|
||||
void ClearSecureSupport() { m_SecureSupport = false; }
|
||||
void SetSecureSupport() { m_SecureSupport = true; }
|
||||
|
||||
// Helper methods
|
||||
string ExtractValue( uint8 const* _data, uint8* _scale, uint8* _precision, uint8 _valueOffset = 1 )const;
|
||||
|
||||
/**
|
||||
* Append a floating-point value to a message.
|
||||
* \param _msg The message to which the value should be appended.
|
||||
* \param _value A string containing a decimal number to be appended.
|
||||
* \param _scale A byte indicating the scale corresponding to this value (e.g., 1=F and 0=C for temperatures).
|
||||
* \see Msg
|
||||
*/
|
||||
void AppendValue( Msg* _msg, string const& _value, uint8 const _scale )const;
|
||||
uint8 const GetAppendValueSize( string const& _value )const;
|
||||
int32 ValueToInteger( string const& _value, uint8* o_precision, uint8* o_size )const;
|
||||
|
||||
void UpdateMappedClass( uint8 const _instance, uint8 const _classId, uint8 const _value ); // Update mapped class's value from BASIC class
|
||||
|
||||
typedef struct RefreshValue {
|
||||
uint8 cc;
|
||||
uint8 genre;
|
||||
uint8 instance;
|
||||
uint8 index;
|
||||
std::vector<RefreshValue *> RefreshClasses;
|
||||
} RefreshValue;
|
||||
|
||||
protected:
|
||||
virtual void CreateVars( uint8 const _instance ){}
|
||||
void ReadValueRefreshXML ( TiXmlElement const* _ccElement );
|
||||
|
||||
public:
|
||||
virtual void CreateVars( uint8 const _instance, uint8 const _index ){}
|
||||
|
||||
private:
|
||||
uint32 m_homeId;
|
||||
uint8 m_nodeId;
|
||||
uint8 m_version;
|
||||
Bitfield m_instances;
|
||||
OPENZWAVE_EXPORT_WARNINGS_OFF
|
||||
map<uint8,uint8> m_endPointMap;
|
||||
OPENZWAVE_EXPORT_WARNINGS_ON
|
||||
bool m_afterMark; // Set to true if the command class is listed after COMMAND_CLASS_MARK, and should not create any values.
|
||||
bool m_createVars; // Do we want to create variables
|
||||
int8 m_overridePrecision; // Override precision when writing values if >=0
|
||||
bool m_getSupported; // Get operation supported
|
||||
bool m_isSecured; // is this command class secured with the Security Command Class
|
||||
bool m_SecureSupport; // Does this commandclass support secure encryption (eg, the Security CC doesn't encrypt itself, so it doesn't support encryption)
|
||||
std::vector<RefreshValue *> m_RefreshClassValues; // what Command Class Values should we refresh ?
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Record which items of static data have been read from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
public:
|
||||
enum StaticRequest
|
||||
{
|
||||
StaticRequest_Instances = 0x01,
|
||||
StaticRequest_Values = 0x02,
|
||||
StaticRequest_Version = 0x04
|
||||
};
|
||||
|
||||
bool HasStaticRequest( uint8 _request )const{ return( (m_staticRequests & _request) != 0 ); }
|
||||
void SetStaticRequest( uint8 _request ){ m_staticRequests |= _request; }
|
||||
void ClearStaticRequest( uint8 _request );
|
||||
|
||||
private:
|
||||
uint8 m_staticRequests;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Statistics
|
||||
//-----------------------------------------------------------------------------
|
||||
public:
|
||||
uint32 GetSentCnt()const{ return m_sentCnt; }
|
||||
uint32 GetReceivedCnt()const{ return m_receivedCnt; }
|
||||
void SentCntIncr(){ m_sentCnt++; }
|
||||
void ReceivedCntIncr(){ m_receivedCnt++; }
|
||||
|
||||
private:
|
||||
uint32 m_sentCnt; // Number of messages sent from this command class.
|
||||
uint32 m_receivedCnt; // Number of messages received from this commandclass.
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,316 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// CommandClasses.cpp
|
||||
//
|
||||
// Singleton holding methods to create each command class object
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "CommandClasses.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
#include "Alarm.h"
|
||||
#include "ApplicationStatus.h"
|
||||
#include "Association.h"
|
||||
#include "AssociationCommandConfiguration.h"
|
||||
#include "Basic.h"
|
||||
#include "BasicWindowCovering.h"
|
||||
#include "Battery.h"
|
||||
#include "ClimateControlSchedule.h"
|
||||
#include "Clock.h"
|
||||
#include "Configuration.h"
|
||||
#include "ControllerReplication.h"
|
||||
#include "CRC16Encap.h"
|
||||
#include "DoorLock.h"
|
||||
#include "DoorLockLogging.h"
|
||||
#include "EnergyProduction.h"
|
||||
#include "Hail.h"
|
||||
#include "Indicator.h"
|
||||
#include "Language.h"
|
||||
#include "Lock.h"
|
||||
#include "ManufacturerSpecific.h"
|
||||
#include "Meter.h"
|
||||
#include "MeterPulse.h"
|
||||
#include "MultiCmd.h"
|
||||
#include "MultiInstance.h"
|
||||
#include "MultiInstanceAssociation.h"
|
||||
#include "NodeNaming.h"
|
||||
#include "NoOperation.h"
|
||||
#include "Powerlevel.h"
|
||||
#include "Proprietary.h"
|
||||
#include "Protection.h"
|
||||
#include "SceneActivation.h"
|
||||
#include "Security.h"
|
||||
#include "SensorAlarm.h"
|
||||
#include "SensorBinary.h"
|
||||
#include "SensorMultilevel.h"
|
||||
#include "SwitchAll.h"
|
||||
#include "SwitchBinary.h"
|
||||
#include "SwitchMultilevel.h"
|
||||
#include "SwitchToggleBinary.h"
|
||||
#include "SwitchToggleMultilevel.h"
|
||||
#include "TimeParameters.h"
|
||||
#include "ThermostatFanMode.h"
|
||||
#include "ThermostatFanState.h"
|
||||
#include "ThermostatMode.h"
|
||||
#include "ThermostatOperatingState.h"
|
||||
#include "ThermostatSetpoint.h"
|
||||
#include "UserCode.h"
|
||||
#include "Version.h"
|
||||
#include "WakeUp.h"
|
||||
|
||||
#include "../value_classes/ValueBool.h"
|
||||
#include "../value_classes/ValueButton.h"
|
||||
#include "../value_classes/ValueByte.h"
|
||||
#include "../value_classes/ValueDecimal.h"
|
||||
#include "../value_classes/ValueInt.h"
|
||||
#include "../value_classes/ValueList.h"
|
||||
#include "../value_classes/ValueSchedule.h"
|
||||
#include "../value_classes/ValueShort.h"
|
||||
#include "../value_classes/ValueString.h"
|
||||
|
||||
#include "../Manager.h"
|
||||
#include "../Options.h"
|
||||
#include "../Utils.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClasses::CommandClasses>
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CommandClasses::CommandClasses
|
||||
(
|
||||
)
|
||||
{
|
||||
memset( m_commandClassCreators, 0, sizeof(pfnCreateCommandClass_t)*256 );
|
||||
memset( m_supportedCommandClasses, 0, sizeof(uint32)*8 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClasses::IsSupported>
|
||||
// Static method to determine whether a command class is supported
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CommandClasses::IsSupported
|
||||
(
|
||||
uint8 const _commandClassId
|
||||
)
|
||||
{
|
||||
// Test the bit representing the command class
|
||||
return( (Get().m_supportedCommandClasses[_commandClassId>>5] & (1u<<(_commandClassId&0x1f))) != 0 );
|
||||
}
|
||||
string CommandClasses::GetName(
|
||||
uint8 const _commandClassId
|
||||
)
|
||||
{
|
||||
for (std::map<string,uint8>::iterator it = Get().m_namesToIDs.begin(); it != Get().m_namesToIDs.end(); it++) {
|
||||
if (it->second == _commandClassId)
|
||||
return it->first;
|
||||
}
|
||||
return string("Unknown");
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClasses::Register>
|
||||
// Static method to register a command class creator method
|
||||
//-----------------------------------------------------------------------------
|
||||
void CommandClasses::Register
|
||||
(
|
||||
uint8 const _commandClassId,
|
||||
string const& _commandClassName,
|
||||
pfnCreateCommandClass_t _creator
|
||||
)
|
||||
{
|
||||
m_commandClassCreators[_commandClassId] = _creator;
|
||||
|
||||
// Set the bit representing the command class
|
||||
Get().m_supportedCommandClasses[_commandClassId>>5] |= (1u<<(_commandClassId&0x1f));
|
||||
|
||||
m_namesToIDs[_commandClassName] = _commandClassId;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClasses::CreateCommandClass>
|
||||
// Create a command class object using the registered method
|
||||
//-----------------------------------------------------------------------------
|
||||
CommandClass* CommandClasses::CreateCommandClass
|
||||
(
|
||||
uint8 const _commandClassId,
|
||||
uint32 const _homeId,
|
||||
uint8 const _nodeId
|
||||
)
|
||||
{
|
||||
// Get a pointer to the required CommandClass's Create method
|
||||
pfnCreateCommandClass_t creator = Get().m_commandClassCreators[_commandClassId];
|
||||
if( NULL == creator )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Create an instance of the command class
|
||||
return creator( _homeId, _nodeId );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClasses::RegisterCommandClasses>
|
||||
// Register all our implemented command classes
|
||||
//-----------------------------------------------------------------------------
|
||||
void CommandClasses::RegisterCommandClasses
|
||||
(
|
||||
)
|
||||
{
|
||||
CommandClasses& cc = Get();
|
||||
cc.Register( Alarm::StaticGetCommandClassId(), Alarm::StaticGetCommandClassName(), Alarm::Create );
|
||||
cc.Register( ApplicationStatus::StaticGetCommandClassId(), ApplicationStatus::StaticGetCommandClassName(), ApplicationStatus::Create );
|
||||
cc.Register( Association::StaticGetCommandClassId(), Association::StaticGetCommandClassName(), Association::Create );
|
||||
cc.Register( AssociationCommandConfiguration::StaticGetCommandClassId(), AssociationCommandConfiguration::StaticGetCommandClassName(), AssociationCommandConfiguration::Create );
|
||||
cc.Register( Basic::StaticGetCommandClassId(), Basic::StaticGetCommandClassName(), Basic::Create );
|
||||
cc.Register( BasicWindowCovering::StaticGetCommandClassId(), BasicWindowCovering::StaticGetCommandClassName(), BasicWindowCovering::Create );
|
||||
cc.Register( Battery::StaticGetCommandClassId(), Battery::StaticGetCommandClassName(), Battery::Create );
|
||||
cc.Register( ClimateControlSchedule::StaticGetCommandClassId(), ClimateControlSchedule::StaticGetCommandClassName(), ClimateControlSchedule::Create );
|
||||
cc.Register( Clock::StaticGetCommandClassId(), Clock::StaticGetCommandClassName(), Clock::Create );
|
||||
cc.Register( Configuration::StaticGetCommandClassId(), Configuration::StaticGetCommandClassName(), Configuration::Create );
|
||||
cc.Register( ControllerReplication::StaticGetCommandClassId(), ControllerReplication::StaticGetCommandClassName(), ControllerReplication::Create );
|
||||
cc.Register( CRC16Encap::StaticGetCommandClassId(), CRC16Encap::StaticGetCommandClassName(), CRC16Encap::Create );
|
||||
cc.Register( DoorLock::StaticGetCommandClassId(), DoorLock::StaticGetCommandClassName(), DoorLock::Create );
|
||||
cc.Register( DoorLockLogging::StaticGetCommandClassId(), DoorLockLogging::StaticGetCommandClassName(), DoorLockLogging::Create);
|
||||
cc.Register( EnergyProduction::StaticGetCommandClassId(), EnergyProduction::StaticGetCommandClassName(), EnergyProduction::Create );
|
||||
cc.Register( Hail::StaticGetCommandClassId(), Hail::StaticGetCommandClassName(), Hail::Create );
|
||||
cc.Register( Indicator::StaticGetCommandClassId(), Indicator::StaticGetCommandClassName(), Indicator::Create );
|
||||
cc.Register( Language::StaticGetCommandClassId(), Language::StaticGetCommandClassName(), Language::Create );
|
||||
cc.Register( Lock::StaticGetCommandClassId(), Lock::StaticGetCommandClassName(), Lock::Create );
|
||||
cc.Register( ManufacturerSpecific::StaticGetCommandClassId(), ManufacturerSpecific::StaticGetCommandClassName(), ManufacturerSpecific::Create );
|
||||
cc.Register( Meter::StaticGetCommandClassId(), Meter::StaticGetCommandClassName(), Meter::Create );
|
||||
cc.Register( MeterPulse::StaticGetCommandClassId(), MeterPulse::StaticGetCommandClassName(), MeterPulse::Create );
|
||||
cc.Register( MultiCmd::StaticGetCommandClassId(), MultiCmd::StaticGetCommandClassName(), MultiCmd::Create );
|
||||
cc.Register( MultiInstance::StaticGetCommandClassId(), MultiInstance::StaticGetCommandClassName(), MultiInstance::Create );
|
||||
cc.Register( MultiInstanceAssociation::StaticGetCommandClassId(), MultiInstanceAssociation::StaticGetCommandClassName(), MultiInstanceAssociation::Create );
|
||||
cc.Register( NodeNaming::StaticGetCommandClassId(), NodeNaming::StaticGetCommandClassName(), NodeNaming::Create );
|
||||
cc.Register( NoOperation::StaticGetCommandClassId(), NoOperation::StaticGetCommandClassName(), NoOperation::Create );
|
||||
cc.Register( Powerlevel::StaticGetCommandClassId(), Powerlevel::StaticGetCommandClassName(), Powerlevel::Create );
|
||||
cc.Register( Proprietary::StaticGetCommandClassId(), Proprietary::StaticGetCommandClassName(), Proprietary::Create );
|
||||
cc.Register( Protection::StaticGetCommandClassId(), Protection::StaticGetCommandClassName(), Protection::Create );
|
||||
cc.Register( SceneActivation::StaticGetCommandClassId(), SceneActivation::StaticGetCommandClassName(), SceneActivation::Create );
|
||||
cc.Register( Security::StaticGetCommandClassId(), Security::StaticGetCommandClassName(), Security::Create);
|
||||
cc.Register( SensorAlarm::StaticGetCommandClassId(), SensorAlarm::StaticGetCommandClassName(), SensorAlarm::Create );
|
||||
cc.Register( SensorBinary::StaticGetCommandClassId(), SensorBinary::StaticGetCommandClassName(), SensorBinary::Create );
|
||||
cc.Register( SensorMultilevel::StaticGetCommandClassId(), SensorMultilevel::StaticGetCommandClassName(), SensorMultilevel::Create );
|
||||
cc.Register( SwitchAll::StaticGetCommandClassId(), SwitchAll::StaticGetCommandClassName(), SwitchAll::Create );
|
||||
cc.Register( SwitchBinary::StaticGetCommandClassId(), SwitchBinary::StaticGetCommandClassName(), SwitchBinary::Create );
|
||||
cc.Register( SwitchMultilevel::StaticGetCommandClassId(), SwitchMultilevel::StaticGetCommandClassName(), SwitchMultilevel::Create );
|
||||
cc.Register( SwitchToggleBinary::StaticGetCommandClassId(), SwitchToggleBinary::StaticGetCommandClassName(), SwitchToggleBinary::Create );
|
||||
cc.Register( SwitchToggleMultilevel::StaticGetCommandClassId(), SwitchToggleMultilevel::StaticGetCommandClassName(), SwitchToggleMultilevel::Create );
|
||||
cc.Register( TimeParameters::StaticGetCommandClassId(), TimeParameters::StaticGetCommandClassName(), TimeParameters::Create);
|
||||
cc.Register( ThermostatFanMode::StaticGetCommandClassId(), ThermostatFanMode::StaticGetCommandClassName(), ThermostatFanMode::Create );
|
||||
cc.Register( ThermostatFanState::StaticGetCommandClassId(), ThermostatFanState::StaticGetCommandClassName(), ThermostatFanState::Create );
|
||||
cc.Register( ThermostatMode::StaticGetCommandClassId(), ThermostatMode::StaticGetCommandClassName(), ThermostatMode::Create );
|
||||
cc.Register( ThermostatOperatingState::StaticGetCommandClassId(), ThermostatOperatingState::StaticGetCommandClassName(), ThermostatOperatingState::Create );
|
||||
cc.Register( ThermostatSetpoint::StaticGetCommandClassId(), ThermostatSetpoint::StaticGetCommandClassName(), ThermostatSetpoint::Create );
|
||||
cc.Register( UserCode::StaticGetCommandClassId(), UserCode::StaticGetCommandClassName(), UserCode::Create );
|
||||
cc.Register( Version::StaticGetCommandClassId(), Version::StaticGetCommandClassName(), Version::Create );
|
||||
cc.Register( WakeUp::StaticGetCommandClassId(), WakeUp::StaticGetCommandClassName(), WakeUp::Create );
|
||||
|
||||
// Now all the command classes have been registered, we can modify the
|
||||
// supported command classes array according to the program options.
|
||||
string str;
|
||||
Options::Get()->GetOptionAsString( "Include", &str );
|
||||
if( str != "" )
|
||||
{
|
||||
// The include list has entries, so we assume that it is a
|
||||
// complete list of what should be supported.
|
||||
// Any existing support is cleared first.
|
||||
memset( cc.m_supportedCommandClasses, 0, sizeof(uint32)*8 );
|
||||
cc.ParseCommandClassOption( str, true );
|
||||
}
|
||||
|
||||
// Apply the excluded command class option
|
||||
Options::Get()->GetOptionAsString( "Exclude", &str );
|
||||
if( str != "" )
|
||||
{
|
||||
cc.ParseCommandClassOption( str, false );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClasses::ParseCommandClassOption>
|
||||
// Parse a comma delimited list of included/excluded command classes
|
||||
//-----------------------------------------------------------------------------
|
||||
void CommandClasses::ParseCommandClassOption
|
||||
(
|
||||
string const& _optionStr,
|
||||
bool const _include
|
||||
)
|
||||
{
|
||||
size_t pos = 0;
|
||||
size_t start = 0;
|
||||
bool parsing = true;
|
||||
while( parsing )
|
||||
{
|
||||
string ccStr;
|
||||
|
||||
pos = _optionStr.find_first_of( ",", start );
|
||||
if( string::npos == pos )
|
||||
{
|
||||
ccStr = _optionStr.substr( start );
|
||||
parsing = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ccStr = _optionStr.substr( start, pos-start );
|
||||
start = pos + 1;
|
||||
}
|
||||
|
||||
if( ccStr != "" )
|
||||
{
|
||||
uint8 ccIdx = GetCommandClassId( ccStr );
|
||||
if( _include )
|
||||
{
|
||||
m_supportedCommandClasses[ccIdx>>5] |= (1u<<(ccIdx&0x1f));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_supportedCommandClasses[ccIdx>>5] &= ~(1u<<(ccIdx&0x1f));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <CommandClasses::GetCommandClassId>
|
||||
// Convert a command class name (e.g COMMAND_CLASS_BASIC) into its 8-bit ID
|
||||
//-----------------------------------------------------------------------------
|
||||
uint8 CommandClasses::GetCommandClassId
|
||||
(
|
||||
string const& _name
|
||||
)
|
||||
{
|
||||
string upperName = ToUpper( _name );
|
||||
map<string,uint8>::iterator it = m_namesToIDs.find( upperName );
|
||||
if( it != m_namesToIDs.end() )
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// CommandClasses.h
|
||||
//
|
||||
// Singleton holding methods to create each command class object
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _CommandClasses_H
|
||||
#define _CommandClasses_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "../Defs.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class CommandClass;
|
||||
|
||||
/** \brief Manages a map of command classes supported by a specific Z-Wave node.
|
||||
*/
|
||||
class CommandClasses
|
||||
{
|
||||
public:
|
||||
typedef CommandClass* (*pfnCreateCommandClass_t)( uint32 const _homeId, uint8 const _nodeId );
|
||||
|
||||
static void RegisterCommandClasses();
|
||||
static CommandClass* CreateCommandClass( uint8 const _commandClassId, uint32 const _homeId, uint8 const _nodeId );
|
||||
|
||||
static bool IsSupported( uint8 const _commandClassId );
|
||||
static string GetName(uint8 const _commandClassId);
|
||||
private:
|
||||
CommandClasses();
|
||||
CommandClasses( CommandClasses const& ); // prevent copy
|
||||
CommandClasses& operator = ( CommandClasses const& ); // prevent assignment
|
||||
|
||||
static CommandClasses& Get()
|
||||
{
|
||||
static CommandClasses instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void Register( uint8 const _commandClassId, string const& _commandClassName, pfnCreateCommandClass_t _create );
|
||||
void ParseCommandClassOption( string const& _optionStr, bool const _include );
|
||||
uint8 GetCommandClassId( string const& _name );
|
||||
|
||||
pfnCreateCommandClass_t m_commandClassCreators[256];
|
||||
map<string,uint8> m_namesToIDs;
|
||||
|
||||
// m_supportedCommandClasses uses single bits to mark whether OpenZWave supports a command class
|
||||
// Checking this is not the same as looking for non-NULL entried in m_commandClassCreators, since
|
||||
// this may be modified by the program options --Include and --Ingnore to filter out support
|
||||
// for unwanted command classes.
|
||||
uint32 m_supportedCommandClasses[8];
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,277 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Configuration.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_CONFIGURATION
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "Configuration.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Driver.h"
|
||||
#include "../Node.h"
|
||||
#include "../platform/Log.h"
|
||||
#include "../value_classes/ValueBool.h"
|
||||
#include "../value_classes/ValueButton.h"
|
||||
#include "../value_classes/ValueByte.h"
|
||||
#include "../value_classes/ValueInt.h"
|
||||
#include "../value_classes/ValueList.h"
|
||||
#include "../value_classes/ValueShort.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum ConfigurationCmd
|
||||
{
|
||||
ConfigurationCmd_Set = 0x04,
|
||||
ConfigurationCmd_Get = 0x05,
|
||||
ConfigurationCmd_Report = 0x06
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Configuration::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Configuration::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
if (ConfigurationCmd_Report == (ConfigurationCmd)_data[0])
|
||||
{
|
||||
// Extract the parameter index and value
|
||||
uint8 parameter = _data[1];
|
||||
uint8 size = _data[2] & 0x07;
|
||||
int32 paramValue = 0;
|
||||
for( uint8 i=0; i<size; ++i )
|
||||
{
|
||||
paramValue <<= 8;
|
||||
paramValue |= (int32)_data[i+3];
|
||||
}
|
||||
|
||||
if ( Value* value = GetValue( 1, parameter ) )
|
||||
{
|
||||
switch ( value->GetID().GetType() )
|
||||
{
|
||||
case ValueID::ValueType_Bool:
|
||||
{
|
||||
ValueBool* valueBool = static_cast<ValueBool*>( value );
|
||||
valueBool->OnValueRefreshed( paramValue != 0 );
|
||||
break;
|
||||
}
|
||||
case ValueID::ValueType_Byte:
|
||||
{
|
||||
ValueByte* valueByte = static_cast<ValueByte*>( value );
|
||||
valueByte->OnValueRefreshed( (uint8)paramValue );
|
||||
break;
|
||||
}
|
||||
case ValueID::ValueType_Short:
|
||||
{
|
||||
ValueShort* valueShort = static_cast<ValueShort*>( value );
|
||||
valueShort->OnValueRefreshed( (int16)paramValue );
|
||||
break;
|
||||
}
|
||||
case ValueID::ValueType_Int:
|
||||
{
|
||||
ValueInt* valueInt = static_cast<ValueInt*>( value );
|
||||
valueInt->OnValueRefreshed( paramValue );
|
||||
break;
|
||||
}
|
||||
case ValueID::ValueType_List:
|
||||
{
|
||||
ValueList* valueList = static_cast<ValueList*>( value );
|
||||
valueList->OnValueRefreshed( paramValue );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Invalid type (%d) for configuration parameter %d", value->GetID().GetType(), parameter );
|
||||
}
|
||||
}
|
||||
value->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
char label[16];
|
||||
snprintf( label, 16, "Parameter #%d", parameter );
|
||||
|
||||
// Create a new value
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
switch( size )
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
node->CreateValueByte( ValueID::ValueGenre_Config, GetCommandClassId(), _instance, parameter, label, "", false, false, (uint8)paramValue, 0 );
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
node->CreateValueShort( ValueID::ValueGenre_Config, GetCommandClassId(), _instance, parameter, label, "", false, false, (int16)paramValue, 0 );
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
node->CreateValueInt( ValueID::ValueGenre_Config, GetCommandClassId(), _instance, parameter, label, "", false, false, (int32)paramValue, 0 );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Invalid size of %d bytes for configuration parameter %d", size, parameter );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received Configuration report: Parameter=%d, Value=%d", parameter, paramValue );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Configuration::SetValue>
|
||||
// Set a value in the Z-Wave device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Configuration::SetValue
|
||||
(
|
||||
Value const& _value
|
||||
)
|
||||
{
|
||||
uint8 param = _value.GetID().GetIndex();
|
||||
switch( _value.GetID().GetType() )
|
||||
{
|
||||
case ValueID::ValueType_Bool:
|
||||
{
|
||||
ValueBool const& valueBool = static_cast<ValueBool const&>( _value );
|
||||
Set( param, (int32)valueBool.GetValue(), 1 );
|
||||
return true;
|
||||
}
|
||||
case ValueID::ValueType_Byte:
|
||||
{
|
||||
ValueByte const& valueByte = static_cast<ValueByte const&>( _value );
|
||||
Set( param, (int32)valueByte.GetValue(), 1 );
|
||||
return true;
|
||||
}
|
||||
case ValueID::ValueType_Short:
|
||||
{
|
||||
ValueShort const& valueShort = static_cast<ValueShort const&>( _value );
|
||||
Set( param, (int32)valueShort.GetValue(), 2 );
|
||||
return true;
|
||||
}
|
||||
case ValueID::ValueType_Int:
|
||||
{
|
||||
ValueInt const& valueInt = static_cast<ValueInt const&>( _value );
|
||||
Set( param, valueInt.GetValue(), 4 );
|
||||
return true;
|
||||
}
|
||||
case ValueID::ValueType_List:
|
||||
{
|
||||
ValueList const& valueList = static_cast<ValueList const&>( _value );
|
||||
Set( param, valueList.GetItem().m_value, valueList.GetSize() );
|
||||
return true;
|
||||
}
|
||||
case ValueID::ValueType_Button:
|
||||
{
|
||||
ValueButton const& valueButton = static_cast<ValueButton const&>( _value );
|
||||
Set( param, valueButton.IsPressed(), 1 );
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Configuration::Set failed (bad value or value type) - Parameter=%d", param );
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Configuration::RequestValue>
|
||||
// Request current parameter value from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Configuration::RequestValue
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _parameter, // parameter number is encoded as the Index portion of ValueID
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( _instance != 1 )
|
||||
{
|
||||
// This command class doesn't work with multiple instances
|
||||
return false;
|
||||
}
|
||||
if ( IsGetSupported() )
|
||||
{
|
||||
Msg* msg = new Msg( "ConfigurationCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 3 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( ConfigurationCmd_Get );
|
||||
msg->Append( _parameter );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
return true;
|
||||
} else {
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "ConfigurationCmd_Get Not Supported on this node");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Configuration::Set>
|
||||
// Set the device's
|
||||
//-----------------------------------------------------------------------------
|
||||
void Configuration::Set
|
||||
(
|
||||
uint8 const _parameter,
|
||||
int32 const _value,
|
||||
uint8 const _size
|
||||
)
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Configuration::Set - Parameter=%d, Value=%d Size=%d", _parameter, _value, _size );
|
||||
|
||||
Msg* msg = new Msg( "ConfigurationCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 4 + _size );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( ConfigurationCmd_Set );
|
||||
msg->Append( _parameter );
|
||||
msg->Append( _size );
|
||||
if( _size > 2 )
|
||||
{
|
||||
msg->Append( (uint8)( ( _value>>24 ) & 0xff ) );
|
||||
msg->Append( (uint8)( ( _value>>16 ) & 0xff ) );
|
||||
}
|
||||
if( _size > 1 )
|
||||
{
|
||||
msg->Append( (uint8)( ( _value>>8 ) & 0xff ) );
|
||||
}
|
||||
msg->Append( (uint8)( _value & 0xff ) );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Configuration.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_CONFIGURATION
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _Configuration_H
|
||||
#define _Configuration_H
|
||||
|
||||
#include <list>
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class Value;
|
||||
|
||||
/** \brief Implements COMMAND_CLASS_CONFIGURATION (x70), a Z-Wave device command class.
|
||||
*/
|
||||
class Configuration: public CommandClass
|
||||
{
|
||||
friend class Node;
|
||||
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new Configuration( _homeId, _nodeId ); }
|
||||
virtual ~Configuration(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x70; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_CONFIGURATION"; }
|
||||
|
||||
virtual bool RequestValue( uint32 const _requestFlags, uint8 const _parameter, uint8 const _index, Driver::MsgQueue const _queue );
|
||||
void Set( uint8 const _parameter, int32 const _value, uint8 const _size );
|
||||
|
||||
// From CommandClass
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
virtual bool SetValue( Value const& _value );
|
||||
|
||||
private:
|
||||
Configuration( uint32 const _homeId, uint8 const _nodeId ): CommandClass( _homeId, _nodeId ){}
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,326 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ControllerReplication.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_CONTROLLER_REPLICATION
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "ControllerReplication.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Driver.h"
|
||||
#include "../Node.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
#include "../value_classes/ValueByte.h"
|
||||
#include "../value_classes/ValueList.h"
|
||||
#include "../value_classes/ValueButton.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum ControllerReplicationCmd
|
||||
{
|
||||
ControllerReplicationCmd_TransferGroup = 0x31,
|
||||
ControllerReplicationCmd_TransferGroupName = 0x32,
|
||||
ControllerReplicationCmd_TransferScene = 0x33,
|
||||
ControllerReplicationCmd_TransferSceneName = 0x34
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ControllerReplicationIndex_NodeId = 0,
|
||||
ControllerReplicationIndex_Function,
|
||||
ControllerReplicationIndex_Replicate
|
||||
};
|
||||
|
||||
static char const* c_controllerReplicationFunctionNames[] =
|
||||
{
|
||||
"Groups",
|
||||
"Group Names",
|
||||
"Scenes",
|
||||
"Scene Names",
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ControllerReplication::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
ControllerReplication::ControllerReplication
|
||||
(
|
||||
uint32 const _homeId,
|
||||
uint8 const _nodeId
|
||||
):
|
||||
CommandClass( _homeId, _nodeId ),
|
||||
m_busy( false ),
|
||||
m_targetNodeId( 0 ),
|
||||
m_funcId( 0 ),
|
||||
m_nodeId( -1 ),
|
||||
m_groupCount( -1 ),
|
||||
m_groupIdx( -1 )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ControllerReplication::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ControllerReplication::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
// When creating replication messages, use FUNC_ID_ZW_SEND_REPLICATION_DATA instead of FUNC_ID_ZW_SEND_DATA
|
||||
// e.g. Msg* msg = new Msg( "TransferGroup", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_REPLICATION_DATA, true, false );
|
||||
|
||||
switch( _data[0] )
|
||||
{
|
||||
case ControllerReplicationCmd_TransferGroup:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case ControllerReplicationCmd_TransferGroupName:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case ControllerReplicationCmd_TransferScene:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case ControllerReplicationCmd_TransferSceneName:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Msg* msg = new Msg( "ControllerReplication Command Complete", GetNodeId(), REQUEST, FUNC_ID_ZW_REPLICATION_COMMAND_COMPLETE, false, false );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Command );
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ControllerReplication::SetValue>
|
||||
// Set a value on the Z-Wave device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ControllerReplication::SetValue
|
||||
(
|
||||
Value const& _value
|
||||
)
|
||||
{
|
||||
bool res = false;
|
||||
uint8 instance = _value.GetID().GetInstance();
|
||||
|
||||
switch( _value.GetID().GetIndex() )
|
||||
{
|
||||
case ControllerReplicationIndex_NodeId:
|
||||
{
|
||||
if( ValueByte* value = static_cast<ValueByte*>( GetValue( instance, ControllerReplicationIndex_NodeId ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( (static_cast<ValueByte const*>( &_value))->GetValue() );
|
||||
value->Release();
|
||||
res = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ControllerReplicationIndex_Function:
|
||||
{
|
||||
if( ValueList* value = static_cast<ValueList*>( GetValue( instance, ControllerReplicationIndex_Function ) ) )
|
||||
{
|
||||
ValueList::Item const& item = (static_cast<ValueList const*>( &_value))->GetItem();
|
||||
value->OnValueRefreshed( item.m_value );
|
||||
value->Release();
|
||||
res = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ControllerReplicationIndex_Replicate:
|
||||
{
|
||||
if( ValueButton* button = static_cast<ValueButton*>( GetValue( instance, ControllerReplicationIndex_Replicate ) ) )
|
||||
{
|
||||
if( button->IsPressed() )
|
||||
{
|
||||
res = StartReplication( instance );
|
||||
}
|
||||
button->Release();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ControllerReplication::StartReplication>
|
||||
// Set up the group and scene data to be sent to the other controller
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ControllerReplication::StartReplication
|
||||
(
|
||||
uint8 const _instance
|
||||
)
|
||||
{
|
||||
if( m_busy )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( ValueByte* value = static_cast<ValueByte*>( GetValue( _instance, ControllerReplicationIndex_NodeId ) ) )
|
||||
{
|
||||
m_targetNodeId = value->GetValue();
|
||||
value->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( ValueList* value = static_cast<ValueList*>( GetValue( _instance, ControllerReplicationIndex_Function ) ) )
|
||||
{
|
||||
ValueList::Item const& item = value->GetItem();
|
||||
m_funcId = item.m_value;
|
||||
value->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Store the Z-Wave command we should use when replication has completed.
|
||||
m_nodeId = -1;
|
||||
m_groupCount = -1;
|
||||
m_groupIdx = -1;
|
||||
m_busy = true;
|
||||
|
||||
// Set up the groups and scenes to be sent
|
||||
SendNextData();
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ControllerReplication::SendNextData>
|
||||
// Send the next block of replication data
|
||||
//-----------------------------------------------------------------------------
|
||||
void ControllerReplication::SendNextData
|
||||
(
|
||||
)
|
||||
{
|
||||
uint16 i = 255;
|
||||
|
||||
if( !m_busy )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
if( m_groupIdx != -1 )
|
||||
{
|
||||
m_groupIdx++;
|
||||
if( m_groupIdx <= m_groupCount )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
i = m_nodeId == -1 ? 0 : m_nodeId+1;
|
||||
GetDriver()->LockNodes();
|
||||
while( i < 256 )
|
||||
{
|
||||
if( GetDriver()->m_nodes[i] )
|
||||
{
|
||||
m_groupCount = GetDriver()->m_nodes[i]->GetNumGroups();
|
||||
if( m_groupCount != 0 )
|
||||
{
|
||||
m_groupName = GetDriver()->m_nodes[i]->GetGroupLabel( m_groupIdx );
|
||||
m_groupIdx = m_groupName.length() > 0 ? 0 : 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
GetDriver()->ReleaseNodes();
|
||||
m_nodeId = i;
|
||||
break;
|
||||
}
|
||||
if( i < 255 )
|
||||
{
|
||||
Msg* msg = new Msg( "Replication Send", m_targetNodeId, REQUEST, FUNC_ID_ZW_REPLICATION_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->Append( m_targetNodeId );
|
||||
if( m_groupName.length() > 0 )
|
||||
{
|
||||
msg->Append((uint8) (m_groupName.length() + 4 ));
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( ControllerReplicationCmd_TransferGroupName );
|
||||
msg->Append( 0 );
|
||||
msg->Append( m_groupIdx );
|
||||
for( uint8 j = 0; j < m_groupName.length(); j++ )
|
||||
{
|
||||
msg->Append( m_groupName[j] );
|
||||
}
|
||||
m_groupName = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
msg->Append( 5 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( ControllerReplicationCmd_TransferGroup );
|
||||
msg->Append( 0 );
|
||||
msg->Append( m_groupIdx );
|
||||
msg->Append( m_nodeId );
|
||||
}
|
||||
msg->Append( TRANSMIT_OPTION_ACK );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Command );
|
||||
}
|
||||
else
|
||||
{
|
||||
GetDriver()->AddNodeStop( m_funcId );
|
||||
m_busy = false;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ControllerReplication::CreateVars>
|
||||
// Create the values managed by this command class
|
||||
//-----------------------------------------------------------------------------
|
||||
void ControllerReplication::CreateVars
|
||||
(
|
||||
uint8 const _instance
|
||||
)
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
node->CreateValueByte( ValueID::ValueGenre_System, GetCommandClassId(), _instance, ControllerReplicationIndex_NodeId, "Node", "", false, false, 0, 0 );
|
||||
vector<ValueList::Item> items;
|
||||
|
||||
ValueList::Item item;
|
||||
for( uint8 i=0; i<4; ++i )
|
||||
{
|
||||
item.m_label = c_controllerReplicationFunctionNames[i];
|
||||
item.m_value = ControllerReplicationCmd_TransferGroup + i;
|
||||
items.push_back( item );
|
||||
}
|
||||
|
||||
node->CreateValueList( ValueID::ValueGenre_System, GetCommandClassId(), _instance, ControllerReplicationIndex_Function, "Functions", "", false, false, 1, items, 0, 0 );
|
||||
node->CreateValueButton( ValueID::ValueGenre_System, GetCommandClassId(), _instance, ControllerReplicationIndex_Replicate, "Replicate", 0 );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ControllerReplication.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_CONTROLLER_REPLICATION
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _ControllerReplication_H
|
||||
#define _ControllerReplication_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
/** \brief Implements COMMAND_CLASS_CONTROLLER_REPLICATION (0x21), a Z-Wave device command class.
|
||||
*/
|
||||
class ControllerReplication: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new ControllerReplication( _homeId, _nodeId ); }
|
||||
virtual ~ControllerReplication(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x21; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_CONTROLLER_REPLICATION"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
virtual bool SetValue( Value const& _value );
|
||||
|
||||
void SendNextData();
|
||||
|
||||
protected:
|
||||
virtual void CreateVars( uint8 const _instance );
|
||||
|
||||
private:
|
||||
ControllerReplication( uint32 const _homeId, uint8 const _nodeId );
|
||||
bool StartReplication( uint8 const _instance );
|
||||
|
||||
|
||||
bool m_busy;
|
||||
uint8 m_targetNodeId;
|
||||
uint8 m_funcId;
|
||||
int m_nodeId;
|
||||
int m_groupCount;
|
||||
int m_groupIdx;
|
||||
string m_groupName;
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,586 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// DoorLock.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_DOOR_LOCK
|
||||
//
|
||||
// Copyright (c) 2014 Justin Hammond <justin@dynam.ac>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "DoorLock.h"
|
||||
#include "WakeUp.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Node.h"
|
||||
#include "../Driver.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
#include "../value_classes/ValueBool.h"
|
||||
#include "../value_classes/ValueByte.h"
|
||||
#include "../value_classes/ValueInt.h"
|
||||
|
||||
#include "../tinyxml.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum DoorLockCmd
|
||||
{
|
||||
DoorLockCmd_Set = 0x01,
|
||||
DoorLockCmd_Get = 0x02,
|
||||
DoorLockCmd_Report = 0x03,
|
||||
DoorLockCmd_Configuration_Set = 0x04,
|
||||
DoorLockCmd_Configuration_Get = 0x05,
|
||||
DoorLockCmd_Configuration_Report= 0x06
|
||||
};
|
||||
|
||||
enum TimeOutMode
|
||||
{
|
||||
DoorLockConfig_NoTimeout = 0x01,
|
||||
DoorLockConfig_Timeout = 0x02
|
||||
};
|
||||
|
||||
static char const* c_TimeOutModeNames[] =
|
||||
{
|
||||
"No Timeout",
|
||||
"Secure Lock after Timeout"
|
||||
};
|
||||
|
||||
enum DoorLockControlState
|
||||
{
|
||||
DoorLockControlState_Handle1 = 0x01,
|
||||
DoorLockControlState_Handle2 = 0x02,
|
||||
DoorLockControlState_Handle3 = 0x04,
|
||||
DoorLockControlState_Handle4 = 0x08
|
||||
};
|
||||
|
||||
enum ValueIDSystemIndexes
|
||||
{
|
||||
Value_Lock = 0x00, /* Simple On/Off Mode for Lock */
|
||||
Value_Lock_Mode = 0x01, /* To Set more Complex Lock Modes (Such as timeouts etc) */
|
||||
Value_System_Config_Mode = 0x02, /* To Set/Unset if Locks should return to Secured Mode after a timeout */
|
||||
Value_System_Config_Minutes = 0x03, /* If Timeouts are enabled, how many minutes before a Lock "AutoLocks" */
|
||||
Value_System_Config_Seconds = 0x04, /* If Timeouts are enabled, how many seconds beofre a Lock "Autolocks" */
|
||||
Value_System_Config_OutsideHandles = 0x05, /* What Outside Handles are controlled via Z-Wave (BitMask 1-4) */
|
||||
Value_System_Config_InsideHandles = 0x06, /* What inside Handles are control via ZWave (BitMask 1-4) */
|
||||
};
|
||||
|
||||
enum DoorLockState
|
||||
{
|
||||
DoorLockState_Unsecured = 0x00,
|
||||
DoorLockState_Unsecured_Timeout = 0x01,
|
||||
DoorLockState_Inside_Unsecured = 0x10,
|
||||
DoorLockState_Inside_Unsecured_Timeout = 0x11,
|
||||
DoorLockState_Outside_Unsecured = 0x20,
|
||||
DoorLockState_Outside_Unsecured_Timeout = 0x21,
|
||||
DoorLockState_Secured = 0xFF
|
||||
};
|
||||
|
||||
|
||||
static char const* c_LockStateNames[] =
|
||||
{
|
||||
"Unsecure",
|
||||
"Unsecured with Timeout",
|
||||
"Inside Handle Unsecured",
|
||||
"Inside Handle Unsecured with Timeout",
|
||||
"Outside Handle Unsecured",
|
||||
"Outside Handle Unsecured with Timeout",
|
||||
"Secured",
|
||||
"Invalid"
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <DoorLock::DoorLock>
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
DoorLock::DoorLock
|
||||
(
|
||||
uint32 const _homeId,
|
||||
uint8 const _nodeId
|
||||
):
|
||||
CommandClass( _homeId, _nodeId ),
|
||||
m_timeoutsupported(0),
|
||||
m_insidehandlemode(0),
|
||||
m_outsidehandlemode(0),
|
||||
m_timeoutmins(0xFE),
|
||||
m_timeoutsecs(0xFE)
|
||||
{
|
||||
SetStaticRequest( StaticRequest_Values );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <UserCode::ReadXML>
|
||||
// Class specific configuration
|
||||
//-----------------------------------------------------------------------------
|
||||
void DoorLock::ReadXML
|
||||
(
|
||||
TiXmlElement const* _ccElement
|
||||
)
|
||||
{
|
||||
int32 intVal;
|
||||
|
||||
CommandClass::ReadXML( _ccElement );
|
||||
if( TIXML_SUCCESS == _ccElement->QueryIntAttribute( "m_timeoutsupported", &intVal ) )
|
||||
{
|
||||
m_timeoutsupported = intVal;
|
||||
}
|
||||
if( TIXML_SUCCESS == _ccElement->QueryIntAttribute( "m_insidehandlemode", &intVal ) )
|
||||
{
|
||||
m_insidehandlemode = intVal;
|
||||
}
|
||||
if( TIXML_SUCCESS == _ccElement->QueryIntAttribute( "m_outsidehandlemode", &intVal ) )
|
||||
{
|
||||
m_outsidehandlemode = intVal;
|
||||
}
|
||||
if( TIXML_SUCCESS == _ccElement->QueryIntAttribute( "m_timeoutmins", &intVal ) )
|
||||
{
|
||||
m_timeoutmins = intVal;
|
||||
}
|
||||
if( TIXML_SUCCESS == _ccElement->QueryIntAttribute( "m_timeoutsecs", &intVal ) )
|
||||
{
|
||||
m_timeoutsecs = intVal;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <UserCode::WriteXML>
|
||||
// Class specific configuration
|
||||
//-----------------------------------------------------------------------------
|
||||
void DoorLock::WriteXML
|
||||
(
|
||||
TiXmlElement* _ccElement
|
||||
)
|
||||
{
|
||||
char str[32];
|
||||
|
||||
CommandClass::WriteXML( _ccElement );
|
||||
snprintf( str, sizeof(str), "%d", m_timeoutsupported );
|
||||
_ccElement->SetAttribute( "m_timeoutsupported", str);
|
||||
|
||||
snprintf( str, sizeof(str), "%d", m_insidehandlemode );
|
||||
_ccElement->SetAttribute( "m_insidehandlemode", str);
|
||||
|
||||
snprintf( str, sizeof(str), "%d", m_outsidehandlemode );
|
||||
_ccElement->SetAttribute( "m_outsidehandlemode", str);
|
||||
|
||||
snprintf( str, sizeof(str), "%d", m_timeoutmins );
|
||||
_ccElement->SetAttribute( "m_timeoutmins", str);
|
||||
|
||||
snprintf( str, sizeof(str), "%d", m_timeoutsecs );
|
||||
_ccElement->SetAttribute( "m_timeoutsecs", str);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <DoorLock::RequestState>
|
||||
// Request current state from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool DoorLock::RequestState
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
bool requests = false;
|
||||
if( ( _requestFlags & RequestFlag_Static ) && HasStaticRequest( StaticRequest_Values ) )
|
||||
{
|
||||
requests = RequestValue( _requestFlags, Value_System_Config_Mode, _instance, _queue );
|
||||
}
|
||||
|
||||
if( _requestFlags & RequestFlag_Dynamic )
|
||||
{
|
||||
requests |= RequestValue( _requestFlags, Value_Lock, _instance, _queue );
|
||||
}
|
||||
|
||||
return requests;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <DoorLock::RequestValue>
|
||||
// Request current value from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool DoorLock::RequestValue
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _what,
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if ( _what >= Value_System_Config_Mode) {
|
||||
Msg* msg = new Msg( "DoorLockCmd_Configuration_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, _instance );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( DoorLockCmd_Configuration_Get );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
return true;
|
||||
|
||||
} else if ((_what == Value_Lock) || (_what == Value_Lock_Mode)) {
|
||||
|
||||
if ( IsGetSupported() )
|
||||
{
|
||||
Msg* msg = new Msg( "DoorLockCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, _instance );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( DoorLockCmd_Get );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
return true;
|
||||
} else {
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "DoorLockCmd_Get Not Supported on this node");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <DoorLock::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool DoorLock::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
|
||||
if( DoorLockCmd_Report == (DoorLockCmd)_data[0] )
|
||||
{
|
||||
uint8 lockState = (_data[1] == 0xFF) ? 6 : _data[1];
|
||||
if (lockState > 6) /* size of c_LockStateNames minus Invalid Entry */
|
||||
{
|
||||
Log::Write (LogLevel_Warning, GetNodeId(), "LockState Value was greater than range. Setting to Invalid");
|
||||
lockState = 7;
|
||||
}
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received DoorLock report: DoorLock is %s", c_LockStateNames[lockState] );
|
||||
|
||||
if( ValueBool* value = static_cast<ValueBool*>( GetValue( _instance, Value_Lock ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( lockState == 0xFF );
|
||||
value->Release();
|
||||
}
|
||||
if( ValueList* value = static_cast<ValueList*>( GetValue( _instance, Value_Lock_Mode ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( lockState);
|
||||
value->Release();
|
||||
}
|
||||
return true;
|
||||
} else if (DoorLockCmd_Configuration_Report == (DoorLockCmd)_data[0] )
|
||||
{
|
||||
switch (_data[1]) {
|
||||
case DoorLockConfig_NoTimeout:
|
||||
m_timeoutsupported = DoorLockConfig_NoTimeout;
|
||||
RemoveValue(_instance, Value_System_Config_Minutes);
|
||||
RemoveValue(_instance, Value_System_Config_Seconds);
|
||||
m_timeoutmins = 0xFE;
|
||||
m_timeoutsecs = 0xFE;
|
||||
break;
|
||||
case DoorLockConfig_Timeout:
|
||||
/* if we have a timeout, then create the Values for the timeout config */
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
node->CreateValueInt( ValueID::ValueGenre_System, GetCommandClassId(), _instance, Value_System_Config_Minutes, "Timeout Minutes", "Mins", false, false, _data[3], 0 );
|
||||
node->CreateValueInt( ValueID::ValueGenre_System, GetCommandClassId(), _instance, Value_System_Config_Seconds, "Timeout Seconds", "Secs", false, false, _data[4], 0 );
|
||||
}
|
||||
m_timeoutsupported = DoorLockConfig_Timeout;
|
||||
m_timeoutmins = _data[3];
|
||||
m_timeoutsecs = _data[4];
|
||||
break;
|
||||
default:
|
||||
Log::Write(LogLevel_Warning, GetNodeId(), "Recieved a Unsupported Door Lock Config Report %d", _data[1]);
|
||||
}
|
||||
|
||||
if( ValueByte* value = static_cast<ValueByte*>( GetValue( _instance, Value_System_Config_OutsideHandles ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( ((_data[2] & 0xF0)>>4) );
|
||||
value->Release();
|
||||
m_outsidehandlemode = ((_data[2] & 0xF0)>>4);
|
||||
}
|
||||
if( ValueByte* value = static_cast<ValueByte*>( GetValue( _instance, Value_System_Config_InsideHandles ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( (_data[2] & 0x0F) );
|
||||
value->Release();
|
||||
m_insidehandlemode = (_data[2] & 0x0F);
|
||||
}
|
||||
|
||||
|
||||
ClearStaticRequest( StaticRequest_Values );
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <DoorLock::SetValue>
|
||||
// Set the lock's state
|
||||
//-----------------------------------------------------------------------------
|
||||
bool DoorLock::SetValue
|
||||
(
|
||||
Value const& _value
|
||||
)
|
||||
{
|
||||
uint8 instance = _value.GetID().GetInstance();
|
||||
if( (Value_Lock == _value.GetID().GetIndex()) && ValueID::ValueType_Bool == _value.GetID().GetType() )
|
||||
{
|
||||
ValueBool const* value = static_cast<ValueBool const*>(&_value);
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Value_Lock::Set - Requesting lock to be %s", value->GetValue() ? "Locked" : "Unlocked" );
|
||||
Msg* msg = new Msg( "DoorLockCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, _value.GetID().GetInstance() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 3 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( DoorLockCmd_Set );
|
||||
msg->Append( value->GetValue() ? 0xFF:0x00 );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
return true;
|
||||
}
|
||||
if ( (Value_Lock_Mode == _value.GetID().GetIndex()) && (ValueID::ValueType_List == _value.GetID().GetType()) )
|
||||
{
|
||||
ValueList const* value = static_cast<ValueList const*>(&_value);
|
||||
ValueList::Item const& item = value->GetItem();
|
||||
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Value_Lock_Mode::Set - Requesting lock to be %s", item.m_label.c_str() );
|
||||
Msg* msg = new Msg( "DoorLockCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, _value.GetID().GetInstance() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 3 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( DoorLockCmd_Set );
|
||||
msg->Append( item.m_value );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
return true;
|
||||
}
|
||||
/* if its any of our System Messages.... */
|
||||
if ( Value_System_Config_Mode >= _value.GetID().GetIndex() )
|
||||
{
|
||||
bool sendmsg = true;
|
||||
switch (_value.GetID().GetIndex()) {
|
||||
/* this is a List */
|
||||
case Value_System_Config_Mode:
|
||||
if (ValueID::ValueType_List != _value.GetID().GetType()) {
|
||||
sendmsg = false;
|
||||
break;
|
||||
}
|
||||
if( ValueList* value = static_cast<ValueList*>( GetValue( instance, _value.GetID().GetIndex() ) ) )
|
||||
{
|
||||
ValueList::Item const& item = (static_cast<ValueList const*>( &_value))->GetItem();
|
||||
value->OnValueRefreshed( item.m_value );
|
||||
value->Release();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/* these are a int */
|
||||
case Value_System_Config_Minutes:
|
||||
case Value_System_Config_Seconds:
|
||||
if (ValueID::ValueType_Int != _value.GetID().GetType()) {
|
||||
sendmsg = false;
|
||||
break;
|
||||
}
|
||||
if( ValueInt* value = static_cast<ValueInt*>( GetValue( instance, _value.GetID().GetIndex() ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( (static_cast<ValueInt const*>( &_value))->GetValue() );
|
||||
value->Release();
|
||||
}
|
||||
break;
|
||||
/* these are a byte */
|
||||
case Value_System_Config_OutsideHandles:
|
||||
case Value_System_Config_InsideHandles:
|
||||
if (ValueID::ValueType_Byte != _value.GetID().GetType()) {
|
||||
sendmsg = false;
|
||||
break;
|
||||
}
|
||||
if( ValueByte* value = static_cast<ValueByte*>( GetValue( instance, _value.GetID().GetIndex() ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( (static_cast<ValueByte const*>( &_value))->GetValue() );
|
||||
value->Release();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Log::Write(LogLevel_Warning, GetNodeId(), "DoorLock::SetValue - Unhandled System_Config Variable %d", _value.GetID().GetIndex());
|
||||
sendmsg = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sendmsg)
|
||||
{
|
||||
bool ok = true;
|
||||
if( ValueList* value = static_cast<ValueList*>( GetValue( instance, Value_System_Config_Mode ) ) ) {
|
||||
ValueList::Item const& item = value->GetItem();
|
||||
m_timeoutsupported = item.m_value;
|
||||
} else {
|
||||
ok = false;
|
||||
Log::Write(LogLevel_Warning, GetNodeId(), "Failed To Retrieve Value_System_Config_Mode For SetValue");
|
||||
}
|
||||
uint8 control = 0;
|
||||
if( ValueByte* value = static_cast<ValueByte*>( GetValue( instance, Value_System_Config_OutsideHandles ) ) )
|
||||
{
|
||||
control = (value->GetValue() << 4);
|
||||
m_insidehandlemode = control;
|
||||
} else {
|
||||
ok = false;
|
||||
Log::Write(LogLevel_Warning, GetNodeId(), "Failed To Retrieve Value_System_Config_OutsideHandles For SetValue");
|
||||
}
|
||||
if( ValueByte* value = static_cast<ValueByte*>( GetValue( instance, Value_System_Config_InsideHandles ) ) )
|
||||
{
|
||||
control += (value->GetValue() & 0x0F);
|
||||
m_outsidehandlemode = (value->GetValue() & 0x0F);
|
||||
} else {
|
||||
ok = false;
|
||||
Log::Write(LogLevel_Warning, GetNodeId(), "Failed To Retrieve Value_System_Config_InsideHandles For SetValue");
|
||||
}
|
||||
if( ValueInt* value = static_cast<ValueInt*>( GetValue( instance, Value_System_Config_Minutes ) ) )
|
||||
{
|
||||
m_timeoutmins = value->GetValue();
|
||||
} else {
|
||||
/* Minutes and Seconds Might Not Exist, this is fine. Set to 0xFE */
|
||||
m_timeoutmins = 0xFE;
|
||||
}
|
||||
if( ValueInt* value = static_cast<ValueInt*>( GetValue( instance, Value_System_Config_Seconds ) ) )
|
||||
{
|
||||
m_timeoutsecs = value->GetValue();
|
||||
} else {
|
||||
/* Minutes and Seconds Might Not Exist, this is fine. Set to 0xFE */
|
||||
m_timeoutsecs = 0xFE;
|
||||
}
|
||||
if (ok) {
|
||||
Msg* msg = new Msg( "DoorLockCmd_Configuration_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, _value.GetID().GetInstance() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 6 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( DoorLockCmd_Configuration_Set );
|
||||
msg->Append( m_timeoutsupported );
|
||||
msg->Append( control );
|
||||
msg->Append( m_timeoutmins );
|
||||
msg->Append( m_timeoutsecs );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <DoorLock::SetValueBasic>
|
||||
// Update class values based in BASIC mapping
|
||||
//-----------------------------------------------------------------------------
|
||||
void DoorLock::SetValueBasic
|
||||
(
|
||||
uint8 const _instance,
|
||||
uint8 const _value
|
||||
)
|
||||
{
|
||||
|
||||
|
||||
|
||||
// Send a request for new value to synchronize it with the BASIC set/report.
|
||||
// In case the device is sleeping, we set the value anyway so the BASIC set/report
|
||||
// stays in sync with it. We must be careful mapping the uint8 BASIC value
|
||||
// into a class specific value.
|
||||
// When the device wakes up, the real requested value will be retrieved.
|
||||
RequestValue( 0, DoorLockCmd_Get, _instance, Driver::MsgQueue_Send );
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
if( WakeUp* wakeUp = static_cast<WakeUp*>( node->GetCommandClass( WakeUp::StaticGetCommandClassId() ) ) )
|
||||
{
|
||||
if( !wakeUp->IsAwake() )
|
||||
{
|
||||
if( ValueBool* value = static_cast<ValueBool*>( GetValue( _instance, Value_Lock ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( _value != 0 );
|
||||
value->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <DoorLock::CreateVars>
|
||||
// Create the values managed by this command class
|
||||
//-----------------------------------------------------------------------------
|
||||
void DoorLock::CreateVars
|
||||
(
|
||||
uint8 const _instance
|
||||
)
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
node->CreateValueBool( ValueID::ValueGenre_User, GetCommandClassId(), _instance, Value_Lock, "Locked", "", false, false, false, 0 );
|
||||
|
||||
/* Complex Lock Option */
|
||||
{
|
||||
vector<ValueList::Item> items;
|
||||
ValueList::Item item;
|
||||
for( uint8 i=0; i<8; ++i )
|
||||
{
|
||||
item.m_label = c_LockStateNames[i];
|
||||
item.m_value = (i < 6) ? i : 0xFF;
|
||||
items.push_back( item );
|
||||
}
|
||||
node->CreateValueList( ValueID::ValueGenre_User, GetCommandClassId(), _instance, Value_Lock_Mode, "Locked (Advanced)", "", false, false, 1, items, 0, 0 );
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* Timeout mode for Locks that support it */
|
||||
{
|
||||
vector<ValueList::Item> items;
|
||||
ValueList::Item item;
|
||||
for( uint8 i=0; i<2; ++i )
|
||||
{
|
||||
item.m_label = c_TimeOutModeNames[i];
|
||||
item.m_value = i+1;
|
||||
items.push_back( item );
|
||||
}
|
||||
node->CreateValueList( ValueID::ValueGenre_System, GetCommandClassId(), _instance, Value_System_Config_Mode, "Timeout Mode", "", false, false, 1, items, 0, 0 );
|
||||
}
|
||||
node->CreateValueByte( ValueID::ValueGenre_System, GetCommandClassId(), _instance, Value_System_Config_OutsideHandles, "Outside Handle Control", "", false, false, 0x0F, 0 );
|
||||
node->CreateValueByte( ValueID::ValueGenre_System, GetCommandClassId(), _instance, Value_System_Config_InsideHandles, "Inside Handle Control", "", false, false, 0x0F, 0 );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// DoorLock.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_DOOR_LOCK
|
||||
//
|
||||
// Copyright (c) 2014 Justin Hammond <justin@dynam.ac>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _DoorLock_H
|
||||
#define _DoorLock_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class ValueBool;
|
||||
|
||||
/** \brief Implements COMMAND_CLASS_DOOR_LOCK (0x62), a Z-Wave device command class.
|
||||
*/
|
||||
class DoorLock: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new DoorLock( _homeId, _nodeId ); }
|
||||
virtual ~DoorLock(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x62; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_DOOR_LOCK"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual void ReadXML( TiXmlElement const* _ccElement );
|
||||
virtual void WriteXML( TiXmlElement* _ccElement );
|
||||
virtual bool RequestState( uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual bool RequestValue( uint32 const _requestFlags, uint8 const _index, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
virtual bool SetValue( Value const& _value );
|
||||
virtual void SetValueBasic( uint8 const _instance, uint8 const _value );
|
||||
|
||||
|
||||
protected:
|
||||
virtual void CreateVars( uint8 const _instance );
|
||||
|
||||
private:
|
||||
DoorLock( uint32 const _homeId, uint8 const _nodeId );
|
||||
uint8 m_timeoutsupported;
|
||||
uint8 m_insidehandlemode;
|
||||
uint8 m_outsidehandlemode;
|
||||
uint8 m_timeoutmins;
|
||||
uint8 m_timeoutsecs;
|
||||
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,375 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// DoorLockLogging.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_DOOR_LOCK_LOGGING
|
||||
//
|
||||
// Copyright (c) 2014 Justin Hammond <justin@dynam.ac>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "DoorLockLogging.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Node.h"
|
||||
#include "../Driver.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
#include "../value_classes/ValueBool.h"
|
||||
#include "../value_classes/ValueByte.h"
|
||||
#include "../value_classes/ValueInt.h"
|
||||
#include "../value_classes/ValueString.h"
|
||||
|
||||
#include "../tinyxml.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum DoorLockLoggingCmd
|
||||
{
|
||||
DoorLockLoggingCmd_RecordSupported_Get = 0x01,
|
||||
DoorLockLoggingCmd_RecordSupported_Report = 0x02,
|
||||
DoorLockLoggingCmd_Record_Get = 0x03,
|
||||
DoorLockLoggingCmd_Record_Report = 0x04
|
||||
};
|
||||
|
||||
enum DoorLockEventType
|
||||
{
|
||||
DoorLockEventType_LockCode = 0x01,
|
||||
DoorLockEventType_UnLockCode = 0x02,
|
||||
DoorLockEventType_LockButton = 0x03,
|
||||
DoorLockEventType_UnLockButton = 0x04,
|
||||
DoorLockEventType_LockCodeOOSchedule = 0x05,
|
||||
DoorLockEventType_UnLockCodeOOSchedule = 0x06,
|
||||
DoorLockEventType_IllegalCode = 0x07,
|
||||
DoorLockEventType_LockManual = 0x08,
|
||||
DoorLockEventType_UnLockManual = 0x09,
|
||||
DoorLockEventType_LockAuto = 0x0A,
|
||||
DoorLockEventType_UnLockAuto = 0x0B,
|
||||
DoorLockEventType_LockRemoteCode = 0x0C,
|
||||
DoorLockEventType_UnLockRemoteCode = 0x0D,
|
||||
DoorLockEventType_LockRemote = 0x0E,
|
||||
DoorLockEventType_UnLockRemote = 0x0F,
|
||||
DoorLockEventType_LockRemoteCodeOOSchedule = 0x10,
|
||||
DoorLockEventType_UnLockRemoteCodeOOSchedule = 0x11,
|
||||
DoorLockEventType_RemoteIllegalCode = 0x12,
|
||||
DoorLockEventType_LockManual2 = 0x13,
|
||||
DoorLockEventType_UnlockManual2 = 0x14,
|
||||
DoorLockEventType_LockSecured = 0x15,
|
||||
DoorLockEventType_LockUnsecured = 0x16,
|
||||
DoorLockEventType_UserCodeAdded = 0x17,
|
||||
DoorLockEventType_UserCodeDeleted = 0x18,
|
||||
DoorLockEventType_AllUserCodesDeleted = 0x19,
|
||||
DoorLockEventType_MasterCodeChanged = 0x1A,
|
||||
DoorLockEventType_UserCodeChanged = 0x1B,
|
||||
DoorLockEventType_LockReset = 0x1C,
|
||||
DoorLockEventType_ConfigurationChanged = 0x1D,
|
||||
DoorLockEventType_LowBattery = 0x1E,
|
||||
DoorLockEventType_NewBattery = 0x1F,
|
||||
DoorLockEventType_Max = 0x20
|
||||
};
|
||||
|
||||
static char const* c_DoorLockEventType[] =
|
||||
{
|
||||
"Locked via Access Code",
|
||||
"Unlocked via Access Code",
|
||||
"Locked via Lock Button",
|
||||
"Unlocked via UnLock Botton",
|
||||
"Lock Attempt via Out of Schedule Access Code",
|
||||
"Unlock Attemp via Out of Schedule Access Code",
|
||||
"Illegal Access Code Entered",
|
||||
"Manually Locked",
|
||||
"Manually UnLocked",
|
||||
"Auto Locked",
|
||||
"Auto Unlocked",
|
||||
"Locked via Remote Out of Schedule Access Code",
|
||||
"Unlocked via Remote Out of Schedule Access Code",
|
||||
"Locked via Remote",
|
||||
"Unlocked via Remote",
|
||||
"Lock Attempt via Remote Out of Schedule Access Code",
|
||||
"Unlock Attempt via Remote Out of Schedule Access Code",
|
||||
"Illegal Remote Access Code",
|
||||
"Manually Locked (2)",
|
||||
"Manually Unlocked (2)",
|
||||
"Lock Secured",
|
||||
"Lock Unsecured",
|
||||
"User Code Added",
|
||||
"User Code Deleted",
|
||||
"All User Codes Deleted",
|
||||
"Master Code Changed",
|
||||
"User Code Changed",
|
||||
"Lock Reset",
|
||||
"Configuration Changed",
|
||||
"Low Battery",
|
||||
"New Battery Installed",
|
||||
"Unknown"
|
||||
};
|
||||
/* size = 31 entries */
|
||||
|
||||
enum ValueIDSystemIndexes
|
||||
{
|
||||
Value_System_Config_MaxRecords = 0x00, /* Max Number of Records the Device can Hold */
|
||||
Value_GetRecordNo = 0x01, /* Current Record Number after refresh */
|
||||
Value_LogRecord = 0x02 /* Simple String Representation of the Log Record - Tab Delimited Fields */
|
||||
};
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <DoorLockLogging::DoorLockLogging>
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
DoorLockLogging::DoorLockLogging
|
||||
(
|
||||
uint32 const _homeId,
|
||||
uint8 const _nodeId
|
||||
):
|
||||
CommandClass( _homeId, _nodeId ),
|
||||
m_MaxRecords(0),
|
||||
m_CurRecord(0)
|
||||
{
|
||||
SetStaticRequest( StaticRequest_Values );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <UserCode::ReadXML>
|
||||
// Class specific configuration
|
||||
//-----------------------------------------------------------------------------
|
||||
void DoorLockLogging::ReadXML
|
||||
(
|
||||
TiXmlElement const* _ccElement
|
||||
)
|
||||
{
|
||||
int32 intVal;
|
||||
|
||||
CommandClass::ReadXML( _ccElement );
|
||||
if( TIXML_SUCCESS == _ccElement->QueryIntAttribute( "m_MaxRecords", &intVal ) )
|
||||
{
|
||||
m_MaxRecords = intVal;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <UserCode::WriteXML>
|
||||
// Class specific configuration
|
||||
//-----------------------------------------------------------------------------
|
||||
void DoorLockLogging::WriteXML
|
||||
(
|
||||
TiXmlElement* _ccElement
|
||||
)
|
||||
{
|
||||
char str[32];
|
||||
|
||||
CommandClass::WriteXML( _ccElement );
|
||||
snprintf( str, sizeof(str), "%d", m_MaxRecords );
|
||||
_ccElement->SetAttribute( "m_MaxRecords", str);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <DoorLockLogging::RequestState>
|
||||
// Request current state from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool DoorLockLogging::RequestState
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
bool requests = false;
|
||||
if( ( _requestFlags & RequestFlag_Static ) && HasStaticRequest( StaticRequest_Values ) )
|
||||
{
|
||||
requests = RequestValue( _requestFlags, DoorLockLoggingCmd_RecordSupported_Get, _instance, _queue );
|
||||
}
|
||||
|
||||
if( _requestFlags & RequestFlag_Dynamic )
|
||||
{
|
||||
requests |= RequestValue( _requestFlags, DoorLockLoggingCmd_Record_Get, _instance, _queue );
|
||||
}
|
||||
|
||||
return requests;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <DoorLockLogging::RequestValue>
|
||||
// Request current value from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool DoorLockLogging::RequestValue
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _what,
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if ( _what == DoorLockLoggingCmd_RecordSupported_Get) {
|
||||
Msg* msg = new Msg( "DoorLockLoggingCmd_RecordSupported_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, _instance );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( DoorLockLoggingCmd_RecordSupported_Get );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
return true;
|
||||
|
||||
} else if (_what == DoorLockLoggingCmd_Record_Get) {
|
||||
Msg* msg = new Msg( "DoorLockLoggingCmd_Record_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, _instance );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( DoorLockLoggingCmd_Record_Get );
|
||||
msg->Append( m_CurRecord );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <DoorLockLogging::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool DoorLockLogging::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
|
||||
if( DoorLockLoggingCmd_RecordSupported_Report == (DoorLockLoggingCmd)_data[0] )
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received DoorLockLoggingCmd_RecordSupported_Report: Max Records is %d ", _data[1]);
|
||||
|
||||
if( ValueByte* value = static_cast<ValueByte*>( GetValue( _instance, Value_System_Config_MaxRecords ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( _data[1]);
|
||||
value->Release();
|
||||
}
|
||||
ClearStaticRequest( StaticRequest_Values );
|
||||
return true;
|
||||
} else if (DoorLockLoggingCmd_Record_Report == (DoorLockLoggingCmd)_data[0] )
|
||||
{
|
||||
uint8 EventType = _data[9];
|
||||
if (EventType >= DoorLockEventType_Max)
|
||||
EventType = DoorLockEventType_Max;
|
||||
|
||||
Log::Write (LogLevel_Info, GetNodeId(), "Recieved a DoorLockLogging Record %d which is \"%s\"", _data[1], c_DoorLockEventType[EventType-1]);
|
||||
|
||||
if( ValueByte* value = static_cast<ValueByte*>( GetValue( _instance, Value_GetRecordNo ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( _data[1]);
|
||||
value->Release();
|
||||
}
|
||||
if( ValueString* value = static_cast<ValueString*>( GetValue( _instance, Value_LogRecord ) ) )
|
||||
{
|
||||
char msg[512];
|
||||
uint16 year = (_data[2] << 8) + (_data[3] & 0xFF);
|
||||
uint8 month = (_data[4] & 0x0F);
|
||||
uint8 day = (_data[5] & 0x1F);
|
||||
uint8 hour = (_data[6] & 0x1F);
|
||||
uint8 minute = (_data[7] & 0x3F);
|
||||
uint8 second = (_data[8] & 0x3F);
|
||||
bool valid = false;
|
||||
if (((_data[6] & 0xE0) >> 5) > 0)
|
||||
{
|
||||
valid = true;
|
||||
}
|
||||
uint8 userid = (_data[10]);
|
||||
uint8 usercodelength = (_data[11]);
|
||||
char usercode[254];
|
||||
snprintf(usercode, sizeof(usercode), "UserCode:");
|
||||
if (usercodelength > 0)
|
||||
for (int i = 0; i < usercodelength; i++ )
|
||||
{
|
||||
snprintf(usercode, sizeof(usercode), "%s %d", usercode, (int)_data[12+i]);
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
snprintf(msg, sizeof(msg), "%02d/%02d/%02d %02d:%02d:%02d \tMessage: %s \tUserID: %d \t%s", (int)day, (int)month, (int)year, (int)hour, (int)minute, (int)second, c_DoorLockEventType[EventType], (int)userid, usercode);
|
||||
} else
|
||||
snprintf(msg, sizeof(msg), "Invalid Record");
|
||||
value->OnValueRefreshed(msg);
|
||||
value->Release();
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <DoorLockLogging::SetValue>
|
||||
// Set the lock's state
|
||||
//-----------------------------------------------------------------------------
|
||||
bool DoorLockLogging::SetValue
|
||||
(
|
||||
Value const& _value
|
||||
)
|
||||
{
|
||||
if( (Value_GetRecordNo == _value.GetID().GetIndex()) && ValueID::ValueType_Byte == _value.GetID().GetType() )
|
||||
{
|
||||
ValueByte const* value = static_cast<ValueByte const*>(&_value);
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "DoorLockLoggingCmd_Record_Get - Requesting Log Record %d", value->GetValue() );
|
||||
Msg* msg = new Msg( "DoorLockLoggingCmd_Record_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, _value.GetID().GetInstance() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 3 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( DoorLockLoggingCmd_Record_Get );
|
||||
msg->Append( value->GetValue() );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
m_CurRecord = value->GetValue();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <DoorLockLogging::CreateVars>
|
||||
// Create the values managed by this command class
|
||||
//-----------------------------------------------------------------------------
|
||||
void DoorLockLogging::CreateVars
|
||||
(
|
||||
uint8 const _instance
|
||||
)
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
node->CreateValueByte( ValueID::ValueGenre_System, GetCommandClassId(), _instance, Value_System_Config_MaxRecords, "Max Number of Records", "", true, false, 0x0, 0 );
|
||||
node->CreateValueByte( ValueID::ValueGenre_User, GetCommandClassId(), _instance, Value_GetRecordNo, "Current Record Number", "", false, false, 0x0, 0 );
|
||||
node->CreateValueString( ValueID::ValueGenre_User, GetCommandClassId(), _instance, Value_LogRecord, "Log Record", "", true, false, "", 0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// DoorLockLogging.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_DOOR_LOCK_LOGGING
|
||||
//
|
||||
// Copyright (c) 2014 Justin Hammond <justin@dynam.ac>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _DoorLockLogging_H
|
||||
#define _DoorLockLogging_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class ValueBool;
|
||||
|
||||
/** \brief Implements COMMAND_CLASS_DOOR_LOCK_LOGGING (0x4C), a Z-Wave device command class.
|
||||
*/
|
||||
class DoorLockLogging: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new DoorLockLogging( _homeId, _nodeId ); }
|
||||
virtual ~DoorLockLogging(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x4c; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_DOOR_LOCK_LOGGING"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual void ReadXML( TiXmlElement const* _ccElement );
|
||||
virtual void WriteXML( TiXmlElement* _ccElement );
|
||||
virtual bool RequestState( uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual bool RequestValue( uint32 const _requestFlags, uint8 const _index, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
virtual bool SetValue( Value const& _value );
|
||||
protected:
|
||||
virtual void CreateVars( uint8 const _instance );
|
||||
|
||||
private:
|
||||
DoorLockLogging( uint32 const _homeId, uint8 const _nodeId );
|
||||
uint8 m_MaxRecords;
|
||||
uint8 m_CurRecord;
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// EnergyProduction.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_ENERGY_PRODUCTION
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "EnergyProduction.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Node.h"
|
||||
#include "../Driver.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
#include "../value_classes/ValueDecimal.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum EnergyProductionCmd
|
||||
{
|
||||
EnergyProductionCmd_Get = 0x02,
|
||||
EnergyProductionCmd_Report = 0x03
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
EnergyProductionIndex_Instant = 0,
|
||||
EnergyProductionIndex_Total,
|
||||
EnergyProductionIndex_Today,
|
||||
EnergyProductionIndex_Time
|
||||
};
|
||||
|
||||
static char const* c_energyParameterNames[] =
|
||||
{
|
||||
"Instant energy production",
|
||||
"Total energy production",
|
||||
"Energy production today",
|
||||
"Total production time"
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <EnergyProduction::RequestState>
|
||||
// Request current state from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool EnergyProduction::RequestState
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
bool request = false;
|
||||
if( _requestFlags & RequestFlag_Dynamic )
|
||||
{
|
||||
// Request each of the production values
|
||||
request |= RequestValue( _requestFlags, EnergyProductionIndex_Instant, _instance, _queue );
|
||||
request |= RequestValue( _requestFlags, EnergyProductionIndex_Total, _instance, _queue );
|
||||
request |= RequestValue( _requestFlags, EnergyProductionIndex_Today, _instance, _queue );
|
||||
request |= RequestValue( _requestFlags, EnergyProductionIndex_Time, _instance, _queue );
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <EnergyProduction::RequestValue>
|
||||
// Request current production from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool EnergyProduction::RequestValue
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _valueEnum, // one of EnergyProductionIndex enums
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if (_valueEnum > EnergyProductionIndex_Time)
|
||||
{
|
||||
Log::Write (LogLevel_Warning, GetNodeId(), "RequestValue _valueEnum was greater than range. Dropping");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( IsGetSupported() )
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Requesting the %s value", c_energyParameterNames[_valueEnum] );
|
||||
Msg* msg = new Msg( "EnergyProductionCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, _instance );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 3 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( EnergyProductionCmd_Get );
|
||||
msg->Append( _valueEnum );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
return true;
|
||||
} else {
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "EnergyProductionCmd_Get Not Supported on this node");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// <EnergyProduction::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool EnergyProduction::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
if (EnergyProductionCmd_Report == (EnergyProductionCmd)_data[0])
|
||||
{
|
||||
uint8 scale;
|
||||
uint8 precision = 0;
|
||||
string value = ExtractValue( &_data[2], &scale, &precision );
|
||||
uint8 paramType = _data[1];
|
||||
if (paramType > 4) /* size of c_energyParameterNames minus Invalid Entry*/
|
||||
{
|
||||
Log::Write (LogLevel_Warning, GetNodeId(), "paramType Value was greater than range. Dropping Message");
|
||||
return false;
|
||||
}
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received an Energy production report: %s = %s", c_energyParameterNames[_data[1]], value.c_str() );
|
||||
if( ValueDecimal* decimalValue = static_cast<ValueDecimal*>( GetValue( _instance, _data[1] ) ) )
|
||||
{
|
||||
decimalValue->OnValueRefreshed( value );
|
||||
if( decimalValue->GetPrecision() != precision )
|
||||
{
|
||||
decimalValue->SetPrecision( precision );
|
||||
}
|
||||
decimalValue->Release();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <EnergyProduction::CreateVars>
|
||||
// Create the values managed by this command class
|
||||
//-----------------------------------------------------------------------------
|
||||
void EnergyProduction::CreateVars
|
||||
(
|
||||
uint8 const _instance
|
||||
)
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
node->CreateValueDecimal( ValueID::ValueGenre_User, GetCommandClassId(), _instance, (uint8)EnergyProductionIndex_Instant, c_energyParameterNames[EnergyProductionIndex_Instant], "W", true, false, "0.0", 0 );
|
||||
node->CreateValueDecimal( ValueID::ValueGenre_User, GetCommandClassId(), _instance, (uint8)EnergyProductionIndex_Total, c_energyParameterNames[EnergyProductionIndex_Total], "kWh", true, false, "0.0", 0 );
|
||||
node->CreateValueDecimal( ValueID::ValueGenre_User, GetCommandClassId(), _instance, (uint8)EnergyProductionIndex_Today, c_energyParameterNames[EnergyProductionIndex_Today], "kWh", true, false, "0.0", 0 );
|
||||
node->CreateValueDecimal( ValueID::ValueGenre_User, GetCommandClassId(), _instance, (uint8)EnergyProductionIndex_Time, c_energyParameterNames[EnergyProductionIndex_Time], "", true, false, "0.0", 0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// EnergyProduction.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_ENERGY_PRODUCTION
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _EnergyProduction_H
|
||||
#define _EnergyProduction_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class ValueDecimal;
|
||||
|
||||
/** \brief Implements COMMAND_CLASS_ENERGY_PRODUCTION (0x90), a Z-Wave device command class.
|
||||
*/
|
||||
class EnergyProduction: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new EnergyProduction( _homeId, _nodeId ); }
|
||||
virtual ~EnergyProduction(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x90; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_ENERGY_PRODUCTION"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual bool RequestState( uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual bool RequestValue( uint32 const _requestFlags, uint8 const _valueEnum, uint8 const _dummy, Driver::MsgQueue const _queue );
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
|
||||
protected:
|
||||
virtual void CreateVars( uint8 const _instance );
|
||||
|
||||
private:
|
||||
EnergyProduction( uint32 const _homeId, uint8 const _nodeId ): CommandClass( _homeId, _nodeId ){}
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Hail.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_HAIL
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "Hail.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Node.h"
|
||||
#include "../Driver.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum HailCmdEnum
|
||||
{
|
||||
HailCmd_Hail = 1
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Hail::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Hail::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
if( HailCmd_Hail == _data[0] )
|
||||
{
|
||||
// We have received a hail from the Z-Wave device.
|
||||
// Request an update of the dynamic values.
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received Hail command from node %d", GetNodeId() );
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
node->RequestDynamicValues();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Hail.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_HAIL
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _Hail_H
|
||||
#define _Hail_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
/** \brief Implements COMMAND_CLASS_HAIL (0x82), a Z-Wave device command class.
|
||||
*/
|
||||
class Hail: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new Hail( _homeId, _nodeId ); }
|
||||
virtual ~Hail(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x82; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_HAIL"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
|
||||
private:
|
||||
Hail( uint32 const _homeId, uint8 const _nodeId ): CommandClass( _homeId, _nodeId ){}
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Indicator.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_INDICATOR
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "Indicator.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Node.h"
|
||||
#include "../Driver.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
#include "../value_classes/ValueByte.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum IndicatorCmd
|
||||
{
|
||||
IndicatorCmd_Set = 0x01,
|
||||
IndicatorCmd_Get = 0x02,
|
||||
IndicatorCmd_Report = 0x03
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Indicator::RequestState>
|
||||
// Request current state from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Indicator::RequestState
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( _requestFlags & RequestFlag_Dynamic )
|
||||
{
|
||||
return RequestValue( _requestFlags, 0, _instance, _queue );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Indicator::RequestValue>
|
||||
// Request current value from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Indicator::RequestValue
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _dummy1, // = 0 (not used)
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if ( IsGetSupported() )
|
||||
{
|
||||
Msg* msg = new Msg( "IndicatorCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, _instance );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( IndicatorCmd_Get );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
return true;
|
||||
} else {
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "IndicatorCmd_Get Not Supported on this node");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Indicator::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Indicator::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
if( IndicatorCmd_Report == (IndicatorCmd)_data[0] )
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received an Indicator report: Indicator=%d", _data[1] );
|
||||
|
||||
if( ValueByte* value = static_cast<ValueByte*>( GetValue( _instance, 0 ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( _data[1] != 0 );
|
||||
value->Release();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Indicator::SetValue>
|
||||
// Set the device's indicator value
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Indicator::SetValue
|
||||
(
|
||||
Value const& _value
|
||||
)
|
||||
{
|
||||
if( ValueID::ValueType_Byte == _value.GetID().GetType() )
|
||||
{
|
||||
ValueByte const* value = static_cast<ValueByte const*>(&_value);
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Indicator::SetValue - Setting indicator to %d", value->GetValue());
|
||||
Msg* msg = new Msg( "Basic Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true );
|
||||
msg->SetInstance( this, _value.GetID().GetInstance() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 3 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( IndicatorCmd_Set );
|
||||
msg->Append( value->GetValue() );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Indicator::CreateVars>
|
||||
// Create the values managed by this command class
|
||||
//-----------------------------------------------------------------------------
|
||||
void Indicator::CreateVars
|
||||
(
|
||||
uint8 const _instance
|
||||
)
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
node->CreateValueByte( ValueID::ValueGenre_User, GetCommandClassId(), _instance, 0, "Indicator", "", false, false, false, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Indicator.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_INDICATOR
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _Indicator_H
|
||||
#define _Indicator_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class ValueByte;
|
||||
|
||||
/** \brief Implements COMMAND_CLASS_INDICATOR (0x87), a Z-Wave device command class.
|
||||
*/
|
||||
class Indicator: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new Indicator( _homeId, _nodeId ); }
|
||||
virtual ~Indicator(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x87; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_INDICATOR"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual bool RequestState( uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual bool RequestValue( uint32 const _requestFlags, uint8 const _index, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
virtual bool SetValue( Value const& _value );
|
||||
|
||||
protected:
|
||||
virtual void CreateVars( uint8 const _instance );
|
||||
|
||||
private:
|
||||
Indicator( uint32 const _homeId, uint8 const _nodeId ): CommandClass( _homeId, _nodeId ){}
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Language.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_LANGUAGE
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "Language.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Node.h"
|
||||
#include "../Driver.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
#include "../value_classes/ValueString.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum LanguageCmd
|
||||
{
|
||||
LanguageCmd_Set = 0x01,
|
||||
LanguageCmd_Get = 0x02,
|
||||
LanguageCmd_Report = 0x03
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
LanguageIndex_Language = 0,
|
||||
LanguageIndex_Country
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Language::RequestState>
|
||||
// Request current state from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Language::RequestState
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( ( _requestFlags & RequestFlag_Static ) && HasStaticRequest( StaticRequest_Values ) )
|
||||
{
|
||||
return RequestValue( _requestFlags, 0, _instance, _queue );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Language::RequestValue>
|
||||
// Request current value from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Language::RequestValue
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _dummy1, // = 0 (not used)
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( _instance != 1 )
|
||||
{
|
||||
// This command class doesn't work with multiple instances
|
||||
return false;
|
||||
}
|
||||
if ( IsGetSupported() )
|
||||
{
|
||||
Msg* msg = new Msg( "LanguageCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( LanguageCmd_Get );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
return true;
|
||||
} else {
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "LanguageCmd_Get Not Supported on this node");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Language::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Language::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
if( LanguageCmd_Report == (LanguageCmd)_data[0] )
|
||||
{
|
||||
char language[4];
|
||||
char country[3];
|
||||
|
||||
language[0] = _data[1];
|
||||
language[1] = _data[2];
|
||||
language[2] = _data[3];
|
||||
language[3] = 0;
|
||||
|
||||
country[0] = _data[4];
|
||||
country[1] = _data[5];
|
||||
country[2] = 0;
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received Language report: Language=%s, Country=%s", language, country );
|
||||
ClearStaticRequest( StaticRequest_Values );
|
||||
|
||||
if( ValueString* languageValue = static_cast<ValueString*>( GetValue( _instance, LanguageIndex_Language ) ) )
|
||||
{
|
||||
languageValue->OnValueRefreshed( language );
|
||||
languageValue->Release();
|
||||
}
|
||||
if( ValueString* countryValue = static_cast<ValueString*>( GetValue( _instance, LanguageIndex_Country ) ) )
|
||||
{
|
||||
countryValue->OnValueRefreshed( country );
|
||||
countryValue->Release();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Language::CreateVars>
|
||||
// Create the values managed by this command class
|
||||
//-----------------------------------------------------------------------------
|
||||
void Language::CreateVars
|
||||
(
|
||||
uint8 const _instance
|
||||
)
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
node->CreateValueString( ValueID::ValueGenre_System, GetCommandClassId(), _instance, (uint8)LanguageIndex_Language, "Language", "", false, false, "", 0 );
|
||||
node->CreateValueString( ValueID::ValueGenre_System, GetCommandClassId(), _instance, (uint8)LanguageIndex_Country, "Country", "", false, false, "", 0 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Language.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_LANGUAGE
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _Language_H
|
||||
#define _Language_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class ValueString;
|
||||
|
||||
/** \brief Implements COMMAND_CLASS_LANGUAGE (0x89), a Z-Wave device command class.
|
||||
*/
|
||||
class Language: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new Language( _homeId, _nodeId ); }
|
||||
virtual ~Language(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x89; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_LANGUAGE"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual bool RequestState( uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual bool RequestValue( uint32 const _requestFlags, uint8 const _index, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
|
||||
protected:
|
||||
virtual void CreateVars( uint8 const _instance );
|
||||
|
||||
private:
|
||||
Language( uint32 const _homeId, uint8 const _nodeId ): CommandClass( _homeId, _nodeId ){ SetStaticRequest( StaticRequest_Values ); }
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Lock.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_LOCK
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "Lock.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Node.h"
|
||||
#include "../Driver.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
#include "../value_classes/ValueBool.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum LockCmd
|
||||
{
|
||||
LockCmd_Set = 0x01,
|
||||
LockCmd_Get = 0x02,
|
||||
LockCmd_Report = 0x03
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Lock::RequestState>
|
||||
// Request current state from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Lock::RequestState
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( _requestFlags & RequestFlag_Dynamic )
|
||||
{
|
||||
return RequestValue( _requestFlags, 0, _instance, _queue );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Lock::RequestValue>
|
||||
// Request current value from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Lock::RequestValue
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _dummy1, // = 0 (not used)
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if ( IsGetSupported() )
|
||||
{
|
||||
Msg* msg = new Msg( "LockCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, _instance );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( LockCmd_Get );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
return true;
|
||||
} else {
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "LockCmd_Get Not Supported on this node");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Lock::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Lock::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
if( LockCmd_Report == (LockCmd)_data[0] )
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received Lock report: Lock is %s", _data[1] ? "Locked" : "Unlocked" );
|
||||
|
||||
if( ValueBool* value = static_cast<ValueBool*>( GetValue( _instance, 0 ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( _data[1] != 0 );
|
||||
value->Release();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Lock::SetValue>
|
||||
// Set the lock's state
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Lock::SetValue
|
||||
(
|
||||
Value const& _value
|
||||
)
|
||||
{
|
||||
if( ValueID::ValueType_Bool == _value.GetID().GetType() )
|
||||
{
|
||||
ValueBool const* value = static_cast<ValueBool const*>(&_value);
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Lock::Set - Requesting lock to be %s", value->GetValue() ? "Locked" : "Unlocked" );
|
||||
Msg* msg = new Msg( "LockCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true );
|
||||
msg->SetInstance( this, _value.GetID().GetInstance() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 3 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( LockCmd_Set );
|
||||
msg->Append( value->GetValue() ? 0x01:0x00 );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Lock::CreateVars>
|
||||
// Create the values managed by this command class
|
||||
//-----------------------------------------------------------------------------
|
||||
void Lock::CreateVars
|
||||
(
|
||||
uint8 const _instance
|
||||
)
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
node->CreateValueBool( ValueID::ValueGenre_User, GetCommandClassId(), _instance, 0, "Locked", "", false, false, false, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Lock.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_LOCK
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _Lock_H
|
||||
#define _Lock_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class ValueBool;
|
||||
|
||||
/** \brief Implements COMMAND_CLASS_LOCK (0x76), a Z-Wave device command class.
|
||||
*/
|
||||
class Lock: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new Lock( _homeId, _nodeId ); }
|
||||
virtual ~Lock(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x76; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_LOCK"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual bool RequestState( uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual bool RequestValue( uint32 const _requestFlags, uint8 const _index, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
virtual bool SetValue( Value const& _value );
|
||||
|
||||
protected:
|
||||
virtual void CreateVars( uint8 const _instance );
|
||||
|
||||
private:
|
||||
Lock( uint32 const _homeId, uint8 const _nodeId ): CommandClass( _homeId, _nodeId ){}
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,444 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ManufacturerSpecific.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_MANUFACTURER_SPECIFIC
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "ManufacturerSpecific.h"
|
||||
#include "../tinyxml.h"
|
||||
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Node.h"
|
||||
#include "../Options.h"
|
||||
#include "../Manager.h"
|
||||
#include "../Driver.h"
|
||||
#include "../Notification.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
#include "../value_classes/ValueStore.h"
|
||||
#include "../value_classes/ValueString.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum ManufacturerSpecificCmd
|
||||
{
|
||||
ManufacturerSpecificCmd_Get = 0x04,
|
||||
ManufacturerSpecificCmd_Report = 0x05
|
||||
};
|
||||
|
||||
map<uint16,string> ManufacturerSpecific::s_manufacturerMap;
|
||||
map<int64,ManufacturerSpecific::Product*> ManufacturerSpecific::s_productMap;
|
||||
bool ManufacturerSpecific::s_bXmlLoaded = false;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ManufacturerSpecific::RequestState>
|
||||
// Request current state from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ManufacturerSpecific::RequestState
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( ( _requestFlags & RequestFlag_Static ) && HasStaticRequest( StaticRequest_Values ) )
|
||||
{
|
||||
return RequestValue( _requestFlags, 0, _instance, _queue );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ManufacturerSpecific::RequestValue>
|
||||
// Request current value from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ManufacturerSpecific::RequestValue
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _dummy1, // = 0 (not used)
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( _instance != 1 )
|
||||
{
|
||||
// This command class doesn't work with multiple instances
|
||||
return false;
|
||||
}
|
||||
if ( IsGetSupported() )
|
||||
{
|
||||
Msg* msg = new Msg( "ManufacturerSpecificCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( ManufacturerSpecificCmd_Get );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
return true;
|
||||
} else {
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "ManufacturerSpecificCmd_Get Not Supported on this node");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
string ManufacturerSpecific::SetProductDetails
|
||||
(
|
||||
Node* node,
|
||||
uint16 manufacturerId,
|
||||
uint16 productType,
|
||||
uint16 productId
|
||||
)
|
||||
{
|
||||
char str[64];
|
||||
|
||||
if (!s_bXmlLoaded) LoadProductXML();
|
||||
|
||||
snprintf( str, sizeof(str), "Unknown: id=%.4x", manufacturerId );
|
||||
string manufacturerName = str;
|
||||
|
||||
snprintf( str, sizeof(str), "Unknown: type=%.4x, id=%.4x", productType, productId );
|
||||
string productName = str;
|
||||
|
||||
string configPath = "";
|
||||
|
||||
// Try to get the real manufacturer and product names
|
||||
map<uint16,string>::iterator mit = s_manufacturerMap.find( manufacturerId );
|
||||
if( mit != s_manufacturerMap.end() )
|
||||
{
|
||||
// Replace the id with the real name
|
||||
manufacturerName = mit->second;
|
||||
|
||||
// Get the product
|
||||
map<int64,Product*>::iterator pit = s_productMap.find( Product::GetKey( manufacturerId, productType, productId ) );
|
||||
if( pit != s_productMap.end() )
|
||||
{
|
||||
productName = pit->second->GetProductName();
|
||||
configPath = pit->second->GetConfigPath();
|
||||
}
|
||||
}
|
||||
|
||||
// Set the values into the node
|
||||
|
||||
// Only set the manufacturer and product name if they are
|
||||
// empty - we don't want to overwrite any user defined names.
|
||||
if( node->GetManufacturerName() == "" )
|
||||
{
|
||||
node->SetManufacturerName( manufacturerName );
|
||||
}
|
||||
|
||||
if( node->GetProductName() == "" )
|
||||
{
|
||||
node->SetProductName( productName );
|
||||
}
|
||||
|
||||
snprintf( str, sizeof(str), "%.4x", manufacturerId );
|
||||
node->SetManufacturerId( str );
|
||||
|
||||
snprintf( str, sizeof(str), "%.4x", productType );
|
||||
node->SetProductType( str );
|
||||
|
||||
snprintf( str, sizeof(str), "%.4x", productId );
|
||||
node->SetProductId( str );
|
||||
|
||||
return configPath;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ManufacturerSpecific::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ManufacturerSpecific::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
if( ManufacturerSpecificCmd_Report == (ManufacturerSpecificCmd)_data[0] )
|
||||
{
|
||||
|
||||
// first two bytes are manufacturer id code
|
||||
uint16 manufacturerId = (((uint16)_data[1])<<8) | (uint16)_data[2];
|
||||
|
||||
// next four are product type and product id
|
||||
uint16 productType = (((uint16)_data[3])<<8) | (uint16)_data[4];
|
||||
uint16 productId = (((uint16)_data[5])<<8) | (uint16)_data[6];
|
||||
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
// Attempt to create the config parameters
|
||||
string configPath = SetProductDetails( node, manufacturerId, productType, productId);
|
||||
if( configPath.size() > 0 )
|
||||
{
|
||||
LoadConfigXML( node, configPath );
|
||||
}
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received manufacturer specific report from node %d: Manufacturer=%s, Product=%s",
|
||||
GetNodeId(), node->GetManufacturerName().c_str(), node->GetProductName().c_str() );
|
||||
ClearStaticRequest( StaticRequest_Values );
|
||||
node->m_manufacturerSpecificClassReceived = true;
|
||||
}
|
||||
|
||||
// Notify the watchers of the name changes
|
||||
Notification* notification = new Notification( Notification::Type_NodeNaming );
|
||||
notification->SetHomeAndNodeIds( GetHomeId(), GetNodeId() );
|
||||
GetDriver()->QueueNotification( notification );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ManufacturerSpecific::LoadProductXML>
|
||||
// Load the XML that maps manufacturer and product IDs to human-readable names
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ManufacturerSpecific::LoadProductXML
|
||||
(
|
||||
)
|
||||
{
|
||||
s_bXmlLoaded = true;
|
||||
|
||||
// Parse the Z-Wave manufacturer and product XML file.
|
||||
string configPath;
|
||||
Options::Get()->GetOptionAsString( "ConfigPath", &configPath );
|
||||
|
||||
string filename = configPath + "manufacturer_specific.xml";
|
||||
|
||||
TiXmlDocument* pDoc = new TiXmlDocument();
|
||||
if( !pDoc->LoadFile( filename.c_str(), TIXML_ENCODING_UTF8 ) )
|
||||
{
|
||||
delete pDoc;
|
||||
Log::Write( LogLevel_Info, "Unable to load %s", filename.c_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
TiXmlElement const* root = pDoc->RootElement();
|
||||
|
||||
char const* str;
|
||||
char* pStopChar;
|
||||
|
||||
TiXmlElement const* manufacturerElement = root->FirstChildElement();
|
||||
while( manufacturerElement )
|
||||
{
|
||||
str = manufacturerElement->Value();
|
||||
if( str && !strcmp( str, "Manufacturer" ) )
|
||||
{
|
||||
// Read in the manufacturer attributes
|
||||
str = manufacturerElement->Attribute( "id" );
|
||||
if( !str )
|
||||
{
|
||||
Log::Write( LogLevel_Info, "Error in manufacturer_specific.xml at line %d - missing manufacturer id attribute", manufacturerElement->Row() );
|
||||
delete pDoc;
|
||||
return false;
|
||||
}
|
||||
uint16 manufacturerId = (uint16)strtol( str, &pStopChar, 16 );
|
||||
|
||||
str = manufacturerElement->Attribute( "name" );
|
||||
if( !str )
|
||||
{
|
||||
Log::Write( LogLevel_Info, "Error in manufacturer_specific.xml at line %d - missing manufacturer name attribute", manufacturerElement->Row() );
|
||||
delete pDoc;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add this manufacturer to the map
|
||||
s_manufacturerMap[manufacturerId] = str;
|
||||
|
||||
// Parse all the products for this manufacturer
|
||||
TiXmlElement const* productElement = manufacturerElement->FirstChildElement();
|
||||
while( productElement )
|
||||
{
|
||||
str = productElement->Value();
|
||||
if( str && !strcmp( str, "Product" ) )
|
||||
{
|
||||
str = productElement->Attribute( "type" );
|
||||
if( !str )
|
||||
{
|
||||
Log::Write( LogLevel_Info, "Error in manufacturer_specific.xml at line %d - missing product type attribute", productElement->Row() );
|
||||
delete pDoc;
|
||||
return false;
|
||||
}
|
||||
uint16 productType = (uint16)strtol( str, &pStopChar, 16 );
|
||||
|
||||
str = productElement->Attribute( "id" );
|
||||
if( !str )
|
||||
{
|
||||
Log::Write( LogLevel_Info, "Error in manufacturer_specific.xml at line %d - missing product id attribute", productElement->Row() );
|
||||
delete pDoc;
|
||||
return false;
|
||||
}
|
||||
uint16 productId = (uint16)strtol( str, &pStopChar, 16 );
|
||||
|
||||
str = productElement->Attribute( "name" );
|
||||
if( !str )
|
||||
{
|
||||
Log::Write( LogLevel_Info, "Error in manufacturer_specific.xml at line %d - missing product name attribute", productElement->Row() );
|
||||
delete pDoc;
|
||||
return false;
|
||||
}
|
||||
string productName = str;
|
||||
|
||||
// Optional config path
|
||||
string configPath;
|
||||
str = productElement->Attribute( "config" );
|
||||
if( str )
|
||||
{
|
||||
configPath = str;
|
||||
}
|
||||
|
||||
// Add the product to the map
|
||||
Product* product = new Product( manufacturerId, productType, productId, productName, configPath );
|
||||
if ( s_productMap[product->GetKey()] != NULL )
|
||||
{
|
||||
Product *c = s_productMap[product->GetKey()];
|
||||
Log::Write( LogLevel_Info, "Product name collision: %s type %x id %x manufacturerid %x, collides with %s, type %x id %x manufacturerid %x", productName.c_str(), productType, productId, manufacturerId, c->GetProductName().c_str(), c->GetProductType(), c->GetProductId(), c->GetManufacturerId());
|
||||
delete product;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_productMap[product->GetKey()] = product;
|
||||
}
|
||||
}
|
||||
|
||||
// Move on to the next product.
|
||||
productElement = productElement->NextSiblingElement();
|
||||
}
|
||||
}
|
||||
|
||||
// Move on to the next manufacturer.
|
||||
manufacturerElement = manufacturerElement->NextSiblingElement();
|
||||
}
|
||||
|
||||
delete pDoc;
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ManufacturerSpecific::UnloadProductXML>
|
||||
// Free the XML that maps manufacturer and product IDs
|
||||
//-----------------------------------------------------------------------------
|
||||
void ManufacturerSpecific::UnloadProductXML
|
||||
(
|
||||
)
|
||||
{
|
||||
if (s_bXmlLoaded)
|
||||
{
|
||||
map<int64,Product*>::iterator pit = s_productMap.begin();
|
||||
while( !s_productMap.empty() )
|
||||
{
|
||||
delete pit->second;
|
||||
s_productMap.erase( pit );
|
||||
pit = s_productMap.begin();
|
||||
}
|
||||
|
||||
map<uint16,string>::iterator mit = s_manufacturerMap.begin();
|
||||
while( !s_manufacturerMap.empty() )
|
||||
{
|
||||
s_manufacturerMap.erase( mit );
|
||||
mit = s_manufacturerMap.begin();
|
||||
}
|
||||
|
||||
s_bXmlLoaded = false;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ManufacturerSpecific::LoadConfigXML>
|
||||
// Try to find and load an XML file describing the device's config params
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ManufacturerSpecific::LoadConfigXML
|
||||
(
|
||||
Node* _node,
|
||||
string const& _configXML
|
||||
)
|
||||
{
|
||||
string configPath;
|
||||
Options::Get()->GetOptionAsString( "ConfigPath", &configPath );
|
||||
|
||||
string filename = configPath + _configXML;
|
||||
|
||||
TiXmlDocument* doc = new TiXmlDocument();
|
||||
Log::Write( LogLevel_Info, _node->GetNodeId(), " Opening config param file %s", filename.c_str() );
|
||||
if( !doc->LoadFile( filename.c_str(), TIXML_ENCODING_UTF8 ) )
|
||||
{
|
||||
delete doc;
|
||||
Log::Write( LogLevel_Info, _node->GetNodeId(), "Unable to find or load Config Param file %s", filename.c_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
Node::QueryStage qs = _node->GetCurrentQueryStage();
|
||||
if( qs == Node::QueryStage_ManufacturerSpecific1 )
|
||||
{
|
||||
_node->ReadDeviceProtocolXML( doc->RootElement() );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !_node->m_manufacturerSpecificClassReceived )
|
||||
{
|
||||
_node->ReadDeviceProtocolXML( doc->RootElement() );
|
||||
}
|
||||
_node->ReadCommandClassesXML( doc->RootElement() );
|
||||
}
|
||||
|
||||
delete doc;
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <ManufacturerSpecific::ReLoadConfigXML>
|
||||
// Reload previously discovered device configuration.
|
||||
//-----------------------------------------------------------------------------
|
||||
void ManufacturerSpecific::ReLoadConfigXML
|
||||
(
|
||||
)
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
if (!s_bXmlLoaded) LoadProductXML();
|
||||
|
||||
uint16 manufacturerId = (uint16)strtol( node->GetManufacturerId().c_str(), NULL, 16 );
|
||||
uint16 productType = (uint16)strtol( node->GetProductType().c_str(), NULL, 16 );
|
||||
uint16 productId = (uint16)strtol( node->GetProductId().c_str(), NULL, 16 );
|
||||
|
||||
map<uint16,string>::iterator mit = s_manufacturerMap.find( manufacturerId );
|
||||
if( mit != s_manufacturerMap.end() )
|
||||
{
|
||||
map<int64,Product*>::iterator pit = s_productMap.find( Product::GetKey( manufacturerId, productType, productId ) );
|
||||
if( pit != s_productMap.end() )
|
||||
{
|
||||
string configPath = pit->second->GetConfigPath();
|
||||
if( configPath.size() > 0 )
|
||||
{
|
||||
LoadConfigXML( node, configPath );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ManufacturerSpecific.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_MANUFACTURER_SPECIFIC
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _ManufacturerSpecific_H
|
||||
#define _ManufacturerSpecific_H
|
||||
|
||||
#include <map>
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
/** \brief Implements COMMAND_CLASS_MANUFACTURER_SPECIFIC (0x72), a Z-Wave device command class.
|
||||
*/
|
||||
class ManufacturerSpecific: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new ManufacturerSpecific( _homeId, _nodeId ); }
|
||||
virtual ~ManufacturerSpecific(){ UnloadProductXML(); }
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x72; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_MANUFACTURER_SPECIFIC"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual bool RequestState( uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual bool RequestValue( uint32 const _requestFlags, uint8 const _index, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
|
||||
static string SetProductDetails( Node *_node, uint16 _manufacturerId, uint16 _productType, uint16 _productId );
|
||||
static bool LoadConfigXML( Node* _node, string const& _configXML );
|
||||
|
||||
void ReLoadConfigXML();
|
||||
|
||||
private:
|
||||
ManufacturerSpecific( uint32 const _homeId, uint8 const _nodeId ): CommandClass( _homeId, _nodeId ){ SetStaticRequest( StaticRequest_Values ); }
|
||||
static bool LoadProductXML();
|
||||
static void UnloadProductXML();
|
||||
|
||||
class Product
|
||||
{
|
||||
public:
|
||||
Product
|
||||
(
|
||||
uint16 _manufacturerId,
|
||||
uint16 _productType,
|
||||
uint16 _productId,
|
||||
string const& _productName,
|
||||
string const& _configPath
|
||||
):
|
||||
m_manufacturerId( _manufacturerId ),
|
||||
m_productType( _productType ),
|
||||
m_productId( _productId ),
|
||||
m_productName( _productName ),
|
||||
m_configPath( _configPath )
|
||||
{
|
||||
}
|
||||
|
||||
int64 GetKey()const
|
||||
{
|
||||
return( GetKey( m_manufacturerId, m_productType, m_productId ) );
|
||||
}
|
||||
|
||||
static int64 GetKey( uint16 _manufacturerId, uint16 _productType, uint16 _productId )
|
||||
{
|
||||
int64 key = (((int64)_manufacturerId)<<32) | (((int64)_productType)<<16) | (int64)_productId;
|
||||
return key;
|
||||
}
|
||||
|
||||
uint16 GetManufacturerId()const{ return m_manufacturerId; }
|
||||
uint16 GetProductType()const{ return m_productType; }
|
||||
uint16 GetProductId()const{ return m_productId; }
|
||||
string GetProductName()const{ return m_productName; }
|
||||
string GetConfigPath()const{ return m_configPath; }
|
||||
|
||||
private:
|
||||
uint16 m_manufacturerId;
|
||||
uint16 m_productType;
|
||||
uint16 m_productId;
|
||||
string m_productName;
|
||||
string m_configPath;
|
||||
};
|
||||
|
||||
static map<uint16,string> s_manufacturerMap;
|
||||
static map<int64,Product*> s_productMap;
|
||||
static bool s_bXmlLoaded;
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,562 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Meter.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_METER
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "Meter.h"
|
||||
#include "MultiInstance.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Bitfield.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Node.h"
|
||||
#include "../Driver.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
#include "../value_classes/ValueDecimal.h"
|
||||
#include "../value_classes/ValueList.h"
|
||||
#include "../value_classes/ValueButton.h"
|
||||
#include "../value_classes/ValueInt.h"
|
||||
#include "../value_classes/ValueBool.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum MeterCmd
|
||||
{
|
||||
MeterCmd_Get = 0x01,
|
||||
MeterCmd_Report = 0x02,
|
||||
// Version 2
|
||||
MeterCmd_SupportedGet = 0x03,
|
||||
MeterCmd_SupportedReport = 0x04,
|
||||
MeterCmd_Reset = 0x05
|
||||
};
|
||||
|
||||
enum MeterType
|
||||
{
|
||||
MeterType_Electric = 1,
|
||||
MeterType_Gas,
|
||||
MeterType_Water
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
MeterIndex_Exporting = 32,
|
||||
MeterIndex_Reset
|
||||
};
|
||||
|
||||
|
||||
static char const* c_meterTypes[] =
|
||||
{
|
||||
"Unknown",
|
||||
"Electric",
|
||||
"Gas",
|
||||
"Water"
|
||||
};
|
||||
|
||||
static char const* c_electricityUnits[] =
|
||||
{
|
||||
"kWh",
|
||||
"kVAh",
|
||||
"W",
|
||||
"pulses",
|
||||
"V",
|
||||
"A",
|
||||
"Power Factor",
|
||||
""
|
||||
};
|
||||
|
||||
static char const* c_gasUnits[] =
|
||||
{
|
||||
"cubic meters",
|
||||
"cubic feet",
|
||||
"",
|
||||
"pulses",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
""
|
||||
};
|
||||
|
||||
static char const* c_waterUnits[] =
|
||||
{
|
||||
"cubic meters",
|
||||
"cubic feet",
|
||||
"US gallons",
|
||||
"pulses",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
""
|
||||
};
|
||||
|
||||
static char const* c_electricityLabels[] =
|
||||
{
|
||||
"Energy",
|
||||
"Energy",
|
||||
"Power",
|
||||
"Count",
|
||||
"Voltage",
|
||||
"Current",
|
||||
"Power Factor",
|
||||
"Unknown"
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Meter::Meter>
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
Meter::Meter
|
||||
(
|
||||
uint32 const _homeId,
|
||||
uint8 const _nodeId
|
||||
):
|
||||
CommandClass( _homeId, _nodeId )
|
||||
{
|
||||
SetStaticRequest( StaticRequest_Values );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Meter::RequestState>
|
||||
// Request current state from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Meter::RequestState
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
bool res = false;
|
||||
if( GetVersion() > 1 )
|
||||
{
|
||||
if( _requestFlags & RequestFlag_Static )
|
||||
{
|
||||
Msg* msg = new Msg( "MeterCmd_SupportedGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, _instance );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( MeterCmd_SupportedGet );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
res = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( _requestFlags & RequestFlag_Dynamic )
|
||||
{
|
||||
res |= RequestValue( _requestFlags, 0, _instance, _queue );
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Meter::RequestValue>
|
||||
// Request current value from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Meter::RequestValue
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _dummy1, // = 0 (not used)
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
bool res = false;
|
||||
if ( !IsGetSupported())
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "MeterCmd_Get Not Supported on this node");
|
||||
return false;
|
||||
}
|
||||
for( uint8 i=0; i<8; ++i )
|
||||
{
|
||||
uint8 baseIndex = i<<2;
|
||||
|
||||
Value* value = GetValue( _instance, baseIndex );
|
||||
if( value != NULL )
|
||||
{
|
||||
value->Release();
|
||||
Msg* msg = new Msg( "MeterCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, _instance );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 3 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( MeterCmd_Get );
|
||||
msg->Append( (uint8)( i << 3 ) );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
res |= true;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Meter::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Meter::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
bool handled = false;
|
||||
if (MeterCmd_SupportedReport == (MeterCmd)_data[0])
|
||||
{
|
||||
handled = HandleSupportedReport( _data, _length, _instance );
|
||||
}
|
||||
else if (MeterCmd_Report == (MeterCmd)_data[0])
|
||||
{
|
||||
handled = HandleReport( _data, _length, _instance );
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Meter::HandleSupportedReport>
|
||||
// Create the values for this command class based on the reported parameters
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Meter::HandleSupportedReport
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance
|
||||
)
|
||||
{
|
||||
bool canReset = ((_data[1] & 0x80) != 0);
|
||||
int8 meterType = (MeterType)(_data[1] & 0x1f);
|
||||
if (meterType > 4) /* size of c_meterTypes */
|
||||
{
|
||||
Log::Write (LogLevel_Warning, GetNodeId(), "meterType Value was greater than range. Dropping Message");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
ClearStaticRequest( StaticRequest_Version );
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
string msg;
|
||||
msg = c_meterTypes[meterType];
|
||||
msg += ": ";
|
||||
// Create the list of supported scales
|
||||
uint8 scaleSupported = _data[2];
|
||||
if( GetVersion() == 2 )
|
||||
{
|
||||
// Only four scales are allowed in version 2
|
||||
scaleSupported &= 0x0f;
|
||||
}
|
||||
|
||||
for( uint8 i=0; i<8; ++i )
|
||||
{
|
||||
if( scaleSupported & (1<<i) )
|
||||
{
|
||||
uint8 baseIndex = i<<2; // We leave space between the value indices to insert previous and time delta values if we need to later on.
|
||||
switch( meterType )
|
||||
{
|
||||
case MeterType_Electric:
|
||||
{
|
||||
if( ValueDecimal* value = static_cast<ValueDecimal*>( GetValue( _instance, baseIndex ) ) )
|
||||
{
|
||||
value->SetLabel( c_electricityLabels[i] );
|
||||
value->SetUnits( c_electricityUnits[i] );
|
||||
value->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
node->CreateValueDecimal( ValueID::ValueGenre_User, GetCommandClassId(), _instance, baseIndex, c_electricityLabels[i], c_electricityUnits[i], true, false, "0.0", 0 );
|
||||
}
|
||||
if( i != 0 )
|
||||
msg += ", ";
|
||||
msg += c_electricityUnits[i];
|
||||
break;
|
||||
}
|
||||
case MeterType_Gas:
|
||||
{
|
||||
if( ValueDecimal* value = static_cast<ValueDecimal*>( GetValue( _instance, baseIndex ) ) )
|
||||
{
|
||||
value->SetLabel( c_meterTypes[MeterType_Gas] );
|
||||
value->SetUnits( c_gasUnits[i] );
|
||||
value->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
node->CreateValueDecimal( ValueID::ValueGenre_User, GetCommandClassId(), _instance, baseIndex, c_meterTypes[meterType], c_gasUnits[i], true, false, "0.0", 0 );
|
||||
}
|
||||
if( i != 0 )
|
||||
msg += ", ";
|
||||
msg += c_gasUnits[i];
|
||||
break;
|
||||
}
|
||||
case MeterType_Water:
|
||||
{
|
||||
if( ValueDecimal* value = static_cast<ValueDecimal*>( GetValue( _instance, baseIndex ) ) )
|
||||
{
|
||||
value->SetLabel( c_meterTypes[MeterType_Water] );
|
||||
value->SetUnits( c_waterUnits[i] );
|
||||
value->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
node->CreateValueDecimal( ValueID::ValueGenre_User, GetCommandClassId(), _instance, baseIndex, c_meterTypes[meterType], c_waterUnits[i], true, false, "0.0", 0 );
|
||||
}
|
||||
if( i != 0 )
|
||||
msg += ", ";
|
||||
msg += c_waterUnits[i];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the export flag
|
||||
node->CreateValueBool( ValueID::ValueGenre_User, GetCommandClassId(), _instance, MeterIndex_Exporting, "Exporting", "", true, false, false, 0 );
|
||||
|
||||
// Create the reset button
|
||||
if( canReset )
|
||||
{
|
||||
node->CreateValueButton( ValueID::ValueGenre_System, GetCommandClassId(), _instance, MeterIndex_Reset, "Reset", 0 );
|
||||
}
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received Meter supported report from node %d, %s", GetNodeId(), msg.c_str() );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Meter::HandleReport>
|
||||
// Read the reported meter value
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Meter::HandleReport
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance
|
||||
)
|
||||
{
|
||||
// Import or Export (only valid in version > 1)
|
||||
bool exporting = false;
|
||||
if( GetVersion() > 1 )
|
||||
{
|
||||
exporting = ((_data[1] & 0x60) == 0x40 );
|
||||
if( ValueBool* value = static_cast<ValueBool*>( GetValue( _instance, MeterIndex_Exporting ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( exporting );
|
||||
value->Release();
|
||||
}
|
||||
}
|
||||
|
||||
// Get the value and scale
|
||||
uint8 scale;
|
||||
uint8 precision = 0;
|
||||
string valueStr = ExtractValue( &_data[2], &scale, &precision );
|
||||
|
||||
if (scale > 7) /* size of c_electricityLabels, c_electricityUnits, c_gasUnits, c_waterUnits */
|
||||
{
|
||||
Log::Write (LogLevel_Warning, GetNodeId(), "Scale was greater than range. Setting to Invalid");
|
||||
scale = 7;
|
||||
}
|
||||
|
||||
|
||||
if( GetVersion() == 1 )
|
||||
{
|
||||
// In version 1, we don't know the scale until we get the first value report
|
||||
string label;
|
||||
string units;
|
||||
int8 meterType = (MeterType)(_data[1] & 0x1f);
|
||||
if (meterType > 4) /* size of c_meterTypes */
|
||||
{
|
||||
Log::Write (LogLevel_Warning, GetNodeId(), "meterType Value was greater than range. Dropping Message");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch( (MeterType)(_data[1] & 0x1f) )
|
||||
{
|
||||
case MeterType_Electric:
|
||||
{
|
||||
// Electricity Meter
|
||||
label = c_electricityLabels[scale];
|
||||
units = c_electricityUnits[scale];
|
||||
break;
|
||||
}
|
||||
case MeterType_Gas:
|
||||
{
|
||||
// Gas Meter
|
||||
label = c_meterTypes[MeterType_Gas];
|
||||
units = c_gasUnits[scale];
|
||||
break;
|
||||
}
|
||||
case MeterType_Water:
|
||||
{
|
||||
// Water Meter
|
||||
label = c_meterTypes[MeterType_Water];
|
||||
units = c_waterUnits[scale];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( ValueDecimal* value = static_cast<ValueDecimal*>( GetValue( _instance, 0 ) ) )
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received Meter report from node %d: %s=%s%s", GetNodeId(), label.c_str(), valueStr.c_str(), units.c_str() );
|
||||
value->SetLabel( label );
|
||||
value->SetUnits( units );
|
||||
value->OnValueRefreshed( valueStr );
|
||||
if( value->GetPrecision() != precision )
|
||||
{
|
||||
value->SetPrecision( precision );
|
||||
}
|
||||
value->Release();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Version 2 and above
|
||||
uint8 baseIndex = scale << 2;
|
||||
if( GetVersion() > 2 )
|
||||
{
|
||||
// In version 3, an extra scale bit is stored in the meter type byte.
|
||||
scale |= ((_data[1]&0x80)>>5);
|
||||
baseIndex = scale << 2;
|
||||
}
|
||||
|
||||
if( ValueDecimal* value = static_cast<ValueDecimal*>( GetValue( _instance, baseIndex ) ) )
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received Meter report from node %d: %s%s=%s%s", GetNodeId(), exporting ? "Exporting ": "", value->GetLabel().c_str(), valueStr.c_str(), value->GetUnits().c_str() );
|
||||
value->OnValueRefreshed( valueStr );
|
||||
if( value->GetPrecision() != precision )
|
||||
{
|
||||
value->SetPrecision( precision );
|
||||
}
|
||||
value->Release();
|
||||
|
||||
// Read any previous value and time delta
|
||||
uint8 size = _data[2] & 0x07;
|
||||
uint16 delta = (uint16)( (_data[3+size]<<8) | _data[4+size]);
|
||||
|
||||
if( delta )
|
||||
{
|
||||
// There is only a previous value if the time delta is non-zero
|
||||
ValueDecimal* previous = static_cast<ValueDecimal*>( GetValue( _instance, baseIndex+1 ) );
|
||||
if( NULL == previous )
|
||||
{
|
||||
// We need to create a value to hold the previous
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
node->CreateValueDecimal( ValueID::ValueGenre_User, GetCommandClassId(), _instance, baseIndex+1, "Previous Reading", value->GetUnits().c_str(), true, false, "0.0", 0 );
|
||||
previous = static_cast<ValueDecimal*>( GetValue( _instance, baseIndex+1 ) );
|
||||
}
|
||||
}
|
||||
if( previous )
|
||||
{
|
||||
precision = 0;
|
||||
valueStr = ExtractValue( &_data[2], &scale, &precision, 3+size );
|
||||
Log::Write( LogLevel_Info, GetNodeId(), " Previous value was %s%s, received %d seconds ago.", valueStr.c_str(), previous->GetUnits().c_str(), delta );
|
||||
previous->OnValueRefreshed( valueStr );
|
||||
if( previous->GetPrecision() != precision )
|
||||
{
|
||||
previous->SetPrecision( precision );
|
||||
}
|
||||
previous->Release();
|
||||
}
|
||||
|
||||
// Time delta
|
||||
ValueInt* interval = static_cast<ValueInt*>( GetValue( _instance, baseIndex+2 ) );
|
||||
if( NULL == interval )
|
||||
{
|
||||
// We need to create a value to hold the time delta
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
node->CreateValueInt( ValueID::ValueGenre_User, GetCommandClassId(), _instance, baseIndex+2, "Interval", "seconds", true, false, 0, 0 );
|
||||
interval = static_cast<ValueInt*>( GetValue( _instance, baseIndex+2 ) );
|
||||
}
|
||||
}
|
||||
if( interval )
|
||||
{
|
||||
interval->OnValueRefreshed( (int32)delta );
|
||||
interval->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Meter::SetValue>
|
||||
// Set the device's scale, or reset its accumulated values.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Meter::SetValue
|
||||
(
|
||||
Value const& _value
|
||||
)
|
||||
{
|
||||
if( MeterIndex_Reset == _value.GetID().GetIndex() )
|
||||
{
|
||||
ValueButton const* button = static_cast<ValueButton const*>(&_value);
|
||||
if( button->IsPressed() )
|
||||
{
|
||||
Msg* msg = new Msg( "MeterCmd_Reset", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true );
|
||||
msg->SetInstance( this, _value.GetID().GetInstance() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( MeterCmd_Reset );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Meter::CreateVars>
|
||||
// Create the values managed by this command class
|
||||
//-----------------------------------------------------------------------------
|
||||
void Meter::CreateVars
|
||||
(
|
||||
uint8 const _instance
|
||||
)
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
node->CreateValueDecimal( ValueID::ValueGenre_User, GetCommandClassId(), _instance, 0, "Unknown", "", true, false, "0.0", 0 );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Meter.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_METER
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _Meter_H
|
||||
#define _Meter_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class ValueDecimal;
|
||||
|
||||
/** \brief Implements COMMAND_CLASS_METER (0x32), a Z-Wave device command class.
|
||||
*/
|
||||
class Meter: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new Meter( _homeId, _nodeId ); }
|
||||
virtual ~Meter(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x32; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_METER"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual bool RequestState( uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual bool RequestValue( uint32 const _requestFlags, uint8 const _index, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
virtual bool SetValue( Value const& _value );
|
||||
virtual uint8 GetMaxVersion(){ return 3; }
|
||||
|
||||
protected:
|
||||
virtual void CreateVars( uint8 const _instance );
|
||||
|
||||
private:
|
||||
Meter( uint32 const _homeId, uint8 const _nodeId );
|
||||
|
||||
bool HandleSupportedReport( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
bool HandleReport( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// MeterPulse.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_METER_PULSE
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "MeterPulse.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Node.h"
|
||||
#include "../Driver.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
#include "../value_classes/ValueInt.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum MeterPulseCmd
|
||||
{
|
||||
MeterPulseCmd_Get = 0x04,
|
||||
MeterPulseCmd_Report = 0x05
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <MeterPulse::RequestState>
|
||||
// Request current state from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool MeterPulse::RequestState
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( _requestFlags & RequestFlag_Dynamic )
|
||||
{
|
||||
return RequestValue( _requestFlags, 0, _instance, _queue );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <MeterPulse::RequestValue>
|
||||
// Request current value from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool MeterPulse::RequestValue
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _dummy1, // = 0 (not used)
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if ( IsGetSupported() )
|
||||
{
|
||||
Msg* msg = new Msg( "MeterPulseCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, _instance );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( MeterPulseCmd_Get );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
return true;
|
||||
} else {
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "MeterPulseCmd_Get Not Supported on this node");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <MeterPulse::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool MeterPulse::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
if( MeterPulseCmd_Report == (MeterPulseCmd)_data[0] )
|
||||
{
|
||||
int32 count = 0;
|
||||
for( uint8 i=0; i<4; ++i )
|
||||
{
|
||||
count <<= 8;
|
||||
count |= (uint32)_data[i+1];
|
||||
}
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received a meter pulse count: Count=%d", count );
|
||||
if( ValueInt* value = static_cast<ValueInt*>( GetValue( _instance, 0 ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( count );
|
||||
value->Release();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <MeterPulse::CreateVars>
|
||||
// Create the values managed by this command class
|
||||
//-----------------------------------------------------------------------------
|
||||
void MeterPulse::CreateVars
|
||||
(
|
||||
uint8 const _instance
|
||||
)
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
node->CreateValueInt( ValueID::ValueGenre_User, GetCommandClassId(), _instance, 0, "Count", "", true, false, 0, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// MeterPulse.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_METER_PULSE
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _MeterPulse_H
|
||||
#define _MeterPulse_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class ValueInt;
|
||||
|
||||
/** \brief Implements COMMAND_CLASS_METER_PULSE (0x35), a Z-Wave device command class.
|
||||
*/
|
||||
class MeterPulse: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new MeterPulse( _homeId, _nodeId ); }
|
||||
virtual ~MeterPulse(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x35; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_METER_PULSE"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual bool RequestState( uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual bool RequestValue( uint32 const _requestFlags, uint8 const _index, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
|
||||
protected:
|
||||
virtual void CreateVars( uint8 const _instance );
|
||||
|
||||
private:
|
||||
MeterPulse( uint32 const _homeId, uint8 const _nodeId ): CommandClass( _homeId, _nodeId ){}
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// MultiCmd.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_MULTI_CMD
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "MultiCmd.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Node.h"
|
||||
#include "../Driver.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <MultiCmd::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool MultiCmd::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
if( MultiCmdCmd_Encap == (MultiCmdCmd)_data[0] )
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received encapsulated multi-command from node %d", GetNodeId() );
|
||||
|
||||
if( Node const* node = GetNodeUnsafe() )
|
||||
{
|
||||
// Iterate over commands
|
||||
uint8 base = 2;
|
||||
for( uint8 i=0; i<_data[1]; ++i )
|
||||
{
|
||||
uint8 length = _data[base];
|
||||
uint8 commandClassId = _data[base+1];
|
||||
|
||||
if( CommandClass* pCommandClass = node->GetCommandClass( commandClassId ) )
|
||||
{
|
||||
pCommandClass->HandleMsg( &_data[base+2], length-1 );
|
||||
}
|
||||
|
||||
base += (length + 1);
|
||||
}
|
||||
}
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "End of encapsulated multi-command from node %d", GetNodeId() );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// MultiCmd.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_MULTI_CMD
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _MultiCmd_H
|
||||
#define _MultiCmd_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
/** \brief Implements COMMAND_CLASS_MULTI_CMD (0x8f), a Z-Wave device command class.
|
||||
*/
|
||||
class MultiCmd: public CommandClass
|
||||
{
|
||||
public:
|
||||
enum MultiCmdCmd
|
||||
{
|
||||
MultiCmdCmd_Encap = 0x01
|
||||
};
|
||||
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new MultiCmd( _homeId, _nodeId ); }
|
||||
virtual ~MultiCmd(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x8f; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_MULTI_CMD"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
|
||||
private:
|
||||
MultiCmd( uint32 const _homeId, uint8 const _nodeId ): CommandClass( _homeId, _nodeId ){}
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,676 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// MultiInstance.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_MULTI_INSTANCE
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "../tinyxml.h"
|
||||
#include "CommandClasses.h"
|
||||
#include "Basic.h"
|
||||
#include "MultiInstance.h"
|
||||
#include "NoOperation.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Driver.h"
|
||||
#include "../Node.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
// Reduced set of Generic Device classes sorted to reduce
|
||||
// the likely number of calls to MultiChannelCmd_EndPointFind.
|
||||
uint8 const c_genericClass[] =
|
||||
{
|
||||
0x21, // Multilevel Sensor
|
||||
0x20, // Binary Sensor
|
||||
0x31, // Meter
|
||||
0x08, // Thermostat
|
||||
0x11, // Multilevel Switch
|
||||
0x10, // Binary Switch
|
||||
0x12, // Remote Switch
|
||||
0xa1, // Alarm Sensor
|
||||
0x16, // Ventilation
|
||||
0x30, // Pulse Meter
|
||||
0x40, // Entry Control
|
||||
0x13, // Toggle Switch
|
||||
0x03, // AV Control Point
|
||||
0x04, // Display
|
||||
0x00 // End of list
|
||||
};
|
||||
|
||||
char const* c_genericClassName[] =
|
||||
{
|
||||
"Multilevel Sensor",
|
||||
"Binary Sensor",
|
||||
"Meter",
|
||||
"Thermostat",
|
||||
"Multilevel Switch",
|
||||
"Binary Switch",
|
||||
"Remote Switch",
|
||||
"Alarm Sensor",
|
||||
"Ventilation",
|
||||
"Pulse Meter",
|
||||
"Entry Control",
|
||||
"Toggle Switch",
|
||||
"AV Control Point",
|
||||
"Display",
|
||||
"Unknown"
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <MultiInstance::MultiInstance>
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
MultiInstance::MultiInstance
|
||||
(
|
||||
uint32 const _homeId,
|
||||
uint8 const _nodeId
|
||||
):
|
||||
CommandClass( _homeId, _nodeId ),
|
||||
m_numEndPoints( 0 ),
|
||||
m_numEndPointsHint( 0 ),
|
||||
m_endPointMap( MultiInstanceMapAll ),
|
||||
m_endPointFindSupported( false )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <MultiInstance::ReadXML>
|
||||
// Class specific configuration
|
||||
//-----------------------------------------------------------------------------
|
||||
void MultiInstance::ReadXML
|
||||
(
|
||||
TiXmlElement const* _ccElement
|
||||
)
|
||||
{
|
||||
int32 intVal;
|
||||
char const* str;
|
||||
|
||||
CommandClass::ReadXML( _ccElement );
|
||||
|
||||
if( TIXML_SUCCESS == _ccElement->QueryIntAttribute( "endpoints", &intVal ) )
|
||||
{
|
||||
m_numEndPointsHint = (uint8)intVal;
|
||||
}
|
||||
|
||||
str = _ccElement->Attribute("mapping");
|
||||
if( str )
|
||||
{
|
||||
if( strcmp( str, "all") == 0 )
|
||||
{
|
||||
m_endPointMap = MultiInstanceMapAll;
|
||||
}
|
||||
else if( strcmp( str, "endpoints") == 0 )
|
||||
{
|
||||
m_endPointMap = MultiInstanceMapEndPoints;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Bad value for mapping: %s", str);
|
||||
}
|
||||
}
|
||||
|
||||
str = _ccElement->Attribute("findsupport");
|
||||
if( str )
|
||||
{
|
||||
m_endPointFindSupported = !strcmp( str, "true");
|
||||
}
|
||||
str = _ccElement->Attribute("ignoreUnsolicitedMultiChnCapReport");
|
||||
if( str )
|
||||
{
|
||||
m_ignoreUnsolicitedMultiChannelCapabilityReport = !strcmp( str, "true");
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <MultiInstance::WriteXML>
|
||||
// Class specific configuration
|
||||
//-----------------------------------------------------------------------------
|
||||
void MultiInstance::WriteXML
|
||||
(
|
||||
TiXmlElement* _ccElement
|
||||
)
|
||||
{
|
||||
char str[32];
|
||||
|
||||
CommandClass::WriteXML( _ccElement );
|
||||
if( m_numEndPointsHint != 0 )
|
||||
{
|
||||
snprintf( str, sizeof(str), "%d", m_numEndPointsHint );
|
||||
_ccElement->SetAttribute( "endpoints", str);
|
||||
}
|
||||
|
||||
if( m_endPointMap == MultiInstanceMapEndPoints )
|
||||
{
|
||||
_ccElement->SetAttribute( "mapping", "endpoints" );
|
||||
}
|
||||
|
||||
if( m_endPointFindSupported )
|
||||
{
|
||||
_ccElement->SetAttribute( "findsupport", "true" );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <MultiInstance::RequestInstances>
|
||||
// Request number of instances of the specified command class from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool MultiInstance::RequestInstances
|
||||
(
|
||||
)
|
||||
{
|
||||
bool res = false;
|
||||
|
||||
if( GetVersion() == 1 )
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
// MULTI_INSTANCE
|
||||
char str[128];
|
||||
for( map<uint8,CommandClass*>::const_iterator it = node->m_commandClassMap.begin(); it != node->m_commandClassMap.end(); ++it )
|
||||
{
|
||||
CommandClass* cc = it->second;
|
||||
if( cc->GetCommandClassId() == NoOperation::StaticGetCommandClassId() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if( cc->HasStaticRequest( StaticRequest_Instances ) )
|
||||
{
|
||||
snprintf( str, sizeof( str ), "MultiInstanceCmd_Get for %s", cc->GetCommandClassName().c_str() );
|
||||
|
||||
Msg* msg = new Msg( str, GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 3 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( MultiInstanceCmd_Get );
|
||||
msg->Append( cc->GetCommandClassId() );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Query );
|
||||
res = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// MULTI_CHANNEL
|
||||
char str[128];
|
||||
snprintf( str, sizeof( str ), "MultiChannelCmd_EndPointGet for node %d", GetNodeId() );
|
||||
|
||||
Msg* msg = new Msg( str, GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( MultiChannelCmd_EndPointGet );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Query );
|
||||
res = true;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <MultiInstance::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool MultiInstance::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
bool handled = false;
|
||||
Node* node = GetNodeUnsafe();
|
||||
if( node != NULL )
|
||||
{
|
||||
handled = true;
|
||||
switch( (MultiInstanceCmd)_data[0] )
|
||||
{
|
||||
case MultiInstanceCmd_Report:
|
||||
{
|
||||
HandleMultiInstanceReport( _data, _length );
|
||||
break;
|
||||
}
|
||||
case MultiInstanceCmd_Encap:
|
||||
{
|
||||
HandleMultiInstanceEncap( _data, _length );
|
||||
break;
|
||||
}
|
||||
case MultiChannelCmd_EndPointReport:
|
||||
{
|
||||
HandleMultiChannelEndPointReport( _data, _length );
|
||||
break;
|
||||
}
|
||||
case MultiChannelCmd_CapabilityReport:
|
||||
{
|
||||
HandleMultiChannelCapabilityReport( _data, _length );
|
||||
break;
|
||||
}
|
||||
case MultiChannelCmd_EndPointFindReport:
|
||||
{
|
||||
HandleMultiChannelEndPointFindReport( _data, _length );
|
||||
break;
|
||||
}
|
||||
case MultiChannelCmd_Encap:
|
||||
{
|
||||
HandleMultiChannelEncap( _data, _length );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
handled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <MultiInstance::HandleMultiInstanceReport>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
void MultiInstance::HandleMultiInstanceReport
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length
|
||||
)
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
uint8 commandClassId = _data[1];
|
||||
uint8 instances = _data[2];
|
||||
|
||||
if( CommandClass* pCommandClass = node->GetCommandClass( commandClassId ) )
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received MultiInstanceReport from node %d for %s: Number of instances = %d", GetNodeId(), pCommandClass->GetCommandClassName().c_str(), instances );
|
||||
pCommandClass->SetInstances( instances );
|
||||
pCommandClass->ClearStaticRequest( StaticRequest_Instances );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <MultiInstance::HandleMultiInstanceEncap>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
void MultiInstance::HandleMultiInstanceEncap
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length
|
||||
)
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
uint8 instance = _data[1];
|
||||
if( GetVersion() > 1 )
|
||||
{
|
||||
instance &= 0x7f;
|
||||
}
|
||||
uint8 commandClassId = _data[2];
|
||||
|
||||
if( CommandClass* pCommandClass = node->GetCommandClass( commandClassId ) )
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received a MultiInstanceEncap from node %d, instance %d, for Command Class %s", GetNodeId(), instance, pCommandClass->GetCommandClassName().c_str() );
|
||||
pCommandClass->ReceivedCntIncr();
|
||||
pCommandClass->HandleMsg( &_data[3], _length-3, instance );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <MultiInstance::HandleMultiChannelEndPointReport>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
void MultiInstance::HandleMultiChannelEndPointReport
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length
|
||||
)
|
||||
{
|
||||
int len;
|
||||
|
||||
if( m_numEndPoints != 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_numEndPointsCanChange = (( _data[1] & 0x80 ) != 0 ); // Number of endpoints can change.
|
||||
m_endPointsAreSameClass = (( _data[1] & 0x40 ) != 0 ); // All endpoints are the same command class.
|
||||
m_numEndPoints = _data[2] & 0x7f;
|
||||
if( m_numEndPointsHint != 0 )
|
||||
{
|
||||
m_numEndPoints = m_numEndPointsHint; // don't use device's number
|
||||
}
|
||||
|
||||
len = m_numEndPoints;
|
||||
if( m_endPointsAreSameClass ) // only need to check single end point
|
||||
{
|
||||
len = 1;
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received MultiChannelEndPointReport from node %d. All %d endpoints are the same.", GetNodeId(), m_numEndPoints );
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received MultiChannelEndPointReport from node %d. %d endpoints are not all the same.", GetNodeId(), m_numEndPoints );
|
||||
}
|
||||
|
||||
// This code assumes the endpoints are all in numeric sequential order.
|
||||
// Since the end point finds do not appear to work this is the best estimate.
|
||||
for( uint8 i = 1; i <= len; i++ )
|
||||
{
|
||||
|
||||
// Send a single capability request to each endpoint
|
||||
char str[128];
|
||||
snprintf( str, sizeof( str ), "MultiChannelCmd_CapabilityGet for endpoint %d", i );
|
||||
Msg* msg = new Msg( str, GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 3 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( MultiChannelCmd_CapabilityGet );
|
||||
msg->Append( i );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <MultiInstance::HandleMultiChannelCapabilityReport>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
void MultiInstance::HandleMultiChannelCapabilityReport
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length
|
||||
)
|
||||
{
|
||||
|
||||
bool dynamic = ((_data[1] & 0x80)!=0);
|
||||
|
||||
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
/* if you having problems with Dynamic Devices not correctly
|
||||
* updating the commandclasses, see this email thread:
|
||||
* https://groups.google.com/d/topic/openzwave/IwepxScRAVo/discussion
|
||||
*/
|
||||
if ((m_ignoreUnsolicitedMultiChannelCapabilityReport && (node->GetCurrentQueryStage() != Node::QueryStage_Instances))
|
||||
&& !dynamic && m_endPointCommandClasses.size() > 0) {
|
||||
Log::Write(LogLevel_Error, GetNodeId(), "Recieved a Unsolicited MultiChannelEncap when we are not in QueryState_Instances");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 endPoint = _data[1] & 0x7f;
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received MultiChannelCapabilityReport from node %d for endpoint %d", GetNodeId(), endPoint );
|
||||
Log::Write( LogLevel_Info, GetNodeId(), " Endpoint is%sdynamic, and is a %s", dynamic ? " " : " not ", node->GetEndPointDeviceClassLabel( _data[2], _data[3] ).c_str() );
|
||||
Log::Write( LogLevel_Info, GetNodeId(), " Command classes supported by the endpoint are:" );
|
||||
|
||||
// Store the command classes for later use
|
||||
bool afterMark = false;
|
||||
m_endPointCommandClasses.clear();
|
||||
uint8 numCommandClasses = _length - 5;
|
||||
for( uint8 i = 0; i < numCommandClasses; ++i )
|
||||
{
|
||||
uint8 commandClassId = _data[i+4];
|
||||
if( commandClassId == 0xef )
|
||||
{
|
||||
afterMark = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
m_endPointCommandClasses.insert( commandClassId );
|
||||
|
||||
// Ensure the node supports this command class
|
||||
CommandClass* cc = node->GetCommandClass( commandClassId );
|
||||
if( !cc )
|
||||
{
|
||||
cc = node->AddCommandClass( commandClassId );
|
||||
if( cc && afterMark )
|
||||
{
|
||||
cc->SetAfterMark();
|
||||
}
|
||||
}
|
||||
if( cc )
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), " %s", cc->GetCommandClassName().c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
// Create internal library instances for each command class in the list
|
||||
// Also set up mapping from intances to endpoints for encapsulation
|
||||
Basic* basic = static_cast<Basic*>( node->GetCommandClass( Basic::StaticGetCommandClassId() ) );
|
||||
if( m_endPointsAreSameClass ) // Create all the same instances here
|
||||
{
|
||||
int len;
|
||||
|
||||
if( m_endPointMap == MultiInstanceMapAll ) // Include the non-endpoint instance
|
||||
{
|
||||
endPoint = 0;
|
||||
len = m_numEndPoints + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
endPoint = 1;
|
||||
len = m_numEndPoints;
|
||||
}
|
||||
|
||||
// Create all the command classes for all the endpoints
|
||||
for( uint8 i = 1; i <= len; i++ )
|
||||
{
|
||||
for( set<uint8>::iterator it = m_endPointCommandClasses.begin(); it != m_endPointCommandClasses.end(); ++it )
|
||||
{
|
||||
uint8 commandClassId = *it;
|
||||
CommandClass* cc = node->GetCommandClass( commandClassId );
|
||||
if( cc )
|
||||
{
|
||||
cc->SetInstance( i );
|
||||
if( m_endPointMap != MultiInstanceMapAll || i != 1 )
|
||||
{
|
||||
cc->SetEndPoint( i, endPoint );
|
||||
}
|
||||
// If we support the BASIC command class and it is mapped to a command class
|
||||
// assigned to this end point, make sure the BASIC command class is also associated
|
||||
// with this end point.
|
||||
if( basic != NULL && basic->GetMapping() == commandClassId )
|
||||
{
|
||||
basic->SetInstance( i );
|
||||
if( m_endPointMap != MultiInstanceMapAll || i != 1 )
|
||||
{
|
||||
basic->SetEndPoint( i, endPoint );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
endPoint++;
|
||||
}
|
||||
}
|
||||
else // Endpoints are different
|
||||
{
|
||||
for( set<uint8>::iterator it = m_endPointCommandClasses.begin(); it != m_endPointCommandClasses.end(); ++it )
|
||||
{
|
||||
uint8 commandClassId = *it;
|
||||
CommandClass* cc = node->GetCommandClass( commandClassId );
|
||||
if( cc )
|
||||
{
|
||||
uint8 i;
|
||||
// Find the next free instance of this class
|
||||
for( i = 1; i <= 127; i++ )
|
||||
{
|
||||
if( m_endPointMap == MultiInstanceMapAll ) // Include the non-endpoint instance
|
||||
{
|
||||
if( !cc->GetInstances()->IsSet( i ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Reuse non-endpoint instances first time we see it
|
||||
else if( i == 1 && cc->GetInstances()->IsSet( i ) && cc->GetEndPoint( i ) == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
// Find the next free instance
|
||||
else if( !cc->GetInstances()->IsSet( i ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
cc->SetInstance( i );
|
||||
cc->SetEndPoint( i, endPoint );
|
||||
// If we support the BASIC command class and it is mapped to a command class
|
||||
// assigned to this end point, make sure the BASIC command class is also associated
|
||||
// with this end point.
|
||||
if( basic != NULL && basic->GetMapping() == commandClassId )
|
||||
{
|
||||
basic->SetInstance( i );
|
||||
basic->SetEndPoint( i, endPoint );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <MultiInstance::HandleMultiChannelEndPointFindReport>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
void MultiInstance::HandleMultiChannelEndPointFindReport
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length
|
||||
)
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received MultiChannelEndPointFindReport from node %d", GetNodeId() );
|
||||
uint8 numEndPoints = _length - 5;
|
||||
for( uint8 i=0; i<numEndPoints; ++i )
|
||||
{
|
||||
uint8 endPoint = _data[i+4] & 0x7f;
|
||||
|
||||
if( m_endPointsAreSameClass )
|
||||
{
|
||||
// Use the stored command class list to set up the endpoint.
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
for( set<uint8>::iterator it=m_endPointCommandClasses.begin(); it!=m_endPointCommandClasses.end(); ++it )
|
||||
{
|
||||
uint8 commandClassId = *it;
|
||||
CommandClass* cc = node->GetCommandClass( commandClassId );
|
||||
if( cc )
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), " Endpoint %d: Adding %s", endPoint, cc->GetCommandClassName().c_str() );
|
||||
cc->SetInstance( endPoint );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Endpoints are different, so request the capabilities
|
||||
char str[128];
|
||||
snprintf( str, 128, "MultiChannelCmd_CapabilityGet for node %d, endpoint %d", GetNodeId(), endPoint );
|
||||
Msg* msg = new Msg( str, GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 3 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( MultiChannelCmd_CapabilityGet );
|
||||
msg->Append( endPoint );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
}
|
||||
}
|
||||
|
||||
m_numEndPointsFound += numEndPoints;
|
||||
if( !m_endPointsAreSameClass )
|
||||
{
|
||||
if( _data[1] == 0 )
|
||||
{
|
||||
// No more reports to follow this one, so we can continue the search.
|
||||
if( m_numEndPointsFound < numEndPoints )
|
||||
{
|
||||
// We have not yet found all the endpoints, so move to the next generic class request
|
||||
++m_endPointFindIndex;
|
||||
if (m_endPointFindIndex <= 13) /* we are finished */
|
||||
{
|
||||
if( c_genericClass[m_endPointFindIndex] > 0 )
|
||||
{
|
||||
if (m_endPointFindIndex > 13) /* size of c_genericClassName minus Unknown Entry */
|
||||
{
|
||||
Log::Write (LogLevel_Warning, GetNodeId(), "m_endPointFindIndex Value was greater than range. Setting to Unknown");
|
||||
m_endPointFindIndex = 14;
|
||||
}
|
||||
|
||||
char str[128];
|
||||
snprintf( str, 128, "MultiChannelCmd_EndPointFind for generic device class 0x%.2x (%s)", c_genericClass[m_endPointFindIndex], c_genericClassName[m_endPointFindIndex] );
|
||||
Msg* msg = new Msg( str, GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 4 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( MultiChannelCmd_EndPointFind );
|
||||
msg->Append( c_genericClass[m_endPointFindIndex] ); // Generic device class
|
||||
msg->Append( 0xff ); // Any specific device class
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
}
|
||||
} else {
|
||||
Log::Write (LogLevel_Warning, GetNodeId(), "m_endPointFindIndex is higher than range. Not Sending MultiChannelCmd_EndPointFind message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <MultiInstance::HandleMultiChannelEncap>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
void MultiInstance::HandleMultiChannelEncap
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length
|
||||
)
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
uint8 endPoint = _data[1] & 0x7f;
|
||||
uint8 commandClassId = _data[3];
|
||||
if( CommandClass* pCommandClass = node->GetCommandClass( commandClassId ) )
|
||||
{
|
||||
uint8 instance = pCommandClass->GetInstance( endPoint );
|
||||
if( instance == 0 )
|
||||
{
|
||||
Log::Write( LogLevel_Error, GetNodeId(), "Cannot find endpoint map to instance for Command Class %s endpoint %d", pCommandClass->GetCommandClassName().c_str(), endPoint );
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received a MultiChannelEncap from node %d, endpoint %d for Command Class %s", GetNodeId(), endPoint, pCommandClass->GetCommandClassName().c_str() );
|
||||
pCommandClass->HandleMsg( &_data[4], _length-4, instance );
|
||||
}
|
||||
} else {
|
||||
Log::Write(LogLevel_Error, GetNodeId(), "Recieved a MultiChannelEncap for endpoint %d for Command Class %d, which we can't find", endPoint, commandClassId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// MultiInstance.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_MULTI_INSTANCE
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _MultiInstance_H
|
||||
#define _MultiInstance_H
|
||||
|
||||
#include <set>
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
/** \brief Implements COMMAND_CLASS_MULTI_INSTANCE (0x60), a Z-Wave device command class.
|
||||
*/
|
||||
class MultiInstance: public CommandClass
|
||||
{
|
||||
public:
|
||||
enum MultiInstanceCmd
|
||||
{
|
||||
MultiInstanceCmd_Get = 0x04,
|
||||
MultiInstanceCmd_Report = 0x05,
|
||||
MultiInstanceCmd_Encap = 0x06,
|
||||
|
||||
// Version 2
|
||||
MultiChannelCmd_EndPointGet = 0x07,
|
||||
MultiChannelCmd_EndPointReport = 0x08,
|
||||
MultiChannelCmd_CapabilityGet = 0x09,
|
||||
MultiChannelCmd_CapabilityReport = 0x0a,
|
||||
MultiChannelCmd_EndPointFind = 0x0b,
|
||||
MultiChannelCmd_EndPointFindReport = 0x0c,
|
||||
MultiChannelCmd_Encap = 0x0d
|
||||
};
|
||||
|
||||
enum MultiInstanceMapping
|
||||
{
|
||||
MultiInstanceMapAll,
|
||||
MultiInstanceMapEndPoints,
|
||||
MultiInstanceMapOther
|
||||
};
|
||||
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new MultiInstance( _homeId, _nodeId ); }
|
||||
virtual ~MultiInstance(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x60; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_MULTI_INSTANCE/CHANNEL"; }
|
||||
|
||||
bool RequestInstances();
|
||||
|
||||
// From CommandClass
|
||||
virtual void ReadXML( TiXmlElement const* _ccElement );
|
||||
virtual void WriteXML( TiXmlElement* _ccElement );
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
virtual uint8 GetMaxVersion(){ return 2; }
|
||||
|
||||
MultiInstanceMapping GetEndPointMap(){ return m_endPointMap; }
|
||||
|
||||
private:
|
||||
MultiInstance( uint32 const _homeId, uint8 const _nodeId );
|
||||
|
||||
void HandleMultiInstanceReport( uint8 const* _data, uint32 const _length );
|
||||
void HandleMultiInstanceEncap( uint8 const* _data, uint32 const _length );
|
||||
void HandleMultiChannelEndPointReport( uint8 const* _data, uint32 const _length );
|
||||
void HandleMultiChannelCapabilityReport( uint8 const* _data, uint32 const _length );
|
||||
void HandleMultiChannelEndPointFindReport( uint8 const* _data, uint32 const _length );
|
||||
void HandleMultiChannelEncap( uint8 const* _data, uint32 const _length );
|
||||
|
||||
bool m_numEndPointsCanChange;
|
||||
bool m_endPointsAreSameClass;
|
||||
uint8 m_numEndPoints;
|
||||
|
||||
// Finding endpoints
|
||||
uint8 m_endPointFindIndex;
|
||||
uint8 m_numEndPointsFound;
|
||||
set<uint8> m_endPointCommandClasses;
|
||||
|
||||
// configuration
|
||||
uint8 m_numEndPointsHint; // for nodes that do not report correct number of end points
|
||||
MultiInstanceMapping m_endPointMap; // Determine how to map end points to value id instances
|
||||
bool m_endPointFindSupported; // for nodes that (someday may) support endpointfind
|
||||
bool m_ignoreUnsolicitedMultiChannelCapabilityReport;
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// MultiInstanceAssociation.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_MULTI_INSTANCE_ASSOCIATION
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "MultiInstanceAssociation.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Driver.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum MultiInstanceAssociationCmd
|
||||
{
|
||||
MultiInstanceAssociationCmd_Set = 0x01,
|
||||
MultiInstanceAssociationCmd_Get = 0x02,
|
||||
MultiInstanceAssociationCmd_Report = 0x03,
|
||||
MultiInstanceAssociationCmd_Remove = 0x04,
|
||||
MultiInstanceAssociationCmd_GroupingsGet = 0x05,
|
||||
MultiInstanceAssociationCmd_GroupingsReport = 0x06
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <MultiInstanceAssociation::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool MultiInstanceAssociation::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// MultiInstanceAssociation.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_MULTI_INSTANCE_ASSOCIATION
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _MultiInstanceAssociation_H
|
||||
#define _MultiInstanceAssociation_H
|
||||
|
||||
#include <vector>
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
/** \brief Implements COMMAND_CLASS_MULTI_INSTANCE_ASSOCIATION (0x8E), a Z-Wave device command class.
|
||||
*/
|
||||
class MultiInstanceAssociation: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new MultiInstanceAssociation( _homeId, _nodeId ); }
|
||||
virtual ~MultiInstanceAssociation(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x8e; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_MULTI_INSTANCE_ASSOCIATION"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
|
||||
private:
|
||||
MultiInstanceAssociation( uint32 const _homeId, uint8 const _nodeId ): CommandClass( _homeId, _nodeId ){}
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// NoOperation.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_NO_OPERATION
|
||||
//
|
||||
// Copyright (c) 2012 Greg Satz <satz@iranger.com>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "NoOperation.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Node.h"
|
||||
#include "../Driver.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <NoOperation::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool NoOperation::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
// We have received a no operation from the Z-Wave device.
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received NoOperation command from node %d", GetNodeId() );
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <NoOperation::Set>
|
||||
// Send a No Operation message class.
|
||||
//-----------------------------------------------------------------------------
|
||||
void NoOperation::Set
|
||||
(
|
||||
bool const _route,
|
||||
Driver::MsgQueue _queue // = Driver::MsgQueue_NoOp
|
||||
)
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "NoOperation::Set - Routing=%s", _route ? "true" : "false" );
|
||||
|
||||
Msg* msg = new Msg( "NoOperation_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( 0 );
|
||||
if( _route )
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
else
|
||||
msg->Append( TRANSMIT_OPTION_ACK | TRANSMIT_OPTION_NO_ROUTE );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// NoOperation.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_NO_OPERATION
|
||||
//
|
||||
// Copyright (c) 2012 Greg Satz <satz@iranger.com>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _NoOperation_H
|
||||
#define _NoOperation_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
/** \brief Implements COMMAND_CLASS_NO_OPERATION (0x00), a Z-Wave device command class.
|
||||
*/
|
||||
class NoOperation: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new NoOperation( _homeId, _nodeId ); }
|
||||
virtual ~NoOperation(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x00; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_NO_OPERATION"; }
|
||||
|
||||
void Set( bool const _route, Driver::MsgQueue const _queue = Driver::MsgQueue_NoOp );
|
||||
|
||||
// From CommandClass
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
|
||||
private:
|
||||
NoOperation( uint32 const _homeId, uint8 const _nodeId ): CommandClass( _homeId, _nodeId ){}
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,531 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// NodeNaming.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_NODE_NAMING
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "NodeNaming.h"
|
||||
#include "Association.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Node.h"
|
||||
#include "../Driver.h"
|
||||
#include "../Notification.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum NodeNamingCmd
|
||||
{
|
||||
NodeNamingCmd_Set = 0x01,
|
||||
NodeNamingCmd_Get = 0x02,
|
||||
NodeNamingCmd_Report = 0x03,
|
||||
NodeNamingCmd_LocationSet = 0x04,
|
||||
NodeNamingCmd_LocationGet = 0x05,
|
||||
NodeNamingCmd_LocationReport = 0x06
|
||||
};
|
||||
|
||||
enum StringEncoding
|
||||
{
|
||||
StringEncoding_ASCII = 0,
|
||||
StringEncoding_ExtendedASCII,
|
||||
StringEncoding_UTF16
|
||||
};
|
||||
|
||||
// Mapping of characters 0x80 and above to Unicode.
|
||||
uint16 const c_extendedAsciiToUnicode[] =
|
||||
{
|
||||
0x20ac, // 0x80 - Euro Sign
|
||||
0x0081, // 0x81 -
|
||||
0x201a, // 0x82 - Single Low-9 Quotation Mark
|
||||
0x0192, // 0x83 - Latin Small Letter F With Hook
|
||||
0x201e, // 0x84 - Double Low-9 Quotation Mark
|
||||
0x2026, // 0x85 - Horizontal Ellipsis
|
||||
0x2020, // 0x86 - Dagger
|
||||
0x2021, // 0x87 - Double Dagger
|
||||
0x02c6, // 0x88 - Modifier Letter Circumflex Accent
|
||||
0x2030, // 0x89 - Per Mille Sign
|
||||
0x0160, // 0x8a - Latin Capital Letter S With Caron
|
||||
0x2039, // 0x8b - Single Left-Pointing Angle Quotation Mark
|
||||
0x0152, // 0x8c - Latin Capital Ligature Oe
|
||||
0x008d, // 0x8d -
|
||||
0x017d, // 0x8e - Latin Capital Letter Z With Caron
|
||||
0x008f, // 0x8f -
|
||||
|
||||
0x0090, // 0x90 -
|
||||
0x2018, // 0x91 - Left Single Quotation Mark
|
||||
0x2019, // 0x92 - Right Single Quotation Mark
|
||||
0x201c, // 0x93 - Left Double Quotation Mark
|
||||
0x201d, // 0x94 - Right Double Quotation Mark
|
||||
0x2022, // 0x95 - Bullet
|
||||
0x2013, // 0x96 - En Dash
|
||||
0x2014, // 0x97 - Em Dash
|
||||
0x02dc, // 0x98 - Small Tilde
|
||||
0x2122, // 0x99 - Trade Mark Sign
|
||||
0x0161, // 0x9a - Latin Small Letter S With Caron
|
||||
0x203a, // 0x9b - Single Right-Pointing Angle Quotation Mark
|
||||
0x0153, // 0x9c - Latin Small Ligature Oe
|
||||
0x009d, // 0x9d -
|
||||
0x017e, // 0x9e - Latin Small Letter Z With Caron
|
||||
0x0178, // 0x9f - Latin Capital Letter Y With Diaeresis
|
||||
|
||||
0x00a0, // 0xa0 - No-Break Space
|
||||
0x00a1, // 0xa1 - Inverted Exclamation Mark
|
||||
0x00a2, // 0xa2 - Cent Sign
|
||||
0x00a3, // 0xa3 - Pound Sign
|
||||
0x00a4, // 0xa4 - Currency Sign
|
||||
0x00a5, // 0xa5 - Yen Sign
|
||||
0x00a6, // 0xa6 - Broken Bar
|
||||
0x00a7, // 0xa7 - Section Sign
|
||||
0x00a8, // 0xa8 - Diaeresis
|
||||
0x00a9, // 0xa9 - Copyright Sign
|
||||
0x00aa, // 0xaa - Feminine Ordinal Indicator
|
||||
0x00ab, // 0xab - Left-Pointing Double Angle Quotation Mark
|
||||
0x00ac, // 0xac - Not Sign
|
||||
0x00ad, // 0xad - Soft Hyphen
|
||||
0x00ae, // 0xae - Registered Sign
|
||||
0x00af, // 0xaf - Macron
|
||||
|
||||
0x00b0, // 0xb0 - Degree Sign
|
||||
0x00b1, // 0xb1 - Plus-Minus Sign
|
||||
0x00b2, // 0xb2 - Superscript Two
|
||||
0x00b3, // 0xb3 - Superscript Three
|
||||
0x00b4, // 0xb4 - Acute Accent
|
||||
0x00b5, // 0xb5 - Micro Sign
|
||||
0x00b6, // 0xb6 - Pilcrow Sign
|
||||
0x00b7, // 0xb7 - Middle Dot
|
||||
0x00b8, // 0xb8 - Cedilla
|
||||
0x00b9, // 0xb9 - Superscript One
|
||||
0x00ba, // 0xba - Masculine Ordinal Indicator
|
||||
0x00bb, // 0xbb - Right-Pointing Double Angle Quotation Mark
|
||||
0x00bc, // 0xbc - Vulgar Fraction One Quarter
|
||||
0x00bd, // 0xbd - Vulgar Fraction One Half
|
||||
0x00be, // 0xbe - Vulgar Fraction Three Quarters
|
||||
0x00bf, // 0xbf - Inverted Question Mark
|
||||
|
||||
0x00c0, // 0xc0 - Latin Capital Letter A With Grave
|
||||
0x00c1, // 0xc1 - Latin Capital Letter A With Acute
|
||||
0x00c2, // 0xc2 - Latin Capital Letter A With Circumflex
|
||||
0x00c3, // 0xc3 - Latin Capital Letter A With Tilde
|
||||
0x00c4, // 0xc4 - Latin Capital Letter A With Diaeresis
|
||||
0x00c5, // 0xc5 - Latin Capital Letter A With Ring Above
|
||||
0x00c6, // 0xc6 - Latin Capital Ligature Ae
|
||||
0x00c7, // 0xc7 - Latin Capital Letter C With Cedilla
|
||||
0x00c8, // 0xc8 - Latin Capital Letter E With Grave
|
||||
0x00c9, // 0xc9 - Latin Capital Letter E With Acute
|
||||
0x00ca, // 0xca - Latin Capital Letter E With Circumflex
|
||||
0x00cb, // 0xcb - Latin Capital Letter E With Diaeresis
|
||||
0x00cc, // 0xcc - Latin Capital Letter I With Grave
|
||||
0x00cd, // 0xcd - Latin Capital Letter I With Acute
|
||||
0x00ce, // 0xce - Latin Capital Letter I With Circumflex
|
||||
0x00cf, // 0xcf - Latin Capital Letter I With Diaeresis
|
||||
|
||||
0x00d0, // 0xd0 - Latin Capital Letter Eth
|
||||
0x00d1, // 0xd1 - Latin Capital Letter N With Tilde
|
||||
0x00d2, // 0xd2 - Latin Capital Letter O With Grave
|
||||
0x00d3, // 0xd3 - Latin Capital Letter O With Acute
|
||||
0x00d4, // 0xd4 - Latin Capital Letter O With Circumflex
|
||||
0x00d5, // 0xd5 - Latin Capital Letter O With Tilde
|
||||
0x00d6, // 0xd6 - Latin Capital Letter O With Diaeresis
|
||||
0x00d7, // 0xd7 - Multiplication Sign
|
||||
0x00d8, // 0xd8 - Latin Capital Letter O With Stroke
|
||||
0x00d9, // 0xd9 - Latin Capital Letter U With Grave
|
||||
0x00da, // 0xda - Latin Capital Letter U With Acute
|
||||
0x00db, // 0xdb - Latin Capital Letter U With Circumflex
|
||||
0x00dc, // 0xdc - Latin Capital Letter U With Diaeresis
|
||||
0x00dd, // 0xdd - Latin Capital Letter Y With Acute
|
||||
0x00de, // 0xde - Latin Capital Letter Thorn
|
||||
0x00df, // 0xdf - Latin Small Letter Sharp S
|
||||
|
||||
0x00e0, // 0xe0 - Latin Small Letter A With Grave
|
||||
0x00e1, // 0xe1 - Latin Small Letter A With Acute
|
||||
0x00e2, // 0xe2 - Latin Small Letter A With Circumflex
|
||||
0x00e3, // 0xe3 - Latin Small Letter A With Tilde
|
||||
0x00e4, // 0xe4 - Latin Small Letter A With Diaeresis
|
||||
0x00e5, // 0xe5 - Latin Small Letter A With Ring Above
|
||||
0x00e6, // 0xe6 - Latin Small Ligature Ae
|
||||
0x00e7, // 0xe7 - Latin Small Letter C With Cedilla
|
||||
0x00e8, // 0xe8 - Latin Small Letter E With Grave
|
||||
0x00e9, // 0xe9 - Latin Small Letter E With Acute
|
||||
0x00ea, // 0xea - Latin Small Letter E With Circumflex
|
||||
0x00eb, // 0xeb - Latin Small Letter E With Diaeresis
|
||||
0x00ec, // 0xec - Latin Small Letter I With Grave
|
||||
0x00ed, // 0xed - Latin Small Letter I With Acute
|
||||
0x00ee, // 0xee - Latin Small Letter I With Circumflex
|
||||
0x00ef, // 0xef - Latin Small Letter I With Diaeresis
|
||||
|
||||
0x00f0, // 0xf0 - Latin Small Letter Eth
|
||||
0x00f1, // 0xf1 - Latin Small Letter N With Tilde
|
||||
0x00f2, // 0xf2 - Latin Small Letter O With Grave
|
||||
0x00f3, // 0xf3 - Latin Small Letter O With Acute
|
||||
0x00f4, // 0xf4 - Latin Small Letter O With Circumflex
|
||||
0x00f5, // 0xf5 - Latin Small Letter O With Tilde
|
||||
0x00f6, // 0xf6 - Latin Small Letter O With Diaeresis
|
||||
0x00f7, // 0xf7 - Division Sign
|
||||
0x00f8, // 0xf8 - Latin Small Letter O With Stroke
|
||||
0x00f9, // 0xf9 - Latin Small Letter U With Grave
|
||||
0x00fa, // 0xfa - Latin Small Letter U With Acute
|
||||
0x00fb, // 0xfb - Latin Small Letter U With Circumflex
|
||||
0x00fc, // 0xfc - Latin Small Letter U With Diaeresis
|
||||
0x00fd, // 0xfd - Latin Small Letter Y With Acute
|
||||
0x00fe, // 0xfe - Latin Small Letter Thorn
|
||||
0x00ff // 0xff - Latin Small Letter Y With Diaeresis
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <NodeNaming::RequestState>
|
||||
// Request current state from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool NodeNaming::RequestState
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
bool res = false;
|
||||
if( _requestFlags & RequestFlag_Session )
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
if( node->m_nodeName == "" )
|
||||
{
|
||||
// If we don't already have a user-defined name, fetch it from the device
|
||||
res |= RequestValue( _requestFlags, NodeNamingCmd_Get, _instance, _queue );
|
||||
}
|
||||
|
||||
if( node->m_location == "" )
|
||||
{
|
||||
// If we don't already have a user-defined location, fetch it from the device
|
||||
res |= RequestValue( _requestFlags, NodeNamingCmd_LocationGet, _instance, _queue );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <NodeNaming::RequestValue>
|
||||
// Request current value from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool NodeNaming::RequestValue
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _getTypeEnum,
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( _instance != 1 )
|
||||
{
|
||||
// This command class doesn't work with multiple instances
|
||||
return false;
|
||||
}
|
||||
|
||||
Msg* msg;
|
||||
if( _getTypeEnum == NodeNamingCmd_Get )
|
||||
{
|
||||
if ( IsGetSupported() )
|
||||
{
|
||||
msg = new Msg( "NodeNamingCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( NodeNamingCmd_Get );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
return true;
|
||||
} else {
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "NodeNamingCmd_Get Not Supported on this node");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if( _getTypeEnum == NodeNamingCmd_LocationGet )
|
||||
{
|
||||
// If we don't already have a user-defined name, fetch it from the device
|
||||
msg = new Msg( "NodeNamingCmd_LocationGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( NodeNamingCmd_LocationGet );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <NodeNaming::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool NodeNaming::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
bool updated = false;
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
if( NodeNamingCmd_Report == (NodeNamingCmd)_data[0] )
|
||||
{
|
||||
string name = ExtractString( _data, _length );
|
||||
if( node->m_nodeName == "" )
|
||||
{
|
||||
// We only overwrite the name if it is empty
|
||||
node->m_nodeName = name;
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received the name: %s.", name.c_str() );
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
else if( NodeNamingCmd_LocationReport == (NodeNamingCmd)_data[0] )
|
||||
{
|
||||
string location = ExtractString( _data, _length );
|
||||
if( node->m_location == "" )
|
||||
{
|
||||
// We only overwrite the location if it is empty
|
||||
node->m_location = location;
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received the location: %s.", location.c_str() );
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( updated )
|
||||
{
|
||||
Notification* notification = new Notification( Notification::Type_NodeNaming );
|
||||
notification->SetHomeAndNodeIds( GetHomeId(), GetNodeId() );
|
||||
GetDriver()->QueueNotification( notification );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <NodeNaming::SetName>
|
||||
// Set the name in the device
|
||||
//-----------------------------------------------------------------------------
|
||||
void NodeNaming::SetName
|
||||
(
|
||||
string const& _name
|
||||
)
|
||||
{
|
||||
size_t length = _name.size();
|
||||
if( length > 16 )
|
||||
{
|
||||
length = 16;
|
||||
}
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "NodeNaming::Set - Naming to '%s'", _name.c_str() );
|
||||
Msg* msg = new Msg( "NodeNaming Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( (uint8)(length + 3) );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( NodeNamingCmd_Set );
|
||||
msg->Append( (uint8)StringEncoding_ASCII );
|
||||
|
||||
for( uint32 i=0; i<length; ++i )
|
||||
{
|
||||
msg->Append( _name[i] );
|
||||
}
|
||||
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <NodeNaming::SetLocation>
|
||||
// Set the location in the device
|
||||
//-----------------------------------------------------------------------------
|
||||
void NodeNaming::SetLocation
|
||||
(
|
||||
string const& _location
|
||||
)
|
||||
{
|
||||
size_t length = _location.size();
|
||||
if( length > 16 )
|
||||
{
|
||||
length = 16;
|
||||
}
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "NodeNaming::SetLocation - Setting location to '%s'", _location.c_str() );
|
||||
Msg* msg = new Msg( "NodeNaming Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( (uint8)(length + 3) );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( NodeNamingCmd_LocationSet );
|
||||
msg->Append( (uint8)StringEncoding_ASCII );
|
||||
|
||||
for( uint32 i=0; i<length; ++i )
|
||||
{
|
||||
msg->Append( _location[i] );
|
||||
}
|
||||
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <NodeNaming::ExtractString>
|
||||
// Extract a string from the report data
|
||||
//-----------------------------------------------------------------------------
|
||||
string NodeNaming::ExtractString
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length
|
||||
)
|
||||
{
|
||||
uint8 i;
|
||||
char str[32];
|
||||
uint32 pos = 0;
|
||||
|
||||
str[0] = 0;
|
||||
StringEncoding encoding = (StringEncoding)( _data[1] & 0x07 );
|
||||
|
||||
if( _length >= 3 )
|
||||
{
|
||||
// Get the length of the string (maximum allowed is 16 bytes)
|
||||
uint8 numBytes = _length - 3;
|
||||
if( numBytes > 16 )
|
||||
{
|
||||
numBytes = 16;
|
||||
}
|
||||
|
||||
switch( encoding )
|
||||
{
|
||||
case StringEncoding_ASCII:
|
||||
{
|
||||
// Copy data as-is
|
||||
for( i=0; i<numBytes; ++i )
|
||||
{
|
||||
str[pos++] = _data[i+2];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case StringEncoding_ExtendedASCII:
|
||||
{
|
||||
// Convert Extended ASCII characters to UTF-8
|
||||
for( i=0; i<numBytes; ++i )
|
||||
{
|
||||
uint8 ch = _data[i+2];
|
||||
if( ch >= 0x80 )
|
||||
{
|
||||
uint16 utf16 = c_extendedAsciiToUnicode[ch-0x80];
|
||||
pos = ConvertUFT16ToUTF8( utf16, str, pos );
|
||||
}
|
||||
else
|
||||
{
|
||||
str[pos++] = (char)ch;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case StringEncoding_UTF16:
|
||||
{
|
||||
// Convert UTF-16 characters to UTF-8
|
||||
for( i=0; i<numBytes; i+=2 )
|
||||
{
|
||||
uint16 utf16 = (((uint16)_data[i+2])<<8) | (uint16)_data[i+3];
|
||||
pos = ConvertUFT16ToUTF8( utf16, str, pos );
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
str[pos] = 0;
|
||||
}
|
||||
|
||||
return string( str );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <NodeNaming::ConvertUFT16ToUTF8>
|
||||
// Convert a UTF-16 string into UTF-8 encoding.
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32 NodeNaming::ConvertUFT16ToUTF8
|
||||
(
|
||||
uint16 _utf16,
|
||||
char* _buffer,
|
||||
uint32 pos
|
||||
)
|
||||
{
|
||||
static uint16 surrogate = 0;
|
||||
|
||||
if( ( surrogate != 0 ) && ( ( _utf16 & 0xdc00 ) == 0xdc00 ) )
|
||||
{
|
||||
// UTF-16 surrogate character pair converts to four UTF-8 characters.
|
||||
// We have the second member of the pair, so we can do the conversion now.
|
||||
_buffer[pos++] = (char)( ((surrogate>>7) & 0x0007) | 0x00f0 );
|
||||
_buffer[pos++] = (char)( ((surrogate>>1) & 0x0020) | ((surrogate>>2) & 0x000f) | 0x0090 );
|
||||
_buffer[pos++] = (char)( ((_utf16>>6) & 0x000f) | ((surrogate<<4) & 0x0030) | 0x0080 );
|
||||
_buffer[pos++] = (char)( (_utf16 & 0x003f) | 0x0080 );
|
||||
}
|
||||
else
|
||||
{
|
||||
surrogate = 0;
|
||||
if( _utf16 & 0xff80 )
|
||||
{
|
||||
if( _utf16 & 0xf800 )
|
||||
{
|
||||
if( ( _utf16 & 0xd800 ) == 0xd800 )
|
||||
{
|
||||
// UTF-16 surrogate character pair converts to four UTF-8 characters.
|
||||
// We have the first member of the pair, so we store it for next time.
|
||||
surrogate = _utf16;
|
||||
}
|
||||
else
|
||||
{
|
||||
// UTF-16 character can be represented by three UTF-8 characters.
|
||||
_buffer[pos++] = (char)( (_utf16>>12) | 0x00e0 );
|
||||
_buffer[pos++] = (char)( ((_utf16>>6) & 0x003f) | 0x0080 );
|
||||
_buffer[pos++] = (char)( (_utf16 & 0x003f) | 0x0080 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// UTF-16 character can be represented by two UTF-8 characters.
|
||||
_buffer[pos++] = (char)( (_utf16>>6) | 0x00c0 );
|
||||
_buffer[pos++] = (char)( (_utf16 & 0x003f) | 0x0080 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// UTF-16 character matches single ascii character.
|
||||
_buffer[pos++] = (char)_utf16;
|
||||
}
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// NodeNaming.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_NODE_NAMING
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _NodeNaming_H
|
||||
#define _NodeNaming_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
/** \brief Implements COMMAND_CLASS_NODE_NAMING (0x77), a Z-Wave device command class.
|
||||
*/
|
||||
class NodeNaming: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new NodeNaming( _homeId, _nodeId ); }
|
||||
virtual ~NodeNaming(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x77; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_NODE_NAMING"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual bool RequestState( uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual bool RequestValue( uint32 const _requestFlags, uint8 const _index, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
|
||||
void SetName( string const& _name );
|
||||
void SetLocation( string const& _location );
|
||||
|
||||
private:
|
||||
NodeNaming( uint32 const _homeId, uint8 const _nodeId ): CommandClass( _homeId, _nodeId ){}
|
||||
|
||||
string ExtractString( uint8 const* _data, uint32 const _length );
|
||||
uint32 ConvertUFT16ToUTF8( uint16 _utf16, char* _buffer, uint32 pos );
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,501 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Powerlevel.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_POWERLEVEL
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "Powerlevel.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Driver.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
#include "../value_classes/ValueByte.h"
|
||||
#include "../value_classes/ValueShort.h"
|
||||
#include "../value_classes/ValueList.h"
|
||||
#include "../value_classes/ValueButton.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum PowerlevelCmd
|
||||
{
|
||||
PowerlevelCmd_Set = 0x01,
|
||||
PowerlevelCmd_Get = 0x02,
|
||||
PowerlevelCmd_Report = 0x03,
|
||||
PowerlevelCmd_TestNodeSet = 0x04,
|
||||
PowerlevelCmd_TestNodeGet = 0x05,
|
||||
PowerlevelCmd_TestNodeReport = 0x06
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PowerlevelIndex_Powerlevel = 0,
|
||||
PowerlevelIndex_Timeout,
|
||||
PowerlevelIndex_Set,
|
||||
PowerlevelIndex_TestNode,
|
||||
PowerlevelIndex_TestPowerlevel,
|
||||
PowerlevelIndex_TestFrames,
|
||||
PowerlevelIndex_Test,
|
||||
PowerlevelIndex_Report,
|
||||
PowerlevelIndex_TestStatus,
|
||||
PowerlevelIndex_TestAckFrames
|
||||
};
|
||||
|
||||
static char const* c_powerLevelNames[] =
|
||||
{
|
||||
"Normal",
|
||||
"-1dB",
|
||||
"-2dB",
|
||||
"-3dB",
|
||||
"-4dB",
|
||||
"-5dB",
|
||||
"-6dB",
|
||||
"-7dB",
|
||||
"-8dB",
|
||||
"-9dB",
|
||||
"Unknown"
|
||||
};
|
||||
|
||||
static char const* c_powerLevelStatusNames[] =
|
||||
{
|
||||
"Failed",
|
||||
"Success",
|
||||
"In Progress",
|
||||
"Unknown"
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Powerlevel::RequestState>
|
||||
// Request current state from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Powerlevel::RequestState
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( _requestFlags & RequestFlag_Session )
|
||||
{
|
||||
return RequestValue( _requestFlags, 0, _instance, _queue );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Powerlevel::RequestValue>
|
||||
// Request current value from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Powerlevel::RequestValue
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _index,
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( _index == 0 )
|
||||
{
|
||||
if ( IsGetSupported() )
|
||||
{
|
||||
Msg* msg = new Msg( "Powerlevel_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, _instance );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( PowerlevelCmd_Get );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
return true;
|
||||
} else {
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Powerlevel_Get Not Supported on this node");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Powerlevel::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Powerlevel::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
if( PowerlevelCmd_Report == (PowerlevelCmd)_data[0] )
|
||||
{
|
||||
PowerLevelEnum powerLevel = (PowerLevelEnum)_data[1];
|
||||
if (powerLevel > 9) /* size of c_powerLevelNames minus Unknown*/
|
||||
{
|
||||
Log::Write (LogLevel_Warning, GetNodeId(), "powerLevel Value was greater than range. Setting to Invalid");
|
||||
powerLevel = (PowerLevelEnum)10;
|
||||
}
|
||||
uint8 timeout = _data[2];
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received a PowerLevel report: PowerLevel=%s, Timeout=%d", c_powerLevelNames[powerLevel], timeout );
|
||||
if( ValueList* value = static_cast<ValueList*>( GetValue( _instance, PowerlevelIndex_Powerlevel ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( (int)powerLevel );
|
||||
value->Release();
|
||||
}
|
||||
if( ValueByte* value = static_cast<ValueByte*>( GetValue( _instance, PowerlevelIndex_Timeout ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( timeout );
|
||||
value->Release();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if( PowerlevelCmd_TestNodeReport == (PowerlevelCmd)_data[0] )
|
||||
{
|
||||
uint8 testNode = _data[1];
|
||||
PowerLevelStatusEnum status = (PowerLevelStatusEnum)_data[2];
|
||||
uint16 ackCount = (((uint16)_data[3])<<8) | (uint16)_data[4];
|
||||
|
||||
if (status > 2) /* size of c_powerLevelStatusNames minus Unknown */
|
||||
{
|
||||
Log::Write (LogLevel_Warning, GetNodeId(), "status Value was greater than range. Setting to Unknown");
|
||||
status = (PowerLevelStatusEnum)3;
|
||||
}
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received a PowerLevel Test Node report: Test Node=%d, Status=%s, Test Frame ACK Count=%d", testNode, c_powerLevelStatusNames[status], ackCount );
|
||||
if( ValueByte* value = static_cast<ValueByte*>( GetValue( _instance, PowerlevelIndex_TestNode ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( testNode );
|
||||
value->Release();
|
||||
}
|
||||
if( ValueList* value = static_cast<ValueList*>( GetValue( _instance, PowerlevelIndex_TestStatus ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( (int)status );
|
||||
value->Release();
|
||||
}
|
||||
if( ValueShort* value = static_cast<ValueShort*>( GetValue( _instance, PowerlevelIndex_TestAckFrames ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( (short)ackCount );
|
||||
value->Release();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Powerlevel::SetValue>
|
||||
// Set a value on the Z-Wave device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Powerlevel::SetValue
|
||||
(
|
||||
Value const& _value
|
||||
)
|
||||
{
|
||||
bool res = false;
|
||||
uint8 instance = _value.GetID().GetInstance();
|
||||
|
||||
switch( _value.GetID().GetIndex() )
|
||||
{
|
||||
case PowerlevelIndex_Powerlevel:
|
||||
{
|
||||
if( ValueList* value = static_cast<ValueList*>( GetValue( instance, PowerlevelIndex_Powerlevel ) ) )
|
||||
{
|
||||
ValueList::Item const& item = (static_cast<ValueList const*>( &_value))->GetItem();
|
||||
value->OnValueRefreshed( item.m_value );
|
||||
value->Release();
|
||||
}
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
case PowerlevelIndex_Timeout:
|
||||
{
|
||||
if( ValueByte* value = static_cast<ValueByte*>( GetValue( instance, PowerlevelIndex_Timeout ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( (static_cast<ValueByte const*>( &_value))->GetValue() );
|
||||
value->Release();
|
||||
}
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
case PowerlevelIndex_Set:
|
||||
{
|
||||
// Set
|
||||
if( ValueButton* button = static_cast<ValueButton*>( GetValue( instance, PowerlevelIndex_Set ) ) )
|
||||
{
|
||||
if( button->IsPressed() )
|
||||
{
|
||||
res = Set( instance );
|
||||
}
|
||||
button->Release();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PowerlevelIndex_TestNode:
|
||||
{
|
||||
if( ValueByte* value = static_cast<ValueByte*>( GetValue( instance, PowerlevelIndex_TestNode ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( (static_cast<ValueByte const*>( &_value))->GetValue() );
|
||||
value->Release();
|
||||
}
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
case PowerlevelIndex_TestPowerlevel:
|
||||
{
|
||||
if( ValueList* value = static_cast<ValueList*>( GetValue( instance, PowerlevelIndex_TestPowerlevel ) ) )
|
||||
{
|
||||
ValueList::Item const& item = (static_cast<ValueList const*>( &_value))->GetItem();
|
||||
value->OnValueRefreshed( item.m_value );
|
||||
value->Release();
|
||||
}
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
case PowerlevelIndex_TestFrames:
|
||||
{
|
||||
if( ValueShort* value = static_cast<ValueShort*>( GetValue( instance, PowerlevelIndex_TestFrames ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( (static_cast<ValueByte const*>( &_value))->GetValue() );
|
||||
value->Release();
|
||||
}
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
case PowerlevelIndex_Test:
|
||||
{
|
||||
// Test
|
||||
if( ValueButton* button = static_cast<ValueButton*>( GetValue( instance, PowerlevelIndex_Test ) ) )
|
||||
{
|
||||
if( button->IsPressed() )
|
||||
{
|
||||
res = Test( instance );
|
||||
}
|
||||
button->Release();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PowerlevelIndex_Report:
|
||||
{
|
||||
// Test
|
||||
if( ValueButton* button = static_cast<ValueButton*>( GetValue( instance, PowerlevelIndex_Report ) ) )
|
||||
{
|
||||
if( button->IsPressed() )
|
||||
{
|
||||
res = Report( instance );
|
||||
}
|
||||
button->Release();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Powerlevel::Set>
|
||||
// Set the transmit power of a node for a specified time
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Powerlevel::Set
|
||||
(
|
||||
uint8 const _instance
|
||||
)
|
||||
{
|
||||
PowerLevelEnum powerLevel;
|
||||
uint8 timeout;
|
||||
|
||||
if( ValueList* value = static_cast<ValueList*>( GetValue( _instance, PowerlevelIndex_Powerlevel ) ) )
|
||||
{
|
||||
ValueList::Item const& item = value->GetItem();
|
||||
powerLevel = (PowerLevelEnum)item.m_value;
|
||||
value->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( ValueByte* value = static_cast<ValueByte*>( GetValue( _instance, PowerlevelIndex_Timeout ) ) )
|
||||
{
|
||||
timeout = value->GetValue();
|
||||
value->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (powerLevel > 9) /* size of c_powerLevelNames minus Unknown */
|
||||
{
|
||||
Log::Write (LogLevel_Warning, GetNodeId(), "powerLevel Value was greater than range. Dropping");
|
||||
/* Drop it */
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Setting the power level to %s for %d seconds", c_powerLevelNames[powerLevel], timeout );
|
||||
Msg* msg = new Msg( "PowerlevelCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, _instance );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 4 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( PowerlevelCmd_Set );
|
||||
msg->Append( (uint8)powerLevel );
|
||||
msg->Append( timeout );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Powerlevel::Test>
|
||||
// Test node to node communications
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Powerlevel::Test
|
||||
(
|
||||
uint8 const _instance
|
||||
)
|
||||
{
|
||||
uint8 testNodeId;
|
||||
PowerLevelEnum powerLevel;
|
||||
uint16 numFrames;
|
||||
|
||||
if( ValueByte* value = static_cast<ValueByte*>( GetValue( _instance, PowerlevelIndex_TestNode ) ) )
|
||||
{
|
||||
testNodeId = value->GetValue();
|
||||
value->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( ValueList* value = static_cast<ValueList*>( GetValue( _instance, PowerlevelIndex_TestPowerlevel ) ) )
|
||||
{
|
||||
ValueList::Item const& item = value->GetItem();
|
||||
powerLevel = (PowerLevelEnum)item.m_value;
|
||||
value->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( ValueShort* value = static_cast<ValueShort*>( GetValue( _instance, PowerlevelIndex_TestFrames ) ) )
|
||||
{
|
||||
numFrames = value->GetValue();
|
||||
value->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (powerLevel > 9) /* size of c_powerLevelNames minus Unknown */
|
||||
{
|
||||
Log::Write (LogLevel_Warning, GetNodeId(), "powerLevel Value was greater than range. Dropping");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Running a Power Level Test: Target Node = %d, Power Level = %s, Number of Frames = %d", testNodeId, c_powerLevelNames[powerLevel], numFrames );
|
||||
Msg* msg = new Msg( "PowerlevelCmd_TestNodeSet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, _instance );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 6 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( PowerlevelCmd_TestNodeSet );
|
||||
msg->Append( testNodeId );
|
||||
msg->Append( (uint8)powerLevel );
|
||||
msg->Append( (uint8)(numFrames >> 8) );
|
||||
msg->Append( (uint8)(numFrames & 0x00ff) );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Powerlevel::Report>
|
||||
// Request test report
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Powerlevel::Report
|
||||
(
|
||||
uint8 const _instance
|
||||
)
|
||||
{
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Power Level Report" );
|
||||
Msg* msg = new Msg( "PowerlevelCmd_TestNodeGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, _instance );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 6 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( PowerlevelCmd_TestNodeGet );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Powerlevel::CreateVars>
|
||||
// Create the values managed by this command class
|
||||
//-----------------------------------------------------------------------------
|
||||
void Powerlevel::CreateVars
|
||||
(
|
||||
uint8 const _instance
|
||||
)
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
vector<ValueList::Item> items;
|
||||
|
||||
ValueList::Item item;
|
||||
for( uint8 i=0; i<10; ++i )
|
||||
{
|
||||
item.m_label = c_powerLevelNames[i];
|
||||
item.m_value = i;
|
||||
items.push_back( item );
|
||||
}
|
||||
|
||||
node->CreateValueList( ValueID::ValueGenre_System, GetCommandClassId(), _instance, PowerlevelIndex_Powerlevel, "Powerlevel", "dB", false, false, 1, items, 0, 0 );
|
||||
node->CreateValueByte( ValueID::ValueGenre_System, GetCommandClassId(), _instance, PowerlevelIndex_Timeout, "Timeout", "seconds", false, false, 0, 0 );
|
||||
node->CreateValueButton( ValueID::ValueGenre_System, GetCommandClassId(), _instance, PowerlevelIndex_Set, "Set Powerlevel", 0 );
|
||||
node->CreateValueByte( ValueID::ValueGenre_System, GetCommandClassId(), _instance, PowerlevelIndex_TestNode, "Test Node", "", false, false, 0, 0 );
|
||||
node->CreateValueList( ValueID::ValueGenre_System, GetCommandClassId(), _instance, PowerlevelIndex_TestPowerlevel, "Test Powerlevel", "dB", false, false, 1, items, 0, 0 );
|
||||
node->CreateValueShort( ValueID::ValueGenre_System, GetCommandClassId(), _instance, PowerlevelIndex_TestFrames, "Frame Count", "", false, false, 0, 0 );
|
||||
node->CreateValueButton( ValueID::ValueGenre_System, GetCommandClassId(), _instance, PowerlevelIndex_Test, "Test", 0 );
|
||||
node->CreateValueButton( ValueID::ValueGenre_System, GetCommandClassId(), _instance, PowerlevelIndex_Report, "Report", 0 );
|
||||
|
||||
items.clear();
|
||||
for( uint8 i=0; i<3; ++i )
|
||||
{
|
||||
item.m_label = c_powerLevelStatusNames[i];
|
||||
item.m_value = i;
|
||||
items.push_back( item );
|
||||
}
|
||||
node->CreateValueList( ValueID::ValueGenre_System, GetCommandClassId(), _instance, PowerlevelIndex_TestStatus, "Test Status", "", true, false, 1, items, 0, 0 );
|
||||
node->CreateValueShort( ValueID::ValueGenre_System, GetCommandClassId(), _instance, PowerlevelIndex_TestAckFrames, "Acked Frames", "", true, false, 0, 0 );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Powerlevel.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_POWERLEVEL
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _Powerlevel_H
|
||||
#define _Powerlevel_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class ValueList;
|
||||
|
||||
/** \brief Implements COMMAND_CLASS_POWERLEVEL (0x73), a Z-Wave device command class.
|
||||
*/
|
||||
class Powerlevel: public CommandClass
|
||||
{
|
||||
public:
|
||||
enum PowerLevelEnum
|
||||
{
|
||||
PowerLevel_Normal = 0,
|
||||
PowerLevel_Minus1dB,
|
||||
PowerLevel_Minus2dB,
|
||||
PowerLevel_Minus3dB,
|
||||
PowerLevel_Minus4dB,
|
||||
PowerLevel_Minus5dB,
|
||||
PowerLevel_Minus6dB,
|
||||
PowerLevel_Minus7dB,
|
||||
PowerLevel_Minus8dB,
|
||||
PowerLevel_Minus9dB
|
||||
};
|
||||
|
||||
enum PowerLevelStatusEnum
|
||||
{
|
||||
PowerLevelStatus_Failed = 0,
|
||||
PowerLevelStatus_Success,
|
||||
PowerLevelStatus_InProgress
|
||||
};
|
||||
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new Powerlevel( _homeId, _nodeId ); }
|
||||
virtual ~Powerlevel(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x73; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_POWERLEVEL"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual bool RequestState( uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual bool RequestValue( uint32 const _requestFlags, uint8 const _index, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
virtual bool SetValue( Value const& _value );
|
||||
|
||||
protected:
|
||||
virtual void CreateVars( uint8 const _instance );
|
||||
|
||||
private:
|
||||
Powerlevel( uint32 const _homeId, uint8 const _nodeId ): CommandClass( _homeId, _nodeId ){}
|
||||
|
||||
bool Set( uint8 const _instance );
|
||||
bool Test( uint8 const _instance );
|
||||
bool Report( uint8 const _instance );
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Proprietary.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_PROPRIETARY
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "Proprietary.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Driver.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum ProprietaryCmd
|
||||
{
|
||||
ProprietaryCmd_Set = 0x01,
|
||||
ProprietaryCmd_Get = 0x02,
|
||||
ProprietaryCmd_Report = 0x03
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Proprietary::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Proprietary::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
if (ProprietaryCmd_Report == (ProprietaryCmd)_data[0])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Proprietary.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_PROPRIETARY
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _Proprietary_H
|
||||
#define _Proprietary_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
/** \brief Implements COMMAND_CLASS_PROPRIETARY (0x88), a Z-Wave device command class.
|
||||
*/
|
||||
class Proprietary: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new Proprietary( _homeId, _nodeId ); }
|
||||
virtual ~Proprietary(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x88; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_PROPRIETARY"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
|
||||
private:
|
||||
Proprietary( uint32 const _homeId, uint8 const _nodeId ): CommandClass( _homeId, _nodeId ){}
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Protection.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_PROTECTION
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "Protection.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Node.h"
|
||||
#include "../Driver.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
#include "../value_classes/ValueList.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum ProtectionCmd
|
||||
{
|
||||
ProtectionCmd_Set = 0x01,
|
||||
ProtectionCmd_Get = 0x02,
|
||||
ProtectionCmd_Report = 0x03
|
||||
};
|
||||
|
||||
static char const* c_protectionStateNames[] =
|
||||
{
|
||||
"Unprotected",
|
||||
"Protection by Sequence",
|
||||
"No Operation Possible",
|
||||
"Unknown"
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Protection::RequestState>
|
||||
// Request current state from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Protection::RequestState
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if( _requestFlags & RequestFlag_Session )
|
||||
{
|
||||
return RequestValue( _requestFlags, 0, _instance, _queue );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Protection::RequestValue>
|
||||
// Request current value from the device
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Protection::RequestValue
|
||||
(
|
||||
uint32 const _requestFlags,
|
||||
uint8 const _dummy1, // = 0 (not used)
|
||||
uint8 const _instance,
|
||||
Driver::MsgQueue const _queue
|
||||
)
|
||||
{
|
||||
if ( IsGetSupported() )
|
||||
{
|
||||
Msg* msg = new Msg( "ProtectionCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
|
||||
msg->SetInstance( this, _instance );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 2 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( ProtectionCmd_Get );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, _queue );
|
||||
return true;
|
||||
} else {
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "ProtectionCmd_Get Not Supported on this node");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Protection::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Protection::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
if (ProtectionCmd_Report == (ProtectionCmd)_data[0])
|
||||
{
|
||||
int8 stateValue = _data[1];
|
||||
if (stateValue > 2) /* size of c_protectionStateNames minus Invalid */
|
||||
{
|
||||
Log::Write (LogLevel_Warning, GetNodeId(), "State Value was greater than range. Setting to Invalid");
|
||||
stateValue = 3;
|
||||
}
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received a Protection report: %s", c_protectionStateNames[_data[1]] );
|
||||
if( ValueList* value = static_cast<ValueList*>( GetValue( _instance, 0 ) ) )
|
||||
{
|
||||
value->OnValueRefreshed( (int)_data[1] );
|
||||
value->Release();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Protection::SetValue>
|
||||
// Set the device's protection state
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Protection::SetValue
|
||||
(
|
||||
Value const& _value
|
||||
)
|
||||
{
|
||||
if( ValueID::ValueType_List == _value.GetID().GetType() )
|
||||
{
|
||||
ValueList const* value = static_cast<ValueList const*>(&_value);
|
||||
ValueList::Item const& item = value->GetItem();
|
||||
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Protection::Set - Setting protection state to '%s'", item.m_label.c_str() );
|
||||
Msg* msg = new Msg( "Protection Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true );
|
||||
msg->SetInstance( this, _value.GetID().GetInstance() );
|
||||
msg->Append( GetNodeId() );
|
||||
msg->Append( 3 );
|
||||
msg->Append( GetCommandClassId() );
|
||||
msg->Append( ProtectionCmd_Set );
|
||||
msg->Append( (uint8)item.m_value );
|
||||
msg->Append( GetDriver()->GetTransmitOptions() );
|
||||
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <Protection::CreateVars>
|
||||
// Create the values managed by this command class
|
||||
//-----------------------------------------------------------------------------
|
||||
void Protection::CreateVars
|
||||
(
|
||||
uint8 const _instance
|
||||
)
|
||||
{
|
||||
if( Node* node = GetNodeUnsafe() )
|
||||
{
|
||||
vector<ValueList::Item> items;
|
||||
|
||||
ValueList::Item item;
|
||||
for( uint8 i=0; i<3; ++i )
|
||||
{
|
||||
item.m_label = c_protectionStateNames[i];
|
||||
item.m_value = i;
|
||||
items.push_back( item );
|
||||
}
|
||||
|
||||
node->CreateValueList( ValueID::ValueGenre_System, GetCommandClassId(), _instance, 0, "Protection", "", false, false, 1, items, 0, 0 );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Protection.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_PROTECTION
|
||||
//
|
||||
// Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _Protection_H
|
||||
#define _Protection_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class ValueList;
|
||||
|
||||
/** \brief Implements COMMAND_CLASS_PROTECTION (0x75), a Z-Wave device command class.
|
||||
*/
|
||||
class Protection: public CommandClass
|
||||
{
|
||||
public:
|
||||
enum ProtectionEnum
|
||||
{
|
||||
Protection_Unprotected = 0,
|
||||
Protection_Sequence,
|
||||
Protection_NOP
|
||||
};
|
||||
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new Protection( _homeId, _nodeId ); }
|
||||
virtual ~Protection(){}
|
||||
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x75; }
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_PROTECTION"; }
|
||||
|
||||
// From CommandClass
|
||||
virtual bool RequestState( uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual bool RequestValue( uint32 const _requestFlags, uint8 const _index, uint8 const _instance, Driver::MsgQueue const _queue );
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
virtual bool SetValue( Value const& _value );
|
||||
|
||||
protected:
|
||||
virtual void CreateVars( uint8 const _instance );
|
||||
|
||||
private:
|
||||
Protection( uint32 const _homeId, uint8 const _nodeId ): CommandClass( _homeId, _nodeId ){}
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// SceneActivation.cpp
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_SCENE_ACTIVATION
|
||||
//
|
||||
// Copyright (c) 2012 Greg Satz <satz@iranger.com>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "CommandClasses.h"
|
||||
#include "SceneActivation.h"
|
||||
#include "../Defs.h"
|
||||
#include "../Msg.h"
|
||||
#include "../Node.h"
|
||||
#include "../Driver.h"
|
||||
#include "../Notification.h"
|
||||
#include "../platform/Log.h"
|
||||
|
||||
using namespace OpenZWave;
|
||||
|
||||
enum SceneActivationCmd
|
||||
{
|
||||
SceneActivationCmd_Set = 0x01
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <SceneActivation::HandleMsg>
|
||||
// Handle a message from the Z-Wave network
|
||||
//-----------------------------------------------------------------------------
|
||||
bool SceneActivation::HandleMsg
|
||||
(
|
||||
uint8 const* _data,
|
||||
uint32 const _length,
|
||||
uint32 const _instance // = 1
|
||||
)
|
||||
{
|
||||
if( SceneActivationCmd_Set == (SceneActivationCmd)_data[0] )
|
||||
{
|
||||
// Scene Activation Set received so send notification
|
||||
char msg[64];
|
||||
if( _data[2] == 0 )
|
||||
snprintf( msg, sizeof(msg), "now" );
|
||||
else if( _data[2] <= 0x7F )
|
||||
snprintf( msg, sizeof(msg), "%d seconds", _data[2] );
|
||||
else if( _data[2] <= 0xFE )
|
||||
snprintf( msg, sizeof(msg), "%d minutes", _data[2] );
|
||||
else
|
||||
snprintf( msg, sizeof(msg), "via configuration" );
|
||||
Log::Write( LogLevel_Info, GetNodeId(), "Received Scene Activation set from node %d: scene id=%d %s. Sending event notification.", GetNodeId(), _data[1], msg );
|
||||
Notification* notification = new Notification( Notification::Type_SceneEvent );
|
||||
notification->SetHomeAndNodeIds( GetHomeId(), GetNodeId() );
|
||||
notification->SetSceneId( _data[1] );
|
||||
GetDriver()->QueueNotification( notification );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// SceneActivation.h
|
||||
//
|
||||
// Implementation of the Z-Wave COMMAND_CLASS_SCENE_ACTIVATION
|
||||
//
|
||||
// Copyright (c) 2012 Greg Satz <satz@iranger.com>
|
||||
//
|
||||
// SOFTWARE NOTICE AND LICENSE
|
||||
//
|
||||
// This file is part of OpenZWave.
|
||||
//
|
||||
// OpenZWave is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// OpenZWave is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _SceneActivation_H
|
||||
#define _SceneActivation_H
|
||||
|
||||
#include "CommandClass.h"
|
||||
|
||||
namespace OpenZWave
|
||||
{
|
||||
class ValueByte;
|
||||
|
||||
/** \brief Implements COMMAND_CLASS_SCENEACTIVATION (0x2B), a Z-Wave device command class.
|
||||
*/
|
||||
class SceneActivation: public CommandClass
|
||||
{
|
||||
public:
|
||||
static CommandClass* Create( uint32 const _homeId, uint8 const _nodeId ){ return new SceneActivation( _homeId, _nodeId ); }
|
||||
virtual ~SceneActivation(){}
|
||||
|
||||
/** \brief Get command class ID (1 byte) identifying this command class. */
|
||||
static uint8 const StaticGetCommandClassId(){ return 0x2B; }
|
||||
/** \brief Get a string containing the name of this command class. */
|
||||
static string const StaticGetCommandClassName(){ return "COMMAND_CLASS_SCENE_ACTIVATION"; }
|
||||
|
||||
// From CommandClass
|
||||
/** \brief Get command class ID (1 byte) identifying this command class. (Inherited from CommandClass) */
|
||||
virtual uint8 const GetCommandClassId()const{ return StaticGetCommandClassId(); }
|
||||
/** \brief Get a string containing the name of this command class. (Inherited from CommandClass) */
|
||||
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
|
||||
/** \brief Handle a response to a message associated with this command class. (Inherited from CommandClass) */
|
||||
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
|
||||
|
||||
private:
|
||||
SceneActivation( uint32 const _homeId, uint8 const _nodeId ): CommandClass( _homeId, _nodeId ){}
|
||||
};
|
||||
|
||||
} // namespace OpenZWave
|
||||
|
||||
#endif
|
||||
Loaded 100 of 1030 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user