Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / app / tests / integration / chip_im_initiator.cpp
1 /*
2  *
3  *    Copyright (c) 2020-2021 Project CHIP Authors
4  *
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
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17
18 /**
19  *    @file
20  *      This file implements a chip-im-initiator, for the
21  *      CHIP Interaction Data Model Protocol.
22  *
23  *      Currently it provides simple command sender with sample cluster and command
24  *
25  */
26
27 #include <app/CommandHandler.h>
28 #include <app/CommandSender.h>
29 #include <app/InteractionModelEngine.h>
30 #include <app/tests/integration/common.h>
31 #include <chrono>
32 #include <condition_variable>
33 #include <core/CHIPCore.h>
34 #include <mutex>
35 #include <platform/CHIPDeviceLayer.h>
36
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>
42
43 #define IM_CLIENT_PORT (CHIP_PORT + 1)
44
45 namespace {
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;
51
52 // The CommandSender object.
53 chip::app::CommandSender * gpCommandSender = nullptr;
54
55 // The ReadClient object.
56 chip::app::ReadClient * gpReadClient = nullptr;
57
58 chip::TransportMgr<chip::Transport::UDP> gTransportManager;
59
60 chip::SecureSessionMgr gSessionManager;
61
62 chip::Inet::IPAddress gDestAddr;
63
64 // The last time a CHIP Command was attempted to be sent.
65 uint64_t gLastMessageTime = 0;
66
67 // Count of the number of CommandRequests sent.
68 uint64_t gCommandCount = 0;
69
70 // Count of the number of CommandResponses received.
71 uint64_t gCommandRespCount = 0;
72
73 // Count of the number of CommandRequests sent.
74 uint64_t gReadCount = 0;
75
76 // Count of the number of CommandResponses received.
77 uint64_t gReadRespCount = 0;
78
79 std::condition_variable gCond;
80
81 CHIP_ERROR SendCommandRequest(void)
82 {
83     CHIP_ERROR err = CHIP_NO_ERROR;
84
85     gLastMessageTime = chip::System::Timer::GetCurrentEpoch();
86
87     printf("\nSend invoke command request message to Node: %" PRIu64 "\n", chip::kTestDeviceNodeId);
88
89     chip::app::Command::CommandParams CommandParams = { kTestEndPointId, // Endpoint
90                                                         kTestGroupId,    // GroupId
91                                                         kTestClusterId,  // ClusterId
92                                                         kTestCommandId,  // CommandId
93                                                         (chip::app::Command::CommandPathFlags::kEndpointIdValid) };
94
95     // Add command data here
96
97     uint8_t effectIdentifier = 1; // Dying light
98     uint8_t effectVariant    = 1;
99
100     chip::TLV::TLVType dummyType = chip::TLV::kTLVType_NotSpecified;
101
102     chip::TLV::TLVWriter writer = gpCommandSender->CreateCommandDataElementTLVWriter();
103
104     err = writer.StartContainer(chip::TLV::AnonymousTag, chip::TLV::kTLVType_Structure, dummyType);
105     SuccessOrExit(err);
106
107     err = writer.Put(chip::TLV::ContextTag(1), effectIdentifier);
108     SuccessOrExit(err);
109
110     err = writer.Put(chip::TLV::ContextTag(2), effectVariant);
111     SuccessOrExit(err);
112
113     err = writer.EndContainer(dummyType);
114     SuccessOrExit(err);
115
116     err = writer.Finalize();
117     SuccessOrExit(err);
118
119     err = gpCommandSender->AddCommand(CommandParams);
120     SuccessOrExit(err);
121
122     err = gpCommandSender->SendCommandRequest(chip::kTestDeviceNodeId, gAdminId);
123     SuccessOrExit(err);
124
125     if (err == CHIP_NO_ERROR)
126     {
127         gCommandCount++;
128     }
129     else
130     {
131         printf("Send invoke command request failed, err: %s\n", chip::ErrorStr(err));
132     }
133 exit:
134     return err;
135 }
136
137 CHIP_ERROR SendReadRequest(void)
138 {
139     CHIP_ERROR err = CHIP_NO_ERROR;
140
141     gLastMessageTime = chip::System::Timer::GetCurrentEpoch();
142
143     printf("\nSend read request message to Node: %" PRIu64 "\n", chip::kTestDeviceNodeId);
144
145     err = gpReadClient->SendReadRequest(chip::kTestDeviceNodeId, gAdminId, nullptr, 0);
146     SuccessOrExit(err);
147
148     if (err == CHIP_NO_ERROR)
149     {
150         gReadCount++;
151     }
152     else
153     {
154         printf("Send read request failed, err: %s\n", chip::ErrorStr(err));
155     }
156 exit:
157     return err;
158 }
159
160 CHIP_ERROR EstablishSecureSession()
161 {
162     CHIP_ERROR err = CHIP_NO_ERROR;
163
164     chip::SecurePairingUsingTestSecret * testSecurePairingSecret = chip::Platform::New<chip::SecurePairingUsingTestSecret>();
165     VerifyOrExit(testSecurePairingSecret != nullptr, err = CHIP_ERROR_NO_MEMORY);
166
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);
172
173 exit:
174     if (err != CHIP_NO_ERROR)
175     {
176         printf("Establish secure session failed, err: %s\n", chip::ErrorStr(err));
177         gLastMessageTime = chip::System::Timer::GetCurrentEpoch();
178     }
179     else
180     {
181         printf("Establish secure session succeeded\n");
182     }
183
184     return err;
185 }
186
187 void HandleReadComplete()
188 {
189     uint32_t respTime    = chip::System::Timer::GetCurrentEpoch();
190     uint32_t transitTime = respTime - gLastMessageTime;
191
192     gReadRespCount++;
193
194     printf("Read Response: %" PRIu64 "/%" PRIu64 "(%.2f%%) time=%.3fms\n", gReadRespCount, gReadCount,
195            static_cast<double>(gReadRespCount) * 100 / gReadCount, static_cast<double>(transitTime) / 1000);
196
197     gCond.notify_one();
198 }
199
200 class MockInteractionModelApp : public chip::app::InteractionModelDelegate
201 {
202 public:
203     CHIP_ERROR EventStreamReceived(const chip::Messaging::ExchangeContext * apExchangeContext,
204                                    chip::TLV::TLVReader * apEventListReader) override
205     {
206         return CHIP_NO_ERROR;
207     }
208     CHIP_ERROR ReportProcessed(const chip::app::ReadClient * apReadClient) override
209     {
210         HandleReadComplete();
211         return CHIP_NO_ERROR;
212     }
213     CHIP_ERROR ReportError(const chip::app::ReadClient * apReadClient, CHIP_ERROR aError) override
214     {
215         printf("ReportError with err %d", aError);
216         return CHIP_NO_ERROR;
217     }
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
223     {
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;
228     }
229
230     CHIP_ERROR CommandResponseProtocolError(const chip::app::CommandSender * apCommandSender, uint8_t aCommandIndex) override
231     {
232         printf("CommandResponseProtocolError happens with CommandIndex %d", aCommandIndex);
233         return CHIP_NO_ERROR;
234     }
235
236     CHIP_ERROR CommandResponseTimeout(const chip::app::CommandSender * apCommandSender) override
237     {
238         printf("CommandResponseTimeout happens");
239         return CHIP_NO_ERROR;
240     }
241 };
242
243 } // namespace
244
245 namespace chip {
246 namespace app {
247
248 void DispatchSingleClusterCommand(chip::ClusterId aClusterId, chip::CommandId aCommandId, chip::EndpointId aEndPointId,
249                                   chip::TLV::TLVReader & aReader, Command * apCommandObj)
250 {
251     if (aClusterId != kTestClusterId || aCommandId != kTestCommandId || aEndPointId != kTestEndPointId)
252     {
253         return;
254     }
255
256     uint32_t respTime    = chip::System::Timer::GetCurrentEpoch();
257     uint32_t transitTime = respTime - gLastMessageTime;
258
259     if (aReader.GetLength() != 0)
260     {
261         chip::TLV::Debug::Dump(aReader, TLVPrettyPrinter);
262     }
263     gCommandRespCount++;
264
265     printf("Command Response: %" PRIu64 "/%" PRIu64 "(%.2f%%) time=%.3fms\n", gCommandRespCount, gCommandCount,
266            static_cast<double>(gCommandRespCount) * 100 / gCommandCount, static_cast<double>(transitTime) / 1000);
267
268     gCond.notify_one();
269 }
270 } // namespace app
271 } // namespace chip
272
273 int main(int argc, char * argv[])
274 {
275     CHIP_ERROR err = CHIP_NO_ERROR;
276
277     std::mutex mutex;
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);
283
284     if (argc <= 1)
285     {
286         printf("Missing Command Server IP address\n");
287         ExitNow(err = CHIP_ERROR_INVALID_ARGUMENT);
288     }
289
290     if (!chip::Inet::IPAddress::FromString(argv[1], gDestAddr))
291     {
292         printf("Invalid Command Server IP address: %s\n", argv[1]);
293         ExitNow(err = CHIP_ERROR_INVALID_ARGUMENT);
294     }
295
296     InitializeChip();
297
298     chip::DeviceLayer::PlatformMgr().StartEventLoopTask();
299
300     err = gTransportManager.Init(chip::Transport::UdpListenParameters(&chip::DeviceLayer::InetLayer)
301                                      .SetAddressType(chip::Inet::kIPAddressType_IPv4)
302                                      .SetListenPort(IM_CLIENT_PORT));
303     SuccessOrExit(err);
304
305     err = gSessionManager.Init(chip::kTestControllerNodeId, &chip::DeviceLayer::SystemLayer, &gTransportManager, &admins);
306     SuccessOrExit(err);
307
308     err = gExchangeManager.Init(&gSessionManager);
309     SuccessOrExit(err);
310
311     err = chip::app::InteractionModelEngine::GetInstance()->Init(&gExchangeManager, &mockDelegate);
312     SuccessOrExit(err);
313
314     // Start the CHIP connection to the CHIP im responder.
315     err = EstablishSecureSession();
316     SuccessOrExit(err);
317
318     err = chip::app::InteractionModelEngine::GetInstance()->NewCommandSender(&gpCommandSender);
319     SuccessOrExit(err);
320
321     err = chip::app::InteractionModelEngine::GetInstance()->NewReadClient(&gpReadClient);
322     SuccessOrExit(err);
323
324     // Connection has been established. Now send the CommandRequests.
325     for (unsigned int i = 0; i < kMaxCommandMessageCount; i++)
326     {
327         err = SendCommandRequest();
328         if (err != CHIP_NO_ERROR)
329         {
330             printf("Send command request failed: %s\n", chip::ErrorStr(err));
331             goto exit;
332         }
333
334         if (gCond.wait_for(lock, std::chrono::seconds(gMessageIntervalSeconds)) == std::cv_status::timeout)
335         {
336             printf("Invoke Command: No response received\n");
337         }
338     }
339
340     // Connection has been established. Now send the ReadRequests.
341     for (unsigned int i = 0; i < kMaxReadMessageCount; i++)
342     {
343         err = SendReadRequest();
344         if (err != CHIP_NO_ERROR)
345         {
346             printf("Send read request failed: %s\n", chip::ErrorStr(err));
347             goto exit;
348         }
349
350         if (gCond.wait_for(lock, std::chrono::seconds(gMessageIntervalSeconds)) == std::cv_status::timeout)
351         {
352             printf("read request: No response received\n");
353         }
354     }
355
356     gpCommandSender->Shutdown();
357     chip::app::InteractionModelEngine::GetInstance()->Shutdown();
358     ShutdownChip();
359
360 exit:
361     if (err != CHIP_NO_ERROR || (gCommandRespCount != kMaxCommandMessageCount))
362     {
363         printf("ChipCommandSender failed: %s\n", chip::ErrorStr(err));
364         exit(EXIT_FAILURE);
365     }
366
367     if (err != CHIP_NO_ERROR || (gReadRespCount != kMaxReadMessageCount))
368     {
369         printf("ChipReadClient failed: %s\n", chip::ErrorStr(err));
370         exit(EXIT_FAILURE);
371     }
372     printf("Test success \n");
373     return EXIT_SUCCESS;
374 }