/* * Copyright (c) 2016, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "pch.h" #include "MainPage.xaml.h" #include "TalkGrid.xaml.h" using namespace ot; using namespace Platform; using namespace Windows::Foundation; using namespace Windows::Foundation::Collections; using namespace Windows::UI::Xaml; using namespace Windows::UI::Xaml::Controls; using namespace Windows::UI::Xaml::Controls::Primitives; using namespace Windows::UI::Xaml::Data; using namespace Windows::UI::Xaml::Input; using namespace Windows::UI::Xaml::Media; using namespace Windows::UI::Xaml::Navigation; #define GUID_FORMAT L"{%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}" #define GUID_ARG(guid) guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7] void otLog(PCSTR aFormat, ...) { va_list args; va_start(args, aFormat); CHAR logString[512] = { 0 }; int charsWritten = vsprintf_s(logString, sizeof(logString), aFormat, args); if (charsWritten > 0) OutputDebugStringA(logString); va_end(args); } MainPage::MainPage() : _otApi(nullptr) { InitializeComponent(); InterfaceConfigCancelButton->Click += ref new RoutedEventHandler( [=](Platform::Object^, RoutedEventArgs^) { this->InterfaceConfiguration->Visibility = Windows::UI::Xaml::Visibility::Collapsed; this->_curAdapter = nullptr; } ); InterfaceConfigOkButton->Click += ref new RoutedEventHandler( [=](Platform::Object^, RoutedEventArgs^) { this->InterfaceConfiguration->Visibility = Windows::UI::Xaml::Visibility::Collapsed; this->ConnectNetwork(_curAdapter); this->_curAdapter = nullptr; } ); InterfaceDetailsCloseButton->Click += ref new RoutedEventHandler( [=](Platform::Object^, RoutedEventArgs^) { this->InterfaceDetails->Visibility = Windows::UI::Xaml::Visibility::Collapsed; } ); Talk->Click += ref new RoutedEventHandler( [=](Platform::Object^, RoutedEventArgs^) { this->ThreadGrid->Visibility = Windows::UI::Xaml::Visibility::Collapsed; this->TalkGrid->Visibility = Windows::UI::Xaml::Visibility::Visible; } ); TlkGrid->Init(this); } void MainPage::OnNavigatedTo(NavigationEventArgs^ e) { Loaded += ref new RoutedEventHandler(this, &MainPage::OnLoaded); Unloaded += ref new RoutedEventHandler(this, &MainPage::OnUnloaded); } void MainPage::OnLoaded(Object^ sender, RoutedEventArgs^ e) { try { // Initialize api handle _otApi = ref new otApi(); // 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) { if (_otApi) { // Unregister _otApi->AdapterArrival -= _adapterArrivalToken; // 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::ShowInterfaceDetails(otAdapter^ adapter) { try { InterfaceMacAddress->Text = otApi::MacToString(adapter->ExtendedAddress); InterfaceML_EID->Text = adapter->MeshLocalEid->ToString(); InterfaceRLOC->Text = otApi::Rloc16ToString(adapter->Rloc16); if (adapter->State > otThreadState::Child) { uint8_t index = 0; otChildInfo childInfo; while (OT_ERROR_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; } // Show the details InterfaceDetails->Visibility = Windows::UI::Xaml::Visibility::Visible; } catch (Exception^) { } } void MainPage::AddAdapterToList(otAdapter^ adapter) { 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^) { this->_curAdapter = adapter; this->InterfaceConfiguration->Visibility = Windows::UI::Xaml::Visibility::Visible; } ); InterfaceStackPanel->Children->Append(ConnectButton); // 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^) { 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^) { 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::ThreadStateToString(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); } catch (Exception^) { } } 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^) { } } void MainPage::DisconnectNetwork(otAdapter^ adapter) { try { GUID interfaceGuid = adapter->InterfaceGuid; WCHAR szName[256] = { 0 }; swprintf_s(szName, 256, GUID_FORMAT, GUID_ARG(interfaceGuid)); otLog("%S disconnecting...\n", szName); // Stop the Thread network and bring down the interface adapter->ThreadEnabled = false; adapter->IpEnabled = false; } catch (Exception^) { } } Windows::UI::Xaml::UIElement^ MainPage::ThreadGrid::get() { return ThrdGrid; } Windows::UI::Xaml::UIElement^ MainPage::TalkGrid::get() { return TlkGrid; }