Skip to content

Commit

Permalink
[EFR32] Lock app UDP broadcast and BLE provisionning support (#2275)
Browse files Browse the repository at this point in the history
* Broadcast a UDP message for Service discovery for the EFR lock app
Add bluetooth handler for the thread provision in the app task
Reuse Function button (PB0) for a Join button instead. OTA function isn't implemented yet and the WSTK has only 2 set button

* Add Pointer validation in appTask Function
Init deviceName to 0

* Use secure Paring key exchange for example app
Fix conflict errors

* Fix Include of chip-zcl-zpro-codec
Add EFR32 prefix to broadcast name
set deviceName Array as static

* Restyled by whitespace

Co-authored-by: Restyled.io <[email protected]>
  • Loading branch information
jmartinez-silabs and restyled-commits authored Aug 21, 2020
1 parent cc32bc0 commit 1cf3b1f
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 23 deletions.
8 changes: 7 additions & 1 deletion examples/lock-app/efr32/include/AppConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,19 @@
// EFR32 WSTK Buttons
#define PB0 0
#define PB1 1
// TODO There is no set 3rd push button on the WSTK keep.
// Keep this for function button future use
#define PB2 2

// EFR32 WSTK LEDs
#define BSP_LED_0 0
#define BSP_LED_1 1

#define APP_FUNCTION_BUTTON PB0
#define APP_JOIN_BUTTON PB0
#define APP_LOCK_BUTTON PB1
// TODO Currently no Function Button for EFR32,
// OTA not implemented but keep for future use. (Reused PB0 for Join button)
#define APP_FUNCTION_BUTTON PB2
#define APP_BUTTON_DEBOUNCE_PERIOD_MS 50

#define APP_BUTTON_PRESSED 0
Expand Down
12 changes: 8 additions & 4 deletions examples/lock-app/efr32/include/AppTask.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
#include "AppEvent.h"
#include "BoltLockManager.h"

#include <platform/CHIPDeviceLayer.h>

#include "FreeRTOS.h"
#include "timers.h" // provides FreeRTOS timer support
#include <ble/BLEEndPoint.h>
#include <platform/CHIPDeviceLayer.h>

class AppTask
{
Expand Down Expand Up @@ -57,11 +57,14 @@ class AppTask

static void FunctionTimerEventHandler(AppEvent * aEvent);
static void FunctionHandler(AppEvent * aEvent);
static void JoinHandler(AppEvent * aEvent);
static void LockActionEventHandler(AppEvent * aEvent);
static void InstallEventHandler(AppEvent * aEvent);

static void TimerEventHandler(TimerHandle_t xTimer);

static void HandleBLEConnectionOpened(chip::Ble::BLEEndPoint * endPoint);
static void HandleBLEConnectionClosed(chip::Ble::BLEEndPoint * endPoint, BLE_ERROR err);
static void HandleBLEMessageReceived(chip::Ble::BLEEndPoint * endPoint, chip::System::PacketBuffer * buffer);

void StartTimer(uint32_t aTimeoutMs);

enum Function_t
Expand All @@ -75,6 +78,7 @@ class AppTask

Function_t mFunction;
bool mFunctionTimerActive;
chip::Ble::BLEEndPoint * mBLEEndPoint;

static AppTask sAppTask;
};
Expand Down
2 changes: 2 additions & 0 deletions examples/lock-app/efr32/include/Server.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@

using DemoSessionManager = chip::SecureSessionMgr<chip::Transport::UDP>;

void SetDeviceName(const char * newDeviceName);
void PublishService();
void StartServer(DemoSessionManager * sessions);
void InitDataModelHandler();

Expand Down
143 changes: 125 additions & 18 deletions examples/lock-app/efr32/src/AppTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,28 @@
*/

#include "AppTask.h"
#include "AppConfig.h"
#include "AppEvent.h"
#include "ButtonHandler.h"
#include "DataModelHandler.h"
#include "LEDWidget.h"
#include "Server.h"

#include "AppConfig.h"
#include <assert.h>

using namespace chip::TLV;
using namespace chip::DeviceLayer;

#include <platform/CHIPDeviceLayer.h>
#if CHIP_ENABLE_OPENTHREAD
#include <platform/EFR32/ThreadStackManagerImpl.h>
#include <platform/OpenThread/OpenThreadUtils.h>
#include <platform/ThreadStackManager.h>
#include <platform/internal/DeviceNetworkInfo.h>
#endif
#define FACTORY_RESET_TRIGGER_TIMEOUT 3000
#define FACTORY_RESET_CANCEL_WINDOW_TIMEOUT 3000
#define APP_TASK_STACK_SIZE (2048)
#define APP_TASK_STACK_SIZE (4096)
#define APP_TASK_PRIORITY 2
#define APP_EVENT_QUEUE_SIZE 10

Expand All @@ -42,13 +51,12 @@ static QueueHandle_t sAppEventQueue;
static LEDWidget sStatusLED;
static LEDWidget sLockLED;

static bool sIsThreadProvisioned = false;
static bool sIsThreadEnabled = false;
static bool sIsThreadAttached = false;
static bool sIsPairedToAccount = false;
static bool sIsServiceSubscriptionEstablished = false;
static bool sHaveBLEConnections = false;
static bool sHaveServiceConnectivity = false;
static bool sIsThreadProvisioned = false;
static bool sIsThreadEnabled = false;
static bool sIsThreadAttached = false;
static bool sIsPairedToAccount = false;
static bool sHaveBLEConnections = false;
static bool sHaveServiceConnectivity = false;

using namespace ::chip::DeviceLayer;

Expand Down Expand Up @@ -114,10 +122,77 @@ int AppTask::Init()
return err;
}

