Skip to content

Commit

Permalink
Merge branch 'master' into feature/add-pcc-cluster-implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
tlykkeberg-grundfos committed May 27, 2021
2 parents a9e7ea2 + 4262811 commit 60c7df9
Show file tree
Hide file tree
Showing 14 changed files with 1,289 additions and 20 deletions.
493 changes: 493 additions & 0 deletions examples/lock-app/esp32/main/AppTask.cpp

Large diffs are not rendered by default.

217 changes: 217 additions & 0 deletions examples/lock-app/esp32/main/BoltLockManager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
/*
*
* 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.
*/

#include "BoltLockManager.h"

#include "AppConfig.h"
#include "AppTask.h"
#include "esp_log.h"
#include <freertos/FreeRTOS.h>
static const char * TAG = "BoltLockManager";
BoltLockManager BoltLockManager::sLock;

TimerHandle_t sLockTimer;

int BoltLockManager::Init()
{
// Create FreeRTOS sw timer for lock timer.
sLockTimer = xTimerCreate("lockTmr", // Just a text name, not used by the RTOS kernel
1, // == default timer period (mS)
false, // no timer reload (==one-shot)
(void *) this, // init timer id = lock obj context
TimerEventHandler // timer callback handler
);

if (sLockTimer == NULL)
{
ESP_LOGE(TAG, "sLockTimer timer create failed");
return CHIP_ERROR_MAX;
}

mState = kState_LockingCompleted;
mAutoLockTimerArmed = false;
mAutoRelock = false;
mAutoLockDuration = 0;

return CHIP_NO_ERROR;
}

void BoltLockManager::SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callback_fn_completed aActionCompleted_CB)
{
mActionInitiated_CB = aActionInitiated_CB;
mActionCompleted_CB = aActionCompleted_CB;
}

bool BoltLockManager::IsActionInProgress()
{
return (mState == kState_LockingInitiated || mState == kState_UnlockingInitiated);
}

bool BoltLockManager::IsUnlocked()
{
return (mState == kState_UnlockingCompleted);
}

void BoltLockManager::SetAutoLockDuration(uint32_t aDurationInSecs)
{
mAutoLockDuration = aDurationInSecs;
}

bool BoltLockManager::InitiateAction(int32_t aActor, Action_t aAction)
{
bool action_initiated = false;
State_t new_state;
// Initiate Lock/Unlock Action only when the previous one is complete.
if (mState == kState_LockingCompleted && aAction == UNLOCK_ACTION)
{
action_initiated = true;

new_state = kState_UnlockingInitiated;
}
else if (mState == kState_UnlockingCompleted && aAction == LOCK_ACTION)
{
action_initiated = true;

new_state = kState_LockingInitiated;
}

if (action_initiated)
{
if (mAutoLockTimerArmed && new_state == kState_LockingInitiated)
{
// If auto lock timer has been armed and someone initiates locking,
// cancel the timer and continue as normal.
mAutoLockTimerArmed = false;

CancelTimer();
}

StartTimer(ACTUATOR_MOVEMENT_PERIOS_MS);

// Since the timer started successfully, update the state and trigger callback
mState = new_state;

if (mActionInitiated_CB)
{
mActionInitiated_CB(aAction, aActor);
}
}

return action_initiated;
}

void BoltLockManager::StartTimer(uint32_t aTimeoutMs)
{
if (xTimerIsTimerActive(sLockTimer))
{
ESP_LOGI(TAG, "app timer already started!");
CancelTimer();
}

// timer is not active, change its period to required value (== restart).
// FreeRTOS- Block for a maximum of 100 ticks if the change period command
// cannot immediately be sent to the timer command queue.
if (xTimerChangePeriod(sLockTimer, (aTimeoutMs / portTICK_PERIOD_MS), 100) != pdPASS)
{
ESP_LOGI(TAG, "sLockTimer timer start() failed");
return;
}
}

void BoltLockManager::CancelTimer(void)
{
if (xTimerStop(sLockTimer, 0) == pdFAIL)
{
ESP_LOGI(TAG, "Lock timer timer stop() failed");
return;
}
}
void BoltLockManager::TimerEventHandler(TimerHandle_t xTimer)
{
// Get lock obj context from timer id.
BoltLockManager * lock = static_cast<BoltLockManager *>(pvTimerGetTimerID(xTimer));

// The timer event handler will be called in the context of the timer task
// once sLockTimer expires. Post an event to apptask queue with the actual handler
// so that the event can be handled in the context of the apptask.
AppEvent event;
event.Type = AppEvent::kEventType_Timer;
event.TimerEvent.Context = lock;
if (lock->mAutoLockTimerArmed)
{
event.Handler = AutoReLockTimerEventHandler;
}
else
{
event.Handler = ActuatorMovementTimerEventHandler;
}
GetAppTask().PostEvent(&event);
}

void BoltLockManager::AutoReLockTimerEventHandler(AppEvent * aEvent)
{
BoltLockManager * lock = static_cast<BoltLockManager *>(aEvent->TimerEvent.Context);
int32_t actor = 0;

// Make sure auto lock timer is still armed.
if (!lock->mAutoLockTimerArmed)
{
return;
}

lock->mAutoLockTimerArmed = false;

ESP_LOGI(TAG, "Auto Re-Lock has been triggered!");

lock->InitiateAction(actor, LOCK_ACTION);
}

