#include "sample-mei-server.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace chip; using namespace chip::app; using namespace chip::app::Clusters; using namespace chip::app::Clusters::SampleMei; using namespace chip::app::Clusters::SampleMei::Commands; using namespace chip::app::Clusters::SampleMei::Attributes; // ***************************************************************************** // Init/Shutdown Callbacks void MatterSampleMeiPluginServerInitCallback() { ChipLogProgress(Zcl, "Sample MEI Init. Ep %d, Total Ep %u", MATTER_DM_SAMPLE_MEI_CLUSTER_SERVER_ENDPOINT_COUNT, static_cast(kNumSupportedEndpoints)); ReturnOnFailure(CommandHandlerInterfaceRegistry::Instance().RegisterCommandHandler(&SampleMeiServer::Instance())); VerifyOrReturn(AttributeAccessInterfaceRegistry::Instance().Register(&SampleMeiServer::Instance()), CHIP_ERROR_INCORRECT_STATE); } void emberAfSampleMeiClusterServerInitCallback(chip::EndpointId endpoint) { ChipLogProgress(Zcl, "Creating Sample MEI cluster, Ep %d", endpoint); SampleMeiServer::Instance().RegisterEndpoint(endpoint); } void MatterSampleMeiClusterServerShutdownCallback(chip::EndpointId endpoint) { // There's currently no whole-cluster shutdown callback. That would trigger // call to `Shutdown`. Thus ep-based shutdown calls `UnregisterEndpoint` ChipLogProgress(Zcl, "Shutting down Sample MEI cluster, Ep %d", endpoint); SampleMeiServer::Instance().UnregisterEndpoint(endpoint); } // ***************************************************************************** // SampleMeiContent namespace chip { namespace app { namespace Clusters { namespace SampleMei { SampleMeiContent::SampleMeiContent() : SampleMeiContent(kInvalidEndpointId) {} SampleMeiContent::SampleMeiContent(EndpointId aEndpoint) { endpoint = aEndpoint; pingCount = 10000; // Attribute default values flipflop = false; } // ***************************************************************************** // SampleMeiServer void SampleMeiServer::InvokeCommand(HandlerContext & ctxt) { auto endpoint = ctxt.mRequestPath.mEndpointId; auto fabricIndex = ctxt.mCommandHandler.GetAccessingFabricIndex(); auto endpointIndex = EndpointIndex(endpoint); if (endpointIndex == std::numeric_limits::max()) { ctxt.mCommandHandler.AddStatus(ctxt.mRequestPath, Protocols::InteractionModel::Status::UnsupportedEndpoint); return; } switch (ctxt.mRequestPath.mCommandId) { case Commands::Ping::Id: HandleCommand( ctxt, [this, endpoint, fabricIndex, endpointIndex](HandlerContext & ctx, const auto & req) { ChipLogProgress(Zcl, "Ping Command on Ep %d", endpoint); Events::PingCountEvent::Type event{ .count = content[endpointIndex].pingCount++, .fabricIndex = fabricIndex }; chip::EventNumber placeholderEventNumber; CHIP_ERROR err = LogEvent(event, endpoint, placeholderEventNumber); if (CHIP_NO_ERROR != err) { ChipLogError(Zcl, "Failed to record event on endpoint %d: %" CHIP_ERROR_FORMAT, static_cast(endpoint), err.Format()); } ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::Success); }); return; case Commands::AddArguments::Id: HandleCommand(ctxt, [endpoint](HandlerContext & ctx, const auto & req) { ChipLogProgress(Zcl, "AddArgumentsCommand on Ep %d", endpoint); if (req.arg1 > UINT8_MAX - req.arg2) { ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand); return; } AddArgumentsResponse::Type response; response.returnValue = static_cast(req.arg1 + req.arg2); ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); }); return; } } CHIP_ERROR SampleMeiServer::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) { CHIP_ERROR err = CHIP_NO_ERROR; auto endpoint = aPath.mEndpointId; auto endpointIndex = EndpointIndex(endpoint); if (endpointIndex == std::numeric_limits::max()) { return CHIP_IM_GLOBAL_STATUS(UnsupportedEndpoint); } switch (aPath.mAttributeId) { case Attributes::FlipFlop::Id: ChipLogProgress(Zcl, "Read Attribute flip-flop from Ep %d index %u value %d", endpoint, static_cast(endpointIndex), content[endpointIndex].flipflop); err = aEncoder.Encode(content[endpointIndex].flipflop); break; default: break; } return err; } CHIP_ERROR SampleMeiServer::Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder) { CHIP_ERROR err = CHIP_NO_ERROR; auto endpoint = aPath.mEndpointId; auto endpointIndex = EndpointIndex(endpoint); if (endpointIndex == std::numeric_limits::max()) { return CHIP_IM_GLOBAL_STATUS(UnsupportedEndpoint); } switch (aPath.mAttributeId) { case Attributes::FlipFlop::Id: { auto oldValue = content[endpointIndex].flipflop; ReturnErrorOnFailure(aDecoder.Decode(content[endpointIndex].flipflop)); ChipLogProgress(Zcl, "Write Attribute flip-flop on Ep %d index %u newValue %d oldValue %d", endpoint, static_cast(endpointIndex), content[endpointIndex].flipflop, oldValue); break; } default: break; } return err; } SampleMeiServer & SampleMeiServer::Instance() { static SampleMeiServer sampleMeiServer; return sampleMeiServer; } void SampleMeiServer::Shutdown() { for (size_t i = 0; i < kNumSupportedEndpoints; ++i) { content[i].endpoint = kInvalidEndpointId; } } size_t SampleMeiServer::GetNumSupportedEndpoints() const { return kNumSupportedEndpoints; } CHIP_ERROR SampleMeiServer::RegisterEndpoint(EndpointId endpointId) { size_t endpointIndex = NextEmptyIndex(); if (endpointIndex == std::numeric_limits::max()) { return CHIP_ERROR_NO_MEMORY; } content[endpointIndex] = SampleMeiContent(endpointId); return CHIP_NO_ERROR; } CHIP_ERROR SampleMeiServer::UnregisterEndpoint(EndpointId endpointId) { size_t endpointIndex = EndpointIndex(endpointId); if (endpointIndex == std::numeric_limits::max()) { return CHIP_ERROR_INVALID_ARGUMENT; } content[endpointIndex].endpoint = kInvalidEndpointId; return CHIP_NO_ERROR; } size_t SampleMeiServer::EndpointIndex(EndpointId endpointId) const { for (size_t i = 0; i < kNumSupportedEndpoints; ++i) { if (content[i].endpoint == endpointId) { return i; } } return std::numeric_limits::max(); } size_t SampleMeiServer::NextEmptyIndex() const { for (size_t i = 0; i < kNumSupportedEndpoints; ++i) { if (content[i].endpoint == kInvalidEndpointId) { return i; } } return std::numeric_limits::max(); } } // namespace SampleMei } // namespace Clusters } // namespace app } // namespace chip