Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
19 changes: 14 additions & 5 deletions examples/light-switch-app/silabs/src/AppTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,10 @@ void AppTask::AppEventHandler(AppEvent * aEvent)
closureData->isGroup = false;
closureData->commandId = Clusters::ClosureControl::Commands::MoveTo::Id;
if (BaseApplication::ScheduleWorkGatedOnThreadDirectLink(AppTask::SwitchWorkerFunction,
reinterpret_cast<intptr_t>(closureData)) != CHIP_NO_ERROR)
reinterpret_cast<intptr_t>(closureData),
[](intptr_t context) {
Platform::Delete(reinterpret_cast<BindingCommandData *>(context));
}) != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "Failed to schedule closure switch worker");
Platform::Delete(closureData);
Expand All @@ -339,7 +342,10 @@ void AppTask::AppEventHandler(AppEvent * aEvent)
toggleData->isGroup = false;
toggleData->commandId = OnOff::Commands::Toggle::Id;
if (BaseApplication::ScheduleWorkGatedOnThreadDirectLink(AppTask::SwitchWorkerFunction,
reinterpret_cast<intptr_t>(toggleData)) != CHIP_NO_ERROR)
reinterpret_cast<intptr_t>(toggleData),
[](intptr_t context) {
Platform::Delete(reinterpret_cast<BindingCommandData *>(context));
}) != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "Failed to schedule switch worker");
Platform::Delete(toggleData);
Expand Down Expand Up @@ -384,8 +390,10 @@ void AppTask::AppEventHandler(AppEvent * aEvent)
stepData.optionsMask.Set(kStepCommand.optionsMask);
stepData.optionsOverride.Set(kStepCommand.optionsOverride);
data->commandData = stepData;
if (BaseApplication::ScheduleWorkGatedOnThreadDirectLink(AppTask::SwitchWorkerFunction, reinterpret_cast<intptr_t>(data)) !=
CHIP_NO_ERROR)
if (BaseApplication::ScheduleWorkGatedOnThreadDirectLink(AppTask::SwitchWorkerFunction, reinterpret_cast<intptr_t>(data),
[](intptr_t context) {
Platform::Delete(reinterpret_cast<BindingCommandData *>(context));
}) != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "Failed to schedule switch worker");
Platform::Delete(data);
Expand Down Expand Up @@ -789,7 +797,8 @@ void AppTask::ProcessClosureControlBindingCommand(CommandId commandId, const Bin
{
VerifyOrDie(peer_device->ConnectionReady());
Messaging::ExchangeManager * exchangeMgr = peer_device->GetExchangeManager();
const SessionHandle & sessionHandle = peer_device->GetSecureSession().Value();
auto optionalSession = peer_device->GetSecureSession();
const SessionHandle & sessionHandle = optionalSession.Value();
Comment on lines +800 to +801

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reasoning for this split? if it is a optionalSession should we check that it has a values?
optionalSession.HasValue()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The split keeps the returned optional alive, avoiding a dangling reference after the semicolon. Both versions appeared to work in testing, but an LLM-assisted review flagged the lifetime issue.

I could add a HasValue() check, but I think it would be redundant as there is already a VerifyOrDie(HasValue()) inside Value(). If the intent is to handle a missing session gracefully, the earlier VerifyOrDie would also need to change.


switch (commandId)
{
Expand Down
94 changes: 77 additions & 17 deletions examples/platform/silabs/BaseApplication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
#include <atomic>
#if OPENTHREAD_CONFIG_THREAD_DIRECT_WAKE_INITIATOR_ENABLE
#include <platform/silabs/address_resolve/AddressResolverImpl.h>
#include <platform/silabs/address_resolve/PreCommissioning.h>
#endif // OPENTHREAD_CONFIG_THREAD_DIRECT_WAKE_INITIATOR_ENABLE
#endif // SL_USE_THREAD_DIRECT

Expand Down Expand Up @@ -222,6 +223,7 @@ struct PendingThreadDirectWork
{
chip::DeviceLayer::AsyncWorkFunct work;
intptr_t arg;
chip::DeviceLayer::AsyncWorkFunct onCancel;
};

constexpr size_t kPendingThreadDirectWorkQueueSize = 4;
Expand All @@ -234,61 +236,117 @@ constexpr osMessageQueueAttr_t pendingThreadDirectWorkQueueAttr = { .cb_mem = &
.mq_size =
sizeof(sPendingThreadDirectWorkQueueBuffer) };

// Written from the OpenThread task, read from the CHIP/App task.
std::atomic<bool> sThreadDirectLinked{ false };

void DrainPendingThreadDirectWork(AppEvent *)
{
PendingThreadDirectWork pending;
while (osMessageQueueGet(sPendingThreadDirectWorkQueue, &pending, nullptr, 0) == osOK)
{
TEMPORARY_RETURN_IGNORED PlatformMgr().ScheduleWork(pending.work, pending.arg);
CHIP_ERROR err = PlatformMgr().ScheduleWork(pending.work, pending.arg);
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "Failed to schedule pending Thread Direct work: %" CHIP_ERROR_FORMAT, err.Format());
VerifyOrDo(pending.onCancel == nullptr, pending.onCancel(pending.arg));
}
}
}

#if OPENTHREAD_CONFIG_THREAD_DIRECT_WAKE_INITIATOR_ENABLE
void NotifyResolverThreadDirectLinked(intptr_t)
CHIP_ERROR InvalidateThreadDirectPeerSessions()
{
static_cast<chip::AddressResolve::Impl::Resolver &>(chip::AddressResolve::Resolver::Instance()).OnThreadDirectLinked();
chip::PeerId peerId;
CHIP_ERROR err = chip::DeviceLayer::Internal::PreCommissioning::GetInstance().GetTargetPeerId(peerId);
VerifyOrReturnError(err == CHIP_NO_ERROR, err,
ChipLogError(AppServer, "Failed to get Thread Direct peer: %" CHIP_ERROR_FORMAT, err.Format()));

auto & server = chip::Server::GetInstance();
const auto * fabric = server.GetFabricTable().FindFabricWithCompressedId(peerId.GetCompressedFabricId());
VerifyOrReturnError(fabric != nullptr, CHIP_ERROR_NOT_FOUND, ChipLogError(AppServer, "Thread Direct peer fabric not found"));

server.GetSecureSessionManager().MarkSessionsAsDefunct(
chip::ScopedNodeId(peerId.GetNodeId(), fabric->GetFabricIndex()),
chip::MakeOptional(chip::Transport::SecureSession::Type::kCASE));
ChipLogProgress(AppServer, "TD linked: prior peer CASE sessions marked defunct");

return CHIP_NO_ERROR;
}

void NotifyResolverThreadDirectUnlinked(intptr_t)
void CancelPendingThreadDirectWork()
{
static_cast<chip::AddressResolve::Impl::Resolver &>(chip::AddressResolve::Resolver::Instance()).OnThreadDirectUnlinked();
PendingThreadDirectWork pending;
for (size_t count = 0; count < kPendingThreadDirectWorkQueueSize; ++count)
{
VerifyOrReturn(osMessageQueueGet(sPendingThreadDirectWorkQueue, &pending, nullptr, 0) == osOK);
VerifyOrDo(pending.onCancel == nullptr, pending.onCancel(pending.arg));
}
}

void NotifyResolverThreadDirectLinkFailed(intptr_t)
{
sThreadDirectLinked.store(false, std::memory_order_relaxed);
CancelPendingThreadDirectWork();
static_cast<chip::AddressResolve::Impl::Resolver &>(chip::AddressResolve::Resolver::Instance()).OnThreadDirectLinkFailed();
}

void NotifyResolverThreadDirectLinked(intptr_t)
{
CHIP_ERROR err = InvalidateThreadDirectPeerSessions();
if (err != CHIP_NO_ERROR)
{
NotifyResolverThreadDirectLinkFailed(0);
return;
}
sThreadDirectLinked.store(true, std::memory_order_relaxed);
static_cast<chip::AddressResolve::Impl::Resolver &>(chip::AddressResolve::Resolver::Instance()).OnThreadDirectLinked();
DrainPendingThreadDirectWork(nullptr);
}

void NotifyResolverThreadDirectUnlinked(intptr_t)
{
static_cast<chip::AddressResolve::Impl::Resolver &>(chip::AddressResolve::Resolver::Instance()).OnThreadDirectUnlinked();
}
#endif // OPENTHREAD_CONFIG_THREAD_DIRECT_WAKE_INITIATOR_ENABLE

class ThreadDirectLinkDelegate : public chip::DeviceLayer::ThreadDirectDelegate
{
public:
void OnThreadDirectLinked() override
{
sThreadDirectLinked.store(true, std::memory_order_relaxed);
VerifyOrReturn(!sThreadDirectLinked.load(std::memory_order_relaxed));
#if OPENTHREAD_CONFIG_THREAD_DIRECT_WAKE_INITIATOR_ENABLE
// OT callbacks run off the Matter stack; hop before touching AddressResolve / SystemLayer.
TEMPORARY_RETURN_IGNORED PlatformMgr().ScheduleWork(NotifyResolverThreadDirectLinked);
#endif // OPENTHREAD_CONFIG_THREAD_DIRECT_WAKE_INITIATOR_ENABLE
CHIP_ERROR err = PlatformMgr().ScheduleWork(NotifyResolverThreadDirectLinked);
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "Failed to schedule Thread Direct link preparation: %" CHIP_ERROR_FORMAT, err.Format());
}
#else
sThreadDirectLinked.store(true, std::memory_order_relaxed);
AppEvent event = {};
event.Handler = DrainPendingThreadDirectWork;
BaseApplication::PostEvent(&event);
#endif // OPENTHREAD_CONFIG_THREAD_DIRECT_WAKE_INITIATOR_ENABLE
}
void OnThreadDirectUnlinked() override
{
sThreadDirectLinked.store(false, std::memory_order_relaxed);
#if OPENTHREAD_CONFIG_THREAD_DIRECT_WAKE_INITIATOR_ENABLE
TEMPORARY_RETURN_IGNORED PlatformMgr().ScheduleWork(NotifyResolverThreadDirectUnlinked);
CHIP_ERROR err = PlatformMgr().ScheduleWork(NotifyResolverThreadDirectUnlinked);
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "Failed to schedule Thread Direct unlink notification: %" CHIP_ERROR_FORMAT, err.Format());
}
#endif // OPENTHREAD_CONFIG_THREAD_DIRECT_WAKE_INITIATOR_ENABLE
}
void OnThreadDirectLinkFailed() override
{
sThreadDirectLinked.store(false, std::memory_order_relaxed);
#if OPENTHREAD_CONFIG_THREAD_DIRECT_WAKE_INITIATOR_ENABLE
TEMPORARY_RETURN_IGNORED PlatformMgr().ScheduleWork(NotifyResolverThreadDirectLinkFailed);
CHIP_ERROR err = PlatformMgr().ScheduleWork(NotifyResolverThreadDirectLinkFailed);
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "Failed to schedule Thread Direct failure notification: %" CHIP_ERROR_FORMAT, err.Format());
}
#endif // OPENTHREAD_CONFIG_THREAD_DIRECT_WAKE_INITIATOR_ENABLE
}
};
Expand Down Expand Up @@ -1066,20 +1124,22 @@ void BaseApplication::DispatchEvent(AppEvent * aEvent)
}
}

