| /* |
| * |
| * 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 <app/CommandHandler.h> |
| #include <app/CommandSender.h> |
| #include <app/ConcreteAttributePath.h> |
| #include <app/InteractionModelEngine.h> |
| #include <app/tests/integration/common.h> |
| #include <chrono> |
| #include <lib/core/CHIPCore.h> |
| #include <lib/support/ErrorStr.h> |
| #include <lib/support/TypeTraits.h> |
| #include <memory> |
| #include <mutex> |
| #include <platform/CHIPDeviceLayer.h> |
| #include <protocols/secure_channel/PASESession.h> |
| #include <system/SystemClock.h> |
| #include <system/SystemPacketBuffer.h> |
| #include <transport/SessionManager.h> |
| #include <transport/raw/UDP.h> |
| |
| #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<chip::Transport::UDP> 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<double>(gReadRespCount) * 100 / static_cast<double>(gReadCount), |
| static_cast<double>(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<double>(gSubRespCount) * 100 / static_cast<double>(gSubCount), |
| static_cast<double>(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<double>(gCommandRespCount) * 100 / static_cast<double>(gCommandCount), |
| static_cast<double>(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<double>(gWriteRespCount) * 100 / static_cast<double>(gWriteCount), |
| static_cast<double>(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<chip::app::ReadClient> 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<chip::app::ReadClient> 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<chip::app::CommandSender> && 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<chip::app::CommandSender> && 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::ReadClient>(chip::app::InteractionModelEngine::GetInstance(), &gExchangeManager, |
| gMockDelegate, chip::app::ReadClient::InteractionType::Read); |
| |
| SuccessOrExit(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::ReadClient>(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<chip::app::CommandSender>(&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<chip::app::CommandSender>(&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<uint16_t>::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, |
| AttributeValueEncoder::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().GetError(); |
| } |
| |
| 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; |
| } |
| |
| 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<std::mutex> 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); |
| SuccessOrExit(err); |
| |
| err = gExchangeManager.Init(&gSessionManager); |
| SuccessOrExit(err); |
| |
| err = gMessageCounterManager.Init(&gExchangeManager); |
| SuccessOrExit(err); |
| |
| err = chip::app::InteractionModelEngine::GetInstance()->Init(&gExchangeManager, &gFabricTable); |
| 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; |
| } |