Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restyle [WIP] ESP32: Add fixes for lock-app #6929

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
473 changes: 473 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);
}
}
}
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
85 changes: 85 additions & 0 deletions examples/lock-app/esp32/main/LEDWidget.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
*
* Copyright (c) 2018 Nest Labs, Inc.
* All rights reserved.
*
* 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 "LEDWidget.h"
#include "AppTask.h"
#include <platform/CHIPDeviceLayer.h>

using namespace chip::System::Platform::Layer;

void LEDWidget::Init(gpio_num_t gpioNum)
{
mLastChangeTimeUS = 0;
mBlinkOnTimeMS = 0;
mBlinkOffTimeMS = 0;
mGPIONum = gpioNum;

if (gpioNum < GPIO_NUM_MAX)
{
gpio_set_direction(gpioNum, GPIO_MODE_OUTPUT);
}
}

void LEDWidget::Invert(void)
{
Set(!mState);
}

void LEDWidget::Set(bool state)
{
mBlinkOnTimeMS = 0;
mBlinkOffTimeMS = 0;
DoSet(state);
}

void LEDWidget::Blink(uint32_t changeRateMS)
{
Blink(changeRateMS, changeRateMS);
}

void LEDWidget::Blink(uint32_t onTimeMS, uint32_t offTimeMS)
{
mBlinkOnTimeMS = onTimeMS;
mBlinkOffTimeMS = offTimeMS;
Animate();
}

void LEDWidget::Animate()
{
if (mBlinkOnTimeMS != 0 && mBlinkOffTimeMS != 0)
{
int64_t nowUS = GetClock_MonotonicHiRes();
int64_t stateDurUS = ((mState) ? mBlinkOnTimeMS : mBlinkOffTimeMS) * 1000LL;
int64_t nextChangeTimeUS = mLastChangeTimeUS + stateDurUS;

if (nowUS > nextChangeTimeUS)
{
DoSet(!mState);
mLastChangeTimeUS = nowUS;
}
}
}

void LEDWidget::DoSet(bool state)
{
mState = state;
if (mGPIONum < GPIO_NUM_MAX)
{
gpio_set_level(mGPIONum, (state) ? 1 : 0);
}
}
39 changes: 39 additions & 0 deletions examples/lock-app/esp32/main/include/AppConfig.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
*
* 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.
*/

#pragma once

#include "driver/gpio.h"

// ---- Lock Example App Config ----

#define APP_TASK_NAME "LOCK-APP"

#define SYSTEM_STATE_LED GPIO_NUM_2
#define LOCK_STATE_LED GPIO_NUM_14

#define APP_LOCK_BUTTON GPIO_NUM_14
#define APP_FUNCTION_BUTTON GPIO_NUM_15

#define APP_BUTTON_DEBOUNCE_PERIOD_MS 50

#define APP_BUTTON_PRESSED 0
#define APP_BUTTON_RELEASED 1

// Time it takes in ms for the simulated actuator to move from one
// state to another.
#define ACTUATOR_MOVEMENT_PERIOS_MS 2000
Loading