void AppTask::HandleBLEConnectionOpened(chip::Ble::BLEEndPoint * endPoint)
{
assert(endPoint != NULL);

ChipLogProgress(DeviceLayer, "AppTask: Connection opened");

GetAppTask().mBLEEndPoint = endPoint;
endPoint->OnMessageReceived = AppTask::HandleBLEMessageReceived;
endPoint->OnConnectionClosed = AppTask::HandleBLEConnectionClosed;
}

void AppTask::HandleBLEConnectionClosed(chip::Ble::BLEEndPoint * endPoint, BLE_ERROR err)
{
ChipLogProgress(DeviceLayer, "AppTask: Connection closed");

GetAppTask().mBLEEndPoint = nullptr;
}

void AppTask::HandleBLEMessageReceived(chip::Ble::BLEEndPoint * endPoint, chip::System::PacketBuffer * buffer)
{
assert(endPoint != NULL);
#if CHIP_ENABLE_OPENTHREAD
assert(buffer != NULL);

uint16_t bufferLen = buffer->DataLength();
uint8_t * data = buffer->Start();
chip::DeviceLayer::Internal::DeviceNetworkInfo networkInfo;
ChipLogProgress(DeviceLayer, "AppTask: Receive message size %u", bufferLen);

memcpy(networkInfo.ThreadNetworkName, data, sizeof(networkInfo.ThreadNetworkName));
data += sizeof(networkInfo.ThreadNetworkName);

memcpy(networkInfo.ThreadExtendedPANId, data, sizeof(networkInfo.ThreadExtendedPANId));
data += sizeof(networkInfo.ThreadExtendedPANId);

memcpy(networkInfo.ThreadMeshPrefix, data, sizeof(networkInfo.ThreadMeshPrefix));
data += sizeof(networkInfo.ThreadMeshPrefix);

memcpy(networkInfo.ThreadNetworkKey, data, sizeof(networkInfo.ThreadNetworkKey));
data += sizeof(networkInfo.ThreadNetworkKey);

memcpy(networkInfo.ThreadPSKc, data, sizeof(networkInfo.ThreadPSKc));
data += sizeof(networkInfo.ThreadPSKc);

networkInfo.ThreadPANId = data[0] | (data[1] << 8);
data += sizeof(networkInfo.ThreadPANId);
networkInfo.ThreadChannel = data[0];
data += sizeof(networkInfo.ThreadChannel);

networkInfo.FieldPresent.ThreadExtendedPANId = *data;
data++;
networkInfo.FieldPresent.ThreadMeshPrefix = *data;
data++;
networkInfo.FieldPresent.ThreadPSKc = *data;
data++;
networkInfo.NetworkId = 0;
networkInfo.FieldPresent.NetworkId = true;

ThreadStackMgr().SetThreadEnabled(false);
ThreadStackMgr().SetThreadProvision(networkInfo);
ThreadStackMgr().SetThreadEnabled(true);
#endif
endPoint->Close();
chip::System::PacketBuffer::Free(buffer);
}

