Commit 640a131b authored by luz's avatar luz

EnOcean Buttons: Added profile variant for dual rocker button F6-02-xx and...

EnOcean Buttons: Added profile variant for dual rocker button F6-02-xx and F6-03-xx to use each up and down button as separate device.

- previously unused MSB of 32-bit EEP is now defined as VARIANT, to allow for varying interpretations of the same EEP.

- single button variant of F6-02-xx is 01-F6-02-xx

- the single button variant would also work for 4-rocker switches (01-F6-03-xx), but for now we do not offer profile switching for those. 
parent 6cc79576
......@@ -45,7 +45,7 @@ namespace p44 {
/// factory: (re-)create logical device from address|channel|profile|manufacturer tuple
/// @param aClassContainerP the class container
/// @param aSubDeviceIndex subdevice number to create (multiple logical EnoceanDevices might exists for the same EnoceanAddress)
/// @param aEEProfile RORG/FUNC/TYPE EEP profile number
/// @param aEEProfile VARIANT/RORG/FUNC/TYPE EEP profile number
/// @param aEEManufacturer manufacturer number (or manufacturer_unknown)
/// @param aSendTeachInResponse enable sending teach-in response for this device
/// @return returns NULL if no device can be created for the given aSubDeviceIndex, new device otherwise
......
......@@ -70,7 +70,7 @@ void Enocean4BSDevice::sendTeachInResponse()
// set destination
responsePacket->setRadioDestination(getAddress());
// now send
LOG(LOG_INFO, "Sending 4BS teach-in response for EEP %06X\n", getEEProfile());
LOG(LOG_INFO, "Sending 4BS teach-in response for EEP %06X\n", EEP_PURE(getEEProfile()));
getEnoceanDeviceContainer().enoceanComm.sendPacket(responsePacket);
}
}
......
......@@ -110,7 +110,7 @@ namespace p44 {
/// factory: (re-)create logical device from address|channel|profile|manufacturer tuple
/// @param aClassContainerP the class container
/// @param aSubDeviceIndex subdevice number to create (multiple logical EnoceanDevices might exists for the same EnoceanAddress)
/// @param aEEProfile RORG/FUNC/TYPE EEP profile number
/// @param aEEProfile VARIANT/RORG/FUNC/TYPE EEP profile number
/// @param aEEManufacturer manufacturer number (or manufacturer_unknown)
/// @param aSendTeachInResponse enable sending teach-in response for this device
/// @return returns NULL if no device can be created for the given aSubDeviceIndex, new device otherwise
......@@ -179,7 +179,7 @@ namespace p44 {
/// factory: (re-)create logical device from address|channel|profile|manufacturer tuple
/// @param aClassContainerP the class container
/// @param aSubDeviceIndex subdevice number to create (multiple logical EnoceanDevices might exists for the same EnoceanAddress)
/// @param aEEProfile RORG/FUNC/TYPE EEP profile number
/// @param aEEProfile VARIANT/RORG/FUNC/TYPE EEP profile number
/// @param aEEManufacturer manufacturer number (or manufacturer_unknown)
/// @param aSendTeachInResponse enable sending teach-in response for this device
/// @return returns NULL if no device can be created for the given aSubDeviceIndex, new device otherwise
......@@ -231,7 +231,7 @@ namespace p44 {
/// factory: (re-)create logical device from address|channel|profile|manufacturer tuple
/// @param aClassContainerP the class container
/// @param aSubDeviceIndex subdevice number to create (multiple logical EnoceanDevices might exists for the same EnoceanAddress)
/// @param aEEProfile RORG/FUNC/TYPE EEP profile number
/// @param aEEProfile VARIANT/RORG/FUNC/TYPE EEP profile number
/// @param aEEManufacturer manufacturer number (or manufacturer_unknown)
/// @param aSendTeachInResponse enable sending teach-in response for this device
/// @return returns NULL if no device can be created for the given aSubDeviceIndex, new device otherwise
......
......@@ -78,12 +78,15 @@ namespace p44 {
const EepFunc eep_func_unknown = 0xFF;
const EepType eep_type_unknown = 0xFF;
const EnoceanProfile eep_profile_unknown = (rorg_invalid<<16) + (eep_func_unknown<<8) + eep_type_unknown;
const EnoceanProfile eep_ignore_type_mask = 0xFFFF00;
// EEP access macros
#define EEP_RORG(eep) ((RadioOrg)(((EnoceanProfile)eep>>16)&0xFF))
#define EEP_FUNC(eep) ((EepFunc)(((EnoceanProfile)eep>>8)&0xFF))
#define EEP_TYPE(eep) ((EepType)((EnoceanProfile)eep&0xFF))
#define EEP_UNTYPED(eep) (eep&0xFFFFFF00) // VARIANT/RORG/FUNC only
// - MSB of 32bit value can be used for profile variants (internal differentiation)
#define EEP_VARIANT(eep) ((EepType)(((EnoceanProfile)eep>>24)&0xFF)) // variant byte
#define EEP_PURE(eep) (eep&0xFFFFFF) // pure EEP, without variant byte
// learn bit
#define LRN_BIT_MASK 0x08 // Bit 3, Byte 0 (4th data byte)
......
......@@ -117,7 +117,7 @@ void EnoceanDevice::deriveDsUid()
DsUid enOceanNamespace(DSUID_ENOCEAN_NAMESPACE_UUID);
string s = string_format("%08lX", getAddress()); // base address comes from
dSUID.setNameInSpace(s, enOceanNamespace);
dSUID.setSubdeviceIndex(getSubDevice()*2); // historically space subdevices in double steps, to (theoretically) allow vdsm to split them (rocker switches) further. Kept this way to prevent existing dSUIDs to change
dSUID.setSubdeviceIndex(getSubDevice()*dsUIDIndexStep()); // historically space subdevices in double steps, to (theoretically) allow vdsm to split them (rocker switches) further. Kept this way to prevent existing dSUIDs to change
}
......@@ -129,7 +129,7 @@ string EnoceanDevice::hardwareGUID()
string EnoceanDevice::hardwareModelGUID()
{
return string_format("enoceaneep:%06lX", getEEProfile());
return string_format("enoceaneep:%06lX", EEP_PURE(getEEProfile()));
}
......@@ -306,13 +306,14 @@ string EnoceanDevice::description()
string_format_append(s, "- Enocean Address = 0x%08lX, subDevice=%d\n", enoceanAddress, subDevice);
const char *mn = EnoceanComm::manufacturerName(eeManufacturer);
string_format_append(s,
"- %s, EEP RORG/FUNC/TYPE: %02X %02X %02X, Manufacturer = %s (%03X)\n",
"- %s, EEP RORG/FUNC/TYPE: %02X %02X %02X, Manufacturer: %s (%03X), Profile variant: %02X\n",
eeFunctionDesc.c_str(),
(eeProfile>>16) & 0xFF,
(eeProfile>>8) & 0xFF,
eeProfile & 0xFF,
EEP_RORG(eeProfile),
EEP_FUNC(eeProfile),
EEP_TYPE(eeProfile),
mn ? mn : "<unknown>",
eeManufacturer
eeManufacturer,
EEP_VARIANT(eeProfile)
);
// show channels
for (EnoceanChannelHandlerVector::iterator pos = channels.begin(); pos!=channels.end(); ++pos) {
......
......@@ -143,7 +143,7 @@ namespace p44 {
/// factory: (re-)create logical device from address|channel|profile|manufacturer tuple
/// @param aAddress 32bit enocean device address/ID
/// @param aSubDeviceIndex subdevice number (multiple logical EnoceanDevices might exists for the same EnoceanAddress)
/// @param aEEProfile RORG/FUNC/TYPE EEP profile number
/// @param aEEProfile VARIANT/RORG/FUNC/TYPE EEP profile number
/// @param aEEManufacturer manufacturer number (or manufacturer_unknown)
/// @param aSendTeachInResponse if this is set, a teach-in response will be sent for profiles that need one
/// (This is set to false when re-creating logical devices from DB)
......@@ -211,8 +211,12 @@ namespace p44 {
/// @return EnOcean device ID/address
EnoceanSubDevice getSubDevice();
/// @return step between dSUID subdevice indices
virtual uint8_t dsUIDIndexStep() { return 1; };
/// set EEP information
/// @param aEEProfile RORG/FUNC/TYPE EEP profile number
/// @param aEEProfile VARIANT/RORG/FUNC/TYPE EEP profile number
/// @param aEEManufacturer manufacturer number (or manufacturer_unknown)
virtual void setEEPInfo(EnoceanProfile aEEProfile, EnoceanManufacturer aEEManufacturer);
......@@ -222,7 +226,7 @@ namespace p44 {
void setFunctionDesc(string aString) { eeFunctionDesc = aString; };
/// @return RORG/FUNC/TYPE EEP profile number
/// @return VARIANT/RORG/FUNC/TYPE EEP profile number with optional variant (MSB of 32bit value)
EnoceanProfile getEEProfile();
/// @return manufacturer code
......
......@@ -154,7 +154,7 @@ void EnoceanDeviceContainer::collectDevices(CompletedCB aCompletedCB, bool aIncr
}
else {
LOG(LOG_ERR,
"EnOcean device could not be created for addr=%08X, subdevice=%d, profile=%06X, manufacturer=%d",
"EnOcean device could not be created for addr=%08X, subdevice=%d, profile=%08X, manufacturer=%d",
i->get<int>(0), i->get<int>(1), // address / subdevice
i->get<int>(2), i->get<int>(3) // profile / manufacturer
);
......
......@@ -36,8 +36,9 @@ using namespace p44;
#pragma mark - EnoceanRPSDevice
EnoceanRPSDevice::EnoceanRPSDevice(EnoceanDeviceContainer *aClassContainerP) :
inherited(aClassContainerP)
EnoceanRPSDevice::EnoceanRPSDevice(EnoceanDeviceContainer *aClassContainerP, uint8_t aDsuidIndexStep) :
inherited(aClassContainerP),
dsuidIndexStep(aDsuidIndexStep)
{
}
......@@ -58,45 +59,80 @@ EnoceanDevicePtr EnoceanRpsHandler::newDevice(
bool aNeedsTeachInResponse
) {
EnoceanDevicePtr newDev; // none so far
EnoceanProfile functionProfile = aEEProfile & eep_ignore_type_mask;
if (functionProfile==0xF60200 || functionProfile==0xF60300) {
// F6-02-xx or F6-03-xx: 2 or 4 rocker switch = max 2 or 4 dsDevices
EnoceanSubDevice numSubDevices = functionProfile==0xF60300 ? 4 : 2;
if (aSubDeviceIndex<numSubDevices) {
// create EnoceanRPSDevice device
newDev = EnoceanDevicePtr(new EnoceanRPSDevice(aClassContainerP));
// standard device settings without scene table
newDev->installSettings();
// assign channel and address
newDev->setAddressingInfo(aAddress, aSubDeviceIndex);
// assign EPP information
newDev->setEEPInfo(aEEProfile, aEEManufacturer);
newDev->setFunctionDesc("rocker switch");
// set icon name: even-numbered subdevice is left, odd is right
newDev->setIconInfo(aSubDeviceIndex & 0x01 ? "enocean_br" : "enocean_bl", true);
// RPS switches can be used for anything
newDev->setPrimaryGroup(group_black_joker);
// Create two handlers, one for the up button, one for the down button
// - create button input for down key
EnoceanRpsButtonHandlerPtr downHandler = EnoceanRpsButtonHandlerPtr(new EnoceanRpsButtonHandler(*newDev.get()));
downHandler->switchIndex = aSubDeviceIndex; // each switch gets its own subdevice
downHandler->isRockerUp = false;
ButtonBehaviourPtr downBhvr = ButtonBehaviourPtr(new ButtonBehaviour(*newDev.get()));
downBhvr->setHardwareButtonConfig(0, buttonType_2way, buttonElement_down, false, 1); // counterpart up-button has index 1
downBhvr->setGroup(group_yellow_light); // pre-configure for light
downBhvr->setHardwareName("down key");
downHandler->behaviour = downBhvr;
newDev->addChannelHandler(downHandler);
// - create button input for up key
EnoceanRpsButtonHandlerPtr upHandler = EnoceanRpsButtonHandlerPtr(new EnoceanRpsButtonHandler(*newDev.get()));
upHandler->switchIndex = aSubDeviceIndex; // each switch gets its own subdevice
upHandler->isRockerUp = true;
ButtonBehaviourPtr upBhvr = ButtonBehaviourPtr(new ButtonBehaviour(*newDev.get()));
upBhvr->setGroup(group_yellow_light); // pre-configure for light
upBhvr->setHardwareButtonConfig(0, buttonType_2way, buttonElement_up, false, 0); // counterpart down-button has index 0
upBhvr->setHardwareName("up key");
upHandler->behaviour = upBhvr;
newDev->addChannelHandler(upHandler);
EnoceanProfile functionProfile = EEP_UNTYPED(aEEProfile);
if (EEP_PURE(functionProfile)==0xF60200 || EEP_PURE(functionProfile)==0xF60300) {
// F6-02-xx or F6-03-xx: 2 or 4 rocker switch
// - we have the standard rocker variant (0) or the separate buttons variant (1)
if (EEP_VARIANT(aEEProfile)==1) {
// Custom variant: up and down are treated as separate buttons -> max 4 or 8 dsDevices
EnoceanSubDevice numSubDevices = functionProfile==0xF60300 ? 8 : 4;
if (aSubDeviceIndex<numSubDevices) {
// create EnoceanRPSDevice device
newDev = EnoceanDevicePtr(new EnoceanRPSDevice(aClassContainerP));
// standard device settings without scene table
newDev->installSettings();
// assign channel and address
newDev->setAddressingInfo(aAddress, aSubDeviceIndex);
// assign EPP information
newDev->setEEPInfo(aEEProfile, aEEManufacturer);
newDev->setFunctionDesc("button");
// set icon name: 4-rocker have a generic icon, 2-rocker have the 4btn icon in separated mode
newDev->setIconInfo(numSubDevices==8 ? "enocean_4rkr" : "enocean_4btn", true);
// RPS switches can be used for anything
newDev->setPrimaryGroup(group_black_joker);
// Create single handler, up button for even aSubDevice, down button for odd aSubDevice
bool isUp = (aSubDeviceIndex & 0x01)==0;
EnoceanRpsButtonHandlerPtr buttonHandler = EnoceanRpsButtonHandlerPtr(new EnoceanRpsButtonHandler(*newDev.get()));
buttonHandler->switchIndex = aSubDeviceIndex>>1; // each switch HALF has its own subdevice
buttonHandler->isRockerUp = isUp;
ButtonBehaviourPtr buttonBhvr = ButtonBehaviourPtr(new ButtonBehaviour(*newDev.get()));
buttonBhvr->setHardwareButtonConfig(0, buttonType_2way, isUp ? buttonElement_up : buttonElement_down, false, isUp ? 0 : 1);
buttonBhvr->setGroup(group_yellow_light); // pre-configure for light
buttonBhvr->setHardwareName(isUp ? "Up key" : "Down key");
buttonHandler->behaviour = buttonBhvr;
newDev->addChannelHandler(buttonHandler);
}
}
else {
// Standard: Up+Down together form a 2-way rocker -> max 2 or 4 dsDevices
EnoceanSubDevice numSubDevices = functionProfile==0xF60300 ? 4 : 2;
if (aSubDeviceIndex<numSubDevices) {
// create EnoceanRPSDevice device
// - 2-way rocker switches use indices 0,2,4,6,... to leave room for separate button mode between
newDev = EnoceanDevicePtr(new EnoceanRPSDevice(aClassContainerP, 2));
// standard device settings without scene table
newDev->installSettings();
// assign channel and address
newDev->setAddressingInfo(aAddress, aSubDeviceIndex);
// assign EPP information
newDev->setEEPInfo(aEEProfile, aEEManufacturer);
newDev->setFunctionDesc("rocker switch");
// set icon name: generic 4-rocker or for 2-rocker: even-numbered subdevice is left, odd is right
newDev->setIconInfo(numSubDevices==4 ? "enocean_4rkr" : (aSubDeviceIndex & 0x01 ? "enocean_br" : "enocean_bl"), true);
// RPS switches can be used for anything
newDev->setPrimaryGroup(group_black_joker);
// Create two handlers, one for the up button, one for the down button
// - create button input for down key
EnoceanRpsButtonHandlerPtr downHandler = EnoceanRpsButtonHandlerPtr(new EnoceanRpsButtonHandler(*newDev.get()));
downHandler->switchIndex = aSubDeviceIndex; // each switch gets its own subdevice
downHandler->isRockerUp = false;
ButtonBehaviourPtr downBhvr = ButtonBehaviourPtr(new ButtonBehaviour(*newDev.get()));
downBhvr->setHardwareButtonConfig(0, buttonType_2way, buttonElement_down, false, 1); // counterpart up-button has index 1
downBhvr->setGroup(group_yellow_light); // pre-configure for light
downBhvr->setHardwareName("down key");
downHandler->behaviour = downBhvr;
newDev->addChannelHandler(downHandler);
// - create button input for up key
EnoceanRpsButtonHandlerPtr upHandler = EnoceanRpsButtonHandlerPtr(new EnoceanRpsButtonHandler(*newDev.get()));
upHandler->switchIndex = aSubDeviceIndex; // each switch gets its own subdevice
upHandler->isRockerUp = true;
ButtonBehaviourPtr upBhvr = ButtonBehaviourPtr(new ButtonBehaviour(*newDev.get()));
upBhvr->setGroup(group_yellow_light); // pre-configure for light
upBhvr->setHardwareButtonConfig(0, buttonType_2way, buttonElement_up, false, 0); // counterpart down-button has index 0
upBhvr->setHardwareName("up key");
upHandler->behaviour = upBhvr;
newDev->addChannelHandler(upHandler);
}
}
}
else if (functionProfile==0xF61000) {
......@@ -531,14 +567,15 @@ typedef struct {
const char *description;
} profileVariantEntry;
static const int numRPSprofileVariants = 6;
static const int numRPSprofileVariants = 7;
static const profileVariantEntry RPSprofileVariants[numRPSprofileVariants] = {
{ 0xF602FF, "dual rocker switch" },
{ 0xF60401, "key card activated switch ERP1" },
{ 0xF60402, "key card activated switch ERP2" },
{ 0xF604C0, "key card switch FKC/FKF" },
{ 0xF60501, "Liquid Leakage detector" },
{ 0xF605C0, "Smoke detector FRW/GUARD" }
{ 0x00F602FF, "dual rocker switch (as 2-way rockers)" },
{ 0x01F602FF, "dual rocker switch (as 4 separate buttons)" },
{ 0x00F60401, "key card activated switch ERP1" },
{ 0x00F60402, "key card activated switch ERP2" },
{ 0x00F604C0, "key card switch FKC/FKF" },
{ 0x00F60501, "Liquid Leakage detector" },
{ 0x00F605C0, "Smoke detector FRW/GUARD" }
};
......
......@@ -46,7 +46,7 @@ namespace p44 {
/// factory: (re-)create logical device from address|channel|profile|manufacturer tuple
/// @param aClassContainerP the class container
/// @param aSubDeviceIndex subdevice number to create (multiple logical EnoceanDevices might exists for the same EnoceanAddress)
/// @param aEEProfile RORG/FUNC/TYPE EEP profile number
/// @param aEEProfile VARIANT/RORG/FUNC/TYPE EEP profile number
/// @param aEEManufacturer manufacturer number (or manufacturer_unknown)
/// @param aSendTeachInResponse enable sending teach-in response for this device
/// @return returns NULL if no device can be created for the given aSubDeviceIndex, new device otherwise
......@@ -196,10 +196,13 @@ namespace p44 {
{
typedef EnoceanDevice inherited;
uint8_t dsuidIndexStep; ///< the step between dSUID indices for subdevices
public:
/// constructor
EnoceanRPSDevice(EnoceanDeviceContainer *aClassContainerP);
/// @param aDsuidIndexStep step between dSUID subdevice indices (default is 1, historically 2 for dual 2-way rocker switches)
EnoceanRPSDevice(EnoceanDeviceContainer *aClassContainerP, uint8_t aDsuidIndexStep = 1);
/// device type identifier
/// @return constant identifier for this type of device (one container might contain more than one type)
......@@ -214,6 +217,9 @@ namespace p44 {
/// @return true if profile variant is valid and can be set
virtual bool setProfileVariant(EnoceanProfile aProfile);
/// @return step between dSUID subdevice indices
virtual uint8_t dsUIDIndexStep() { return dsuidIndexStep; };
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment