blob: d7a9b72ccf10d0d0e85de1441e913f43c9eb7ee0 [file] [log] [blame]
/*
*
* 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;
}