void AppTask::AppTaskMain(void * pvParameter)
{
int err;
AppEvent event;
uint64_t mLastChangeTimeUS = 0;

err = sAppTask.Init();
if (err != CHIP_NO_ERROR)
Expand All @@ -127,6 +202,8 @@ void AppTask::AppTaskMain(void * pvParameter)
}

EFR32_LOG("App Task started");
chip::DeviceLayer::ConnectivityMgr().AddCHIPoBLEConnectionHandler(&AppTask::HandleBLEConnectionOpened);
SetDeviceName("EFR32LockDemo._chip._udp.local.");

while (true)
{
Expand All @@ -152,11 +229,6 @@ void AppTask::AppTaskMain(void * pvParameter)
PlatformMgr().UnlockChipStack();
}

// Consider the system to be "fully connected" if it has service
// connectivity and it is able to interact with the service on a regular
// basis.
bool isFullyConnected = (sHaveServiceConnectivity && sIsServiceSubscriptionEstablished);

// Update the status LED if factory reset has not been initiated.
//
// If system has "full connectivity", keep the LED On constantly.
Expand All @@ -171,11 +243,14 @@ void AppTask::AppTaskMain(void * pvParameter)
// Otherwise, blink the LED ON for a very short time.
if (sAppTask.mFunction != kFunction_FactoryReset)
{
if (isFullyConnected)
// Consider the system to be "fully connected" if it has service
// connectivity
if (sHaveServiceConnectivity)
{
sStatusLED.Set(true);
}
else if (sIsThreadProvisioned && sIsThreadEnabled && sIsPairedToAccount && (!sIsThreadAttached || !isFullyConnected))
else if (sIsThreadProvisioned && sIsThreadEnabled && sIsPairedToAccount &&
(!sIsThreadAttached || !sHaveServiceConnectivity))
{
sStatusLED.Blink(950, 50);
}
Expand All @@ -191,6 +266,15 @@ void AppTask::AppTaskMain(void * pvParameter)

sStatusLED.Animate();
sLockLED.Animate();

uint64_t nowUS = chip::System::Platform::Layer::GetClock_Monotonic();
uint64_t nextChangeTimeUS = mLastChangeTimeUS + 5 * 1000 * 1000UL;

if (nowUS > nextChangeTimeUS)
{
PublishService();
mLastChangeTimeUS = nowUS;
}
}
}

Expand Down Expand Up @@ -234,14 +318,30 @@ void AppTask::LockActionEventHandler(AppEvent * aEvent)
}
}

#if CHIP_ENABLE_OPENTHREAD
void AppTask::JoinHandler(AppEvent * aEvent)
{
assert(aEvent != NULL);
if (aEvent->ButtonEvent.ButtonIdx != APP_JOIN_BUTTON)
return;

CHIP_ERROR error = ThreadStackMgr().JoinerStart();
EFR32_LOG("Thread joiner triggered: %s", chip::ErrorStr(error));
}
#endif

void AppTask::ButtonEventHandler(uint8_t btnIdx, uint8_t btnAction)
{
if (btnIdx != APP_LOCK_BUTTON && btnIdx != APP_FUNCTION_BUTTON)
if (btnIdx != APP_LOCK_BUTTON
#if CHIP_ENABLE_OPENTHREAD
&& btnIdx != APP_JOIN_BUTTON
#endif
&& btnIdx != APP_FUNCTION_BUTTON)
{
return;
}

AppEvent button_event;
AppEvent button_event = {};
button_event.Type = AppEvent::kEventType_Button;
button_event.ButtonEvent.ButtonIdx = btnIdx;
button_event.ButtonEvent.Action = btnAction;
Expand All @@ -256,6 +356,13 @@ void AppTask::ButtonEventHandler(uint8_t btnIdx, uint8_t btnAction)
button_event.Handler = FunctionHandler;
sAppTask.PostEvent(&button_event);
}
#if CHIP_ENABLE_OPENTHREAD
else if (btnIdx == APP_JOIN_BUTTON)
{
button_event.Handler = JoinHandler;
sAppTask.PostEvent(&button_event);
}
#endif
}

