blob: 37800de3d15ecb82f33d064a956e467946c955e8 [file] [log] [blame]
/**
*
* Copyright (c) 2020 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* Copyright (c) 2020 Silicon Labs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/***************************************************************************//**
* @file
* @brief Unit test for barrier-control-server plugin.
*******************************************************************************
******************************************************************************/
#include "af.h"
#include "barrier-control-server.h"
#include "app/framework/test/script/afv2-scripted.h"
// -----------------------------------------------------------------------------
// Utilities
// -------------------------------------
// getAttribute Check
static long getAttribute(EmberAfAttributeId attributeId)
{
unsigned long data = 0;
EmberAfStatus status = emberAfReadServerAttribute(1, // endpoint
ZCL_BARRIER_CONTROL_CLUSTER_ID,
attributeId,
(uint8_t *)&data,
1); // ignored in stub below
assert(status == EMBER_ZCL_STATUS_SUCCESS);
return data;
}
#define addGetAttributeCheck(attributeId, value) \
addFunctionCheck("getAttribute(%d)", \
(value), \
getAttribute, \
1, \
(attributeId))
// -------------------------------------
// goToPercent Action
PERFORMER(goToPercent)
{
// Generated by AppBuilder from Barrier Control cluster XML.
extern bool emberAfBarrierControlClusterBarrierControlGoToPercentCallback(uint8_t);
uint8_t percentOpen = (uint8_t)action->contents[0];
scriptAssert(action,
emberAfBarrierControlClusterBarrierControlGoToPercentCallback(percentOpen));
}
PRINTER(goToPercent)
{
uint8_t percentOpen = (uint8_t)action->contents[0];
fprintf(stderr, "Move barrier to %d%%", percentOpen);
}
ACTION(goToPercent, i);
#define addGoToPercentAction(percentOpen) \
addAction(&goToPercentActionType, (percentOpen))
// -------------------------------------
// stop Action
PERFORMER(stop)
{
// Generated by AppBuilder from Barrier Control cluster XML.
extern bool emberAfBarrierControlClusterBarrierControlStopCallback(void);
scriptAssert(action,
emberAfBarrierControlClusterBarrierControlStopCallback());
}
PRINTER(stop)
{
fprintf(stderr, "Stop barrier movement");
}
ACTION(stop, i); // added one fake integer parameter to please preprocessor
#define addStopAction() addAction(&stopActionType)
// -------------------------------------
// defaultResponse Check
EmberStatus emberAfSendImmediateDefaultResponse(EmberAfStatus status)
{
functionCallCheck("emberAfSendImmediateDefaultResponse", "i", status);
return EMBER_SUCCESS;
}
#define addDefaultResponseCheck(status) \
addSimpleCheck("emberAfSendImmediateDefaultResponse", \
"i", \
(status))
// -------------------------------------
// initialState Check
// The BarrierPosition attribute should be closed to start and the MovingState
// attribute should be set to STOPPED.
#define addInitialStateCheck() \
addGetAttributeCheck(ZCL_BARRIER_POSITION_ATTRIBUTE_ID, \
EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_CLOSED); \
addGetAttributeCheck(ZCL_BARRIER_MOVING_STATE_ATTRIBUTE_ID, \
EMBER_ZCL_BARRIER_CONTROL_MOVING_STATE_STOPPED);
// -------------------------------------
// setRemoteLockout Action
static void setRemoteLockout(bool set)
{
uint16_t remoteLockoutBit
= (set
? EMBER_AF_BARRIER_CONTROL_SAFETY_STATUS_REMOTE_LOCKOUT
: 0);
assert(emberAfWriteServerAttribute(1, // endpoint
ZCL_BARRIER_CONTROL_CLUSTER_ID,
ZCL_BARRIER_SAFETY_STATUS_ATTRIBUTE_ID,
(uint8_t *)&remoteLockoutBit,
ZCL_BITMAP16_ATTRIBUTE_TYPE)
== EMBER_ZCL_STATUS_SUCCESS);
}
#define addSetRemoteLockoutAction(set) \
addSimpleAction("setRemoteLockout(%ld)", setRemoteLockout, 1, (set))
// --------------------------------------
// openCloseEvents Action
static void setOpenCloseEvents(uint16_t openEvents,
uint16_t closeEvents,
uint16_t commandOpenEvents,
uint16_t commandCloseEvents)
{
uint16_t *values[] = {
&openEvents, // ZCL_BARRIER_OPEN_EVENTS_ATTRIBUTE_ID
&closeEvents, // ZCL_BARRIER_CLOSE_EVENTS_ATTRIBUTE_ID
&commandOpenEvents, // ZCL_BARRIER_COMMAND_OPEN_EVENTS_ATTRIBUTE_ID
&commandCloseEvents, // ZCL_BARRIER_COMMAND_CLOSE_EVENTS_ATTRIBUTE_ID
NULL,
};
EmberAfAttributeId attributeId = ZCL_BARRIER_OPEN_EVENTS_ATTRIBUTE_ID;
for (uint16_t *value = values[0]; value != NULL; value++, attributeId++) {
assert(emberAfWriteServerAttribute(1, // endpoint
ZCL_BARRIER_CONTROL_CLUSTER_ID,
attributeId,
(uint8_t *)value,
ZCL_INT16U_ATTRIBUTE_TYPE)
== EMBER_ZCL_STATUS_SUCCESS);
}
}
#define addSetOpenCloseEventsAction(openEvents, \
closeEvents, \
commandOpenEvents, \
commandCloseEvents) \
addSimpleAction("setOpenCloseEvents(%ld, %ld, %ld, %ld)", \
setOpenCloseEvents, \
4, \
(openEvents), \
(closeEvents), \
(commandOpenEvents), \
(commandCloseEvents))
// --------------------------------------
// openCloseEvents Check
#define addOpenCloseEventsCheck(openEvents, \
closeEvents, \
commandOpenEvents, \
commandCloseEvents) \
addGetAttributeCheck(ZCL_BARRIER_OPEN_EVENTS_ATTRIBUTE_ID, \
(openEvents)); \
addGetAttributeCheck(ZCL_BARRIER_CLOSE_EVENTS_ATTRIBUTE_ID, \
(closeEvents)); \
addGetAttributeCheck(ZCL_BARRIER_COMMAND_OPEN_EVENTS_ATTRIBUTE_ID, \
(commandOpenEvents)); \
addGetAttributeCheck(ZCL_BARRIER_COMMAND_CLOSE_EVENTS_ATTRIBUTE_ID, \
(commandCloseEvents)); \
// -------------------------------------
// setPartialBarrier Action
static void setPartialBarrier(bool set)
{
uint8_t partialBarrierBit
= (set
? EMBER_AF_BARRIER_CONTROL_CAPABILITIES_PARTIAL_BARRIER
: 0);
assert(emberAfWriteServerAttribute(1, // endpoint
ZCL_BARRIER_CONTROL_CLUSTER_ID,
ZCL_BARRIER_CAPABILITIES_ATTRIBUTE_ID,
(uint8_t *)&partialBarrierBit,
ZCL_BITMAP8_ATTRIBUTE_TYPE)
== EMBER_ZCL_STATUS_SUCCESS);
}
#define addSetPartialBarrierBitAction(set) \
addSimpleAction("setPartialBarrier(%ld)", setPartialBarrier, 1, (set))
// -----------------------------------------------------------------------------
// Tests
// -------------------------------------
// Open Tests
static void reallyOpenTest(bool partialBarrier)
{
addInitialStateCheck();
runScript();
// Set/clear the partial barrier bit depending on what test we are running.
addSetPartialBarrierBitAction(partialBarrier);
addGetAttributeCheck(ZCL_BARRIER_CAPABILITIES_ATTRIBUTE_ID,
(partialBarrier
? EMBER_AF_BARRIER_CONTROL_CAPABILITIES_PARTIAL_BARRIER
: 0));
runScript();
// If we get a percent higher than 100, we send back INVALID_VALUE.
addGoToPercentAction(101);
addDefaultResponseCheck(EMBER_ZCL_STATUS_INVALID_VALUE);
runScript();
// If we get a percent that is not 0 or 100 and we do not have the
// PartialBarrier bit set in the Capabilities attribute, then we send back
// INVALID_VALUE.
addGoToPercentAction(50);
addDefaultResponseCheck((partialBarrier
? EMBER_ZCL_STATUS_SUCCESS
: EMBER_ZCL_STATUS_INVALID_VALUE));
addRunAction(51 * MIN_POSITION_CHANGE_DELAY_MS);
addGetAttributeCheck(ZCL_BARRIER_POSITION_ATTRIBUTE_ID,
(partialBarrier
? 50
: EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_CLOSED));
runScript();
// Reset the barrier to closed.
addGoToPercentAction(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_CLOSED);
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(101 * MIN_POSITION_CHANGE_DELAY_MS);
addInitialStateCheck();
runScript();
// We are closed right now, so if we receive an open, we should open the door.
addGoToPercentAction(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_OPEN);
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(50 * MIN_POSITION_CHANGE_DELAY_MS);
// Halfway through the opening of the door if we read the Position attribute,
// we will get an invalid value because the PartialBarrier bit is note set in
// the Capabilities attribute...sure. Also, the MovingState attribute should
// be set appropriately.
addGetAttributeCheck(ZCL_BARRIER_POSITION_ATTRIBUTE_ID,
(partialBarrier
? 50
: EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_UNKNOWN));
addGetAttributeCheck(ZCL_BARRIER_MOVING_STATE_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_MOVING_STATE_OPENING);
addRunAction(51 * MIN_POSITION_CHANGE_DELAY_MS);
addGetAttributeCheck(ZCL_BARRIER_POSITION_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_OPEN);
runScript();
// Once the door is opened, the MovingState attribute should go back to
// STOPPED.
addGetAttributeCheck(ZCL_BARRIER_MOVING_STATE_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_MOVING_STATE_STOPPED);
runScript();
// If we try to open the door again, we should just stay at open.
addGoToPercentAction(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_OPEN);
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(1 * MIN_POSITION_CHANGE_DELAY_MS);
addGetAttributeCheck(ZCL_BARRIER_POSITION_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_OPEN);
addRunAction(1 * MIN_POSITION_CHANGE_DELAY_MS);
addGetAttributeCheck(ZCL_BARRIER_POSITION_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_OPEN);
runScript();
// Let's close the door again, for fun.
addGoToPercentAction(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_CLOSED);
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(101 * MIN_POSITION_CHANGE_DELAY_MS);
addGetAttributeCheck(ZCL_BARRIER_POSITION_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_CLOSED);
runScript();
}
static void openTest(void)
{
reallyOpenTest(false); // PartialBarrier bit of Capabilities attribute is off
}
static void openPartialBarrierTest(void)
{
reallyOpenTest(true); // PartialBarrier bit of Capabilities attribute is on
}
// -------------------------------------
// Close Tests
static void reallyCloseTest(bool partialBarrier)
{
addInitialStateCheck();
runScript();
// Set/clear the partial barrier bit depending on what test we are running.
addSetPartialBarrierBitAction(partialBarrier);
addGetAttributeCheck(ZCL_BARRIER_CAPABILITIES_ATTRIBUTE_ID,
(partialBarrier
? EMBER_AF_BARRIER_CONTROL_CAPABILITIES_PARTIAL_BARRIER
: 0));
runScript();
// If we try to close the door again, we should just stay at close.
addGoToPercentAction(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_CLOSED);
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(1);
addGetAttributeCheck(ZCL_BARRIER_POSITION_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_CLOSED);
addRunAction(1);
addGetAttributeCheck(ZCL_BARRIER_POSITION_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_CLOSED);
runScript();
// Open the door and then close it all the way.
addGoToPercentAction(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_OPEN);
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(101 * MIN_POSITION_CHANGE_DELAY_MS);
addGetAttributeCheck(ZCL_BARRIER_POSITION_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_OPEN);
addGoToPercentAction(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_CLOSED);
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(50 * MIN_POSITION_CHANGE_DELAY_MS);
// Halfway through the closing of the door if we read the Position attribute,
// we will get an invalid value because the PartialBarrier bit is not set in
// the Capabilities attribute...sure. Also, the MovingState attribute should
// be set appropriately.
addGetAttributeCheck(ZCL_BARRIER_POSITION_ATTRIBUTE_ID,
(partialBarrier
? 50
: EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_UNKNOWN));
addGetAttributeCheck(ZCL_BARRIER_MOVING_STATE_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_MOVING_STATE_CLOSING);
addRunAction(51 * MIN_POSITION_CHANGE_DELAY_MS);
addGetAttributeCheck(ZCL_BARRIER_POSITION_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_CLOSED);
// Once the door is opened, the MovingState attribute should go back to
// STOPPED.
addGetAttributeCheck(ZCL_BARRIER_MOVING_STATE_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_MOVING_STATE_STOPPED);
runScript();
// If we try to close the door again, we should just stay at close.
addGoToPercentAction(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_CLOSED);
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(1 * MIN_POSITION_CHANGE_DELAY_MS);
addGetAttributeCheck(ZCL_BARRIER_POSITION_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_CLOSED);
addRunAction(1 * MIN_POSITION_CHANGE_DELAY_MS);
addGetAttributeCheck(ZCL_BARRIER_POSITION_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_CLOSED);
runScript();
// Let's open the door again, for fun.
addGoToPercentAction(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_OPEN);
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(101 * MIN_POSITION_CHANGE_DELAY_MS);
addGetAttributeCheck(ZCL_BARRIER_POSITION_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_OPEN);
runScript();
}
static void closeTest(void)
{
reallyCloseTest(false); // PartialBarrier bit of Capabilities attribute is off
}
static void closePartialBarrierTest(void)
{
reallyCloseTest(true); // PartialBarrier bit of Capabilities attribute is on
}
// --------------------------------------
// Stop Tests
static void reallyStopTest(bool partialBarrier)
{
addInitialStateCheck();
runScript();
// Set/clear the partial barrier bit depending on what test we are running.
addSetPartialBarrierBitAction(partialBarrier);
addGetAttributeCheck(ZCL_BARRIER_CAPABILITIES_ATTRIBUTE_ID,
(partialBarrier
? EMBER_AF_BARRIER_CONTROL_CAPABILITIES_PARTIAL_BARRIER
: 0));
runScript();
// Start to open the door, and then stop midway. The door should remain at the
// stopped position. The BarrierPosition attribute returns 0xFF, since the
// PartialBarrier bit in the Capabilities attribute is not set.
addGoToPercentAction(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_OPEN);
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(50 * MIN_POSITION_CHANGE_DELAY_MS);
addGetAttributeCheck(ZCL_BARRIER_MOVING_STATE_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_MOVING_STATE_OPENING);
addStopAction();
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(51 * MIN_POSITION_CHANGE_DELAY_MS);
addGetAttributeCheck(ZCL_BARRIER_POSITION_ATTRIBUTE_ID,
(partialBarrier
? 50
: EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_UNKNOWN));
addGetAttributeCheck(ZCL_BARRIER_MOVING_STATE_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_MOVING_STATE_STOPPED);
runScript();
// Start the opening of the barrier again. It should open up fully.
addGoToPercentAction(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_OPEN);
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(101 * MIN_POSITION_CHANGE_DELAY_MS);
addGetAttributeCheck(ZCL_BARRIER_POSITION_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_OPEN);
addGetAttributeCheck(ZCL_BARRIER_MOVING_STATE_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_MOVING_STATE_STOPPED);
runScript();
// Start to close the door, and then stop midway. The door should remain at the
// stopped position. The BarrierPosition attribute returns 0xFF, since the
// PartialBarrier bit in the Capabilities attribute is not set.
addGoToPercentAction(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_CLOSED);
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(50 * MIN_POSITION_CHANGE_DELAY_MS);
addGetAttributeCheck(ZCL_BARRIER_MOVING_STATE_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_MOVING_STATE_CLOSING);
addStopAction();
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(51 * MIN_POSITION_CHANGE_DELAY_MS);
addGetAttributeCheck(ZCL_BARRIER_POSITION_ATTRIBUTE_ID,
(partialBarrier
? 50
: EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_UNKNOWN));
addGetAttributeCheck(ZCL_BARRIER_MOVING_STATE_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_MOVING_STATE_STOPPED);
runScript();
// Start the closing of the barrier again. It should close up fully.
addGoToPercentAction(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_CLOSED);
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(101 * MIN_POSITION_CHANGE_DELAY_MS);
addGetAttributeCheck(ZCL_BARRIER_POSITION_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_CLOSED);
addGetAttributeCheck(ZCL_BARRIER_MOVING_STATE_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_MOVING_STATE_STOPPED);
runScript();
}
static void stopTest(void)
{
reallyStopTest(false); // PartialBarrier bit of Capabilities attribute is off
}
static void stopPartialBarrierTest(void)
{
reallyStopTest(true); // PartialBarrier bit of Capabilities attribute is on
}
// -------------------------------------
// Remote Lockout Test
static void remoteLockoutTest(void)
{
addInitialStateCheck();
runScript();
// If we try to open the door, we should fail because the RemoteLockout bit
// in the SafetyStatus attribute is set. The door should remain closed.
addSetRemoteLockoutAction(true);
addGoToPercentAction(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_OPEN);
addDefaultResponseCheck(EMBER_ZCL_STATUS_FAILURE);
addRunAction(101 * MIN_POSITION_CHANGE_DELAY_MS);
addGetAttributeCheck(ZCL_BARRIER_POSITION_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_CLOSED);
runScript();
// Clear the RemoteLockout bit of the SafetyStatus attribute and try to
// open the door. We should be able to do so now.
addSetRemoteLockoutAction(false);
addGoToPercentAction(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_OPEN);
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(101 * MIN_POSITION_CHANGE_DELAY_MS);
addGetAttributeCheck(ZCL_BARRIER_POSITION_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_OPEN);
runScript();
// Set the RemoteLockout bit of the SafetyStatus attribute again - we should
// not be able to close the door.
addSetRemoteLockoutAction(true);
addGoToPercentAction(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_CLOSED);
addDefaultResponseCheck(EMBER_ZCL_STATUS_FAILURE);
addRunAction(101 * MIN_POSITION_CHANGE_DELAY_MS);
addGetAttributeCheck(ZCL_BARRIER_POSITION_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_OPEN);
runScript();
// Clear the RemoteLockout bit of the SafetyStatus attribute again - we should
// now be able to close the door.
addSetRemoteLockoutAction(false);
addGoToPercentAction(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_CLOSED);
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(101 * MIN_POSITION_CHANGE_DELAY_MS);
addGetAttributeCheck(ZCL_BARRIER_POSITION_ATTRIBUTE_ID,
EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_CLOSED);
runScript();
}
// -------------------------------------
// Open Close Events Test
static void openCloseEventsTest(void)
{
addInitialStateCheck();
runScript();
// At boot, the open/close events attributes should all be 0.
addOpenCloseEventsCheck(0, 0, 0, 0);
runScript();
// Open the door. Open event counts should be incremented.
addGoToPercentAction(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_OPEN);
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(101 * MIN_POSITION_CHANGE_DELAY_MS);
addOpenCloseEventsCheck(1, 0, 1, 0);
runScript();
// Close the door. Close event counts should be incremented.
addGoToPercentAction(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_CLOSED);
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(101 * MIN_POSITION_CHANGE_DELAY_MS);
addOpenCloseEventsCheck(1, 1, 1, 1);
runScript();
// Open the door half way. Open event counts should be incremented.
addSetPartialBarrierBitAction(true);
addGoToPercentAction(50);
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(50 * MIN_POSITION_CHANGE_DELAY_MS);
addOpenCloseEventsCheck(2, 1, 2, 1);
runScript();
// Open the door the rest of the way. Only the command event count should be incremented.
addGoToPercentAction(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_OPEN);
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(51 * MIN_POSITION_CHANGE_DELAY_MS);
addOpenCloseEventsCheck(2, 1, 3, 1);
runScript();
// Close the door half way. Only the command event count should be incremented.
addGoToPercentAction(50);
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(50 * MIN_POSITION_CHANGE_DELAY_MS);
addOpenCloseEventsCheck(2, 1, 3, 2);
runScript();
// Close the door the rest of the way. Both close event counts should be incremented.
addGoToPercentAction(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_CLOSED);
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(51 * MIN_POSITION_CHANGE_DELAY_MS);
addOpenCloseEventsCheck(2, 2, 3, 3);
runScript();
// Set all of the event counts equal to the maximum value for a 16-bit unsigned
// integer in Zigbee (0xFFFE). Make sure the value doesn't roll past that.
addSetOpenCloseEventsAction(0xFFFE, 0xFFFE, 0xFFFE, 0xFFFE);
addGoToPercentAction(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_OPEN);
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(101 * MIN_POSITION_CHANGE_DELAY_MS);
addOpenCloseEventsCheck(0xFFFE, 0xFFFE, 0xFFFE, 0xFFFE);
addGoToPercentAction(EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_CLOSED);
addDefaultResponseCheck(EMBER_ZCL_STATUS_SUCCESS);
addRunAction(101 * MIN_POSITION_CHANGE_DELAY_MS);
addOpenCloseEventsCheck(0xFFFE, 0xFFFE, 0xFFFE, 0xFFFE);
}
// -----------------------------------------------------------------------------
// Stubs
// --------------------------------------
// Miscellaneous
uint8_t emAfPluginReportingConditionallyAddReportingEntry(EmberAfPluginReportingEntry* newEntry)
{
assert("this function should not be called" == NULL);
return 0;
}
// -------------------------------------
// Messaging Stubs
static EmberApsFrame apsFrame = {
.destinationEndpoint = 1, // endpoint
};
static EmberAfClusterCommand clusterCommand = {
.apsFrame = &apsFrame,
};
EmberAfClusterCommand *emAfCurrentCommand = &clusterCommand;
// -------------------------------------
// Cluster Event Stubs
// This event is used to stub out the cluster ticket functionality.
static EmberEventControl barrierControlClusterEventControl;
static void barrierControlClusterEventHandler(void)
{
// Generated by AppBuilder.
extern void emberAfBarrierControlClusterServerTickCallback(uint8_t);
emberAfBarrierControlClusterServerTickCallback(1); // endpoint
}
EmberStatus emberAfScheduleServerTick(uint8_t endpoint,
EmberAfClusterId clusterId,
uint32_t delayMs)
{
assert(clusterId == ZCL_BARRIER_CONTROL_CLUSTER_ID);
emberEventControlSetDelayMS(barrierControlClusterEventControl, delayMs);
return EMBER_SUCCESS;
}
EmberStatus emberAfDeactivateServerTick(uint8_t endpoint,
EmberAfClusterId clusterId)
{
assert(clusterId == ZCL_BARRIER_CONTROL_CLUSTER_ID);
emberEventControlSetInactive(barrierControlClusterEventControl);
return EMBER_SUCCESS;
}
// -------------------------------------
// Attribute stubs
typedef struct {
void *valueLocation;
uint8_t size;
} AttributeData;
#define ATTRIBUTE_DATA_ENTRY(storage) { &(storage), sizeof((storage)), }
#define ATTRIBUTE_DATA_ENTRY_NULL() { NULL, 0, }
static EmberStatus readOrWriteAttribute(uint8_t endpoint,
EmberAfClusterId cluster,
EmberAfAttributeId attributeId,
uint8_t *dataPtr,
uint8_t dataTypeOrReadLength,
bool read)
{
static uint8_t movingState = 0;
static uint16_t safetyStatus = 0;
static uint8_t capabilities = 0;
static uint16_t openEvents = 0;
static uint16_t closeEvents = 0;
static uint16_t commandOpenEvents = 0;
static uint16_t commandCloseEvents = 0;
static uint16_t openOrClosePeriod = 0;
static uint8_t position = EMBER_ZCL_BARRIER_CONTROL_BARRIER_POSITION_CLOSED;
static const AttributeData attributeData[] = {
ATTRIBUTE_DATA_ENTRY_NULL(), // 0x0000
ATTRIBUTE_DATA_ENTRY(movingState), // 0x0001
ATTRIBUTE_DATA_ENTRY(safetyStatus), // 0x0002
ATTRIBUTE_DATA_ENTRY(capabilities), // 0x0003
ATTRIBUTE_DATA_ENTRY(openEvents), // 0x0004
ATTRIBUTE_DATA_ENTRY(closeEvents), // 0x0004
ATTRIBUTE_DATA_ENTRY(commandOpenEvents), // 0x0006
ATTRIBUTE_DATA_ENTRY(commandCloseEvents), // 0x0007
ATTRIBUTE_DATA_ENTRY(openOrClosePeriod), // 0x0008
ATTRIBUTE_DATA_ENTRY(openOrClosePeriod), // 0x0009
ATTRIBUTE_DATA_ENTRY(position), // 0x000A
};
const AttributeData *attribute = attributeData + attributeId;
assert(cluster == ZCL_BARRIER_CONTROL_CLUSTER_ID);
if (attributeId > COUNTOF(attributeData) || attribute->valueLocation == NULL) {
assert("unknown attribute ID!" == NULL);
}
if (read) {
MEMMOVE(dataPtr, attribute->valueLocation, attribute->size);
} else {
MEMMOVE(attribute->valueLocation, dataPtr, attribute->size);
}
return EMBER_ZCL_STATUS_SUCCESS;
}
EmberAfStatus emberAfReadServerAttribute(uint8_t endpoint,
EmberAfClusterId cluster,
EmberAfAttributeId attributeId,
uint8_t* dataPtr,
uint8_t readLength)
{
return readOrWriteAttribute(endpoint,
cluster,
attributeId,
dataPtr,
readLength,
true);
}
EmberAfStatus emberAfWriteServerAttribute(uint8_t endpoint,
EmberAfClusterId cluster,
EmberAfAttributeId attributeId,
uint8_t* dataPtr,
uint8_t dataType)
{
return readOrWriteAttribute(endpoint,
cluster,
attributeId,
dataPtr,
dataType,
false);
}
// -----------------------------------------------------------------------------
// Main
static Test tests[] = {
{ "open-test", openTest, },
{ "open-partial-barrier-test", openPartialBarrierTest, },
{ "close-test", closeTest, },
{ "close-partial-barrier-test", closePartialBarrierTest, },
{ "stop-test", stopTest, },
{ "stop-partial-barrier-test", stopPartialBarrierTest, },
{ "remote-lockout-test", remoteLockoutTest, },
{ "open-close-events-test", openCloseEventsTest, },
{ NULL, NULL, },
};
int main(int argc, char *argv[])
{
Thunk test = parseTestArgument(argc, argv, tests);
test();
fprintf(stderr, " done ]\n");
return 0;
}
void scriptTickCallback(void)
{
static EmberEventData data[] = {
{ &barrierControlClusterEventControl, barrierControlClusterEventHandler, },
{ NULL, NULL, },
};
emberRunEvents(data);
}