/* * * Copyright (c) 2020-2021 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. */ /** * @file * This file implements a chip-im-initiator, for the * CHIP Interaction Data Model Protocol. * * Currently it provides simple command sender with sample cluster and command * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define IM_CLIENT_PORT (CHIP_PORT + 1) namespace { // Max value for the number of message request sent. constexpr size_t kMaxCommandMessageCount = 3; constexpr size_t kTotalFailureCommandMessageCount = 1; constexpr size_t kMaxReadMessageCount = 3; constexpr size_t kMaxWriteMessageCount = 3; constexpr chip::FabricIndex gFabricIndex = 0; constexpr size_t kMaxSubMessageCount = 1; constexpr uint64_t gSubMaxReport = 5; constexpr chip::System::Clock::Timeout gSubscribeRequestMessageTimeout = chip::System::Clock::Seconds16(1); constexpr chip::System::Clock::Timeout gMessageInterval = chip::System::Clock::Milliseconds32(1200); constexpr chip::System::Clock::Timeout gMessageTimeout = chip::System::Clock::Milliseconds32(1000); chip::TransportMgr gTransportManager; chip::Inet::IPAddress gDestAddr; // The last time a CHIP Command was attempted to be sent. chip::System::Clock::Timestamp gLastMessageTime = chip::System::Clock::kZero; // Count of the number of CommandRequests sent. uint64_t gCommandCount = 0; // Count of the number of CommandResponses received. uint64_t gCommandRespCount = 0; // Count of the number of ReadRequestMessages sent. uint64_t gReadCount = 0; // Count of the number of ReadResponses received. uint64_t gReadRespCount = 0; // Count of the number of WriteRequestMessages sent. uint64_t gWriteCount = 0; // Count of the number of WriteResponseMessages received. uint64_t gWriteRespCount = 0; // Count of the number of SubscribeRequestMessages sent. uint64_t gSubCount = 0; // Count of the number of SubscribeResponseMessages received. uint64_t gSubRespCount = 0; // Count of the number of reports for subscription. uint64_t gSubReportCount = 0; // Whether the last command successed. enum class TestCommandResult : uint8_t { kUndefined, kSuccess, kFailure }; TestCommandResult gLastCommandResult = TestCommandResult::kUndefined; void HandleReadComplete() { auto respTime = chip::System::SystemClock().GetMonotonicTimestamp(); chip::System::Clock::Milliseconds64 transitTime = respTime - gLastMessageTime; gReadRespCount++; printf("Read Response: %" PRIu64 "/%" PRIu64 "(%.2f%%) time=%.3fs\n", gReadRespCount, gReadCount, static_cast(gReadRespCount) * 100 / static_cast(gReadCount), static_cast(transitTime.count()) / 1000); } void HandleSubscribeReportComplete() { auto respTime = chip::System::SystemClock().GetMonotonicTimestamp(); chip::System::Clock::Milliseconds64 transitTime = respTime - gLastMessageTime; gSubRespCount++; printf("Subscribe Complete: %" PRIu64 "/%" PRIu64 "(%.2f%%) time=%.3fs\n", gSubRespCount, gSubCount, static_cast(gSubRespCount) * 100 / static_cast(gSubCount), static_cast(transitTime.count()) / 1000); } class MockInteractionModelApp : public ::chip::app::CommandSender::Callback, public ::chip::app::WriteClient::Callback, public ::chip::app::ReadClient::Callback { public: void OnEventData(const chip::app::EventHeader & aEventHeader, chip::TLV::TLVReader * apData, const chip::app::StatusIB * apStatus) override {} void OnSubscriptionEstablished(chip::SubscriptionId aSubscriptionId) override { if (mReadClient->IsSubscriptionType()) { gSubReportCount++; if (gSubReportCount == gSubMaxReport) { HandleSubscribeReportComplete(); } } } void OnAttributeData(const chip::app::ConcreteDataAttributePath & aPath, chip::TLV::TLVReader * aData, const chip::app::StatusIB & status) override {} void OnError(CHIP_ERROR aError) override { printf("ReadError with err %" CHIP_ERROR_FORMAT, aError.Format()); } void OnDone(chip::app::ReadClient * apReadClient) override { if (apReadClient != mReadClient.get()) { printf("Unexpected read client."); } if (!mReadClient->IsSubscriptionType()) { HandleReadComplete(); } mReadClient.reset(); } void OnResponse(chip::app::CommandSender * apCommandSender, const chip::app::ConcreteCommandPath & aPath, const chip::app::StatusIB & aStatus, chip::TLV::TLVReader * aData) override { printf("Command Response Success with EndpointId %d, ClusterId %d, CommandId %d", aPath.mEndpointId, aPath.mClusterId, aPath.mCommandId); gLastCommandResult = TestCommandResult::kSuccess; auto respTime = chip::System::SystemClock().GetMonotonicTimestamp(); chip::System::Clock::Milliseconds64 transitTime = respTime - gLastMessageTime; gCommandRespCount++; printf("Command Response: %" PRIu64 "/%" PRIu64 "(%.2f%%) time=%.3fs\n", gCommandRespCount, gCommandCount, static_cast(gCommandRespCount) * 100 / static_cast(gCommandCount), static_cast(transitTime.count()) / 1000); } void OnError(const chip::app::CommandSender * apCommandSender, CHIP_ERROR aError) override { gCommandRespCount += (aError.IsIMStatus()); gLastCommandResult = TestCommandResult::kFailure; printf("CommandResponseError happens with %" CHIP_ERROR_FORMAT, aError.Format()); } void OnDone(chip::app::CommandSender * apCommandSender) override { delete apCommandSender; } void OnResponse(const chip::app::WriteClient * apWriteClient, const chip::app::ConcreteDataAttributePath & path, chip::app::StatusIB status) override { auto respTime = chip::System::SystemClock().GetMonotonicTimestamp(); chip::System::Clock::Milliseconds64 transitTime = respTime - gLastMessageTime; gWriteRespCount++; printf("Write Response: %" PRIu64 "/%" PRIu64 "(%.2f%%) time=%.3fs\n", gWriteRespCount, gWriteCount, static_cast(gWriteRespCount) * 100 / static_cast(gWriteCount), static_cast(transitTime.count()) / 1000); } void OnError(const chip::app::WriteClient * apCommandSender, CHIP_ERROR aError) override { printf("WriteClient::OnError happens with %" CHIP_ERROR_FORMAT, aError.Format()); } void OnDone(chip::app::WriteClient * apWriteClient) override {} void AdoptReadClient(chip::Platform::UniquePtr apReadClient) { mReadClient = std::move(apReadClient); } void Shutdown() { mReadClient.reset(); } void OnDeallocatePaths(chip::app::ReadPrepareParams && aReadPrepareParams) override { if (aReadPrepareParams.mpAttributePathParamsList != nullptr) { delete[] aReadPrepareParams.mpAttributePathParamsList; } if (aReadPrepareParams.mpEventPathParamsList != nullptr) { delete[] aReadPrepareParams.mpEventPathParamsList; } } private: chip::Platform::UniquePtr mReadClient; }; MockInteractionModelApp gMockDelegate; void CommandRequestTimerHandler(chip::System::Layer * systemLayer, void * appState); void BadCommandRequestTimerHandler(chip::System::Layer * systemLayer, void * appState); void ReadRequestTimerHandler(chip::System::Layer * systemLayer, void * appState); void WriteRequestTimerHandler(chip::System::Layer * systemLayer, void * appState); void SubscribeRequestTimerHandler(chip::System::Layer * systemLayer, void * appState); CHIP_ERROR SendCommandRequest(std::unique_ptr && commandSender) { CHIP_ERROR err = CHIP_NO_ERROR; VerifyOrReturnError(commandSender != nullptr, CHIP_ERROR_INCORRECT_STATE); gLastMessageTime = chip::System::SystemClock().GetMonotonicTimestamp(); printf("\nSend invoke command request message to Node: %" PRIu64 "\n", chip::kTestDeviceNodeId); chip::app::CommandPathParams commandPathParams = { kTestEndpointId, 0, kTestClusterId, // ClusterId kTestCommandId, // CommandId chip::app::CommandPathFlags::kEndpointIdValid }; // Add command data here uint8_t effectIdentifier = 1; // Dying light uint8_t effectVariant = 1; chip::TLV::TLVWriter * writer; err = commandSender->PrepareCommand(commandPathParams); SuccessOrExit(err); writer = commandSender->GetCommandDataIBTLVWriter(); err = writer->Put(chip::TLV::ContextTag(1), effectIdentifier); SuccessOrExit(err); err = writer->Put(chip::TLV::ContextTag(2), effectVariant); SuccessOrExit(err); err = commandSender->FinishCommand(); SuccessOrExit(err); err = commandSender->SendCommandRequest(gSession.Get().Value(), chip::MakeOptional(gMessageTimeout)); SuccessOrExit(err); gCommandCount++; commandSender.release(); exit: if (err != CHIP_NO_ERROR) { printf("Send invoke command request failed, err: %s\n", chip::ErrorStr(err)); } return err; } CHIP_ERROR SendBadCommandRequest(std::unique_ptr && commandSender) { CHIP_ERROR err = CHIP_NO_ERROR; VerifyOrReturnError(commandSender != nullptr, CHIP_ERROR_INCORRECT_STATE); gLastMessageTime = chip::System::SystemClock().GetMonotonicTimestamp(); printf("\nSend invoke command request message to Node: %" PRIu64 "\n", chip::kTestDeviceNodeId); chip::app::CommandPathParams commandPathParams = { 0xDE, // Bad Endpoint 0xADBE, // Bad GroupId 0xEFCA, // Bad ClusterId 0xFE, // Bad CommandId chip::app::CommandPathFlags::kEndpointIdValid }; err = commandSender->PrepareCommand(commandPathParams); SuccessOrExit(err); err = commandSender->FinishCommand(); SuccessOrExit(err); err = commandSender->SendCommandRequest(gSession.Get().Value(), chip::MakeOptional(gMessageTimeout)); SuccessOrExit(err); gCommandCount++; commandSender.release(); exit: if (err != CHIP_NO_ERROR) { printf("Send invoke command request failed, err: %s\n", chip::ErrorStr(err)); } return err; } CHIP_ERROR SendReadRequest() { CHIP_ERROR err = CHIP_NO_ERROR; chip::app::EventPathParams eventPathParams[2]; eventPathParams[0].mEndpointId = kTestEndpointId; eventPathParams[0].mClusterId = kTestClusterId; eventPathParams[1].mEndpointId = kTestEndpointId; eventPathParams[1].mClusterId = kTestClusterId; eventPathParams[1].mEventId = kTestChangeEvent2; chip::app::AttributePathParams attributePathParams(kTestEndpointId, kTestClusterId, 1); printf("\nSend read request message to Node: %" PRIu64 "\n", chip::kTestDeviceNodeId); chip::app::ReadPrepareParams readPrepareParams(gSession.Get().Value()); readPrepareParams.mTimeout = gMessageTimeout; readPrepareParams.mpAttributePathParamsList = &attributePathParams; readPrepareParams.mAttributePathParamsListSize = 1; readPrepareParams.mpEventPathParamsList = eventPathParams; readPrepareParams.mEventPathParamsListSize = 2; auto readClient = chip::Platform::MakeUnique(chip::app::InteractionModelEngine::GetInstance(), &gExchangeManager, gMockDelegate, chip::app::ReadClient::InteractionType::Read); SuccessOrExit(err = readClient->SendRequest(readPrepareParams)); gMockDelegate.AdoptReadClient(std::move(readClient)); exit: if (err == CHIP_NO_ERROR) { gReadCount++; } else { printf("Send read request failed, err: %s\n", chip::ErrorStr(err)); } return err; } CHIP_ERROR SendWriteRequest(chip::app::WriteClient & apWriteClient) { CHIP_ERROR err = CHIP_NO_ERROR; gLastMessageTime = chip::System::SystemClock().GetMonotonicTimestamp(); printf("\nSend write request message to Node: %" PRIu64 "\n", chip::kTestDeviceNodeId); SuccessOrExit(err = apWriteClient.EncodeAttribute( chip::app::AttributePathParams(2 /* endpoint */, 3 /* cluster */, 4 /* attribute */), true)); SuccessOrExit(err = apWriteClient.SendWriteRequest(gSession.Get().Value(), gMessageTimeout)); gWriteCount++; exit: if (err != CHIP_NO_ERROR) { printf("Send read request failed, err: %s\n", chip::ErrorStr(err)); } return err; } CHIP_ERROR SendSubscribeRequest() { CHIP_ERROR err = CHIP_NO_ERROR; gLastMessageTime = chip::System::SystemClock().GetMonotonicTimestamp(); chip::app::ReadPrepareParams readPrepareParams(gSession.Get().Value()); chip::app::EventPathParams * eventPathParams = new chip::app::EventPathParams[2]; chip::app::AttributePathParams * attributePathParams = new chip::app::AttributePathParams[1]; readPrepareParams.mpEventPathParamsList = eventPathParams; readPrepareParams.mpEventPathParamsList[0].mEndpointId = kTestEndpointId; readPrepareParams.mpEventPathParamsList[0].mClusterId = kTestClusterId; readPrepareParams.mpEventPathParamsList[0].mEventId = kTestChangeEvent1; readPrepareParams.mpEventPathParamsList[1].mEndpointId = kTestEndpointId; readPrepareParams.mpEventPathParamsList[1].mClusterId = kTestClusterId; readPrepareParams.mpEventPathParamsList[1].mEventId = kTestChangeEvent2; readPrepareParams.mEventPathParamsListSize = 2; readPrepareParams.mpAttributePathParamsList = attributePathParams; readPrepareParams.mpAttributePathParamsList[0].mEndpointId = kTestEndpointId; readPrepareParams.mpAttributePathParamsList[0].mClusterId = kTestClusterId; readPrepareParams.mpAttributePathParamsList[0].mAttributeId = 1; readPrepareParams.mAttributePathParamsListSize = 1; readPrepareParams.mMinIntervalFloorSeconds = 5; readPrepareParams.mMaxIntervalCeilingSeconds = 5; printf("\nSend subscribe request message to Node: %" PRIu64 "\n", chip::kTestDeviceNodeId); auto readClient = chip::Platform::MakeUnique(chip::app::InteractionModelEngine::GetInstance(), &gExchangeManager, gMockDelegate, chip::app::ReadClient::InteractionType::Subscribe); err = readClient->SendAutoResubscribeRequest(std::move(readPrepareParams)); gMockDelegate.AdoptReadClient(std::move(readClient)); gSubCount++; if (err != CHIP_NO_ERROR) { printf("Send subscribe request failed, err: %s\n", chip::ErrorStr(err)); } return err; } CHIP_ERROR EstablishSecureSession() { // Attempt to connect to the peer. chip::Transport::PeerAddress peer = chip::Transport::PeerAddress::UDP(gDestAddr, CHIP_PORT, chip::Inet::InterfaceId::Null()); CHIP_ERROR err = gSessionManager.InjectPaseSessionWithTestKey(gSession, 1, chip::kTestDeviceNodeId, 1, gFabricIndex, peer, chip::CryptoContext::SessionRole::kInitiator); if (err != CHIP_NO_ERROR) { printf("Establish secure session failed, err: %s\n", chip::ErrorStr(err)); gLastMessageTime = chip::System::SystemClock().GetMonotonicTimestamp(); } else { printf("Establish secure session succeeded\n"); } return err; } void CommandRequestTimerHandler(chip::System::Layer * systemLayer, void * appState) { CHIP_ERROR err = CHIP_NO_ERROR; if (gCommandRespCount != gCommandCount) { printf("No response received\n"); // Set gCommandRespCount to gCommandCount to start next iteration if there is any. gCommandRespCount = gCommandCount; } if (gCommandRespCount < kMaxCommandMessageCount) { auto commandSender = std::make_unique(&gMockDelegate, &gExchangeManager); VerifyOrExit(commandSender != nullptr, err = CHIP_ERROR_NO_MEMORY); err = SendCommandRequest(std::move(commandSender)); VerifyOrExit(err == CHIP_NO_ERROR, printf("Failed to send command request with error: %s\n", chip::ErrorStr(err))); err = chip::DeviceLayer::SystemLayer().StartTimer(gMessageInterval, CommandRequestTimerHandler, nullptr); VerifyOrExit(err == CHIP_NO_ERROR, printf("Failed to schedule timer with error: %s\n", chip::ErrorStr(err))); } else { err = chip::DeviceLayer::SystemLayer().StartTimer(gMessageInterval, BadCommandRequestTimerHandler, nullptr); VerifyOrExit(err == CHIP_NO_ERROR, printf("Failed to schedule timer with error: %s\n", chip::ErrorStr(err))); } exit: if (err != CHIP_NO_ERROR) { chip::DeviceLayer::PlatformMgr().StopEventLoopTask(); } } void BadCommandRequestTimerHandler(chip::System::Layer * systemLayer, void * appState) { // Test with invalid endpoint / cluster / command combination. CHIP_ERROR err = CHIP_NO_ERROR; auto commandSender = std::make_unique(&gMockDelegate, &gExchangeManager); VerifyOrExit(commandSender != nullptr, err = CHIP_ERROR_NO_MEMORY); err = SendBadCommandRequest(std::move(commandSender)); VerifyOrExit(err == CHIP_NO_ERROR, printf("Failed to send bad command request with error: %s\n", chip::ErrorStr(err))); err = chip::DeviceLayer::SystemLayer().StartTimer(gMessageInterval, ReadRequestTimerHandler, nullptr); VerifyOrExit(err == CHIP_NO_ERROR, printf("Failed to schedule timer with error: %s\n", chip::ErrorStr(err))); exit: if (err != CHIP_NO_ERROR) { chip::DeviceLayer::PlatformMgr().StopEventLoopTask(); } } void ReadRequestTimerHandler(chip::System::Layer * systemLayer, void * appState) { CHIP_ERROR err = CHIP_NO_ERROR; if (gReadRespCount != gReadCount) { printf("No response received\n"); // Set gReadRespCount to gReadCount to start next iteration if there is any. gReadRespCount = gReadCount; } if (gReadRespCount < kMaxReadMessageCount) { err = SendReadRequest(); VerifyOrExit(err == CHIP_NO_ERROR, printf("Failed to send read request with error: %s\n", chip::ErrorStr(err))); err = chip::DeviceLayer::SystemLayer().StartTimer(gMessageInterval, ReadRequestTimerHandler, nullptr); VerifyOrExit(err == CHIP_NO_ERROR, printf("Failed to schedule timer with error: %s\n", chip::ErrorStr(err))); } else { err = chip::DeviceLayer::SystemLayer().StartTimer(gMessageInterval, WriteRequestTimerHandler, nullptr); VerifyOrExit(err == CHIP_NO_ERROR, printf("Failed to schedule timer with error: %s\n", chip::ErrorStr(err))); } exit: if (err != CHIP_NO_ERROR) { chip::DeviceLayer::PlatformMgr().StopEventLoopTask(); } } void WriteRequestTimerHandler(chip::System::Layer * systemLayer, void * appState) { CHIP_ERROR err = CHIP_NO_ERROR; if (gWriteRespCount != gWriteCount) { printf("No response received\n"); // Set gWriteRespCount to gWriteCount to start next iteration if there is any. gWriteRespCount = gWriteCount; } if (gWriteRespCount < kMaxWriteMessageCount) { chip::app::WriteClient writeClient(chip::app::InteractionModelEngine::GetInstance()->GetExchangeManager(), &gMockDelegate, chip::Optional::Missing()); SuccessOrExit(err); err = SendWriteRequest(writeClient); VerifyOrExit(err == CHIP_NO_ERROR, printf("Failed to send write request with error: %s\n", chip::ErrorStr(err))); err = chip::DeviceLayer::SystemLayer().StartTimer(gMessageInterval, WriteRequestTimerHandler, nullptr); VerifyOrExit(err == CHIP_NO_ERROR, printf("Failed to schedule timer with error: %s\n", chip::ErrorStr(err))); } else { err = chip::DeviceLayer::SystemLayer().StartTimer(gSubscribeRequestMessageTimeout, SubscribeRequestTimerHandler, nullptr); VerifyOrExit(err == CHIP_NO_ERROR, printf("Failed to schedule timer with error: %s\n", chip::ErrorStr(err))); } exit: if (err != CHIP_NO_ERROR) { chip::DeviceLayer::PlatformMgr().StopEventLoopTask(); } } void SubscribeRequestTimerHandler(chip::System::Layer * systemLayer, void * appState) { CHIP_ERROR err = CHIP_NO_ERROR; if (gSubRespCount != gSubCount) { printf("No response received\n"); // Set gSubRespCount to gSubCount to start next iteration if there is any. gSubRespCount = gSubCount; } if (gSubRespCount < kMaxSubMessageCount) { err = SendSubscribeRequest(); VerifyOrExit(err == CHIP_NO_ERROR, printf("Failed to send write request with error: %s\n", chip::ErrorStr(err))); err = chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds16(20), SubscribeRequestTimerHandler, nullptr); VerifyOrExit(err == CHIP_NO_ERROR, printf("Failed to schedule timer with error: %s\n", chip::ErrorStr(err))); } else { // Complete all tests. chip::DeviceLayer::PlatformMgr().StopEventLoopTask(); } exit: if (err != CHIP_NO_ERROR) { chip::DeviceLayer::PlatformMgr().StopEventLoopTask(); } } } // namespace namespace chip { namespace app { Protocols::InteractionModel::Status ServerClusterCommandExists(const ConcreteCommandPath & aCommandPath) { // Always return success in test. return Protocols::InteractionModel::Status::Success; } void DispatchSingleClusterCommand(const ConcreteCommandPath & aCommandPath, chip::TLV::TLVReader & aReader, CommandHandler * apCommandObj) { // Nothing todo. } CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered, const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports, AttributeEncodeState * apEncoderState) { AttributeReportIB::Builder & attributeReport = aAttributeReports.CreateAttributeReport(); ReturnErrorOnFailure(aAttributeReports.GetError()); AttributeStatusIB::Builder & attributeStatus = attributeReport.CreateAttributeStatus(); ReturnErrorOnFailure(attributeReport.GetError()); AttributePathIB::Builder & attributePath = attributeStatus.CreatePath(); ReturnErrorOnFailure(attributeStatus.GetError()); attributePath.Endpoint(aPath.mEndpointId).Cluster(aPath.mClusterId).Attribute(aPath.mAttributeId).EndOfAttributePathIB(); ReturnErrorOnFailure(attributePath.GetError()); StatusIB::Builder & errorStatus = attributeStatus.CreateErrorStatus(); errorStatus.EncodeStatusIB(StatusIB(Protocols::InteractionModel::Status::UnsupportedAttribute)); ReturnErrorOnFailure(errorStatus.GetError()); attributeStatus.EndOfAttributeStatusIB(); ReturnErrorOnFailure(attributeStatus.GetError()); return attributeReport.EndOfAttributeReportIB(); } const EmberAfAttributeMetadata * GetAttributeMetadata(const ConcreteAttributePath & aConcreteClusterPath) { // Note: This test does not make use of the real attribute metadata. static EmberAfAttributeMetadata stub = { .defaultValue = EmberAfDefaultOrMinMaxAttributeValue(uint32_t(0)) }; return &stub; } bool ConcreteAttributePathExists(const ConcreteAttributePath & aPath) { return true; } Protocols::InteractionModel::Status CheckEventSupportStatus(const ConcreteEventPath & aPath) { return Protocols::InteractionModel::Status::Success; } CHIP_ERROR WriteSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, const ConcreteDataAttributePath & aPath, TLV::TLVReader & aReader, WriteHandler *) { if (aPath.mClusterId != kTestClusterId || aPath.mEndpointId != kTestEndpointId) { return CHIP_ERROR_INVALID_ARGUMENT; } if (aReader.GetLength() != 0) { chip::TLV::Debug::Dump(aReader, TLVPrettyPrinter); } return CHIP_NO_ERROR; } bool IsClusterDataVersionEqual(const ConcreteClusterPath & aConcreteClusterPath, DataVersion aRequiredVersion) { return true; } bool IsDeviceTypeOnEndpoint(DeviceTypeId deviceType, EndpointId endpoint) { return false; } } // namespace app } // namespace chip int main(int argc, char * argv[]) { CHIP_ERROR err = CHIP_NO_ERROR; std::mutex mutex; std::unique_lock lock(mutex); if (argc <= 1) { printf("Missing Command Server IP address\n"); ExitNow(err = CHIP_ERROR_INVALID_ARGUMENT); } if (!chip::Inet::IPAddress::FromString(argv[1], gDestAddr)) { printf("Invalid Command Server IP address: %s\n", argv[1]); ExitNow(err = CHIP_ERROR_INVALID_ARGUMENT); } static_assert(gMessageInterval > gMessageTimeout, "Interval period too small"); InitializeChip(); err = gTransportManager.Init(chip::Transport::UdpListenParameters(chip::DeviceLayer::UDPEndPointManager()) .SetAddressType(chip::Inet::IPAddressType::kIPv6) .SetListenPort(IM_CLIENT_PORT)); SuccessOrExit(err); err = gSessionManager.Init(&chip::DeviceLayer::SystemLayer(), &gTransportManager, &gMessageCounterManager, &gStorage, &gFabricTable, gSessionKeystore); SuccessOrExit(err); err = gExchangeManager.Init(&gSessionManager); SuccessOrExit(err); err = gMessageCounterManager.Init(&gExchangeManager); SuccessOrExit(err); err = chip::app::InteractionModelEngine::GetInstance()->Init(&gExchangeManager, &gFabricTable, chip::app::reporting::GetDefaultReportScheduler()); SuccessOrExit(err); // Start the CHIP connection to the CHIP im responder. err = EstablishSecureSession(); SuccessOrExit(err); err = chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::kZero, CommandRequestTimerHandler, nullptr); SuccessOrExit(err); chip::DeviceLayer::PlatformMgr().RunEventLoop(); gMockDelegate.Shutdown(); chip::app::InteractionModelEngine::GetInstance()->Shutdown(); gTransportManager.Close(); ShutdownChip(); exit: if (err != CHIP_NO_ERROR || (gCommandRespCount != kMaxCommandMessageCount + kTotalFailureCommandMessageCount)) { printf("ChipCommandSender failed: %s\n", chip::ErrorStr(err)); exit(EXIT_FAILURE); } if (err != CHIP_NO_ERROR || (gReadRespCount != kMaxReadMessageCount)) { printf("ChipReadClient failed: %s\n", chip::ErrorStr(err)); exit(EXIT_FAILURE); } if (err != CHIP_NO_ERROR || (gWriteRespCount != kMaxWriteMessageCount)) { printf("ChipWriteClient failed: %s\n", chip::ErrorStr(err)); exit(EXIT_FAILURE); } printf("Test success \n"); return EXIT_SUCCESS; }