CHIP_ERROR BaseApplication::ScheduleWorkGatedOnThreadDirectLink(chip::DeviceLayer::AsyncWorkFunct work, intptr_t arg)
CHIP_ERROR BaseApplication::ScheduleWorkGatedOnThreadDirectLink(chip::DeviceLayer::AsyncWorkFunct work, intptr_t arg,
chip::DeviceLayer::AsyncWorkFunct onCancel)
{
#if SL_USE_THREAD_DIRECT && OPENTHREAD_CONFIG_THREAD_DIRECT_WAKE_INITIATOR_ENABLE
if (sThreadDirectLinked.load(std::memory_order_relaxed))
{
return PlatformMgr().ScheduleWork(work, arg);
}

PendingThreadDirectWork pending{ work, arg };
VerifyOrReturnError(osMessageQueuePut(sPendingThreadDirectWorkQueue, &pending, osPriorityNormal, 0) == osOK,
CHIP_ERROR_NO_MEMORY, ChipLogError(AppServer, "Failed to queue pending Thread Direct work"));
PendingThreadDirectWork pending{ work, arg, onCancel };
osStatus_t queueStatus = osMessageQueuePut(sPendingThreadDirectWorkQueue, &pending, osPriorityNormal, 0);
VerifyOrReturnError(queueStatus == osOK, CHIP_ERROR_NO_MEMORY,
ChipLogError(AppServer, "Failed to queue pending Thread Direct work"));
ThreadStackMgrImpl().ThreadDirectSendWakeup();
return CHIP_NO_ERROR;
#else
static_cast<void>(onCancel);
return PlatformMgr().ScheduleWork(work, arg);
#endif // SL_USE_THREAD_DIRECT
}
Expand Down
5 changes: 4 additions & 1 deletion examples/platform/silabs/BaseApplication.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,11 @@ class BaseApplication
*
* @param work Work function to run on the CHIP task once the link is established
* @param arg Context passed to work function
* @param onCancel Optional cleanup if accepted work fails or times out waiting for the link.
* @note If this function returns an error, the caller remains responsible for arg.
*/
static CHIP_ERROR ScheduleWorkGatedOnThreadDirectLink(chip::DeviceLayer::AsyncWorkFunct work, intptr_t arg = 0);
static CHIP_ERROR ScheduleWorkGatedOnThreadDirectLink(chip::DeviceLayer::AsyncWorkFunct work, intptr_t arg = 0,
chip::DeviceLayer::AsyncWorkFunct onCancel = nullptr);

