| /** |
| * |
| * 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); |
| } |