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. + +![Interface List](../../../doc/images/windows-app-interface-list.png) + +The details list provides some more information, including extended MAC address, RLOC16 and information +about the current children. + +![Interface List](../../../doc/images/windows-app-details.png) 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); /** * @}