diff --git a/doc/images/windows-app-details.png b/doc/images/windows-app-details.png
new file mode 100644
index 000000000..be3e3c5fb
Binary files /dev/null and b/doc/images/windows-app-details.png differ
diff --git a/doc/images/windows-app-interface-list.png b/doc/images/windows-app-interface-list.png
new file mode 100644
index 000000000..8fdde7d13
Binary files /dev/null and b/doc/images/windows-app-interface-list.png differ
diff --git a/etc/visual-studio/OpenThread.vcxproj b/etc/visual-studio/OpenThread.vcxproj
index 1c4de0dc6..f2a392e57 100644
--- a/etc/visual-studio/OpenThread.vcxproj
+++ b/etc/visual-studio/OpenThread.vcxproj
@@ -59,6 +59,8 @@
+
+
..\..\examples\apps\windows\App.xaml
diff --git a/etc/visual-studio/OpenThread.vcxproj.filters b/etc/visual-studio/OpenThread.vcxproj.filters
index ac15ec70e..6fc36479f 100644
--- a/etc/visual-studio/OpenThread.vcxproj.filters
+++ b/etc/visual-studio/OpenThread.vcxproj.filters
@@ -21,6 +21,8 @@
+
+
diff --git a/examples/apps/windows/MainPage.xaml b/examples/apps/windows/MainPage.xaml
index 05aaec872..73698f02e 100644
--- a/examples/apps/windows/MainPage.xaml
+++ b/examples/apps/windows/MainPage.xaml
@@ -114,7 +114,7 @@
/>
0) OutputDebugStringA(logString);
+
+ va_end(args);
}
-void OTCALL
-ThreadDeviceAvailabilityCallback(
- bool /* aAdded */,
- const GUID* /* aDeviceGuid */,
- _In_ void* /* aContext */
- )
-{
- // Trigger the interface list to update
- MainPage::Current->Dispatcher->RunAsync(
- Windows::UI::Core::CoreDispatcherPriority::Normal,
- ref new Windows::UI::Core::DispatchedHandler(
- [=]() {
- MainPage::Current->BuildInterfaceList();
- }
- )
- );
-}
-
-void OTCALL
-ThreadStateChangeCallback(
- uint32_t aFlags,
- _In_ void* /* aContext */
- )
-{
- if ((aFlags & OT_NET_ROLE) != 0)
- {
- // Trigger the interface list to update
- MainPage::Current->Dispatcher->RunAsync(
- Windows::UI::Core::CoreDispatcherPriority::Normal,
- ref new Windows::UI::Core::DispatchedHandler(
- [=]() {
- MainPage::Current->BuildInterfaceList();
- }
- )
- );
- }
-}
-
-MainPage::MainPage()
+MainPage::MainPage() : _otApi(nullptr)
{
InitializeComponent();
- MainPage::Current = this;
- _isFullScreen = false;
-
- _apiInstance = nullptr;
InterfaceConfigCancelButton->Click +=
ref new RoutedEventHandler(
[=](Platform::Object^, RoutedEventArgs^) {
- InterfaceConfiguration->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
+ this->InterfaceConfiguration->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
+ this->_curAdapter = nullptr;
}
);
InterfaceConfigOkButton->Click +=
ref new RoutedEventHandler(
[=](Platform::Object^, RoutedEventArgs^) {
- InterfaceConfiguration->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
- ConnectNetwork(_currentInterface);
+ this->InterfaceConfiguration->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
+ this->ConnectNetwork(_curAdapter);
+ this->_curAdapter = nullptr;
}
);
InterfaceDetailsCloseButton->Click +=
ref new RoutedEventHandler(
[=](Platform::Object^, RoutedEventArgs^) {
- InterfaceDetails->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
+ this->InterfaceDetails->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
}
);
}
void MainPage::OnNavigatedTo(NavigationEventArgs^ e)
{
- Window::Current->CoreWindow->VisibilityChanged += ref new TypedEventHandler(this, &MainPage::OnVisibilityChanged);
-
- SizeChanged += ref new SizeChangedEventHandler(this, &MainPage::OnWindowSizeChanged);
Loaded += ref new RoutedEventHandler(this, &MainPage::OnLoaded);
Unloaded += ref new RoutedEventHandler(this, &MainPage::OnUnloaded);
-
- _isVisible = Window::Current->CoreWindow->Visible;
}
void MainPage::OnLoaded(Object^ sender, RoutedEventArgs^ e)
{
- // Initialize api handle
- _apiInstance = otApiInit();
- if (_apiInstance)
+ try
{
- // Register for device availability callbacks
- otSetDeviceAvailabilityChangedCallback(ApiInstance, ThreadDeviceAvailabilityCallback, nullptr);
+ // Initialize api handle
+ _otApi = ref new otApi();
- // Build the initial list
- BuildInterfaceList();
+ // Register for state changes
+ _adapterArrivalToken =
+ _otApi->AdapterArrival +=
+ ref new otAdapterArrivalDelegate(
+ [=](otAdapter^ adapter) {
+ // Update on the UI thread
+ this->Dispatcher->RunAsync(
+ Windows::UI::Core::CoreDispatcherPriority::Normal,
+ ref new Windows::UI::Core::DispatchedHandler(
+ [=]() {
+ this->AddAdapterToList(adapter);
+ }));
+ });
+
+ // Enumerate the adapter list
+ auto adapters = _otApi->GetAdapters();
+ for (auto&& adapter : adapters) {
+ AddAdapterToList(adapter);
+ }
+ }
+ catch (Exception^)
+ {
}
}
void MainPage::OnUnloaded(Object^ sender, RoutedEventArgs^ e)
{
- // Unregister for callbacks
- otSetDeviceAvailabilityChangedCallback(ApiInstance, nullptr, nullptr);
+ if (_otApi)
+ {
+ // Unregister
+ _otApi->AdapterArrival -= _adapterArrivalToken;
- // Clean up api handle
- otApiFinalize(ApiInstance);
- _apiInstance = nullptr;
+ // Clear current adapter
+ _curAdapter = nullptr;
+
+ // Remove the adapter list
+ auto adapters = _otApi->GetAdapters();
+ for (auto&& adapter : adapters) {
+ adapter->InvokeAdapterRemoval();
+ }
+
+ // Free the api handle
+ _otApi = nullptr;
+ }
}
void MainPage::OnResuming()
{
}
-void MainPage::OnWindowSizeChanged(Object^ sender, SizeChangedEventArgs^ args)
+void MainPage::ShowInterfaceDetails(otAdapter^ adapter)
{
- _windowSize = args->NewSize;
-}
-
-void MainPage::OnVisibilityChanged(Windows::UI::Core::CoreWindow^ coreWindow, Windows::UI::Core::VisibilityChangedEventArgs^ args)
-{
- // The Visible property is toggled when the app enters and exits minimized state.
- // But obscuring the app with another window does not change Visible state, oddly enough.
- _isVisible = args->Visible;
-}
-
-void MainPage::ShowInterfaceDetails(Platform::Guid InterfaceGuid)
-{
- if (ApiInstance == nullptr) return;
-
- GUID deviceGuid = InterfaceGuid;
- auto device = otInstanceInit(ApiInstance, &deviceGuid);
-
- auto extendedAddress = otLinkGetExtendedAddress(device);
- if (extendedAddress)
+ try
{
- WCHAR szMac[256] = { 0 };
- swprintf_s(szMac, 256, MAC8_FORMAT, MAC8_ARG(extendedAddress));
- InterfaceMacAddress->Text = ref new String(szMac);
+ InterfaceMacAddress->Text = otApi::ToString(adapter->ExtendedAddress);
+ InterfaceML_EID->Text = adapter->MeshLocalEid->ToString();
+ InterfaceRLOC->Text = otApi::ToString(adapter->Rloc16);
- otFreeMemory(extendedAddress);
- }
- else
- {
- InterfaceMacAddress->Text = L"ERROR";
- }
-
- auto ml_eid = otThreadGetMeshLocalEid(device);
- if (ml_eid)
- {
- WCHAR szAddress[46] = { 0 };
- RtlIpv6AddressToStringW((const PIN6_ADDR)ml_eid, szAddress);
- InterfaceML_EID->Text = ref new String(szAddress);
-
- otFreeMemory(ml_eid);
- }
- else
- {
- InterfaceML_EID->Text = L"ERROR";
- }
-
- auto rloc16 = otThreadGetRloc16(device);
- WCHAR szRloc[16] = { 0 };
- swprintf_s(szRloc, 16, L"%4x", rloc16);
- InterfaceRLOC->Text = ref new String(szRloc);
-
- if (otThreadGetDeviceRole(device) > kDeviceRoleChild)
- {
- uint8_t index = 0;
- otChildInfo childInfo;
- while (kThreadError_None == otThreadGetChildInfoByIndex(device, index, &childInfo))
+ if (adapter->State > otThreadState::Child)
{
- index++;
+ uint8_t index = 0;
+ otChildInfo childInfo;
+ while (kThreadError_None == otThreadGetChildInfoByIndex((otInstance*)(void*)adapter->RawHandle, index, &childInfo))
+ {
+ index++;
+ }
+
+ WCHAR szText[64] = { 0 };
+ swprintf_s(szText, 64, L"%d", index);
+ InterfaceChildren->Text = ref new String(szText);
+
+ InterfaceNeighbors->Text = L"unknown";
+
+ InterfaceNeighbors->Visibility = Windows::UI::Xaml::Visibility::Visible;
+ InterfaceNeighborsText->Visibility = Windows::UI::Xaml::Visibility::Visible;
+ InterfaceChildren->Visibility = Windows::UI::Xaml::Visibility::Visible;
+ InterfaceChildrenText->Visibility = Windows::UI::Xaml::Visibility::Visible;
}
- WCHAR szText[64] = { 0 };
- swprintf_s(szText, 64, L"%d", index);
- InterfaceChildren->Text = ref new String(szText);
-
- InterfaceNeighbors->Text = L"unknown";
-
- InterfaceNeighbors->Visibility = Windows::UI::Xaml::Visibility::Visible;
- InterfaceNeighborsText->Visibility = Windows::UI::Xaml::Visibility::Visible;
- InterfaceChildren->Visibility = Windows::UI::Xaml::Visibility::Visible;
- InterfaceChildrenText->Visibility = Windows::UI::Xaml::Visibility::Visible;
+ // Show the details
+ InterfaceDetails->Visibility = Windows::UI::Xaml::Visibility::Visible;
}
+ catch (Exception^)
+ {
- // Show the details
- InterfaceDetails->Visibility = Windows::UI::Xaml::Visibility::Visible;
-
- otFreeMemory(device);
+ }
}
-UIElement^ MainPage::CreateNewInterface(Platform::Guid InterfaceGuid)
+void MainPage::AddAdapterToList(otAdapter^ adapter)
{
- GUID deviceGuid = InterfaceGuid;
-
- auto device = otInstanceInit(ApiInstance, &deviceGuid);
- auto deviceRole = otThreadGetDeviceRole(device);
-
- WCHAR szText[256] = { 0 };
- swprintf_s(szText, 256, L"%s\r\n\t" GUID_FORMAT L"\r\n\t%s",
- L"openthread interface", // TODO ...
- GUID_ARG(deviceGuid),
- ::ToString(deviceRole));
-
- auto InterfaceStackPanel = ref new StackPanel();
- InterfaceStackPanel->Orientation = Orientation::Horizontal;
-
- auto InterfaceTextBlock = ref new TextBlock();
- InterfaceTextBlock->Text = ref new String(szText);
- InterfaceTextBlock->FontSize = 16;
- InterfaceTextBlock->Margin = Thickness(10);
- InterfaceTextBlock->TextWrapping = TextWrapping::Wrap;
- InterfaceStackPanel->Children->Append(InterfaceTextBlock);
-
- if (deviceRole == kDeviceRoleDisabled)
+ try
{
+ GUID interfaceGuid = adapter->InterfaceGuid;
+ WCHAR szName[256] = { 0 };
+ swprintf_s(szName, 256, GUID_FORMAT, GUID_ARG(interfaceGuid));
+
+ auto InterfaceStackPanel = ref new StackPanel();
+ InterfaceStackPanel->Name = ref new String(szName);
+ InterfaceStackPanel->Orientation = Orientation::Horizontal;
+
+ otLog("%S arrival!\n", InterfaceStackPanel->Name->Data());
+
+ // Basic description text
+ auto InterfaceTextBlock = ref new TextBlock();
+ InterfaceTextBlock->Text = ref new String(L"openthread interface");
+ InterfaceTextBlock->FontSize = 16;
+ InterfaceTextBlock->Margin = Thickness(10);
+ InterfaceTextBlock->TextWrapping = TextWrapping::Wrap;
+ InterfaceStackPanel->Children->Append(InterfaceTextBlock);
+
+ // Connect button
auto ConnectButton = ref new Button();
+ ConnectButton->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
ConnectButton->Content = ref new String(L"Connect");
ConnectButton->Click +=
ref new RoutedEventHandler(
[=](Platform::Object^, RoutedEventArgs^) {
- _currentInterface = InterfaceGuid;
- InterfaceConfiguration->Visibility = Windows::UI::Xaml::Visibility::Visible;
+ this->_curAdapter = adapter;
+ this->InterfaceConfiguration->Visibility = Windows::UI::Xaml::Visibility::Visible;
}
- );
+ );
InterfaceStackPanel->Children->Append(ConnectButton);
- }
- else
- {
+
+ // Details button
auto DetailsButton = ref new Button();
+ DetailsButton->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
DetailsButton->Content = ref new String(L"Details");
DetailsButton->Click +=
ref new RoutedEventHandler(
[=](Platform::Object^, RoutedEventArgs^) {
- ShowInterfaceDetails(InterfaceGuid);
+ this->ShowInterfaceDetails(adapter);
}
- );
+ );
InterfaceStackPanel->Children->Append(DetailsButton);
+ // Disconnect button
auto DisconnectButton = ref new Button();
+ DisconnectButton->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
DisconnectButton->Content = ref new String(L"Disconnect");
DisconnectButton->Click +=
ref new RoutedEventHandler(
[=](Platform::Object^, RoutedEventArgs^) {
- DisconnectNetwork(InterfaceGuid);
+ this->DisconnectNetwork(adapter);
}
- );
+ );
InterfaceStackPanel->Children->Append(DisconnectButton);
+
+ // Delegate for handling role changes
+ auto OnAdapterRoleChanged =
+ [=]() {
+ GUID interfaceGuid = adapter->InterfaceGuid;
+ auto state = adapter->State;
+ auto stateStr = otApi::ToString(adapter->State);
+
+ WCHAR szText[256] = { 0 };
+ swprintf_s(szText, 256, GUID_FORMAT L"\r\n\t%s\r\n\t%s",
+ GUID_ARG(interfaceGuid),
+ stateStr->Data(),
+ state >= otThreadState::Child ?
+ adapter->MeshLocalEid->ToString()->Data() :
+ L"");
+
+ InterfaceTextBlock->Text = ref new String(szText);
+
+ otLog("%S state = %S\n", InterfaceStackPanel->Name->Data(), stateStr->Data());
+
+ if (state == otThreadState::Disabled)
+ {
+ ConnectButton->Visibility = Windows::UI::Xaml::Visibility::Visible;
+ DetailsButton->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
+ DisconnectButton->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
+ }
+ else
+ {
+ ConnectButton->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
+ DetailsButton->Visibility = Windows::UI::Xaml::Visibility::Visible;
+ DisconnectButton->Visibility = Windows::UI::Xaml::Visibility::Visible;
+ }
+ };
+
+ // Register for role change callbacks
+ auto adapterRoleChangedToken =
+ adapter->NetRoleChanged +=
+ ref new otNetRoleChangedDelegate(
+ [=](auto sender) {
+ // Update the text on the UI thread
+ this->Dispatcher->RunAsync(
+ Windows::UI::Core::CoreDispatcherPriority::Normal,
+ ref new Windows::UI::Core::DispatchedHandler(
+ [=]() {
+ OnAdapterRoleChanged();
+ }
+ )
+ );
+ }
+ );
+
+ // Register for address change callbacks
+ auto adapterMeshLocalAddresChangedToken =
+ adapter->IpMeshLocalAddresChanged +=
+ ref new otIpMeshLocalAddresChangedDelegate(
+ [=](auto sender) {
+ // Update the text on the UI thread
+ this->Dispatcher->RunAsync(
+ Windows::UI::Core::CoreDispatcherPriority::Normal,
+ ref new Windows::UI::Core::DispatchedHandler(
+ [=]() {
+ OnAdapterRoleChanged();
+ }
+ )
+ );
+ }
+ );
+
+ // Register for adapter removal callbacks
+ Windows::Foundation::EventRegistrationToken adapterRemovalToken;
+ adapterRemovalToken =
+ adapter->AdapterRemoval +=
+ ref new otAdapterRemovalDelegate(
+ [=](otAdapter^ adapter) {
+ // Unregister
+ adapter->NetRoleChanged -= adapterRoleChangedToken;
+ adapter->IpMeshLocalAddresChanged -= adapterMeshLocalAddresChangedToken;
+ adapter->AdapterRemoval -= adapterRemovalToken;
+
+ // Remove the item on the UI thread
+ this->Dispatcher->RunAsync(
+ Windows::UI::Core::CoreDispatcherPriority::Normal,
+ ref new Windows::UI::Core::DispatchedHandler(
+ [=]() {
+ for (uint32_t i = 0; i < this->InterfaceList->Items->Size; i++)
+ {
+ auto Item = dynamic_cast(this->InterfaceList->Items->GetAt(i));
+ if (Item == InterfaceStackPanel)
+ {
+ otLog("%S removal!\n", InterfaceStackPanel->Name->Data());
+ this->InterfaceList->Items->RemoveAt(i);
+ break;
+ }
+ }
+ }));
+ });
+
+ // Trigger the initial role change
+ OnAdapterRoleChanged();
+
+ // Add the interface to the list
+ InterfaceList->Items->Append(InterfaceStackPanel);
}
-
- // Register for callbacks on the device
- otSetStateChangedCallback(device, ThreadStateChangeCallback, nullptr);
-
- // Cache the device
- _devices.push_back(device);
-
- return InterfaceStackPanel;
-}
-
-void MainPage::BuildInterfaceList()
-{
- if (ApiInstance == nullptr) return;
-
- // Clear all existing children
- InterfaceList->Items->Clear();
-
- // Clean up devices
- for each (auto device in _devices)
+ catch (Exception^)
{
- // Unregister for callbacks for the device
- otSetStateChangedCallback((otInstance*)device, nullptr, nullptr);
-
- // Free the device
- otFreeMemory(device);
}
- _devices.clear();
+}
- // Enumerate the new device list
- auto deviceList = otEnumerateDevices(ApiInstance);
- if (deviceList)
+void MainPage::ConnectNetwork(otAdapter^ adapter)
+{
+ try
+ {
+ GUID interfaceGuid = adapter->InterfaceGuid;
+ WCHAR szName[256] = { 0 };
+ swprintf_s(szName, 256, GUID_FORMAT, GUID_ARG(interfaceGuid));
+ otLog("%S starting connection...\n", szName);
+
+ // Configure
+ adapter->NetworkName = InterfaceConfigName->Text;
+ adapter->MasterKey = InterfaceConfigKey->Text;
+ adapter->Channel = (uint8_t)InterfaceConfigChannel->Value;
+ adapter->MaxAllowedChildren = (uint8_t)InterfaceConfigMaxChildren->Value;
+ adapter->PanId = 0x4567;
+
+ // Bring up the interface and start the Thread logic
+ adapter->IpEnabled = true;
+ adapter->ThreadEnabled = true;
+ }
+ catch (Exception^)
{
- // Dump the results to the console
- for (DWORD dwIndex = 0; dwIndex < deviceList->aDevicesLength; dwIndex++)
- {
- InterfaceList->Items->Append(
- CreateNewInterface(deviceList->aDevices[dwIndex]));
- }
- otFreeMemory(deviceList);
}
}
-void MainPage::ConnectNetwork(Platform::Guid InterfaceGuid)
+void MainPage::DisconnectNetwork(otAdapter^ adapter)
{
- if (ApiInstance == nullptr) return;
+ try
+ {
+ GUID interfaceGuid = adapter->InterfaceGuid;
+ WCHAR szName[256] = { 0 };
+ swprintf_s(szName, 256, GUID_FORMAT, GUID_ARG(interfaceGuid));
+ otLog("%S disconnecting...\n", szName);
- GUID deviceGuid = InterfaceGuid;
- auto device = otInstanceInit(ApiInstance, &deviceGuid);
+ // Stop the Thread network and bring down the interface
+ adapter->ThreadEnabled = false;
+ adapter->IpEnabled = false;
+ }
+ catch (Exception^)
+ {
- //
- // Configure
- //
-
- otNetworkName networkName = {};
- wcstombs(networkName.m8, InterfaceConfigName->Text->Data(), sizeof(networkName.m8));
- otThreadSetNetworkName(device, networkName.m8);
-
- otMasterKey masterKey = {};
- wcstombs((char*)masterKey.m8, InterfaceConfigKey->Text->Data(), sizeof(masterKey.m8));
- otThreadSetMasterKey(device, masterKey.m8, sizeof(masterKey.m8));
-
- otLinkSetChannel(device, (uint8_t)InterfaceConfigChannel->Value);
- otThreadSetMaxAllowedChildren(device, (uint8_t)InterfaceConfigMaxChildren->Value);
-
- otLinkSetPanId(device, 0x4567);
-
- //
- // Bring up the interface and start the Thread logic
- //
-
- otIp6SetEnabled(device, true);
-
- otThreadSetEnabled(device, true);
-
- // Cleanup
- otFreeMemory(device);
-}
-
-void MainPage::DisconnectNetwork(Platform::Guid InterfaceGuid)
-{
- if (ApiInstance == nullptr) return;
-
- GUID deviceGuid = InterfaceGuid;
- auto device = otInstanceInit(ApiInstance, &deviceGuid);
-
- //
- // Start the Thread logic and the interface
- //
-
- otThreadSetEnabled(device, false);
-
- otIp6SetEnabled(device, false);
-
- // Cleanup
- otFreeMemory(device);
+ }
}
diff --git a/examples/apps/windows/MainPage.xaml.h b/examples/apps/windows/MainPage.xaml.h
index 549337d46..57d1b8402 100644
--- a/examples/apps/windows/MainPage.xaml.h
+++ b/examples/apps/windows/MainPage.xaml.h
@@ -42,11 +42,9 @@ namespace Thread
void OnResuming();
- void BuildInterfaceList();
-
- void ConnectNetwork(Platform::Guid InterfaceGuid);
- void ShowInterfaceDetails(Platform::Guid InterfaceGuid);
- void DisconnectNetwork(Platform::Guid InterfaceGuid);
+ void ConnectNetwork(otAdapter^ adapter);
+ void ShowInterfaceDetails(otAdapter^ adapter);
+ void DisconnectNetwork(otAdapter^ adapter);
protected:
virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override;
@@ -56,25 +54,13 @@ namespace Thread
void OnLoaded(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
void OnUnloaded(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
- void OnWindowSizeChanged(Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ args);
- void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ coreWindow, Windows::UI::Core::VisibilityChangedEventArgs^ args);
-
- UIElement^ CreateNewInterface(Platform::Guid InterfaceGuid);
-
- bool _isVisible;
- bool _isFullScreen;
-
- Windows::Foundation::Size _windowSize;
+ void AddAdapterToList(otAdapter^ adapter);
- void *_apiInstance;
- #define ApiInstance ((otApiInstance*)_apiInstance)
+ otApi^ _otApi;
- std::vector _devices;
+ Windows::Foundation::EventRegistrationToken _adapterArrivalToken;
- Platform::Guid _currentInterface;
-
- internal:
- static MainPage^ Current;
+ otAdapter^ _curAdapter;
};
}
diff --git a/examples/apps/windows/README.md b/examples/apps/windows/README.md
new file mode 100644
index 000000000..bc6926e79
--- /dev/null
+++ b/examples/apps/windows/README.md
@@ -0,0 +1,15 @@
+# OpenThread App for Windows #
+
+This sample app provides an example of how to interface with the OpenThread API in a
+[Universal Windows App](https://developer.microsoft.com/en-us/windows/apps). The app is written in C++ /CX
+and provides a simple wrapper around the OpenThread API, hiding the raw C/C++ interface.
+
+The main page of the App is a list of the available interfaces, their current connection state,
+their current ML-EID IPv6 address, and buttons to connect/disconnect and to view some more details.
+
+
+
+The details list provides some more information, including extended MAC address, RLOC16 and information
+about the current children.
+
+
diff --git a/examples/apps/windows/otAdapter.h b/examples/apps/windows/otAdapter.h
new file mode 100644
index 000000000..746cd5eab
--- /dev/null
+++ b/examples/apps/windows/otAdapter.h
@@ -0,0 +1,613 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#define OTDLL 1
+#include
+#include
+#include
+
+#include
+#include
+
+using namespace Platform;
+using namespace Platform::Collections;
+using namespace Platform::Metadata;
+using namespace Windows::Foundation::Collections;
+using namespace Windows::Networking;
+
+namespace Thread
+{
+
+ref class otAdapter;
+
+public delegate void otAdapterRemovalDelegate(otAdapter^ sender);
+
+public delegate void otIpAddressAddedDelegate(otAdapter^ sender);
+public delegate void otIpAddressRemovedDelegate(otAdapter^ sender);
+public delegate void otIpRlocAddedDelegate(otAdapter^ sender);
+public delegate void otIpRlocRemovedDelegate(otAdapter^ sender);
+public delegate void otIpLinkLocalAddresChangedDelegate(otAdapter^ sender);
+public delegate void otIpMeshLocalAddresChangedDelegate(otAdapter^ sender);
+
+public delegate void otNetRoleChangedDelegate(otAdapter^ sender);
+public delegate void otNetPartitionIdChangedDelegate(otAdapter^ sender);
+public delegate void otNetKeySequenceCounterChangedDelegate(otAdapter^ sender);
+
+public delegate void otThreadChildAddedDelegate(otAdapter^ sender);
+public delegate void otThreadChildRemovedDelegate(otAdapter^ sender);
+public delegate void otThreadNetDataUpdatedDelegate(otAdapter^ sender);
+
+[Flags]
+public enum class otLinkModeFlags : unsigned int
+{
+ None = 0,
+ RxOnWhenIdle = 0x1, /* 1, if the sender has its receiver on when not transmitting. 0, otherwise. */
+ SecureDataRequests = 0x2, /* 1, if the sender will use IEEE 802.15.4 to secure all data requests. 0, otherwise. */
+ DeviceType = 0x4, /* 1, if the sender is an FFD. 0, otherwise. */
+ NetworkData = 0x8 /* 1, if the sender requires the full Network Data. 0, otherwise. */
+};
+
+public enum class otThreadState
+{
+ Offline,
+ Disabled,
+ Detached,
+ Child,
+ Router,
+ Leader
+};
+
+// Helper class for OpenThread Interface/Adapter specific APIs
+public ref class otAdapter sealed
+{
+private:
+
+ void *_Instance;
+ #define DeviceInstance ((otInstance*)_Instance)
+
+ #define ThrowOnFailure(exp) \
+ do { \
+ auto res = exp; \
+ if (res != 0) \
+ throw Exception::CreateException(TheadErrorToHResult(res), #exp); \
+ } while (false)
+
+public:
+
+#pragma region Events
+
+ event otAdapterRemovalDelegate^ AdapterRemoval;
+
+ event otIpAddressAddedDelegate^ IpAddressAdded;
+ event otIpAddressRemovedDelegate^ IpAddressRemoved;
+ event otIpRlocAddedDelegate^ IpRlocAdded;
+ event otIpRlocRemovedDelegate^ IpRlocRemoved;
+ event otIpLinkLocalAddresChangedDelegate^ IpLinkLocalAddresChanged;
+ event otIpMeshLocalAddresChangedDelegate^ IpMeshLocalAddresChanged;
+
+ event otNetRoleChangedDelegate^ NetRoleChanged;
+ event otNetPartitionIdChangedDelegate^ NetPartitionIdChanged;
+ event otNetKeySequenceCounterChangedDelegate^ NetKeySequenceCounterChanged;
+
+ event otThreadChildAddedDelegate^ ThreadChildAdded;
+ event otThreadChildRemovedDelegate^ ThreadChildRemoved;
+ event otThreadNetDataUpdatedDelegate^ ThreadNetDataUpdated;
+
+#pragma endregion
+
+#pragma region Properties
+
+ property IntPtr RawHandle
+ {
+ IntPtr get() { return _Instance; }
+ }
+
+ property Guid InterfaceGuid
+ {
+ Guid get() { return otGetDeviceGuid(DeviceInstance); }
+ }
+
+ property uint32_t IfIndex
+ {
+ uint32_t get() { return otGetDeviceIfIndex(DeviceInstance); }
+ }
+
+ property uint32_t CompartmentId
+ {
+ uint32_t get() { return otGetCompartmentId(DeviceInstance); }
+ }
+
+#pragma region Link Layer
+
+ property signed int /*int8_t*/ MaxTransmitPower
+ {
+ signed int get() { return otLinkGetMaxTransmitPower(DeviceInstance); }
+ void set(signed int value)
+ {
+ if (value > 127) throw Exception::CreateException(E_INVALIDARG);
+ otLinkSetMaxTransmitPower(DeviceInstance, (int8_t)value);
+ }
+ }
+
+ property uint32_t PollPeriod
+ {
+ uint32_t get() { return otLinkGetPollPeriod(DeviceInstance); }
+ void set(uint32_t value) { otLinkSetPollPeriod(DeviceInstance, value); }
+ }
+
+ property uint8_t Channel
+ {
+ uint8_t get() { return otLinkGetChannel(DeviceInstance); }
+ void set(uint8_t value) { ThrowOnFailure(otLinkSetChannel(DeviceInstance, value)); }
+ }
+
+ property uint16_t PanId
+ {
+ uint16_t get() { return otLinkGetPanId(DeviceInstance); }
+ void set(uint16_t value) { ThrowOnFailure(otLinkSetPanId(DeviceInstance, value)); }
+ }
+
+ property uint16_t ShortAddress
+ {
+ uint16_t get() { return otLinkGetShortAddress(DeviceInstance); }
+ }
+
+ property uint64_t ExtendedAddress
+ {
+ uint64_t get()
+ {
+ auto addr = otLinkGetExtendedAddress(DeviceInstance);
+ auto ret = *(uint64_t*)addr;
+ otFreeMemory(addr);
+ return ret;
+ }
+ void set(uint64_t value)
+ {
+ ThrowOnFailure(otLinkSetExtendedAddress(DeviceInstance, (otExtAddress*)&value));
+ }
+ }
+
+ property uint64_t FactoryAssignedIeeeEui64
+ {
+ uint64_t get()
+ {
+ uint64_t addr;
+ otLinkGetFactoryAssignedIeeeEui64(DeviceInstance, (otExtAddress*)&addr);
+ return addr;
+ }
+ }
+
+ property uint64_t JoinerId
+ {
+ uint64_t get()
+ {
+ uint64_t addr;
+ otLinkGetJoinerId(DeviceInstance, (otExtAddress*)&addr);
+ return addr;
+ }
+ }
+
+#pragma endregion
+
+#pragma region IP Layer
+
+ property bool IpEnabled
+ {
+ bool get() { return otIp6IsEnabled(DeviceInstance); }
+ void set(bool value) { ThrowOnFailure(otIp6SetEnabled(DeviceInstance, value)); }
+ }
+
+#pragma endregion
+
+#pragma region Thread Layer
+
+ property uint64_t ExtendedPanId
+ {
+ uint64_t get()
+ {
+ auto panid = otThreadGetExtendedPanId(DeviceInstance);
+ auto ret = *(uint64_t*)panid;
+ otFreeMemory(panid);
+ return ret;
+ }
+ void set(uint64_t value)
+ {
+ otThreadSetExtendedPanId(DeviceInstance, (uint8_t*)&value);
+ }
+ }
+
+ property otLinkModeFlags LinkMode
+ {
+ otLinkModeFlags get()
+ {
+ auto linkmode = otThreadGetLinkMode(DeviceInstance);
+ otLinkModeFlags flags = otLinkModeFlags::None;
+ if (linkmode.mRxOnWhenIdle) flags = flags | otLinkModeFlags::RxOnWhenIdle;
+ if (linkmode.mSecureDataRequests) flags = flags | otLinkModeFlags::SecureDataRequests;
+ if (linkmode.mDeviceType) flags = flags | otLinkModeFlags::DeviceType;
+ if (linkmode.mNetworkData) flags = flags | otLinkModeFlags::NetworkData;
+ return flags;
+ }
+ void set(otLinkModeFlags value)
+ {
+ otLinkModeConfig linkmode = { 0 };
+ if ((value & otLinkModeFlags::RxOnWhenIdle) != otLinkModeFlags::None)
+ linkmode.mRxOnWhenIdle = true;
+ if ((value & otLinkModeFlags::SecureDataRequests) != otLinkModeFlags::None)
+ linkmode.mSecureDataRequests = true;
+ if ((value & otLinkModeFlags::DeviceType) != otLinkModeFlags::None)
+ linkmode.mDeviceType = true;
+ if ((value & otLinkModeFlags::NetworkData) != otLinkModeFlags::None)
+ linkmode.mNetworkData = true;
+ ThrowOnFailure(otThreadSetLinkMode(DeviceInstance, linkmode));
+ }
+ }
+
+ static uint32_t charToValue(wchar_t c)
+ {
+ if (c >= L'a' && c <= L'f')
+ {
+ return c - L'a';
+ }
+ else if (c >= L'A' && c <= L'F')
+ {
+ return c - L'A';
+ }
+ else if (c >= L'0' && c <= L'9')
+ {
+ return c - L'0';
+ }
+ else
+ {
+ throw Exception::CreateException(E_INVALIDARG);
+ }
+ }
+
+ property String^ MasterKey
+ {
+ String^ get()
+ {
+ constexpr char hexmap[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+ uint8_t keyLen;
+ auto key = otThreadGetMasterKey(DeviceInstance, &keyLen);
+ WCHAR szKey[OT_MASTER_KEY_SIZE * 2 + 1] = { 0 };
+ for (uint8_t i = 0; i < keyLen; i++)
+ {
+ szKey[2 * i] = hexmap[(key[i] & 0xF0) >> 4];
+ szKey[2 * i + 1] = hexmap[key[i] & 0x0F];
+ }
+ otFreeMemory(key);
+ return ref new String(szKey);
+ }
+ void set(String^ value)
+ {
+ uint8_t key[OT_MASTER_KEY_SIZE];
+ uint8_t keyLen = 0;
+ if (value->Length() % 2 == 0)
+ {
+ for (uint32_t i = 0; i < value->Length(); i+=2)
+ {
+ key[keyLen++] = (uint8_t)((charToValue(value->Data()[i]) << 4) |
+ charToValue(value->Data()[i + 1]));
+ }
+ }
+ else
+ {
+ key[keyLen++] = (uint8_t)(charToValue(value->Data()[0]));
+ for (uint32_t i = 1; i < value->Length(); i += 2)
+ {
+ key[keyLen++] = (uint8_t)((charToValue(value->Data()[i]) << 4) |
+ charToValue(value->Data()[i + 1]));
+ }
+ }
+ ThrowOnFailure(otThreadSetMasterKey(DeviceInstance, key, keyLen));
+ }
+ }
+
+ property String^ NetworkName
+ {
+ String^ get()
+ {
+ auto _name = otThreadGetNetworkName(DeviceInstance);
+ WCHAR name[OT_NETWORK_NAME_MAX_SIZE + 1];
+ MultiByteToWideChar(CP_UTF8, 0, _name, -1, name, ARRAYSIZE(name));
+ otFreeMemory(_name);
+ return ref new String(name);
+ }
+ void set(String^ value)
+ {
+ char name[OT_NETWORK_NAME_MAX_SIZE + 1];
+ auto err = WideCharToMultiByte(CP_UTF8, WC_NO_BEST_FIT_CHARS, value->Data(), -1, name, ARRAYSIZE(name), nullptr, nullptr);
+ if (err == 0) ThrowOnFailure(otThreadSetNetworkName(DeviceInstance, name));
+ else throw Exception::CreateException(E_INVALIDARG);
+ }
+ }
+
+ property uint8_t MaxAllowedChildren
+ {
+ uint8_t get() { return otThreadGetMaxAllowedChildren(DeviceInstance); }
+ void set(uint8_t value) { ThrowOnFailure(otThreadSetMaxAllowedChildren(DeviceInstance, value)); }
+ }
+
+ property uint32_t ChildTimeout
+ {
+ uint32_t get() { return otThreadGetChildTimeout(DeviceInstance); }
+ void set(uint32_t value) { otThreadSetChildTimeout(DeviceInstance, value); }
+ }
+
+ property bool ThreadEnabled
+ {
+ //bool get() { return otIsThreadStarted(DeviceInstance); }
+ void set(bool value) { ThrowOnFailure(otThreadSetEnabled(DeviceInstance, value)); }
+ }
+
+ property bool AutoStart
+ {
+ bool get() { return otThreadGetAutoStart(DeviceInstance); }
+ void set(bool value) { ThrowOnFailure(otThreadSetAutoStart(DeviceInstance, value)); }
+ }
+
+ property bool Singleton
+ {
+ bool get() { return otThreadIsSingleton(DeviceInstance); }
+ }
+
+ property bool RouterRoleEnabled
+ {
+ bool get() { return otThreadIsRouterRoleEnabled(DeviceInstance); }
+ void set(bool value) { otThreadSetRouterRoleEnabled(DeviceInstance, value); }
+ }
+
+ property uint8_t PreferredRouterId
+ {
+ void set(uint8_t value) { ThrowOnFailure(otThreadSetPreferredRouterId(DeviceInstance, value)); }
+ }
+
+ property HostName^ MeshLocalEid
+ {
+ HostName^ get()
+ {
+ auto addr = otThreadGetMeshLocalEid(DeviceInstance);
+ WCHAR szAddr[46];
+ RtlIpv6AddressToString((IN6_ADDR*)addr, szAddr);
+ otFreeMemory(addr);
+ return ref new HostName(ref new String(szAddr));
+ }
+ }
+
+ property HostName^ LeaderRloc
+ {
+ HostName^ get()
+ {
+ IN6_ADDR addr;
+ ThrowOnFailure(otThreadGetLeaderRloc(DeviceInstance, (otIp6Address*)&addr));
+ WCHAR szAddr[46];
+ RtlIpv6AddressToString(&addr, szAddr);
+ return ref new HostName(ref new String(szAddr));
+ }
+ }
+
+ property uint8_t LocalLeaderWeight
+ {
+ uint8_t get() { return otThreadGetLocalLeaderWeight(DeviceInstance); }
+ void set(uint8_t value) { otThreadSetLocalLeaderWeight(DeviceInstance, value); }
+ }
+
+ property uint32_t LocalLeaderPartitionId
+ {
+ uint32_t get() { return otThreadGetLocalLeaderPartitionId(DeviceInstance); }
+ void set(uint32_t value) { otThreadSetLocalLeaderPartitionId(DeviceInstance, value); }
+ }
+
+ property uint8_t LeaderWeight
+ {
+ uint8_t get() { return otThreadGetLeaderWeight(DeviceInstance); }
+ }
+
+ property uint32_t LeaderRouterId
+ {
+ uint32_t get() { return otThreadGetLeaderRouterId(DeviceInstance); }
+ }
+
+ property uint32_t PartitionId
+ {
+ uint32_t get() { return otThreadGetPartitionId(DeviceInstance); }
+ }
+
+ property uint16_t Rloc16
+ {
+ uint16_t get() { return otThreadGetRloc16(DeviceInstance); }
+ }
+
+ property otThreadState State
+ {
+ otThreadState get()
+ {
+ return (otThreadState)otThreadGetDeviceRole(DeviceInstance);
+ }
+ }
+
+#pragma endregion
+
+#pragma endregion
+
+#pragma region Constructor/Destructor
+
+ otAdapter(_In_ IntPtr /*otInstance**/ aInstance)
+ {
+ _Instance = (void*)aInstance;
+
+ IInspectable* pInspectable = reinterpret_cast(this);
+
+ // Register for device availability callbacks
+ otSetStateChangedCallback(DeviceInstance, ThreadStateChangeCallback, pInspectable);
+ }
+
+ virtual ~otAdapter()
+ {
+ // Unregister for callbacks for the device
+ otSetStateChangedCallback(DeviceInstance, nullptr, nullptr);
+
+ // Free the device
+ otFreeMemory(DeviceInstance);
+ }
+
+#pragma endregion
+
+#pragma region Functions
+
+ void PlatformReset()
+ {
+ otInstanceReset(DeviceInstance);
+ }
+
+ void FactoryReset()
+ {
+ otInstanceFactoryReset(DeviceInstance);
+ }
+
+ void BecomeRouter()
+ {
+ ThrowOnFailure(otThreadBecomeRouter(DeviceInstance));
+ }
+
+ void BecomeLeader()
+ {
+ ThrowOnFailure(otThreadBecomeLeader(DeviceInstance));
+ }
+
+#pragma endregion
+
+internal:
+
+ void InvokeAdapterRemoval()
+ {
+ AdapterRemoval(this);
+ }
+
+private:
+
+ friend ref class otApi;
+
+ static void OTCALL
+ ThreadStateChangeCallback(
+ uint32_t aFlags,
+ _In_ void* aContext
+ )
+ {
+ IInspectable* pInspectable = (IInspectable*)aContext;
+ otAdapter^ pThis = reinterpret_cast(pInspectable);
+
+ if (aFlags & OT_IP6_ADDRESS_ADDED)
+ {
+ pThis->IpAddressAdded(pThis);
+ }
+
+ if (aFlags & OT_IP6_ADDRESS_REMOVED)
+ {
+ pThis->IpAddressRemoved(pThis);
+ }
+
+ if (aFlags & OT_IP6_RLOC_ADDED)
+ {
+ pThis->IpRlocAdded(pThis);
+ }
+
+ if (aFlags & OT_IP6_RLOC_REMOVED)
+ {
+ pThis->IpRlocRemoved(pThis);
+ }
+
+ if (aFlags & OT_IP6_LL_ADDR_CHANGED)
+ {
+ pThis->IpLinkLocalAddresChanged(pThis);
+ }
+
+ if (aFlags & OT_IP6_ML_ADDR_CHANGED)
+ {
+ pThis->IpMeshLocalAddresChanged(pThis);
+ }
+
+ if (aFlags & OT_NET_ROLE)
+ {
+ pThis->NetRoleChanged(pThis);
+ }
+
+ if (aFlags & OT_NET_PARTITION_ID)
+ {
+ pThis->NetPartitionIdChanged(pThis);
+ }
+
+ if (aFlags & OT_NET_KEY_SEQUENCE_COUNTER)
+ {
+ pThis->NetKeySequenceCounterChanged(pThis);
+ }
+
+ if (aFlags & OT_THREAD_CHILD_ADDED)
+ {
+ pThis->ThreadChildAdded(pThis);
+ }
+
+ if (aFlags & OT_THREAD_CHILD_REMOVED)
+ {
+ pThis->ThreadChildRemoved(pThis);
+ }
+
+ if (aFlags & OT_THREAD_NETDATA_UPDATED)
+ {
+ pThis->ThreadNetDataUpdated(pThis);
+ }
+ }
+
+ static HRESULT
+ TheadErrorToHResult(
+ int /* ThreadError */ error
+ )
+ {
+ switch (error)
+ {
+ case kThreadError_NoBufs: return E_OUTOFMEMORY;
+ case kThreadError_Drop:
+ case kThreadError_NoRoute: return HRESULT_FROM_WIN32(ERROR_NETWORK_UNREACHABLE);
+ case kThreadError_InvalidArgs: return E_INVALIDARG;
+ case kThreadError_Security: return E_ACCESSDENIED;
+ case kThreadError_NotCapable:
+ case kThreadError_NotImplemented: return E_NOTIMPL;
+ case kThreadError_InvalidState: return E_NOT_VALID_STATE;
+ case kThreadError_NotFound: return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
+ case kThreadError_Already: return HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
+ case kThreadError_ResponseTimeout: return HRESULT_FROM_WIN32(ERROR_TIMEOUT);
+ default: return E_FAIL;
+ }
+ }
+};
+
+} // namespace Thread
+
diff --git a/examples/apps/windows/otApi.h b/examples/apps/windows/otApi.h
new file mode 100644
index 000000000..e4d9d4eac
--- /dev/null
+++ b/examples/apps/windows/otApi.h
@@ -0,0 +1,252 @@
+/*
+* 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.
+*/
+
+#pragma once
+
+#include "otAdapter.h"
+#include
+
+using namespace Platform;
+using namespace Platform::Collections;
+using namespace Windows::Foundation::Collections;
+
+#define MAC8_FORMAT L"%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X"
+#define MAC8_ARG(mac) mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], mac[6], mac[7]
+
+namespace Thread
+{
+
+public delegate void otAdapterArrivalDelegate(otAdapter^ aAdapter);
+
+// Helper class for OpenThread API
+public ref class otApi sealed
+{
+private:
+
+ void *_apiInstance;
+ #define ApiInstance ((otApiInstance*)_apiInstance)
+
+ CRITICAL_SECTION _cs;
+ Vector^ _adapters;
+
+public:
+
+ // Event for device availability changes
+ event otAdapterArrivalDelegate^ AdapterArrival;
+
+ property IntPtr RawHandle
+ {
+ IntPtr get() { return _apiInstance; }
+ }
+
+ // Constructor
+ otApi() :
+ _adapters(ref new Vector())
+ {
+ // Initialize the API handle
+ _apiInstance = otApiInit();
+ if (_apiInstance == nullptr)
+ {
+ throw Exception::CreateException(E_UNEXPECTED, L"otApiInit failed.");
+ }
+
+ InitializeCriticalSection(&_cs);
+
+ IInspectable* pInspectable = reinterpret_cast(this);
+
+ // Register for device availability callbacks
+ otSetDeviceAvailabilityChangedCallback(ApiInstance, ThreadDeviceAvailabilityCallback, pInspectable);
+
+ // Query list of devices
+ auto deviceList = otEnumerateDevices(ApiInstance);
+ if (deviceList)
+ {
+ EnterCriticalSection(&_cs);
+
+ // Add each adapter to our cache unless it already was inserted from a notification
+ for (DWORD i = 0; i < deviceList->aDevicesLength; i++)
+ {
+ if (GetAdapter(deviceList->aDevices[i]) == nullptr)
+ {
+ auto deviceInstance = otInstanceInit(ApiInstance, &deviceList->aDevices[i]);
+ if (deviceInstance)
+ {
+ _adapters->Append(ref new otAdapter(deviceInstance));
+ }
+ }
+ }
+
+ LeaveCriticalSection(&_cs);
+
+ otFreeMemory(deviceList);
+ }
+ }
+
+ // Destructor
+ virtual ~otApi()
+ {
+ // Clear registration for callbacks
+ otSetDeviceAvailabilityChangedCallback(ApiInstance, nullptr, nullptr);
+
+ DeleteCriticalSection(&_cs);
+
+ // Clean up api
+ otApiFinalize(ApiInstance);
+ _apiInstance = nullptr;
+ }
+
+ // Returns the entire list of adapters
+ IVectorView^ GetAdapters()
+ {
+ IVectorView^ adapters;
+ EnterCriticalSection(&_cs);
+ adapters = _adapters->GetView(); // TODO - Need to copy
+ LeaveCriticalSection(&_cs);
+ return adapters;
+ }
+
+ // Helper to get an adapter, given its device guid
+ otAdapter^ GetAdapter(Guid aDeviceGuid)
+ {
+ otAdapter^ ret = nullptr;
+
+ EnterCriticalSection(&_cs);
+
+ for (auto&& adapter : _adapters)
+ {
+ if (adapter->InterfaceGuid == aDeviceGuid)
+ {
+ ret = adapter;
+ break;
+ }
+ }
+
+ LeaveCriticalSection(&_cs);
+
+ return ret;
+ }
+
+ // Helper function to convert mac address to string
+ static String^ ToString(uint64_t mac)
+ {
+ WCHAR szMac[64] = { 0 };
+ swprintf_s(szMac, 64, MAC8_FORMAT, MAC8_ARG(((UCHAR*)&mac)));
+ return ref new String(szMac);
+ }
+
+ // Helper function to convert RLOC16/PANID to string
+ static String^ ToString(uint16_t rloc)
+ {
+ WCHAR szRloc[16] = { 0 };
+ swprintf_s(szRloc, 16, L"0x%X", rloc);
+ return ref new String(szRloc);
+ }
+
+ // Helper function to convert state to string
+ static String^ ToString(otThreadState state)
+ {
+ switch (state)
+ {
+ default:
+ case otThreadState::Offline: return L"Offline";
+ case otThreadState::Disabled: return L"Disabled";
+ case otThreadState::Detached: return L"Disconnected";
+ case otThreadState::Child: return L"Connected - Child";
+ case otThreadState::Router: return L"Connected - Router";
+ case otThreadState::Leader: return L"Connected - Leader";
+ }
+ }
+
+private:
+
+ // Callback from OpenThread indicating arrival or removal of interfaces
+ static void OTCALL
+ ThreadDeviceAvailabilityCallback(
+ bool aAdded,
+ const GUID* aDeviceGuid,
+ _In_ void* aContext
+ )
+ {
+ IInspectable* pInspectable = (IInspectable*)aContext;
+ otApi^ pThis = reinterpret_cast(pInspectable);
+
+ if (aAdded)
+ {
+ otAdapter^ adapter = nullptr;
+
+ // Add the device to the list, if it isn't already there
+ EnterCriticalSection(&pThis->_cs);
+
+ if (pThis->GetAdapter(*aDeviceGuid) == nullptr)
+ {
+ auto deviceInstance = otInstanceInit((otApiInstance*)pThis->_apiInstance, aDeviceGuid);
+ if (deviceInstance)
+ {
+ pThis->_adapters->Append(adapter = ref new otAdapter(deviceInstance));
+ }
+ }
+
+ LeaveCriticalSection(&pThis->_cs);
+
+ if (adapter)
+ {
+ // Send a notification of arrival
+ pThis->AdapterArrival(adapter);
+ }
+ }
+ else
+ {
+ otAdapter^ ret = nullptr;
+ Guid guid = *aDeviceGuid;
+
+ EnterCriticalSection(&pThis->_cs);
+
+ // Look up in the cached list of adapters to remove it
+ uint32_t i = 0;
+ for (auto&& adapter : pThis->_adapters)
+ {
+ if (adapter->InterfaceGuid == guid)
+ {
+ ret = adapter;
+ pThis->_adapters->RemoveAt(i);
+ break;
+ }
+ i++;
+ }
+
+ LeaveCriticalSection(&pThis->_cs);
+
+ if (ret)
+ {
+ ret->InvokeAdapterRemoval();
+ }
+ }
+ }
+};
+
+} // namespace Thread
diff --git a/examples/apps/windows/pch.h b/examples/apps/windows/pch.h
index a90a2c493..af044ab1f 100644
--- a/examples/apps/windows/pch.h
+++ b/examples/apps/windows/pch.h
@@ -38,9 +38,7 @@
#include
#include
#include
-#define OTDLL 1
-#include
-#include
-#include
+
+#include "otApi.h"
#include "App.xaml.h"
diff --git a/examples/drivers/windows/include/otLwfIoctl.h b/examples/drivers/windows/include/otLwfIoctl.h
index 2e7a74926..30bb888fe 100644
--- a/examples/drivers/windows/include/otLwfIoctl.h
+++ b/examples/drivers/windows/include/otLwfIoctl.h
@@ -115,7 +115,7 @@ typedef enum _OTLWF_NOTIF_TYPE
uint32_t ChannelMask;
uint8_t EnergyListLength;
uint8_t EnergyList[MAX_ENERGY_REPORT_LENGTH];
-
+
} CommissionerEnergyReportPayload;
// Payload for OTLWF_NOTIF_COMMISSIONER_PANID_QUERY
@@ -168,298 +168,298 @@ typedef enum _OTLWF_NOTIF_TYPE
OTLWF_CTL_CODE(101, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// BOOLEAN - aUp
-
+
#define IOCTL_OTLWF_OT_THREAD \
OTLWF_CTL_CODE(102, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
// BOOLEAN - aStarted
-
+
#define IOCTL_OTLWF_OT_ACTIVE_SCAN \
OTLWF_CTL_CODE(103, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint32_t - aScanChannels
// uint16_t - aScanDuration
-
+
#define IOCTL_OTLWF_OT_DISCOVER \
OTLWF_CTL_CODE(104, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint32_t - aScanChannels
// uint16_t - aScanDuration
// uint16_t - aPanid
-
+
#define IOCTL_OTLWF_OT_CHANNEL \
OTLWF_CTL_CODE(105, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint8_t - aChannel
-
+
#define IOCTL_OTLWF_OT_CHILD_TIMEOUT \
OTLWF_CTL_CODE(106, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint32_t - aTimeout
-
+
#define IOCTL_OTLWF_OT_EXTENDED_ADDRESS \
OTLWF_CTL_CODE(107, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otExtAddress - aExtendedAddress
-
+
#define IOCTL_OTLWF_OT_EXTENDED_PANID \
OTLWF_CTL_CODE(108, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otExtendedPanId - aExtendedPanId
-
+
#define IOCTL_OTLWF_OT_LEADER_RLOC \
OTLWF_CTL_CODE(109, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// otIp6Address - aLeaderRloc
-
+
#define IOCTL_OTLWF_OT_LINK_MODE \
OTLWF_CTL_CODE(110, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otLinkModeConfig - aConfig
-
+
#define IOCTL_OTLWF_OT_MASTER_KEY \
OTLWF_CTL_CODE(111, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otMasterKey - aKey
// uint8_t - aKeyLength
-
+
#define IOCTL_OTLWF_OT_MESH_LOCAL_EID \
OTLWF_CTL_CODE(112, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// otIp6Address - aMeshLocalEid
-
+
#define IOCTL_OTLWF_OT_MESH_LOCAL_PREFIX \
OTLWF_CTL_CODE(113, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otMeshLocalPrefix - aPrefix
-
+
#define IOCTL_OTLWF_OT_NETWORK_DATA_LEADER \
OTLWF_CTL_CODE(114, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// uint8_t[] - aData
-
+
#define IOCTL_OTLWF_OT_NETWORK_DATA_LOCAL \
OTLWF_CTL_CODE(115, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// uint8_t[] - aData
-
+
#define IOCTL_OTLWF_OT_NETWORK_NAME \
OTLWF_CTL_CODE(116, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otNetworkName - aNetworkName
-
+
#define IOCTL_OTLWF_OT_PAN_ID \
OTLWF_CTL_CODE(117, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otPanId - aPanId
-
+
#define IOCTL_OTLWF_OT_ROUTER_ROLL_ENABLED \
OTLWF_CTL_CODE(118, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// BOOLEAN - aEnabled
-
+
#define IOCTL_OTLWF_OT_SHORT_ADDRESS \
OTLWF_CTL_CODE(119, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// otShortAddress - aShortAddress
-
+
/* NOT USED
#define IOCTL_OTLWF_OT_UNICAST_ADDRESSES \
OTLWF_CTL_CODE(120, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// otNetifAddress[] - aAddresses
*/
-
+
#define IOCTL_OTLWF_OT_ACTIVE_DATASET \
OTLWF_CTL_CODE(121, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otOperationalDataset - aDataset
-
+
#define IOCTL_OTLWF_OT_PENDING_DATASET \
OTLWF_CTL_CODE(122, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otOperationalDataset - aDataset
-
+
#define IOCTL_OTLWF_OT_LOCAL_LEADER_WEIGHT \
OTLWF_CTL_CODE(123, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint8_t - aWeight
-
+
#define IOCTL_OTLWF_OT_ADD_BORDER_ROUTER \
OTLWF_CTL_CODE(124, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otBorderRouterConfig - aConfig
-
+
#define IOCTL_OTLWF_OT_REMOVE_BORDER_ROUTER \
OTLWF_CTL_CODE(125, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otIp6Prefix - aPrefix
-
+
#define IOCTL_OTLWF_OT_ADD_EXTERNAL_ROUTE \
OTLWF_CTL_CODE(126, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otExternalRouteConfig - aConfig
-
+
#define IOCTL_OTLWF_OT_REMOVE_EXTERNAL_ROUTE \
OTLWF_CTL_CODE(127, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otIp6Prefix - aPrefix
-
+
#define IOCTL_OTLWF_OT_SEND_SERVER_DATA \
OTLWF_CTL_CODE(128, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
-
+
#define IOCTL_OTLWF_OT_CONTEXT_ID_REUSE_DELAY \
OTLWF_CTL_CODE(129, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint32_t - aDelay
-
+
#define IOCTL_OTLWF_OT_KEY_SEQUENCE_COUNTER \
OTLWF_CTL_CODE(130, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint32_t - aKeySequenceCounter
-
+
#define IOCTL_OTLWF_OT_NETWORK_ID_TIMEOUT \
OTLWF_CTL_CODE(131, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint8_t - aTimeout
-
+
#define IOCTL_OTLWF_OT_ROUTER_UPGRADE_THRESHOLD \
OTLWF_CTL_CODE(132, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint8_t - aThreshold
-
+
#define IOCTL_OTLWF_OT_RELEASE_ROUTER_ID \
OTLWF_CTL_CODE(133, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint8_t - aRouterId
-
+
#define IOCTL_OTLWF_OT_MAC_WHITELIST_ENABLED \
OTLWF_CTL_CODE(134, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// BOOLEAN - aEnabled
-
+
#define IOCTL_OTLWF_OT_ADD_MAC_WHITELIST \
OTLWF_CTL_CODE(135, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otExtAddress - aExtAddr
// int8_t - aRssi (optional)
-
+
#define IOCTL_OTLWF_OT_REMOVE_MAC_WHITELIST \
OTLWF_CTL_CODE(136, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otExtAddress - aExtAddr
-
+
#define IOCTL_OTLWF_OT_MAC_WHITELIST_ENTRY \
OTLWF_CTL_CODE(137, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// uint8_t - aIndex (input)
// otMacWhitelistEntry - aEntry (output)
-
+
#define IOCTL_OTLWF_OT_CLEAR_MAC_WHITELIST \
OTLWF_CTL_CODE(138, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
-
+
#define IOCTL_OTLWF_OT_DEVICE_ROLE \
OTLWF_CTL_CODE(139, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otDeviceRole - aRole
// otMleAttachFilter - aFilter (only for kDeviceRoleChild)
-
+
#define IOCTL_OTLWF_OT_CHILD_INFO_BY_ID \
OTLWF_CTL_CODE(140, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// uint16_t - aChildId (input)
// otChildInfo - aChildInfo (output)
-
+
#define IOCTL_OTLWF_OT_CHILD_INFO_BY_INDEX \
OTLWF_CTL_CODE(141, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// uint8_t - aChildIndex (input)
// otChildInfo - aChildInfo (output)
-
+
#define IOCTL_OTLWF_OT_EID_CACHE_ENTRY \
OTLWF_CTL_CODE(142, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// uint8_t - aIndex (input)
// otEidCacheEntry - aEntry (output)
-
+
#define IOCTL_OTLWF_OT_LEADER_DATA \
OTLWF_CTL_CODE(143, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// otLeaderData - aLeaderData
-
+
#define IOCTL_OTLWF_OT_LEADER_ROUTER_ID \
OTLWF_CTL_CODE(144, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// uint8_t - aRouterID
-
+
#define IOCTL_OTLWF_OT_LEADER_WEIGHT \
OTLWF_CTL_CODE(145, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// uint8_t - aWeight
-
+
#define IOCTL_OTLWF_OT_NETWORK_DATA_VERSION \
OTLWF_CTL_CODE(146, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// uint8_t - aVersion
-
+
#define IOCTL_OTLWF_OT_PARTITION_ID \
OTLWF_CTL_CODE(147, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// uint32_t - aPartition
-
+
#define IOCTL_OTLWF_OT_RLOC16 \
OTLWF_CTL_CODE(148, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// uint16_t - aRloc16
-
+
#define IOCTL_OTLWF_OT_ROUTER_ID_SEQUENCE \
OTLWF_CTL_CODE(149, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// uint8_t - aIdSequence
-
+
#define IOCTL_OTLWF_OT_ROUTER_INFO \
OTLWF_CTL_CODE(150, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// uint16_t - aRouterId (input)
// otRouterInfo - aRouterInfo (output)
-
+
#define IOCTL_OTLWF_OT_STABLE_NETWORK_DATA_VERSION \
OTLWF_CTL_CODE(151, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// uint8_t - aVersion
-
+
#define IOCTL_OTLWF_OT_MAC_BLACKLIST_ENABLED \
OTLWF_CTL_CODE(152, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// BOOLEAN - aEnabled
-
+
#define IOCTL_OTLWF_OT_ADD_MAC_BLACKLIST \
OTLWF_CTL_CODE(153, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otExtAddress - aExtAddr
-
+
#define IOCTL_OTLWF_OT_REMOVE_MAC_BLACKLIST \
OTLWF_CTL_CODE(154, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otExtAddress - aExtAddr
-
+
#define IOCTL_OTLWF_OT_MAC_BLACKLIST_ENTRY \
OTLWF_CTL_CODE(155, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// uint8_t - aIndex (input)
// otMacBlacklistEntry - aEntry (output)
-
+
#define IOCTL_OTLWF_OT_CLEAR_MAC_BLACKLIST \
OTLWF_CTL_CODE(156, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
-
+
#define IOCTL_OTLWF_OT_MAX_TRANSMIT_POWER \
OTLWF_CTL_CODE(157, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// int8_t - aPower
-
+
#define IOCTL_OTLWF_OT_NEXT_ON_MESH_PREFIX \
OTLWF_CTL_CODE(158, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
@@ -467,37 +467,37 @@ typedef enum _OTLWF_NOTIF_TYPE
// uint8_t - aIterator (input)
// uint8_t - aNewIterator (output)
// otBorderRouterConfig - aConfig (output)
-
+
#define IOCTL_OTLWF_OT_POLL_PERIOD \
OTLWF_CTL_CODE(159, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint32_t - aPollPeriod
-
+
#define IOCTL_OTLWF_OT_LOCAL_LEADER_PARTITION_ID \
OTLWF_CTL_CODE(160, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint32_t - aPartitionId
-
+
#define IOCTL_OTLWF_OT_ASSIGN_LINK_QUALITY \
OTLWF_CTL_CODE(161, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otExtAddress - aExtAddr (input)
// uint8_t - aLinkQuality (input or output)
-
+
#define IOCTL_OTLWF_OT_PLATFORM_RESET \
OTLWF_CTL_CODE(162, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
-
+
#define IOCTL_OTLWF_OT_PARENT_INFO \
OTLWF_CTL_CODE(163, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// otRouterInfo - aParentInfo
-
+
#define IOCTL_OTLWF_OT_SINGLETON \
OTLWF_CTL_CODE(164, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// BOOLEAN - aSingleton
-
+
#define IOCTL_OTLWF_OT_MAC_COUNTERS \
OTLWF_CTL_CODE(165, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
@@ -507,11 +507,11 @@ typedef enum _OTLWF_NOTIF_TYPE
OTLWF_CTL_CODE(166, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint8_t - aMaxChildren
-
+
#define IOCTL_OTLWF_OT_COMMISIONER_START \
OTLWF_CTL_CODE(167, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
-
+
#define IOCTL_OTLWF_OT_COMMISIONER_STOP \
OTLWF_CTL_CODE(168, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
@@ -531,38 +531,38 @@ typedef struct otCommissionConfig
char VendorSwVersion[OPENTHREAD_VENDOR_SW_VERSION_MAX_LENGTH + 1];
char VendorData[OPENTHREAD_VENDOR_DATA_MAX_LENGTH + 1];
} otCommissionConfig;
-
+
#define IOCTL_OTLWF_OT_JOINER_START \
OTLWF_CTL_CODE(169, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otCommissionConfig - aConfig
-
+
#define IOCTL_OTLWF_OT_JOINER_STOP \
OTLWF_CTL_CODE(170, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
-
+
#define IOCTL_OTLWF_OT_FACTORY_EUI64 \
OTLWF_CTL_CODE(171, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// otExtAddress - aEui64
-
+
#define IOCTL_OTLWF_OT_HASH_MAC_ADDRESS \
OTLWF_CTL_CODE(172, METHOD_BUFFERED, FILE_READ_DATA)
// GUID - InterfaceGuid
// otExtAddress - aEui64
-
+
#define IOCTL_OTLWF_OT_ROUTER_DOWNGRADE_THRESHOLD \
OTLWF_CTL_CODE(173, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint8_t - aThreshold
-
+
#define IOCTL_OTLWF_OT_COMMISSIONER_PANID_QUERY \
OTLWF_CTL_CODE(174, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint16_t - aPanId
// uint32_t - aChannekMask
// otIp6Address - aAddress
-
+
#define IOCTL_OTLWF_OT_COMMISSIONER_ENERGY_SCAN \
OTLWF_CTL_CODE(175, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
@@ -571,49 +571,49 @@ typedef struct otCommissionConfig
// uint16_t - aPeriod
// uint16_t - aScanDuration
// otIp6Address - aAddress
-
+
#define IOCTL_OTLWF_OT_ROUTER_SELECTION_JITTER \
OTLWF_CTL_CODE(176, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint8_t - aRouterJitter
-
+
#define IOCTL_OTLWF_OT_JOINER_UDP_PORT \
OTLWF_CTL_CODE(177, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint16_t - aJoinerUdpPort
-
+
#define IOCTL_OTLWF_OT_SEND_DIAGNOSTIC_GET \
OTLWF_CTL_CODE(178, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otIp6Address - aDestination
// uint8_t - aCount
// uint8_t[aCount] - aTlvTypes
-
+
#define IOCTL_OTLWF_OT_SEND_DIAGNOSTIC_RESET \
OTLWF_CTL_CODE(179, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otIp6Address - aDestination
// uint8_t - aCount
// uint8_t[aCount] - aTlvTypes
-
+
#define IOCTL_OTLWF_OT_COMMISIONER_ADD_JOINER \
OTLWF_CTL_CODE(180, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint8_t - aExtAddressValid
// otExtAddress - aExtAddress (optional)
// char[OPENTHREAD_PSK_MAX_LENGTH + 1] - aPSKd
-
+
#define IOCTL_OTLWF_OT_COMMISIONER_REMOVE_JOINER \
OTLWF_CTL_CODE(181, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint8_t - aExtAddressValid
// otExtAddress - aExtAddress (optional)
-
+
#define IOCTL_OTLWF_OT_COMMISIONER_PROVISIONING_URL \
OTLWF_CTL_CODE(182, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// char[OPENTHREAD_PROV_URL_MAX_LENGTH + 1] - aProvisioningUrl (optional)
-
+
#define IOCTL_OTLWF_OT_COMMISIONER_ANNOUNCE_BEGIN \
OTLWF_CTL_CODE(183, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
@@ -621,70 +621,75 @@ typedef struct otCommissionConfig
// uint8_t - aCount
// uint16_t - aPeriod
// otIp6Address - aAddress
-
+
#define IOCTL_OTLWF_OT_ENERGY_SCAN \
OTLWF_CTL_CODE(184, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint32_t - aScanChannels
// uint16_t - aScanDuration
-
+
#define IOCTL_OTLWF_OT_SEND_ACTIVE_GET \
OTLWF_CTL_CODE(185, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint8_t - aLength
// uint8_t[aLength] - aTlvTypes
// otIp6Address - aAddress (optional)
-
+
#define IOCTL_OTLWF_OT_SEND_ACTIVE_SET \
OTLWF_CTL_CODE(186, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otOperationalDataset - aDataset
// uint8_t - aLength
// uint8_t[aLength] - aTlvTypes
-
+
#define IOCTL_OTLWF_OT_SEND_PENDING_GET \
OTLWF_CTL_CODE(187, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint8_t - aLength
// uint8_t[aLength] - aTlvTypes
// otIp6Address - aAddress (optional)
-
+
#define IOCTL_OTLWF_OT_SEND_PENDING_SET \
OTLWF_CTL_CODE(188, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otOperationalDataset - aDataset
// uint8_t - aLength
// uint8_t[aLength] - aTlvTypes
-
+
#define IOCTL_OTLWF_OT_SEND_MGMT_COMMISSIONER_GET \
OTLWF_CTL_CODE(189, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint8_t - aLength
// uint8_t[aLength] - aTlvs
-
+
#define IOCTL_OTLWF_OT_SEND_MGMT_COMMISSIONER_SET \
OTLWF_CTL_CODE(190, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
// otOperationalDataset - aDataset
// uint8_t - aLength
// uint8_t[aLength] - aTlvs
-
+
#define IOCTL_OTLWF_OT_KEY_SWITCH_GUARDTIME \
OTLWF_CTL_CODE(191, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// uint32_t - aKeySwitchGuardTime
-
+
#define IOCTL_OTLWF_OT_FACTORY_RESET \
OTLWF_CTL_CODE(192, METHOD_BUFFERED, FILE_WRITE_DATA)
// GUID - InterfaceGuid
-
+
#define IOCTL_OTLWF_OT_THREAD_AUTO_START \
OTLWF_CTL_CODE(193, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
// GUID - InterfaceGuid
// BOOLEAN - aAutoStart
+#define IOCTL_OTLWF_OT_PREFERRED_ROUTER_ID \
+ OTLWF_CTL_CODE(194, METHOD_BUFFERED, FILE_WRITE_DATA)
+ // GUID - InterfaceGuid
+ // uint8_t - aRouterId
+
// OpenThread function IOCTL codes
#define MIN_OTLWF_IOCTL_FUNC_CODE 100
-#define MAX_OTLWF_IOCTL_FUNC_CODE 193
+#define MAX_OTLWF_IOCTL_FUNC_CODE 194
#endif //__OTLWFIOCTL_H__
diff --git a/examples/drivers/windows/otApi/otApi.cpp b/examples/drivers/windows/otApi/otApi.cpp
index 877dade34..4cfbff67b 100644
--- a/examples/drivers/windows/otApi/otApi.cpp
+++ b/examples/drivers/windows/otApi/otApi.cpp
@@ -1867,6 +1867,18 @@ otThreadSetRouterRoleEnabled(
if (aInstance) (void)SetIOCTL(aInstance, IOCTL_OTLWF_OT_ROUTER_ROLL_ENABLED, (BOOLEAN)aEnabled);
}
+OTAPI
+ThreadError
+OTCALL
+otThreadSetPreferredRouterId(
+ _In_ otInstance *aInstance,
+ uint8_t aRouterId
+ )
+{
+ if (aInstance == nullptr) return kThreadError_InvalidArgs;
+ return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_PAN_ID, aRouterId));
+}
+
OTAPI
otShortAddress
OTCALL
diff --git a/examples/drivers/windows/otLwf/iocontrol.c b/examples/drivers/windows/otLwf/iocontrol.c
index c84a277ef..d00fa0443 100644
--- a/examples/drivers/windows/otLwf/iocontrol.c
+++ b/examples/drivers/windows/otLwf/iocontrol.c
@@ -138,7 +138,8 @@ OTLWF_IOCTL_HANDLER IoCtls[] =
{ "IOCTL_OTLWF_OT_SEND_MGMT_COMMISSIONER_SET", REF_IOCTL_FUNC(otSendMgmtCommissionerSet) },
{ "IOCTL_OTLWF_OT_KEY_SWITCH_GUARDTIME", REF_IOCTL_FUNC_WITH_TUN(otKeySwitchGuardtime) },
{ "IOCTL_OTLWF_OT_FACTORY_RESET", REF_IOCTL_FUNC(otFactoryReset) },
- { "IOCTL_OTLWF_OT_THREAD_AUTO_START", REF_IOCTL_FUNC(otThreadAutoStart) }
+ { "IOCTL_OTLWF_OT_THREAD_AUTO_START", REF_IOCTL_FUNC(otThreadAutoStart) },
+ { "IOCTL_OTLWF_OT_PREFERRED_ROUTER_ID", REF_IOCTL_FUNC(otThreadPreferredRouterId) },
};
static_assert(ARRAYSIZE(IoCtls) == (MAX_OTLWF_IOCTL_FUNC_CODE - MIN_OTLWF_IOCTL_FUNC_CODE) + 1,
@@ -6084,3 +6085,34 @@ otLwfIoCtl_otThreadAutoStart(
return status;
}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+otLwfIoCtl_otThreadPreferredRouterId(
+ _In_ PMS_FILTER pFilter,
+ _In_reads_bytes_(InBufferLength)
+ PUCHAR InBuffer,
+ _In_ ULONG InBufferLength,
+ _Out_writes_bytes_(*OutBufferLength)
+ PVOID OutBuffer,
+ _Inout_ PULONG OutBufferLength
+ )
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ *OutBufferLength = 0;
+ UNREFERENCED_PARAMETER(OutBuffer);
+
+ if (InBufferLength >= sizeof(uint8_t))
+ {
+ status =
+ ThreadErrorToNtstatus(
+ otThreadSetPreferredRouterId(
+ pFilter->otCtx,
+ *(uint8_t*)InBuffer != FALSE)
+ );
+ *OutBufferLength = 0;
+ }
+
+ return status;
+}
diff --git a/examples/drivers/windows/otLwf/iocontrol.h b/examples/drivers/windows/otLwf/iocontrol.h
index 2b3d58ee2..18b1022de 100644
--- a/examples/drivers/windows/otLwf/iocontrol.h
+++ b/examples/drivers/windows/otLwf/iocontrol.h
@@ -225,5 +225,6 @@ DECL_IOCTL_FUNC(otSendMgmtCommissionerSet);
DECL_IOCTL_FUNC_WITH_TUN2(otKeySwitchGuardtime);
DECL_IOCTL_FUNC(otFactoryReset);
DECL_IOCTL_FUNC(otThreadAutoStart);
+DECL_IOCTL_FUNC(otThreadPreferredRouterId);
#endif // _IOCONTROL_H
diff --git a/include/openthread/thread.h b/include/openthread/thread.h
index b5bacfad8..a88eaa21f 100644
--- a/include/openthread/thread.h
+++ b/include/openthread/thread.h
@@ -366,7 +366,7 @@ OTAPI void OTCALL otThreadSetRouterRoleEnabled(otInstance *aInstance, bool aEnab
* @retval kThreadError_InvalidState Could not set (role is not detached or disabled)
*
*/
-ThreadError otThreadSetPreferredRouterId(otInstance *aInstance, uint8_t aRouterId);
+OTAPI ThreadError OTCALL otThreadSetPreferredRouterId(otInstance *aInstance, uint8_t aRouterId);
/**
* @}