diff --git a/etc/visual-studio/libopenthread-cli-windows.vcxproj b/etc/visual-studio/libopenthread-cli-windows.vcxproj
new file mode 100644
index 000000000..828aa280a
--- /dev/null
+++ b/etc/visual-studio/libopenthread-cli-windows.vcxproj
@@ -0,0 +1,64 @@
+
+
+
+
+ {28834498-3837-44A5-8F67-249ABAB7B97D}
+ StaticLibrary
+ Thread
+ Windows Store
+ 14.0
+ 10.0.10586.0
+ 10.0.10240.0
+ 10.0
+
+
+
+ StaticLibrary
+ true
+ v140
+
+
+ StaticLibrary
+ false
+ v140
+ true
+
+
+
+
+
+
+
+
+
+ ..\..\build\obj\$(Platform)\$(Configuration)\$(ProjectName)\
+ ..\..\build\bin\$(Platform)\$(Configuration)\lib\
+
+
+
+
+ %(PreprocessorDefinitions);
+ MBEDTLS_CONFIG_FILE="mbedtls-config.h";
+ OPENTHREAD_CONFIG_FILE="openthread-windows-config.h";
+ OTDLL;
+
+
+ %(AdditionalIncludeDirectories);
+ ..\..\include;
+ ..\..\src;
+ ..\..\src\core;
+
+ Level3
+ true
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/etc/visual-studio/libopenthread-cli-windows.vcxproj.filters b/etc/visual-studio/libopenthread-cli-windows.vcxproj.filters
new file mode 100644
index 000000000..d0ba0e979
--- /dev/null
+++ b/etc/visual-studio/libopenthread-cli-windows.vcxproj.filters
@@ -0,0 +1,23 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/etc/visual-studio/openthread.sln b/etc/visual-studio/openthread.sln
index ca938ec83..8de9f53c2 100644
--- a/etc/visual-studio/openthread.sln
+++ b/etc/visual-studio/openthread.sln
@@ -48,6 +48,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "otLwf", "otLwf.vcxproj", "{
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "otApi", "otApi.vcxproj", "{ED0EA262-C222-42C7-98D3-E70C72978ED2}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libopenthread-cli-windows", "libopenthread-cli-windows.vcxproj", "{28834498-3837-44A5-8F67-249ABAB7B97D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "otCli", "otCli.vcxproj", "{CAC8A00E-C6C8-4CF0-BA5A-C9A9A601C6DB}"
+EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "otNodeApi", "otNodeApi.vcxproj", "{B7C6F344-7287-4930-AF38-223622BD8CBB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "otTestRunner", "otTestRunner.csproj", "{D5577E51-FA31-4802-8669-1DB32805935E}"
@@ -253,6 +257,30 @@ Global
{ED0EA262-C222-42C7-98D3-E70C72978ED2}.Release|x64.Build.0 = Release|x64
{ED0EA262-C222-42C7-98D3-E70C72978ED2}.Release|x86.ActiveCfg = Release|Win32
{ED0EA262-C222-42C7-98D3-E70C72978ED2}.Release|x86.Build.0 = Release|Win32
+ {28834498-3837-44A5-8F67-249ABAB7B97D}.Debug|ARM.ActiveCfg = Debug|ARM
+ {28834498-3837-44A5-8F67-249ABAB7B97D}.Debug|ARM.Build.0 = Debug|ARM
+ {28834498-3837-44A5-8F67-249ABAB7B97D}.Debug|x64.ActiveCfg = Debug|x64
+ {28834498-3837-44A5-8F67-249ABAB7B97D}.Debug|x64.Build.0 = Debug|x64
+ {28834498-3837-44A5-8F67-249ABAB7B97D}.Debug|x86.ActiveCfg = Debug|Win32
+ {28834498-3837-44A5-8F67-249ABAB7B97D}.Debug|x86.Build.0 = Debug|Win32
+ {28834498-3837-44A5-8F67-249ABAB7B97D}.Release|ARM.ActiveCfg = Release|ARM
+ {28834498-3837-44A5-8F67-249ABAB7B97D}.Release|ARM.Build.0 = Release|ARM
+ {28834498-3837-44A5-8F67-249ABAB7B97D}.Release|x64.ActiveCfg = Release|x64
+ {28834498-3837-44A5-8F67-249ABAB7B97D}.Release|x64.Build.0 = Release|x64
+ {28834498-3837-44A5-8F67-249ABAB7B97D}.Release|x86.ActiveCfg = Release|Win32
+ {28834498-3837-44A5-8F67-249ABAB7B97D}.Release|x86.Build.0 = Release|Win32
+ {CAC8A00E-C6C8-4CF0-BA5A-C9A9A601C6DB}.Debug|ARM.ActiveCfg = Debug|ARM
+ {CAC8A00E-C6C8-4CF0-BA5A-C9A9A601C6DB}.Debug|ARM.Build.0 = Debug|ARM
+ {CAC8A00E-C6C8-4CF0-BA5A-C9A9A601C6DB}.Debug|x64.ActiveCfg = Debug|x64
+ {CAC8A00E-C6C8-4CF0-BA5A-C9A9A601C6DB}.Debug|x64.Build.0 = Debug|x64
+ {CAC8A00E-C6C8-4CF0-BA5A-C9A9A601C6DB}.Debug|x86.ActiveCfg = Debug|Win32
+ {CAC8A00E-C6C8-4CF0-BA5A-C9A9A601C6DB}.Debug|x86.Build.0 = Debug|Win32
+ {CAC8A00E-C6C8-4CF0-BA5A-C9A9A601C6DB}.Release|ARM.ActiveCfg = Release|ARM
+ {CAC8A00E-C6C8-4CF0-BA5A-C9A9A601C6DB}.Release|ARM.Build.0 = Release|ARM
+ {CAC8A00E-C6C8-4CF0-BA5A-C9A9A601C6DB}.Release|x64.ActiveCfg = Release|x64
+ {CAC8A00E-C6C8-4CF0-BA5A-C9A9A601C6DB}.Release|x64.Build.0 = Release|x64
+ {CAC8A00E-C6C8-4CF0-BA5A-C9A9A601C6DB}.Release|x86.ActiveCfg = Release|Win32
+ {CAC8A00E-C6C8-4CF0-BA5A-C9A9A601C6DB}.Release|x86.Build.0 = Release|Win32
{B7C6F344-7287-4930-AF38-223622BD8CBB}.Debug|ARM.ActiveCfg = Debug|ARM
{B7C6F344-7287-4930-AF38-223622BD8CBB}.Debug|ARM.Build.0 = Debug|ARM
{B7C6F344-7287-4930-AF38-223622BD8CBB}.Debug|x64.ActiveCfg = Debug|x64
@@ -350,6 +378,8 @@ Global
{9EEF9DCD-EA8F-4154-BD02-AB2B31CEC324} = {76EA541E-CAB1-4DB5-A39F-E3DB2A78CDDD}
{3F1F7F6C-2A33-4635-9880-08FC5BC4E435} = {61E8A4A0-8138-49DB-97B4-3BEC87C8E133}
{ED0EA262-C222-42C7-98D3-E70C72978ED2} = {61E8A4A0-8138-49DB-97B4-3BEC87C8E133}
+ {28834498-3837-44A5-8F67-249ABAB7B97D} = {95BD0669-04C8-4EEB-B3CC-0535B03F4468}
+ {CAC8A00E-C6C8-4CF0-BA5A-C9A9A601C6DB} = {61E8A4A0-8138-49DB-97B4-3BEC87C8E133}
{B7C6F344-7287-4930-AF38-223622BD8CBB} = {61E8A4A0-8138-49DB-97B4-3BEC87C8E133}
{D5577E51-FA31-4802-8669-1DB32805935E} = {35F6AB71-5BD2-4D53-8A51-D75CCD4CCC3D}
{F8C22844-9B93-4978-80DF-8AF2B37A7ABB} = {76EA541E-CAB1-4DB5-A39F-E3DB2A78CDDD}
diff --git a/etc/visual-studio/otCli.vcxproj b/etc/visual-studio/otCli.vcxproj
new file mode 100644
index 000000000..3ff87126f
--- /dev/null
+++ b/etc/visual-studio/otCli.vcxproj
@@ -0,0 +1,68 @@
+
+
+
+
+ {CAC8A00E-C6C8-4CF0-BA5A-C9A9A601C6DB}
+ Win32Proj
+ Thread
+ Windows Store
+ 14.0
+ 10.0.10586.0
+ 10.0.10240.0
+ 10.0
+
+
+
+ Application
+ true
+ v140
+
+
+ Application
+ false
+ v140
+ true
+
+
+
+
+
+
+
+
+
+ ..\..\build\obj\$(Platform)\$(Configuration)\$(ProjectName)\
+ ..\..\build\bin\$(Platform)\$(Configuration)\exe\
+
+
+
+
+ %(PreprocessorDefinitions);
+ OTDLL;
+
+
+ %(AdditionalIncludeDirectories);
+ ..\..\include;
+
+ Level3
+ true
+
+
+ Console
+
+
+
+
+
+
+
+ {28834498-3837-44a5-8f67-249abab7b97d}
+
+
+ {ed0ea262-c222-42c7-98d3-e70c72978ed2}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/etc/visual-studio/otCli.vcxproj.filters b/etc/visual-studio/otCli.vcxproj.filters
new file mode 100644
index 000000000..203d16a0d
--- /dev/null
+++ b/etc/visual-studio/otCli.vcxproj.filters
@@ -0,0 +1,22 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/examples/drivers/windows/otApi/otApi.cpp b/examples/drivers/windows/otApi/otApi.cpp
index 87077fb88..393d7ec90 100644
--- a/examples/drivers/windows/otApi/otApi.cpp
+++ b/examples/drivers/windows/otApi/otApi.cpp
@@ -1419,6 +1419,32 @@ otSetChannel(
return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_CHANNEL, aChannel));
}
+OTAPI
+ThreadError
+OTCALL
+otSetDelayTimerMinimal(
+ _In_ otInstance *aInstance,
+ uint32_t aDelayTimerMinimal
+ )
+{
+ if (aInstance == nullptr) return kThreadError_InvalidArgs;
+ // TODO
+ UNREFERENCED_PARAMETER(aDelayTimerMinimal);
+ return kThreadError_NotImplemented;
+}
+
+OTAPI
+uint32_t
+OTCALL
+otGetDelayTimerMinimal(
+ _In_ otInstance *aInstance
+ )
+{
+ if (aInstance == nullptr) return 0;
+ // TODO
+ return 0;
+}
+
OTAPI
uint8_t
OTCALL
@@ -2952,6 +2978,21 @@ otGetChildInfoByIndex(
return DwordToThreadError(QueryIOCTL(aInstance, IOCTL_OTLWF_OT_CHILD_INFO_BY_INDEX, &aChildIndex, aChildInfo));
}
+OTAPI
+ThreadError
+OTCALL
+otGetNextNeighborInfo(
+ _In_ otInstance *aInstance,
+ _Inout_ otNeighborInfoIterator *aIterator,
+ _Out_ otNeighborInfo *aInfo
+ )
+{
+ if (aInstance == nullptr) return kThreadError_InvalidArgs;
+ UNREFERENCED_PARAMETER(aIterator);
+ UNREFERENCED_PARAMETER(aInfo);
+ return kThreadError_NotImplemented; // TODO
+}
+
OTAPI
otDeviceRole
OTCALL
diff --git a/examples/drivers/windows/otCli/main.cpp b/examples/drivers/windows/otCli/main.cpp
new file mode 100644
index 000000000..cd46fe54a
--- /dev/null
+++ b/examples/drivers/windows/otCli/main.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include
+#include
+
+#include
+#include
+#include
+
+bool skipNextLine = false;
+
+int main(int argc, char *argv[])
+{
+ otCliUartInit(NULL);
+
+ char cmd[1024] = "\n";
+ otPlatUartReceived((uint8_t*)cmd, 1);
+
+ for (;;)
+ {
+ cmd[0] = 0;
+ if (NULL == fgets(cmd, sizeof(cmd), stdin))
+ continue;
+
+ size_t cmdLen = strlen(cmd);
+ if (cmdLen >= sizeof(cmd)) cmdLen = sizeof(cmd);
+
+ if (strncmp(cmd, "exit", 4) == 0)
+ break;
+
+ skipNextLine = true;
+ otPlatUartReceived((uint8_t*)cmd, (uint16_t)cmdLen);
+ }
+
+ return NO_ERROR;
+}
+
+EXTERN_C ThreadError otPlatUartEnable(void)
+{
+ return kThreadError_None;
+}
+
+EXTERN_C ThreadError otPlatUartSend(const uint8_t *aBuf, uint16_t aBufLength)
+{
+ ThreadError error = kThreadError_None;
+
+ if (!skipNextLine)
+ {
+ for (uint16_t i = 0; i < aBufLength; i++)
+ fputc(aBuf[i], stdout);
+ }
+
+ if (aBuf[aBufLength - 1] == '\n')
+ skipNextLine = false;
+
+ otPlatUartSendDone();
+
+ return error;
+}
\ No newline at end of file
diff --git a/include/openthread.h b/include/openthread.h
index aa8521863..fa511a9ec 100644
--- a/include/openthread.h
+++ b/include/openthread.h
@@ -1827,7 +1827,8 @@ OTAPI ThreadError OTCALL otGetChildInfoByIndex(otInstance *aInstance, uint8_t aC
* @retval kThreadError_InvalidArgs @p aIterator or @p aInfo was NULL.
*
*/
-ThreadError otGetNextNeighborInfo(otInstance *aInstance, otNeighborInfoIterator *aIterator, otNeighborInfo *aInfo);
+OTAPI ThreadError OTCALL otGetNextNeighborInfo(otInstance *aInstance, otNeighborInfoIterator *aIterator,
+ otNeighborInfo *aInfo);
/**
* Get the device role.
diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp
index 46f99c2da..9b7931a15 100644
--- a/src/cli/cli.cpp
+++ b/src/cli/cli.cpp
@@ -41,22 +41,31 @@
#include
#include
+#ifdef OTDLL
+#include
+#endif
+
#include
+#include
+#include
+
+#ifndef OTDLL
#include
#include
#include
-#include
-#include
+
+#include
+#include
#include
#include
+#include
+#endif
+
+#include
#include "cli.hpp"
#include "cli_dataset.hpp"
#include "cli_uart.hpp"
-#include
-#include
-#include
-#include
using Thread::Encoding::BigEndian::HostSwap16;
using Thread::Encoding::BigEndian::HostSwap32;
@@ -96,8 +105,14 @@ const struct Command Interpreter::sCommands[] =
{ "factoryreset", &Interpreter::ProcessFactoryReset },
{ "hashmacaddr", &Interpreter::ProcessHashMacAddress },
{ "ifconfig", &Interpreter::ProcessIfconfig },
+#ifdef OTDLL
+ { "instance", &Interpreter::ProcessInstance },
+ { "instancelist", &Interpreter::ProcessInstanceList },
+#endif
{ "ipaddr", &Interpreter::ProcessIpAddr },
+#ifndef OTDLL
{ "ipmaddr", &Interpreter::ProcessIpMulticastAddr },
+#endif
#if OPENTHREAD_ENABLE_JOINER
{ "joiner", &Interpreter::ProcessJoiner },
#endif
@@ -115,9 +130,13 @@ const struct Command Interpreter::sCommands[] =
{ "networkname", &Interpreter::ProcessNetworkName },
{ "panid", &Interpreter::ProcessPanId },
{ "parent", &Interpreter::ProcessParent },
+#ifndef OTDLL
{ "ping", &Interpreter::ProcessPing },
+#endif
{ "pollperiod", &Interpreter::ProcessPollPeriod },
+#ifndef OTDLL
{ "promiscuous", &Interpreter::ProcessPromiscuous },
+#endif
{ "prefix", &Interpreter::ProcessPrefix },
{ "releaserouterid", &Interpreter::ProcessReleaseRouterId },
{ "reset", &Interpreter::ProcessReset },
@@ -136,14 +155,51 @@ const struct Command Interpreter::sCommands[] =
{ "whitelist", &Interpreter::ProcessWhitelist },
};
+#ifdef OTDLL
+uint32_t otPlatRandomGet(void)
+{
+ return (uint32_t)rand();
+}
+#else
+void otFreeMemory(const void *)
+{
+ // No-op on systems running OpenThread in-proc
+}
+#endif
+
+template class otPtr
+{
+ T *ptr;
+public:
+ otPtr(T *_ptr) : ptr(_ptr) { }
+ ~otPtr() { if (ptr) { otFreeMemory(ptr); } }
+ T *get() const { return ptr; }
+ operator T *() const { return ptr; }
+ T *operator->() const { return ptr; }
+};
+
+typedef otPtr otMacCountersPtr;
+typedef otPtr otNetifAddressPtr;
+typedef otPtr otBufferPtr;
+typedef otPtr otStringPtr;
+
Interpreter::Interpreter(otInstance *aInstance):
sServer(NULL),
+#ifdef OTDLL
+ mApiInstance(otApiInit()),
+ mInstanceIndex(0),
+#else
sLength(8),
sCount(1),
sInterval(1000),
sPingTimer(aInstance->mIp6.mTimerScheduler, &Interpreter::s_HandlePingTimer, this),
+#endif
mInstance(aInstance)
{
+#ifdef OTDLL
+ assert(mApiInstance);
+ CacheInstances();
+#else
memset(mSlaacAddresses, 0, sizeof(mSlaacAddresses));
otSetStateChangedCallback(mInstance, &Interpreter::s_HandleNetifStateChanged, this);
otSetReceiveDiagnosticGetCallback(mInstance, &Interpreter::s_HandleDiagnosticGetResponse, this);
@@ -155,6 +211,7 @@ Interpreter::Interpreter(otInstance *aInstance):
#if OPENTHREAD_ENABLE_DHCP6_CLIENT
memset(mDhcpAddresses, 0, sizeof(mDhcpAddresses));
#endif // OPENTHREAD_ENABLE_DHCP6_CLIENT
+#endif
}
int Interpreter::Hex2Bin(const char *aHex, uint8_t *aBin, uint16_t aBinLength)
@@ -563,7 +620,7 @@ void Interpreter::ProcessCounters(int argc, char *argv[])
{
if (strcmp(argv[0], "mac") == 0)
{
- const otMacCounters *counters = otGetMacCounters(mInstance);
+ otMacCountersPtr counters(otGetMacCounters(mInstance));
sServer->OutputFormat("TxTotal: %d\r\n", counters->mTxTotal);
sServer->OutputFormat(" TxUnicast: %d\r\n", counters->mTxUnicast);
sServer->OutputFormat(" TxBroadcast: %d\r\n", counters->mTxBroadcast);
@@ -704,7 +761,8 @@ void Interpreter::ProcessExtAddress(int argc, char *argv[])
if (argc == 0)
{
- OutputBytes(otGetExtendedAddress(mInstance), OT_EXT_ADDRESS_SIZE);
+ otBufferPtr extAddress(otGetExtendedAddress(mInstance));
+ OutputBytes(extAddress, OT_EXT_ADDRESS_SIZE);
sServer->OutputFormat("\r\n");
}
else
@@ -735,7 +793,8 @@ void Interpreter::ProcessExtPanId(int argc, char *argv[])
if (argc == 0)
{
- OutputBytes(otGetExtendedPanId(mInstance), OT_EXT_PAN_ID_SIZE);
+ otBufferPtr extPanId(otGetExtendedPanId(mInstance));
+ OutputBytes(extPanId, OT_EXT_PAN_ID_SIZE);
sServer->OutputFormat("\r\n");
}
else
@@ -839,7 +898,9 @@ void Interpreter::ProcessIpAddr(int argc, char *argv[])
if (argc == 0)
{
- for (const otNetifAddress *addr = otGetUnicastAddresses(mInstance); addr; addr = addr->mNext)
+ otNetifAddressPtr unicastAddrs(otGetUnicastAddresses(mInstance));
+
+ for (const otNetifAddress *addr = unicastAddrs; addr; addr = addr->mNext)
{
sServer->OutputFormat("%x:%x:%x:%x:%x:%x:%x:%x\r\n",
HostSwap16(addr->mAddress.mFields.m16[0]),
@@ -868,6 +929,7 @@ exit:
AppendResult(error);
}
+#ifndef OTDLL
ThreadError Interpreter::ProcessIpMulticastAddrAdd(int argc, char *argv[])
{
ThreadError error;
@@ -969,6 +1031,7 @@ void Interpreter::ProcessIpMulticastAddr(int argc, char *argv[])
exit:
AppendResult(error);
}
+#endif
void Interpreter::ProcessKeySequence(int argc, char *argv[])
{
@@ -1096,7 +1159,7 @@ void Interpreter::ProcessMasterKey(int argc, char *argv[])
if (argc == 0)
{
uint8_t keyLength;
- const uint8_t *key = otGetMasterKey(mInstance, &keyLength);
+ otBufferPtr key(otGetMasterKey(mInstance, &keyLength));
for (int i = 0; i < keyLength; i++)
{
@@ -1221,7 +1284,8 @@ void Interpreter::ProcessNetworkName(int argc, char *argv[])
if (argc == 0)
{
- sServer->OutputFormat("%.*s\r\n", OT_NETWORK_NAME_MAX_SIZE, otGetNetworkName(mInstance));
+ otStringPtr networkName(otGetNetworkName(mInstance));
+ sServer->OutputFormat("%.*s\r\n", OT_NETWORK_NAME_MAX_SIZE, (const char *)networkName);
}
else
{
@@ -1274,6 +1338,7 @@ exit:
AppendResult(error);
}
+#ifndef OTDLL
void Interpreter::s_HandleIcmpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo,
const otIcmp6Header *aIcmpHeader)
{
@@ -1396,6 +1461,7 @@ exit:
sPingTimer.Start(sInterval);
}
}
+#endif
void Interpreter::ProcessPollPeriod(int argc, char *argv[])
{
@@ -1416,6 +1482,7 @@ exit:
AppendResult(error);
}
+#ifndef OTDLL
void Interpreter::ProcessPromiscuous(int argc, char *argv[])
{
ThreadError error = kThreadError_None;
@@ -1519,6 +1586,7 @@ void Interpreter::HandleLinkPcapReceive(const RadioPacket *aFrame)
sServer->OutputFormat("\r\n");
}
+#endif
ThreadError Interpreter::ProcessPrefixAdd(int argc, char *argv[])
{
@@ -2072,9 +2140,9 @@ void Interpreter::ProcessScan(int argc, char *argv[])
scanChannels = 1 << value;
}
- SuccessOrExit(error = otActiveScan(mInstance, scanChannels, 0, &Interpreter::s_HandleActiveScanResult, this));
sServer->OutputFormat("| J | Network Name | Extended PAN | PAN | MAC Address | Ch | dBm | LQI |\r\n");
sServer->OutputFormat("+---+------------------+------------------+------+------------------+----+-----+-----+\r\n");
+ SuccessOrExit(error = otActiveScan(mInstance, scanChannels, 0, &Interpreter::s_HandleActiveScanResult, this));
return;
@@ -2082,7 +2150,7 @@ exit:
AppendResult(error);
}
-void Interpreter::s_HandleActiveScanResult(otActiveScanResult *aResult, void *aContext)
+void OTCALL Interpreter::s_HandleActiveScanResult(otActiveScanResult *aResult, void *aContext)
{
static_cast(aContext)->HandleActiveScanResult(aResult);
}
@@ -2216,7 +2284,8 @@ exit:
void Interpreter::ProcessVersion(int argc, char *argv[])
{
- sServer->OutputFormat("%s\r\n", otGetVersionString());
+ otStringPtr version(otGetVersionString());
+ sServer->OutputFormat("%s\r\n", (const char *)version);
AppendResult(kThreadError_None);
(void)argc;
(void)argv;
@@ -2469,8 +2538,9 @@ exit:
AppendResult(error);
}
-void Interpreter::s_HandleEnergyReport(uint32_t aChannelMask, const uint8_t *aEnergyList, uint8_t aEnergyListLength,
- void *aContext)
+void OTCALL Interpreter::s_HandleEnergyReport(uint32_t aChannelMask, const uint8_t *aEnergyList,
+ uint8_t aEnergyListLength,
+ void *aContext)
{
static_cast(aContext)->HandleEnergyReport(aChannelMask, aEnergyList, aEnergyListLength);
}
@@ -2487,7 +2557,7 @@ void Interpreter::HandleEnergyReport(uint32_t aChannelMask, const uint8_t *aEner
sServer->OutputFormat("\r\n");
}
-void Interpreter::s_HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask, void *aContext)
+void OTCALL Interpreter::s_HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask, void *aContext)
{
static_cast(aContext)->HandlePanIdConflict(aPanId, aChannelMask);
}
@@ -2527,7 +2597,7 @@ exit:
#endif // OPENTHREAD_ENABLE_JOINER
-void Interpreter::s_HandleJoinerCallback(ThreadError aError, void *aContext)
+void OTCALL Interpreter::s_HandleJoinerCallback(ThreadError aError, void *aContext)
{
static_cast(aContext)->HandleJoinerCallback(aError);
}
@@ -2707,15 +2777,25 @@ exit:
return;
}
-void Interpreter::s_HandleNetifStateChanged(uint32_t aFlags, void *aContext)
+void OTCALL Interpreter::s_HandleNetifStateChanged(uint32_t aFlags, void *aContext)
{
+#ifdef OTDLL
+ otCliContext *cliContext = static_cast(aContext);
+ cliContext->aInterpreter->HandleNetifStateChanged(cliContext->aInstance, aFlags);
+#else
static_cast(aContext)->HandleNetifStateChanged(aFlags);
+#endif
}
+#ifdef OTDLL
+void Interpreter::HandleNetifStateChanged(otInstance *aInstance, uint32_t aFlags)
+#else
void Interpreter::HandleNetifStateChanged(uint32_t aFlags)
+#endif
{
VerifyOrExit((aFlags & OT_THREAD_NETDATA_UPDATED) != 0, ;);
+#ifndef OTDLL
otSlaacUpdate(mInstance, mSlaacAddresses, sizeof(mSlaacAddresses) / sizeof(mSlaacAddresses[0]), otCreateRandomIid,
NULL);
#if OPENTHREAD_ENABLE_DHCP6_SERVER
@@ -2725,6 +2805,7 @@ void Interpreter::HandleNetifStateChanged(uint32_t aFlags)
#if OPENTHREAD_ENABLE_DHCP6_CLIENT
otDhcp6ClientUpdate(mInstance, mDhcpAddresses, sizeof(mDhcpAddresses) / sizeof(mDhcpAddresses[0]), NULL);
#endif // OPENTHREAD_ENABLE_DHCP6_CLIENT
+#endif
exit:
return;
@@ -2769,6 +2850,7 @@ exit:
AppendResult(error);
}
+#ifndef OTDLL
void Interpreter::s_HandleDiagnosticGetResponse(otMessage aMessage, const otMessageInfo *aMessageInfo,
void *aContext)
{
@@ -2798,6 +2880,7 @@ void Interpreter::HandleDiagnosticGetResponse(Message &aMessage, const Ip6::Mess
sServer->OutputFormat("\r\n");
}
+#endif
} // namespace Cli
} // namespace Thread
diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp
index d94af2ee3..4f91a873b 100644
--- a/src/cli/cli.hpp
+++ b/src/cli/cli.hpp
@@ -39,15 +39,23 @@
#else
#include
#endif
+#include
#include
-
#include
#include
#include
+#include
+
+#ifndef OTDLL
#include
#include
#include
+#endif
+
+#ifdef OTDLL
+#define MAX_CLI_OT_INSTANCES 64
+#endif
namespace Thread {
@@ -82,6 +90,8 @@ public:
/**
* Constructor
+ *
+ * @param[in] aInstance The OpenThread instance structure.
*/
Interpreter(otInstance *aInstance);
@@ -173,9 +183,11 @@ private:
ThreadError ProcessIpAddrAdd(int argc, char *argv[]);
ThreadError ProcessIpAddrDel(int argc, char *argv[]);
void ProcessIpMulticastAddr(int argc, char *argv[]);
+#ifndef OTDLL
ThreadError ProcessIpMulticastAddrAdd(int argc, char *argv[]);
ThreadError ProcessIpMulticastAddrDel(int argc, char *argv[]);
ThreadError ProcessMulticastPromiscuous(int argc, char *argv[]);
+#endif
#if OPENTHREAD_ENABLE_JOINER
void ProcessJoiner(int argc, char *argv[]);
#endif // OPENTHREAD_ENABLE_JOINER
@@ -218,34 +230,74 @@ private:
void ProcessVersion(int argc, char *argv[]);
void ProcessWhitelist(int argc, char *argv[]);
+#ifdef OTDLL
+ void ProcessInstanceList(int argc, char *argv[]);
+ void ProcessInstance(int argc, char *argv[]);
+#endif
+
+#ifndef OTDLL
static void s_HandleIcmpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo,
const otIcmp6Header *aIcmpHeader);
static void s_HandlePingTimer(void *aContext);
- static void s_HandleActiveScanResult(otActiveScanResult *aResult, void *aContext);
- static void s_HandleNetifStateChanged(uint32_t aFlags, void *aContext);
+#endif
+ static void OTCALL s_HandleActiveScanResult(otActiveScanResult *aResult, void *aContext);
+ static void OTCALL s_HandleNetifStateChanged(uint32_t aFlags, void *aContext);
+#ifndef OTDLL
static void s_HandleLinkPcapReceive(const RadioPacket *aFrame, void *aContext);
- static void s_HandleEnergyReport(uint32_t aChannelMask, const uint8_t *aEnergyList, uint8_t aEnergyListLength,
- void *aContext);
- static void s_HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask, void *aContext);
- static void s_HandleDiagnosticGetResponse(otMessage aMessage, const otMessageInfo *aMessageInfo, void *aContext);
- static void s_HandleJoinerCallback(ThreadError aError, void *aContext);
+#endif
+ static void OTCALL s_HandleEnergyReport(uint32_t aChannelMask, const uint8_t *aEnergyList, uint8_t aEnergyListLength,
+ void *aContext);
+ static void OTCALL s_HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask, void *aContext);
+#ifndef OTDLL
+ static void OTCALL s_HandleDiagnosticGetResponse(otMessage aMessage, const otMessageInfo *aMessageInfo,
+ void *aContext);
+#endif
+ static void OTCALL s_HandleJoinerCallback(ThreadError aError, void *aContext);
+#ifndef OTDLL
void HandleIcmpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo,
const Ip6::IcmpHeader &aIcmpHeader);
void HandlePingTimer();
+#endif
void HandleActiveScanResult(otActiveScanResult *aResult);
+#ifdef OTDLL
+ void HandleNetifStateChanged(otInstance *aInstance, uint32_t aFlags);
+#else
void HandleNetifStateChanged(uint32_t aFlags);
+#endif
+#ifndef OTDLL
void HandleLinkPcapReceive(const RadioPacket *aFrame);
+#endif
void HandleEnergyReport(uint32_t aChannelMask, const uint8_t *aEnergyList, uint8_t aEnergyListLength);
void HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask);
+#ifndef OTDLL
void HandleDiagnosticGetResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
+#endif
void HandleJoinerCallback(ThreadError aError);
static const struct Command sCommands[];
+ Server *sServer;
+
+#ifdef OTDLL
+
+ void CacheInstances();
+
+ otApiInstance *mApiInstance;
+
+ struct otCliContext
+ {
+ Interpreter *aInterpreter;
+ otInstance *aInstance;
+ };
+ otCliContext mInstances[MAX_CLI_OT_INSTANCES];
+ uint8_t mInstancesLength;
+ uint8_t mInstanceIndex;
+
+#else
+
Ip6::MessageInfo sMessageInfo;
- Server *sServer;
uint16_t sLength;
uint16_t sCount;
uint32_t sInterval;
@@ -257,6 +309,8 @@ private:
#endif // OPENTHREAD_ENABLE_DHCP6_CLIENT
otIcmp6Handler mIcmpHandler;
+#endif
+
otInstance *mInstance;
};
diff --git a/src/cli/cli_instance.cpp b/src/cli/cli_instance.cpp
new file mode 100644
index 000000000..1b9eaf946
--- /dev/null
+++ b/src/cli/cli_instance.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2016, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * This file implements the CLI interpreter Instance related functions.
+ */
+
+#ifdef OPENTHREAD_CONFIG_FILE
+#include OPENTHREAD_CONFIG_FILE
+#else
+#include
+#endif
+
+#include
+#include
+#include
+#include
+
+#include
+#include "cli.hpp"
+
+namespace Thread {
+
+namespace Cli {
+
+void Interpreter::CacheInstances()
+{
+ if (mApiInstance)
+ {
+ otDeviceList *aDeviceList = otEnumerateDevices(mApiInstance);
+ assert(aDeviceList);
+
+ mInstancesLength = aDeviceList->aDevicesLength > MAX_CLI_OT_INSTANCES ?
+ MAX_CLI_OT_INSTANCES :
+ (uint8_t)aDeviceList->aDevicesLength;
+
+ for (uint8_t i = 0; i < mInstancesLength; i++)
+ {
+ mInstances[i].aInterpreter = this;
+ mInstances[i].aInstance = otInstanceInit(mApiInstance, &aDeviceList->aDevices[i]);
+ assert(mInstances[i].aInstance);
+ otSetStateChangedCallback(mInstances[i].aInstance, &Interpreter::s_HandleNetifStateChanged, &mInstances[i]);
+ }
+
+ otFreeMemory(aDeviceList);
+
+ if (mInstancesLength > 0) { mInstance = mInstances[0].aInstance; }
+ }
+}
+
+#define GUID_FORMAT "{%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}"
+#define GUID_ARG(guid) guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]
+
+void Interpreter::ProcessInstanceList(int argc, char *argv[])
+{
+ sServer->OutputFormat("%d instances found:\r\n", mInstancesLength);
+
+ for (uint8_t i = 0; i < mInstancesLength; i++)
+ {
+ GUID aDeviceGuid = otGetDeviceGuid(mInstances[i].aInstance);
+ uint32_t aCompartment = otGetCompartmentId(mInstances[i].aInstance);
+ sServer->OutputFormat("[%d] " GUID_FORMAT " (Compartment %u)\r\n",
+ i, GUID_ARG(aDeviceGuid), aCompartment);
+ }
+}
+
+void Interpreter::ProcessInstance(int argc, char *argv[])
+{
+ ThreadError error = kThreadError_None;
+ long value;
+
+ if (argc == 0)
+ {
+ if (mInstance == NULL)
+ {
+ sServer->OutputFormat("No Instance Set\r\n");
+ }
+ else
+ {
+ GUID aDeviceGuid = otGetDeviceGuid(mInstance);
+ uint32_t aCompartment = otGetCompartmentId(mInstance);
+ sServer->OutputFormat("[%d] " GUID_FORMAT " (Compartment %u)\r\n",
+ mInstanceIndex, GUID_ARG(aDeviceGuid), aCompartment);
+ }
+ }
+ else
+ {
+ SuccessOrExit(error = ParseLong(argv[0], value));
+ VerifyOrExit(value >= 0 && value < mInstancesLength, error = kThreadError_InvalidArgs);
+
+ mInstanceIndex = (uint8_t)value;
+ mInstance = mInstances[mInstanceIndex].aInstance;
+ }
+
+exit:
+ AppendResult(error);
+}
+
+} // namespace Cli
+} // namespace Thread
diff --git a/src/cli/cli_server.hpp b/src/cli/cli_server.hpp
index dbe788511..84d22b536 100644
--- a/src/cli/cli_server.hpp
+++ b/src/cli/cli_server.hpp
@@ -34,7 +34,7 @@
#ifndef CLI_SERVER_HPP_
#define CLI_SERVER_HPP_
-#include
+#include
namespace Thread {
namespace Cli {