#if SL_MATTER_DISPLAY_ENABLED
/**
Expand Down
2 changes: 1 addition & 1 deletion third_party/silabs/simplicity_sdk
Submodule simplicity_sdk updated 24 files
+2 −4 openthread/platform-abstraction/efr32/radio_direct.cpp
+1 −15 openthread/platform-abstraction/efr32/radio_security.cpp
+3 −5 openthread_stack/util/third_party/openthread/examples/platforms/simulation/radio.c
+6 −9 openthread_stack/util/third_party/openthread/examples/platforms/utils/mac_frame.cpp
+4 −6 openthread_stack/util/third_party/openthread/examples/platforms/utils/mac_frame.h
+1 −1 openthread_stack/util/third_party/openthread/src/core/config/thread_direct.h
+210 −47 openthread_stack/util/third_party/openthread/src/core/mac/direct_handler.cpp
+29 −15 openthread_stack/util/third_party/openthread/src/core/mac/direct_handler.hpp
+3 −7 openthread_stack/util/third_party/openthread/src/core/mac/mac.cpp
+12 −1 openthread_stack/util/third_party/openthread/src/core/mac/mac_frame.cpp
+17 −12 openthread_stack/util/third_party/openthread/src/core/mac/mac_frame.hpp
+6 −18 openthread_stack/util/third_party/openthread/src/core/mac/mac_header_ltv.cpp
+7 −10 openthread_stack/util/third_party/openthread/src/core/mac/mac_header_ltv.hpp
+2 −2 openthread_stack/util/third_party/openthread/src/core/mac/mac_types.hpp
+2 −1 openthread_stack/util/third_party/openthread/src/core/mac/wakeup_tx_scheduler.cpp
+13 −0 openthread_stack/util/third_party/openthread/src/core/mac/wakeup_tx_scheduler.hpp
+5 −5 openthread_stack/util/third_party/openthread/src/core/thread/direct_peer.cpp
+8 −0 openthread_stack/util/third_party/openthread/src/core/thread/direct_peer.hpp
+14 −0 openthread_stack/util/third_party/openthread/src/core/thread/key_manager.cpp
+18 −7 openthread_stack/util/third_party/openthread/tests/nexus/platform/nexus_core.cpp
+2 −0 openthread_stack/util/third_party/openthread/tests/nexus/platform/nexus_radio.cpp
+1 −0 openthread_stack/util/third_party/openthread/tests/nexus/platform/nexus_radio.hpp
+582 −0 openthread_stack/util/third_party/openthread/tests/nexus/test_td_link_handshake.cpp
+35 −67 openthread_stack/util/third_party/openthread/tests/unit/test_td_ltv.cpp