void BoltLockManager::ActuatorMovementTimerEventHandler(AppEvent * aEvent)
{
Action_t actionCompleted = INVALID_ACTION;

BoltLockManager * lock = static_cast<BoltLockManager *>(aEvent->TimerEvent.Context);

if (lock->mState == kState_LockingInitiated)
{
lock->mState = kState_LockingCompleted;
actionCompleted = LOCK_ACTION;
}
else if (lock->mState == kState_UnlockingInitiated)
{
lock->mState = kState_UnlockingCompleted;
actionCompleted = UNLOCK_ACTION;
}

if (actionCompleted != INVALID_ACTION)
{
if (lock->mActionCompleted_CB)
{
lock->mActionCompleted_CB(actionCompleted);
}

if (lock->mAutoRelock && actionCompleted == UNLOCK_ACTION)
{
// Start the timer for auto relock
lock->StartTimer(lock->mAutoLockDuration * 1000);

lock->mAutoLockTimerArmed = true;

ESP_LOGI(TAG, "Auto Re-lock enabled. Will be triggered in %u seconds", lock->mAutoLockDuration);
}
}
}
65 changes: 65 additions & 0 deletions examples/lock-app/esp32/main/Button.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
*
* 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.
*/

#include "Button.h"
#include "AppTask.h"

#include "AppConfig.h"

esp_err_t Button::Init(gpio_num_t gpioNum, uint16_t debouncePeriod)
{
esp_err_t err;

mGPIONum = gpioNum;
mDebouncePeriod = debouncePeriod / portTICK_PERIOD_MS;
mState = false;
mLastPolledState = false;

err = gpio_set_direction(gpioNum, GPIO_MODE_INPUT);
SuccessOrExit(err);

exit:
return err;
}

bool Button::Poll()
{
uint32_t now = xTaskGetTickCount();

bool newState = gpio_get_level(mGPIONum);

if (newState != mLastPolledState)
{
mLastPolledState = newState;
mLastReadTime = now;
}

else if (newState != mState && (now - mLastReadTime) >= mDebouncePeriod)
{
mState = newState;
mPrevStateDur = now - mStateStartTime;
mStateStartTime = now;
return true;
}

return false;
}

uint32_t Button::GetStateDuration()
{
return (xTaskGetTickCount() - mStateStartTime) * portTICK_PERIOD_MS;
}
29 changes: 28 additions & 1 deletion examples/lock-app/esp32/main/DeviceCallbacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
**/

#include "DeviceCallbacks.h"
#include "AppConfig.h"
#include "BoltLockManager.h"

#include "esp_heap_caps.h"
#include "esp_log.h"
Expand Down Expand Up @@ -59,7 +61,16 @@ void DeviceCallbacks::PostAttributeChangeCallback(EndpointId endpointId, Cluster
ESP_LOGI(TAG, "PostAttributeChangeCallback - Cluster ID: '0x%04x', EndPoint ID: '0x%02x', Attribute ID: '0x%04x'", clusterId,
endpointId, attributeId);

ESP_LOGI(TAG, "Unhandled cluster ID: %d", clusterId);
switch (clusterId)
{
case ZCL_ON_OFF_CLUSTER_ID:
OnOnOffPostAttributeChangeCallback(endpointId, attributeId, value);
break;

default:
ESP_LOGI(TAG, "Unhandled cluster ID: %d", clusterId);
break;
}

ESP_LOGI(TAG, "Current free heap: %d\n", heap_caps_get_free_size(MALLOC_CAP_8BIT));
}
Expand Down Expand Up @@ -91,3 +102,19 @@ void DeviceCallbacks::OnSessionEstablished(const ChipDeviceEvent * event)
ESP_LOGI(TAG, "Commissioner detected!");
}
}

void DeviceCallbacks::OnOnOffPostAttributeChangeCallback(EndpointId endpointId, AttributeId attributeId, uint8_t * value)
{
VerifyOrExit(attributeId == ZCL_ON_OFF_ATTRIBUTE_ID, ESP_LOGI(TAG, "Unhandled Attribute ID: '0x%04x", attributeId));
VerifyOrExit(endpointId == 1 || endpointId == 2, ESP_LOGE(TAG, "Unexpected EndPoint ID: `0x%02x'", endpointId));
if (*value)
{
BoltLockMgr().InitiateAction(AppEvent::kEventType_Lock, BoltLockManager::LOCK_ACTION);
}
else
{
BoltLockMgr().InitiateAction(AppEvent::kEventType_Lock, BoltLockManager::UNLOCK_ACTION);
}
exit:
return;
}
2 changes: 0 additions & 2 deletions examples/lock-app/esp32/main/Kconfig.projbuild
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ menu "Demo"

config DEVICE_TYPE_ESP32_DEVKITC
bool "ESP32-DevKitC"
config DEVICE_TYPE_M5STACK
bool "M5Stack"
endchoice

choice
Expand Down
Loading

0 comments on commit 60c7df9

Please sign in to comment.