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 {