420 lines
15 KiB
C++
420 lines
15 KiB
C++
/*
|
|
* 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<StackPanel^>(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;
|
|
}
|