3 * Copyright (c) 2020-2021 Project CHIP Authors
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 * This file implements a chip-im-initiator, for the
21 * CHIP Interaction Data Model Protocol.
23 * Currently it provides simple command sender with sample cluster and command
27 #include <app/CommandHandler.h>
28 #include <app/CommandSender.h>
29 #include <app/InteractionModelEngine.h>
30 #include <app/tests/integration/common.h>
32 #include <condition_variable>
33 #include <core/CHIPCore.h>
35 #include <platform/CHIPDeviceLayer.h>
37 #include <support/ErrorStr.h>
38 #include <system/SystemPacketBuffer.h>
39 #include <transport/PASESession.h>
40 #include <transport/SecureSessionMgr.h>
41 #include <transport/raw/UDP.h>
43 #define IM_CLIENT_PORT (CHIP_PORT + 1)
46 // Max value for the number of message request sent.
47 constexpr size_t kMaxCommandMessageCount = 3;
48 constexpr size_t kMaxReadMessageCount = 0;
49 constexpr int32_t gMessageIntervalSeconds = 1;
50 constexpr chip::Transport::AdminId gAdminId = 0;
52 // The CommandSender object.
53 chip::app::CommandSender * gpCommandSender = nullptr;
55 // The ReadClient object.
56 chip::app::ReadClient * gpReadClient = nullptr;
58 chip::TransportMgr<chip::Transport::UDP> gTransportManager;
60 chip::SecureSessionMgr gSessionManager;
62 chip::Inet::IPAddress gDestAddr;
64 // The last time a CHIP Command was attempted to be sent.
65 uint64_t gLastMessageTime = 0;
67 // Count of the number of CommandRequests sent.
68 uint64_t gCommandCount = 0;
70 // Count of the number of CommandResponses received.
71 uint64_t gCommandRespCount = 0;
73 // Count of the number of CommandRequests sent.
74 uint64_t gReadCount = 0;
76 // Count of the number of CommandResponses received.
77 uint64_t gReadRespCount = 0;
79 std::condition_variable gCond;
81 CHIP_ERROR SendCommandRequest(void)
83 CHIP_ERROR err = CHIP_NO_ERROR;
85 gLastMessageTime = chip::System::Timer::GetCurrentEpoch();
87 printf("\nSend invoke command request message to Node: %" PRIu64 "\n", chip::kTestDeviceNodeId);
89 chip::app::Command::CommandParams CommandParams = { kTestEndPointId, // Endpoint
90 kTestGroupId, // GroupId
91 kTestClusterId, // ClusterId
92 kTestCommandId, // CommandId
93 (chip::app::Command::CommandPathFlags::kEndpointIdValid) };
95 // Add command data here
97 uint8_t effectIdentifier = 1; // Dying light
98 uint8_t effectVariant = 1;
100 chip::TLV::TLVType dummyType = chip::TLV::kTLVType_NotSpecified;
102 chip::TLV::TLVWriter writer = gpCommandSender->CreateCommandDataElementTLVWriter();
104 err = writer.StartContainer(chip::TLV::AnonymousTag, chip::TLV::kTLVType_Structure, dummyType);
107 err = writer.Put(chip::TLV::ContextTag(1), effectIdentifier);
110 err = writer.Put(chip::TLV::ContextTag(2), effectVariant);
113 err = writer.EndContainer(dummyType);
116 err = writer.Finalize();
119 err = gpCommandSender->AddCommand(CommandParams);
122 err = gpCommandSender->SendCommandRequest(chip::kTestDeviceNodeId, gAdminId);
125 if (err == CHIP_NO_ERROR)
131 printf("Send invoke command request failed, err: %s\n", chip::ErrorStr(err));
137 CHIP_ERROR SendReadRequest(void)
139 CHIP_ERROR err = CHIP_NO_ERROR;
141 gLastMessageTime = chip::System::Timer::GetCurrentEpoch();
143 printf("\nSend read request message to Node: %" PRIu64 "\n", chip::kTestDeviceNodeId);
145 err = gpReadClient->SendReadRequest(chip::kTestDeviceNodeId, gAdminId, nullptr, 0);
148 if (err == CHIP_NO_ERROR)
154 printf("Send read request failed, err: %s\n", chip::ErrorStr(err));
160 CHIP_ERROR EstablishSecureSession()
162 CHIP_ERROR err = CHIP_NO_ERROR;
164 chip::SecurePairingUsingTestSecret * testSecurePairingSecret = chip::Platform::New<chip::SecurePairingUsingTestSecret>();
165 VerifyOrExit(testSecurePairingSecret != nullptr, err = CHIP_ERROR_NO_MEMORY);
167 // Attempt to connect to the peer.
168 err = gSessionManager.NewPairing(chip::Optional<chip::Transport::PeerAddress>::Value(
169 chip::Transport::PeerAddress::UDP(gDestAddr, CHIP_PORT, INET_NULL_INTERFACEID)),
170 chip::kTestDeviceNodeId, testSecurePairingSecret,
171 chip::SecureSessionMgr::PairingDirection::kInitiator, gAdminId);
174 if (err != CHIP_NO_ERROR)
176 printf("Establish secure session failed, err: %s\n", chip::ErrorStr(err));
177 gLastMessageTime = chip::System::Timer::GetCurrentEpoch();
181 printf("Establish secure session succeeded\n");
187 void HandleReadComplete()
189 uint32_t respTime = chip::System::Timer::GetCurrentEpoch();
190 uint32_t transitTime = respTime - gLastMessageTime;
194 printf("Read Response: %" PRIu64 "/%" PRIu64 "(%.2f%%) time=%.3fms\n", gReadRespCount, gReadCount,
195 static_cast<double>(gReadRespCount) * 100 / gReadCount, static_cast<double>(transitTime) / 1000);
200 class MockInteractionModelApp : public chip::app::InteractionModelDelegate
203 CHIP_ERROR EventStreamReceived(const chip::Messaging::ExchangeContext * apExchangeContext,
204 chip::TLV::TLVReader * apEventListReader) override
206 return CHIP_NO_ERROR;
208 CHIP_ERROR ReportProcessed(const chip::app::ReadClient * apReadClient) override
210 HandleReadComplete();
211 return CHIP_NO_ERROR;
213 CHIP_ERROR ReportError(const chip::app::ReadClient * apReadClient, CHIP_ERROR aError) override
215 printf("ReportError with err %d", aError);
216 return CHIP_NO_ERROR;
218 CHIP_ERROR CommandResponseStatus(const chip::app::CommandSender * apCommandSender,
219 const chip::Protocols::SecureChannel::GeneralStatusCode aGeneralCode,
220 const uint32_t aProtocolId, const uint16_t aProtocolCode, const chip::EndpointId aEndpointId,
221 const chip::ClusterId aClusterId, const chip::CommandId aCommandId,
222 uint8_t aCommandIndex) override
224 printf("CommandResponseStatus with GeneralCode %d, ProtocolId %d, ProtocolCode %d, EndpointId %d, ClusterId %d, CommandId "
225 "%d, CommandIndex %d",
226 static_cast<uint16_t>(aGeneralCode), aProtocolId, aProtocolCode, aEndpointId, aClusterId, aCommandId, aCommandIndex);
227 return CHIP_NO_ERROR;
230 CHIP_ERROR CommandResponseProtocolError(const chip::app::CommandSender * apCommandSender, uint8_t aCommandIndex) override
232 printf("CommandResponseProtocolError happens with CommandIndex %d", aCommandIndex);
233 return CHIP_NO_ERROR;
236 CHIP_ERROR CommandResponseTimeout(const chip::app::CommandSender * apCommandSender) override
238 printf("CommandResponseTimeout happens");
239 return CHIP_NO_ERROR;
248 void DispatchSingleClusterCommand(chip::ClusterId aClusterId, chip::CommandId aCommandId, chip::EndpointId aEndPointId,
249 chip::TLV::TLVReader & aReader, Command * apCommandObj)
251 if (aClusterId != kTestClusterId || aCommandId != kTestCommandId || aEndPointId != kTestEndPointId)
256 uint32_t respTime = chip::System::Timer::GetCurrentEpoch();
257 uint32_t transitTime = respTime - gLastMessageTime;
259 if (aReader.GetLength() != 0)
261 chip::TLV::Debug::Dump(aReader, TLVPrettyPrinter);
265 printf("Command Response: %" PRIu64 "/%" PRIu64 "(%.2f%%) time=%.3fms\n", gCommandRespCount, gCommandCount,
266 static_cast<double>(gCommandRespCount) * 100 / gCommandCount, static_cast<double>(transitTime) / 1000);
273 int main(int argc, char * argv[])
275 CHIP_ERROR err = CHIP_NO_ERROR;
278 std::unique_lock<std::mutex> lock(mutex);
279 MockInteractionModelApp mockDelegate;
280 chip::Transport::AdminPairingTable admins;
281 chip::Transport::AdminPairingInfo * adminInfo = admins.AssignAdminId(gAdminId, chip::kTestControllerNodeId);
282 VerifyOrExit(adminInfo != nullptr, err = CHIP_ERROR_NO_MEMORY);
286 printf("Missing Command Server IP address\n");
287 ExitNow(err = CHIP_ERROR_INVALID_ARGUMENT);
290 if (!chip::Inet::IPAddress::FromString(argv[1], gDestAddr))
292 printf("Invalid Command Server IP address: %s\n", argv[1]);
293 ExitNow(err = CHIP_ERROR_INVALID_ARGUMENT);
298 chip::DeviceLayer::PlatformMgr().StartEventLoopTask();
300 err = gTransportManager.Init(chip::Transport::UdpListenParameters(&chip::DeviceLayer::InetLayer)
301 .SetAddressType(chip::Inet::kIPAddressType_IPv4)
302 .SetListenPort(IM_CLIENT_PORT));
305 err = gSessionManager.Init(chip::kTestControllerNodeId, &chip::DeviceLayer::SystemLayer, &gTransportManager, &admins);
308 err = gExchangeManager.Init(&gSessionManager);
311 err = chip::app::InteractionModelEngine::GetInstance()->Init(&gExchangeManager, &mockDelegate);
314 // Start the CHIP connection to the CHIP im responder.
315 err = EstablishSecureSession();
318 err = chip::app::InteractionModelEngine::GetInstance()->NewCommandSender(&gpCommandSender);
321 err = chip::app::InteractionModelEngine::GetInstance()->NewReadClient(&gpReadClient);
324 // Connection has been established. Now send the CommandRequests.
325 for (unsigned int i = 0; i < kMaxCommandMessageCount; i++)
327 err = SendCommandRequest();
328 if (err != CHIP_NO_ERROR)
330 printf("Send command request failed: %s\n", chip::ErrorStr(err));
334 if (gCond.wait_for(lock, std::chrono::seconds(gMessageIntervalSeconds)) == std::cv_status::timeout)
336 printf("Invoke Command: No response received\n");
340 // Connection has been established. Now send the ReadRequests.
341 for (unsigned int i = 0; i < kMaxReadMessageCount; i++)
343 err = SendReadRequest();
344 if (err != CHIP_NO_ERROR)
346 printf("Send read request failed: %s\n", chip::ErrorStr(err));
350 if (gCond.wait_for(lock, std::chrono::seconds(gMessageIntervalSeconds)) == std::cv_status::timeout)
352 printf("read request: No response received\n");
356 gpCommandSender->Shutdown();
357 chip::app::InteractionModelEngine::GetInstance()->Shutdown();
361 if (err != CHIP_NO_ERROR || (gCommandRespCount != kMaxCommandMessageCount))
363 printf("ChipCommandSender failed: %s\n", chip::ErrorStr(err));
367 if (err != CHIP_NO_ERROR || (gReadRespCount != kMaxReadMessageCount))
369 printf("ChipReadClient failed: %s\n", chip::ErrorStr(err));
372 printf("Test success \n");