| /* |
| * |
| * Copyright (c) 2016-2017 Nest Labs, Inc. |
| * All rights reserved. |
| * |
| * 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 process to effect a functional test for |
| * a client for the Weave Device Description profile. |
| * |
| */ |
| |
| #define __STDC_FORMAT_MACROS |
| #define __STDC_LIMIT_MACROS |
| |
| #include <stdio.h> |
| #include <inttypes.h> |
| #include "ToolCommon.h" |
| #include <Weave/Core/WeaveTLV.h> |
| #include <Weave/Core/WeaveCore.h> |
| #include <Weave/Support/CodeUtils.h> |
| #include <Weave/Profiles/WeaveProfiles.h> |
| #include <Weave/Profiles/common/CommonProfile.h> |
| #include <Weave/Profiles/device-description/DeviceDescription.h> |
| |
| using nl::Inet::IPAddress; |
| using namespace nl::Weave; |
| using namespace nl::Weave::TLV; |
| using namespace nl::Weave::Profiles; |
| using nl::Weave::WeaveExchangeManager; |
| using namespace nl::Weave::Profiles::DeviceDescription; |
| |
| #define TOOL_NAME "weave-dd-client" |
| |
| static bool HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg); |
| static bool HandleNonOptionArgs(const char *progName, int argc, char *argv[]); |
| static void SendIdentifyRequest(System::Layer* aSystemLayer, void* aAppState, System::Error aError); |
| static void HandleIdentifyResponse(void *appState, uint64_t nodeId, const IPAddress& nodeAddr, const IdentifyResponseMessage& respMsg); |
| |
| DeviceDescriptionClient DDClient; |
| static uint64_t DestNodeId = 1; |
| const char *DestIPAddrStr = NULL; |
| IPAddress DestIPAddr; |
| uint32_t ResendInterval = 200; //ms |
| uint32_t ResendCnt = 0; |
| uint32_t ResendMaxCnt = 3; |
| |
| static OptionDef gToolOptionDefs[] = |
| { |
| { "dest-addr", kArgumentRequired, 'D' }, |
| { } |
| }; |
| |
| static const char *gToolOptionHelp = |
| " -D, --dest-addr <host>\n" |
| " Send an ImageQuery request to a specific address rather than one\n" |
| " derived from the destination node id. <host> can be a hostname,\n" |
| " an IPv4 address or an IPv6 address.\n" |
| "\n"; |
| |
| static OptionSet gToolOptions = |
| { |
| HandleOption, |
| gToolOptionDefs, |
| "GENERAL OPTIONS", |
| gToolOptionHelp |
| }; |
| |
| static HelpOptions gHelpOptions( |
| TOOL_NAME, |
| "Usage: " TOOL_NAME " [<options...>] <dest-node-id>[@<dest-host>]\n", |
| WEAVE_VERSION_STRING "\n" WEAVE_TOOL_COPYRIGHT |
| ); |
| |
| static OptionSet *gToolOptionSets[] = |
| { |
| &gToolOptions, |
| &gNetworkOptions, |
| &gWeaveNodeOptions, |
| &gFaultInjectionOptions, |
| &gHelpOptions, |
| NULL |
| }; |
| |
| int main(int argc, char *argv[]) |
| { |
| WEAVE_ERROR err; |
| |
| InitToolCommon(); |
| |
| SetSIGUSR1Handler(); |
| |
| if (argc == 1) |
| { |
| gHelpOptions.PrintBriefUsage(stderr); |
| exit(EXIT_FAILURE); |
| } |
| |
| if (!ParseArgsFromEnvVar(TOOL_NAME, TOOL_OPTIONS_ENV_VAR_NAME, gToolOptionSets, NULL, true) || |
| !ParseArgs(TOOL_NAME, argc, argv, gToolOptionSets, HandleNonOptionArgs) || |
| !ResolveWeaveNetworkOptions(TOOL_NAME, gWeaveNodeOptions, gNetworkOptions)) |
| { |
| exit(EXIT_FAILURE); |
| } |
| |
| InitSystemLayer(); |
| |
| InitNetwork(); |
| |
| InitWeaveStack(true, true); |
| |
| // Initialize the mock-device-description-client application. |
| err = DDClient.Init(&ExchangeMgr); |
| if (err != WEAVE_NO_ERROR) |
| { |
| printf("DeviceDescriptionClient::Init failed: %s\n", ErrorStr(err)); |
| exit(-1); |
| } |
| |
| DDClient.OnIdentifyResponseReceived = HandleIdentifyResponse; |
| |
| PrintNodeConfig(); |
| |
| err = SystemLayer.StartTimer(ResendInterval, SendIdentifyRequest, NULL); |
| if (err != WEAVE_NO_ERROR) |
| { |
| printf("Inet.StartTimer failed: %s\n", ErrorStr(err)); |
| exit(EXIT_FAILURE); |
| } |
| |
| while (!Done) |
| { |
| struct timeval sleepTime; |
| sleepTime.tv_sec = 0; |
| sleepTime.tv_usec = 100000; |
| |
| ServiceNetwork(sleepTime); |
| } |
| printf("over!\n"); |
| ShutdownWeaveStack(); |
| ShutdownNetwork(); |
| ShutdownSystemLayer(); |
| |
| DDClient.CancelExchange(); |
| DDClient.Shutdown(); |
| return EXIT_SUCCESS; |
| } |
| |
| void SendIdentifyRequest(System::Layer* aSystemLayer, void* aAppState, System::Error aError) |
| { |
| printf("Sending identify requests to node %" PRIX64 " at %s\n", DestNodeId, DestIPAddrStr); |
| |
| IdentifyRequestMessage identifyReqMsg; |
| identifyReqMsg.TargetFabricId = gWeaveNodeOptions.FabricId; |
| identifyReqMsg.TargetModes= kTargetDeviceMode_Any; |
| identifyReqMsg.TargetVendorId = 0xFFFF; |
| identifyReqMsg.TargetProductId = 0xFFFF; |
| identifyReqMsg.TargetDeviceId = DestNodeId; |
| |
| IPAddress::FromString(DestIPAddrStr, DestIPAddr); |
| DDClient.SendIdentifyRequest(DestIPAddr, identifyReqMsg); |
| ResendCnt++; |
| if (ResendCnt <= ResendMaxCnt) |
| { |
| SystemLayer.StartTimer(ResendInterval, SendIdentifyRequest, NULL); |
| } |
| else |
| { |
| Done = true; |
| } |
| } |
| |
| bool HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg) |
| { |
| switch (id) |
| { |
| case 'D': |
| DestIPAddrStr = arg; |
| break; |
| default: |
| PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool HandleNonOptionArgs(const char *progName, int argc, char *argv[]) |
| { |
| if (argc < 1) |
| { |
| PrintArgError("%s: Please specify a node id\n", progName); |
| return false; |
| } |
| |
| if (argc > 1) |
| { |
| PrintArgError("%s: Unexpected argument: %s\n", progName, argv[1]); |
| return false; |
| } |
| |
| const char *nodeId = argv[0]; |
| char *p = (char *)strchr(nodeId, '@'); |
| if (p != NULL) |
| { |
| *p = 0; |
| DestIPAddrStr = p+1; |
| } |
| |
| if (!ParseNodeId(nodeId, DestNodeId)) |
| { |
| PrintArgError("%s: Invalid value specified for destination node-id: %s\n", progName, nodeId); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| static void HandleIdentifyResponse(void *appState, uint64_t nodeId, const IPAddress& nodeAddr, const IdentifyResponseMessage& respMsg) |
| { |
| WeaveDeviceDescriptor deviceDesc = respMsg.DeviceDesc; |
| char ipAddrStr[64]; |
| nodeAddr.ToString(ipAddrStr, sizeof(ipAddrStr)); |
| printf("IdentifyResponse received from node %" PRIX64 " (%s)\n", nodeId, ipAddrStr); |
| printf(" Source Fabric Id: %016" PRIX64 "\n", deviceDesc.FabricId); |
| printf(" Source Vendor Id: %04X\n", (unsigned)deviceDesc.VendorId); |
| printf(" Source Product Id: %04X\n", (unsigned)deviceDesc.ProductId); |
| printf(" Source Product Revision: %04X\n", (unsigned)deviceDesc.ProductRevision); |
| printf("Received IdentifyResponse\n"); |
| printf("Device Description Operation Completed\n"); |
| DDClient.CancelExchange(); |
| DDClient.Shutdown(); |
| Done = true; |
| } |