void AppTask::TimerEventHandler(TimerHandle_t xTimer)
Expand Down
67 changes: 67 additions & 0 deletions examples/lock-app/efr32/src/Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,26 @@
#include <transport/SecureSessionMgr.h>
#include <transport/UDP.h>

#if CHIP_ENABLE_OPENTHREAD
#include <openthread/message.h>
#include <openthread/udp.h>
#include <platform/EFR32/ThreadStackManagerImpl.h>
#include <platform/OpenThread/OpenThreadUtils.h>
#include <platform/ThreadStackManager.h>
#include <platform/internal/DeviceNetworkInfo.h>
#endif

#include "Server.h"

#include "attribute-storage.h"
#include "gen/znet-bookkeeping.h"
#include "util.h"
#include <app/chip-zcl-zpro-codec.h>

using namespace ::chip;
using namespace ::chip::Inet;
using namespace ::chip::Transport;
using namespace ::chip::DeviceLayer;

// Transport Callbacks
namespace {
Expand All @@ -55,6 +66,10 @@ namespace {
#define EXAMPLE_SERVER_NODEID 0x3546526e
#endif // EXAMPLE_SERVER_NODEID

static char sDeviceName[128] = { 0 };
// Hardcode UDP BroadcastPort. Temporary use for demo with OTBR
constexpr uint16_t kUDPBroadcastPort = 23367;

class ServerCallback : public SecureSessionMgrCallback
{
public:
Expand Down Expand Up @@ -139,6 +154,58 @@ static SecurePairingUsingTestSecret gTestPairing;

} // namespace

void SetDeviceName(const char * newDeviceName)
{
strncpy(sDeviceName, newDeviceName, sizeof(sDeviceName) - 1);
}

void PublishService()
{
chip::Inet::IPAddress addr;
if (!ConnectivityMgrImpl().IsThreadAttached())
{
return;
}
ThreadStackMgrImpl().LockThreadStack();
otError error = OT_ERROR_NONE;
otMessageInfo messageInfo;
otUdpSocket mSocket;
otMessage * message = nullptr;

memset(&mSocket, 0, sizeof(mSocket));
memset(&messageInfo, 0, sizeof(messageInfo));

// Use mesh local EID by default, if we have GUA, use that IP address.
memcpy(&messageInfo.mSockAddr, otThreadGetMeshLocalEid(ThreadStackMgrImpl().OTInstance()), sizeof(messageInfo.mSockAddr));

// Select a address to send
const otNetifAddress * otAddrs = otIp6GetUnicastAddresses(ThreadStackMgrImpl().OTInstance());
for (const otNetifAddress * otAddr = otAddrs; otAddr != NULL; otAddr = otAddr->mNext)
{
addr = chip::DeviceLayer::Internal::ToIPAddress(otAddr->mAddress);
if (otAddr->mValid && addr.IsIPv6GlobalUnicast())
{
memcpy(&messageInfo.mSockAddr, &(otAddr->mAddress), sizeof(otAddr->mAddress));
break;
}
}

message = otUdpNewMessage(ThreadStackMgrImpl().OTInstance(), nullptr);
otIp6AddressFromString("ff03::1", &messageInfo.mPeerAddr);
messageInfo.mPeerPort = kUDPBroadcastPort;
otMessageAppend(message, sDeviceName, static_cast<uint16_t>(strlen(sDeviceName)));

error = otUdpSend(ThreadStackMgrImpl().OTInstance(), &mSocket, message, &messageInfo);

if (error != OT_ERROR_NONE && message != nullptr)
{
otMessageFree(message);
EFR32_LOG("Failed to otUdpSend: %d", error);
}
ThreadStackMgrImpl().UnlockThreadStack();
}

;
void InitDataModelHandler()
{
emberAfEndpointConfigure();
Expand Down

0 comments on commit 1cf3b1f

Please sign in to comment.