--- /dev/null
+//*********************************************************\r
+//\r
+// Copyright (c) Microsoft. All rights reserved.\r
+// This code is licensed under the MIT License (MIT).\r
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF\r
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY\r
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR\r
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.\r
+//\r
+//*********************************************************\r
+\r
+#include "pch.h"\r
+#include "Scenario2_Client.h"\r
+#include "Scenario2_Client.g.cpp"\r
+#include "SampleConfiguration.h"\r
+#include "BluetoothLEAttributeDisplay.h"\r
+extern "C" {\r
+#include "stb_app.h"\r
+#include "stb_hal.h"\r
+}\r
+#include <sstream>\r
+#include <iomanip>\r
+\r
+using namespace winrt;\r
+using namespace Windows::Devices::Bluetooth;\r
+using namespace Windows::Devices::Bluetooth::GenericAttributeProfile;\r
+using namespace Windows::Devices::Enumeration;\r
+using namespace Windows::Foundation;\r
+using namespace Windows::Foundation::Collections;\r
+using namespace Windows::Globalization;\r
+using namespace Windows::Security::Cryptography;\r
+using namespace Windows::Storage::Streams;\r
+using namespace Windows::UI::Xaml;\r
+using namespace Windows::UI::Xaml::Controls;\r
+using namespace Windows::UI::Xaml::Navigation;\r
+using namespace Windows::Foundation::Collections;\r
+using namespace Windows::Storage::Streams;\r
+\r
+//\r
+GattCharacteristic CusWriteCharacteristic{ nullptr };\r
+SDKTemplate::MainPage g_rootPage = nullptr;\r
+std::wstring g_tokenStr;\r
+\r
+#include <windows.h>\r
+\r
+\r
+void STB_STDCALL cus_printf(const char* format, ...)\r
+{\r
+ char buffer[1024];\r
+ va_list args;\r
+ va_start(args, format);\r
+ int len = vsnprintf(buffer, sizeof(buffer), format, args);\r
+ va_end(args);\r
+\r
+ OutputDebugStringA(buffer);\r
+\r
+ return;\r
+}\r
+\r
+void STB_STDCALL cus_printf_str(char* str)\r
+{\r
+ OutputDebugStringA(str);\r
+ return;\r
+}\r
+\r
+//int32_t stb_hal_send_data(uint8_t* data, uint32_t len)\r
+int32_t STB_STDCALL cus_hal_send_data2device(uint8_t* data, uint32_t len)\r
+{\r
+ std::ostringstream oss;\r
+ // 把数据转换成十六进制字符串\r
+ IBuffer buffer;\r
+ for (uint32_t i = 0; i < len; ++i)\r
+ {\r
+ oss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(data[i]) << " ";\r
+ }\r
+ // 转换为字符串并使用 OutputDebugString 输出\r
+ std::string hexData = oss.str();\r
+ OutputDebugString(L"[STBAPP] send data 2 device:\n");\r
+ OutputDebugStringA(hexData.c_str());\r
+ DataWriter writer;\r
+ for (uint32_t i = 0; i < len; ++i)\r
+ {\r
+ writer.WriteByte(data[i]);\r
+ }\r
+ writer.WriteByte('\n');\r
+ buffer = writer.DetachBuffer();\r
+ CusWriteCharacteristic.WriteValueAsync(buffer);\r
+ return 0;\r
+}\r
+\r
+void STB_STDCALL cust_event_callback_func(uint32_t type, uint8_t* data, uint32_t data_len)\r
+{\r
+\r
+ switch (type) {\r
+ case STB_DYNREG_SUCCESS:\r
+ OutputDebugString(L"\n\STB_DYNREG_SUCCESS\n\r");\r
+ g_rootPage.NotifyUser(L"dynreg success.", SDKTemplate::NotifyType::StatusMessage);\r
+ break;\r
+ case STB_DYNREG_FAIL:\r
+ OutputDebugString(L"\n\rSTB_DYNREG_FAIL\n\r");\r
+ g_rootPage.NotifyUser(L"dynreg failed.", SDKTemplate::NotifyType::ErrorMessage);\r
+ break;\r
+ case STB_MQTT_CONNECT_SUCCESS:\r
+ OutputDebugString(L"\n\STB_MQTT_CONNECT_SUCCESS\n\r");\r
+ g_rootPage.NotifyUser(L"mqtt connect success.", SDKTemplate::NotifyType::StatusMessage);\r
+ break;\r
+ case STB_MQTT_CONNECT_FAIL:\r
+ OutputDebugString(L"\n\STB_MQTT_CONNECT_FAIL\n\r");\r
+ g_rootPage.NotifyUser(L"mqtt connect fail.", SDKTemplate::NotifyType::ErrorMessage);\r
+ break;\r
+ case STB_MQTT_CONNECT_OFFLINE:\r
+ OutputDebugString(L"\n\STB_MQTT_CONNECT_OFFLINE\n\r");\r
+ g_rootPage.NotifyUser(L"mqtt connect offline.", SDKTemplate::NotifyType::ErrorMessage);\r
+ break;\r
+ case STB_MQTT_CONNECT_ONLINE:\r
+ OutputDebugString(L"\n\STB_MQTT_CONNECT_ONLINE\n\r");\r
+ g_rootPage.NotifyUser(L"mqtt connect online.", SDKTemplate::NotifyType::StatusMessage);\r
+ break;\r
+ case STB_DM_DATA_ARRIVED_TOKEN:\r
+ OutputDebugString(L"\n\STB_DM_DATA_ARRIVED_TOKEN\n\r");\r
+ break;\r
+ case STB_DM_DATA_ARRIVED_TOKEN_TIMEOUT:\r
+ OutputDebugString(L"\n\STB_DM_DATA_ARRIVED_TOKEN_TIMEOUT\n\r");\r
+ break;\r
+ case STB_DM_DATA_ARRIVED_HOST:\r
+ OutputDebugString(L"\n\STB_DM_DATA_ARRIVED_HOST\n\r");\r
+ break;\r
+ case STB_DM_DATA_ARRIVED_PARAMS_SIGN:\r
+ OutputDebugString(L"\n\STB_DM_DATA_ARRIVED_PARAMS_SIGN\n\r");\r
+ break;\r
+ default:\r
+ OutputDebugString(L"\n\UNKNOWN_MSG\n\r");\r
+ break;\r
+ }\r
+\r
+\r
+ if (data != nullptr && data_len > 0)\r
+ {\r
+ if (type == STB_DM_DATA_ARRIVED_TOKEN || type == STB_DM_DATA_ARRIVED_TOKEN_TIMEOUT || type == STB_DM_DATA_ARRIVED_PARAMS_SIGN)\r
+ {\r
+ if (type == STB_DM_DATA_ARRIVED_TOKEN)\r
+ {\r
+ g_tokenStr.clear();\r
+ }\r
+\r
+ for (uint32_t i = 0; i < data_len; ++i)\r
+ {\r
+ g_tokenStr.append(1, static_cast<char>(data[i]));\r
+ }\r
+ g_tokenStr.append(1, '\n');\r
+ if (type == STB_DM_DATA_ARRIVED_PARAMS_SIGN)\r
+ {\r
+ g_rootPage.NotifyUser(g_tokenStr.c_str(), SDKTemplate::NotifyType::StatusMessage);\r
+ }\r
+ \r
+ }\r
+ else\r
+ {\r
+ // 将 data 转换为字符串打印\r
+ std::wstring dataStr = L"[STBAPP]Data: ";\r
+ for (uint32_t i = 0; i < data_len; ++i)\r
+ {\r
+ dataStr.append(1, static_cast<char>(data[i]));\r
+ }\r
+ OutputDebugString(dataStr.c_str());\r
+ OutputDebugString(L"\n\[STBAPP]EndCB\n\r");\r
+\r
+ g_rootPage.NotifyUser(dataStr.c_str(), SDKTemplate::NotifyType::StatusMessage);\r
+ }\r
+\r
+ }\r
+\r
+}\r
+namespace\r
+{\r
+ void SetVisibility(UIElement const& element, bool visible)\r
+ {\r
+ element.Visibility(visible ? Visibility::Visible : Visibility::Collapsed);\r
+ }\r
+\r
+ // Utility function to convert a string to an int32_t and detect bad input\r
+ bool TryParseInt(const wchar_t* str, int32_t& result)\r
+ {\r
+ wchar_t* end;\r
+ errno = 0;\r
+ result = std::wcstol(str, &end, 0);\r
+\r
+ if (str == end)\r
+ {\r
+ // Not parseable.\r
+ return false;\r
+ }\r
+\r
+ if (errno == ERANGE || result < INT_MIN || INT_MAX < result)\r
+ {\r
+ // Out of range.\r
+ return false;\r
+ }\r
+\r
+ if (*end != L'\0')\r
+ {\r
+ // Extra unparseable characters at the end.\r
+ return false;\r
+ }\r
+\r
+ return true;\r
+ }\r
+\r
+ template<typename T>\r
+ T Read(DataReader const& reader);\r
+\r
+ template<>\r
+ uint32_t Read<uint32_t>(DataReader const& reader)\r
+ {\r
+ return reader.ReadUInt32();\r
+ }\r
+\r
+ template<>\r
+ int32_t Read<int32_t>(DataReader const& reader)\r
+ {\r
+ return reader.ReadInt32();\r
+ }\r
+\r
+ template<>\r
+ uint8_t Read<uint8_t>(DataReader const& reader)\r
+ {\r
+ return reader.ReadByte();\r
+ }\r
+\r
+ template<typename T>\r
+ bool TryExtract(IBuffer const& buffer, T& result)\r
+ {\r
+ if (buffer.Length() >= sizeof(T))\r
+ {\r
+ DataReader reader = DataReader::FromBuffer(buffer);\r
+ result = Read<T>(reader);\r
+ return true;\r
+ }\r
+ return false;\r
+ }\r
+}\r
+\r
+namespace winrt\r
+{\r
+ hstring to_hstring(GattCommunicationStatus status)\r
+ {\r
+ switch (status)\r
+ {\r
+ case GattCommunicationStatus::Success: return L"Success";\r
+ case GattCommunicationStatus::Unreachable: return L"Unreachable";\r
+ case GattCommunicationStatus::ProtocolError: return L"ProtocolError";\r
+ case GattCommunicationStatus::AccessDenied: return L"AccessDenied";\r
+ }\r
+ return to_hstring(static_cast<int>(status));\r
+ }\r
+}\r
+\r
+namespace winrt::SDKTemplate::implementation\r
+{\r
+#pragma region UI Code\r
+ Scenario2_Client::Scenario2_Client()\r
+ {\r
+ InitializeComponent();\r
+ g_rootPage = rootPage;\r
+ }\r
+\r
+ void Scenario2_Client::OnNavigatedTo(NavigationEventArgs const&)\r
+ {\r
+ SelectedDeviceRun().Text(SampleState::SelectedBleDeviceName);\r
+ if (SampleState::SelectedBleDeviceId.empty())\r
+ {\r
+ ConnectButton().IsEnabled(false);\r
+ }\r
+ }\r
+\r
+ fire_and_forget Scenario2_Client::OnNavigatedFrom(NavigationEventArgs const&)\r
+ {\r
+ auto lifetime = get_strong();\r
+ if (!co_await ClearBluetoothLEDeviceAsync())\r
+ {\r
+ rootPage.NotifyUser(L"Error: Unable to reset app state", NotifyType::ErrorMessage);\r
+ }\r
+ }\r
+#pragma endregion\r
+\r
+#pragma region Enumerating Services\r
+ IAsyncOperation<bool> Scenario2_Client::ClearBluetoothLEDeviceAsync()\r
+ {\r
+ auto lifetime = get_strong();\r
+\r
+ if (notificationsToken)\r
+ {\r
+ // Need to clear the CCCD from the remote device so we stop receiving notifications\r
+ GattCommunicationStatus result = co_await registeredCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue::None);\r
+ if (result != GattCommunicationStatus::Success)\r
+ {\r
+ co_return false;\r
+ }\r
+ else\r
+ {\r
+ selectedCharacteristic.ValueChanged(std::exchange(notificationsToken, {}));\r
+ }\r
+ }\r
+\r
+ if (bluetoothLeDevice != nullptr)\r
+ {\r
+ bluetoothLeDevice.Close();\r
+ bluetoothLeDevice = nullptr;\r
+ }\r
+ co_return true;\r
+ }\r
+\r
+ fire_and_forget Scenario2_Client::ConnectButton_Click()\r
+ {\r
+ auto lifetime = get_strong();\r
+\r
+ ConnectButton().IsEnabled(false);\r
+\r
+ if (!co_await ClearBluetoothLEDeviceAsync())\r
+ {\r
+ rootPage.NotifyUser(L"Error: Unable to reset state, try again.", NotifyType::ErrorMessage);\r
+ ConnectButton().IsEnabled(true);\r
+ co_return;\r
+ }\r
+\r
+ try\r
+ {\r
+ // BT_Code: BluetoothLEDevice.FromIdAsync must be called from a UI thread because it may prompt for consent.\r
+ bluetoothLeDevice = co_await BluetoothLEDevice::FromIdAsync(SampleState::SelectedBleDeviceId);\r
+\r
+ if (bluetoothLeDevice == nullptr)\r
+ {\r
+ rootPage.NotifyUser(L"Failed to connect to device.", NotifyType::ErrorMessage);\r
+ }\r
+ }\r
+ catch (hresult_error& ex)\r
+ {\r
+ if (ex.to_abi() == HRESULT_FROM_WIN32(ERROR_DEVICE_NOT_AVAILABLE))\r
+ {\r
+ rootPage.NotifyUser(L"Bluetooth radio is not on.", NotifyType::ErrorMessage);\r
+ }\r
+ else\r
+ {\r
+ throw;\r
+ }\r
+ }\r
+\r
+ if (bluetoothLeDevice != nullptr)\r
+ {\r
+ // Note: BluetoothLEDevice.GattServices property will return an empty list for unpaired devices. For all uses we recommend using the GetGattServicesAsync method.\r
+ // BT_Code: GetGattServicesAsync returns a list of all the supported services of the device (even if it's not paired to the system).\r
+ // If the services supported by the device are expected to change during BT usage, subscribe to the GattServicesChanged event.\r
+ GattDeviceServicesResult result = co_await bluetoothLeDevice.GetGattServicesAsync(BluetoothCacheMode::Uncached);\r
+\r
+ if (result.Status() == GattCommunicationStatus::Success)\r
+ {\r
+ IVectorView<GattDeviceService> services = result.Services();\r
+ rootPage.NotifyUser(L"Found " + to_hstring(services.Size()) + L" services", NotifyType::StatusMessage);\r
+ for (auto&& service : services)\r
+ {\r
+ ComboBoxItem item;\r
+ item.Content(box_value(DisplayHelpers::GetServiceName(service)));\r
+ item.Tag(service);\r
+ ServiceList().Items().Append(item);\r
+ }\r
+ ConnectButton().Visibility(Visibility::Collapsed);\r
+ ServiceList().Visibility(Visibility::Visible);\r
+ }\r
+ else\r
+ {\r
+ rootPage.NotifyUser(L"Device unreachable", NotifyType::ErrorMessage);\r
+ }\r
+ }\r
+ ConnectButton().IsEnabled(true);\r
+ }\r
+ void Scenario2_Client::STB_StartAuth_Click()\r
+ {\r
+ OutputDebugString(L"[STBAPP] Auth button cliecked\n");\r
+ OutputDebugString(L"[STBAPP] identify start\n");\r
+ stb_app_start_identify();\r
+ return;\r
+ }\r
+ void Scenario2_Client::STB_Init_Click()\r
+ {\r
+ OutputDebugString(L"[STBAPP] init button cliecked\n");\r
+ stb_app_printf_str_register(cus_printf_str);\r
+ stb_app_init("tis_test");\r
+ stb_app_event_callback_register(cust_event_callback_func);\r
+ //stb_app_printf_register(cus_printf);\r
+ stb_app_send_data_to_device_register(cus_hal_send_data2device);\r
+ return;\r
+ }\r
+ void Scenario2_Client::STB_GetToken_Click()\r
+ {\r
+ OutputDebugString(L"[STBAPP] token button cliecked\n");\r
+ stb_app_get_token_async();\r
+ return;\r
+ }\r
+ void Scenario2_Client::STB_Factory_Dev1_Click()\r
+ {\r
+ OutputDebugString(L"[STBAPP] Factory1 click\n");\r
+ char *ds = device_register("k1r8dWlSOjM","474849404142","wZUBUo2vnR0LvMq9");\r
+ if (ds != NULL)\r
+ {\r
+ device_active("k1r8dWlSOjM", "474849404142", ds);\r
+ }\r
+ return;\r
+ }\r
+ void Scenario2_Client::STB_Factory_Dev2_Click()\r
+ {\r
+ OutputDebugString(L"[STBAPP] Factory2 click\n");\r
+ char* ds = device_register("k1r8dWlSOjM", "474849404140", "wZUBUo2vnR0LvMq9");\r
+ if (ds != NULL)\r
+ {\r
+ device_active("k1r8dWlSOjM", "474849404140", ds);\r
+ }\r
+ return;\r
+ }\r
+ void Scenario2_Client::STB_Factory_Dev3_Click()\r
+ {\r
+ OutputDebugString(L"[STBAPP] Factory3 click\n");\r
+\r
+ return;\r
+ }\r
+#pragma region Enumerating Characteristics\r
+ fire_and_forget Scenario2_Client::ServiceList_SelectionChanged()\r
+ {\r
+ auto lifetime = get_strong();\r
+\r
+ auto selectedItem = ServiceList().SelectedItem().as<ComboBoxItem>();\r
+ GattDeviceService service = selectedItem ? selectedItem.Tag().as<GattDeviceService>() : nullptr;\r
+\r
+ CharacteristicList().Items().Clear();\r
+ RemoveValueChangedHandler();\r
+\r
+ IVectorView<GattCharacteristic> characteristics{ nullptr };\r
+ try\r
+ {\r
+ // Ensure we have access to the device.\r
+ auto accessStatus = co_await service.RequestAccessAsync();\r
+ if (accessStatus == DeviceAccessStatus::Allowed)\r
+ {\r
+ // BT_Code: Get all the child characteristics of a service. Use the cache mode to specify uncached characterstics only \r
+ // and the new Async functions to get the characteristics of unpaired devices as well. \r
+ GattCharacteristicsResult result = co_await service.GetCharacteristicsAsync(BluetoothCacheMode::Uncached);\r
+ if (result.Status() == GattCommunicationStatus::Success)\r
+ {\r
+ characteristics = result.Characteristics();\r
+ }\r
+ else\r
+ {\r
+ rootPage.NotifyUser(L"Error accessing service.", NotifyType::ErrorMessage);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ // Not granted access\r
+ rootPage.NotifyUser(L"Error accessing service.", NotifyType::ErrorMessage);\r
+\r
+ }\r
+ }\r
+ catch (hresult_error& ex)\r
+ {\r
+ rootPage.NotifyUser(L"Restricted service. Can't read characteristics: " + ex.message(), NotifyType::ErrorMessage);\r
+ }\r
+\r
+ if (characteristics)\r
+ {\r
+ for (GattCharacteristic&& c : characteristics)\r
+ {\r
+ ComboBoxItem item;\r
+ item.Content(box_value(DisplayHelpers::GetCharacteristicName(c)));\r
+ item.Tag(c);\r
+ CharacteristicList().Items().Append(item);\r
+ }\r
+ }\r
+ CharacteristicList().Visibility(Visibility::Visible);\r
+ }\r
+#pragma endregion\r
+\r
+ void Scenario2_Client::AddValueChangedHandler()\r
+ {\r
+ ValueChangedSubscribeToggle().Content(box_value(L"Unsubscribe from value changes"));\r
+ if (!notificationsToken)\r
+ {\r
+ registeredCharacteristic = selectedCharacteristic;\r
+ notificationsToken = registeredCharacteristic.ValueChanged({ get_weak(), &Scenario2_Client::Characteristic_ValueChanged });\r
+ }\r
+ }\r
+ void Scenario2_Client::RemoveValueChangedHandler()\r
+ {\r
+ ValueChangedSubscribeToggle().Content(box_value(L"Subscribe to value changes"));\r
+ if (notificationsToken)\r
+ {\r
+ registeredCharacteristic.ValueChanged(std::exchange(notificationsToken, {}));\r
+ registeredCharacteristic = nullptr;\r
+ }\r
+ }\r
+\r
+ fire_and_forget Scenario2_Client::CharacteristicList_SelectionChanged()\r
+ {\r
+ auto lifetime = get_strong();\r
+\r
+ auto selectedItem = CharacteristicList().SelectedItem().as<ComboBoxItem>();\r
+ selectedCharacteristic = selectedItem ? selectedItem.Tag().as<GattCharacteristic>() : nullptr;\r
+ if ((selectedCharacteristic.CharacteristicProperties() & (GattCharacteristicProperties::Indicate | GattCharacteristicProperties::Notify)) != GattCharacteristicProperties::None)\r
+ {\r
+ OutputDebugString(L"[STBAPP] NotifyChar defined\n");\r
+ NotifyCharacteristic = selectedCharacteristic;\r
+ }\r
+ if ((selectedCharacteristic.CharacteristicProperties() & (GattCharacteristicProperties::Write | GattCharacteristicProperties::WriteWithoutResponse)) != GattCharacteristicProperties::None)\r
+ {\r
+ OutputDebugString(L"[STBAPP] WriteChar defined\n");\r
+ CusWriteCharacteristic = selectedCharacteristic;\r
+ }\r
+ \r
+ \r
+\r
+ if (selectedCharacteristic == nullptr)\r
+ {\r
+ EnableCharacteristicPanels(GattCharacteristicProperties::None);\r
+ rootPage.NotifyUser(L"No characteristic selected", NotifyType::ErrorMessage);\r
+ co_return;\r
+ }\r
+\r
+ // Get all the child descriptors of a characteristics. Use the cache mode to specify uncached descriptors only \r
+ // and the new Async functions to get the descriptors of unpaired devices as well. \r
+ GattDescriptorsResult result = co_await selectedCharacteristic.GetDescriptorsAsync(BluetoothCacheMode::Uncached);\r
+ if (result.Status() != GattCommunicationStatus::Success)\r
+ {\r
+ rootPage.NotifyUser(L"Descriptor read failure: " + to_hstring(result.Status()), NotifyType::ErrorMessage);\r
+ }\r
+\r
+ // BT_Code: There's no need to access presentation format unless there's at least one. \r
+ presentationFormat = nullptr;\r
+ if (selectedCharacteristic.PresentationFormats().Size() > 0)\r
+ {\r
+\r
+ if (selectedCharacteristic.PresentationFormats().Size() == 1)\r
+ {\r
+ // Get the presentation format since there's only one way of presenting it\r
+ presentationFormat = selectedCharacteristic.PresentationFormats().GetAt(0);\r
+ }\r
+ else\r
+ {\r
+ // It's difficult to figure out how to split up a characteristic and encode its different parts properly.\r
+ // In this case, we'll just encode the whole thing to a string to make it easy to print out.\r
+ }\r
+ }\r
+\r
+ // Enable/disable operations based on the GattCharacteristicProperties.\r
+ EnableCharacteristicPanels(selectedCharacteristic.CharacteristicProperties());\r
+ }\r
+\r
+ void Scenario2_Client::EnableCharacteristicPanels(GattCharacteristicProperties properties)\r
+ {\r
+ // BT_Code: Hide the controls which do not apply to this characteristic.\r
+ SetVisibility(CharacteristicReadButton(),\r
+ (properties & GattCharacteristicProperties::Read) != GattCharacteristicProperties::None);\r
+\r
+ SetVisibility(CharacteristicWritePanel(),\r
+ (properties & (GattCharacteristicProperties::Write | GattCharacteristicProperties::WriteWithoutResponse)) != GattCharacteristicProperties::None);\r
+ CharacteristicWriteValue().Text(L"");\r
+\r
+ SetVisibility(ValueChangedSubscribeToggle(),\r
+ (properties & (GattCharacteristicProperties::Indicate | GattCharacteristicProperties::Notify)) != GattCharacteristicProperties::None);\r
+ }\r
+\r
+ fire_and_forget Scenario2_Client::CharacteristicReadButton_Click()\r
+ {\r
+ auto lifetime = get_strong();\r
+\r
+ // BT_Code: Read the actual value from the device by using Uncached.\r
+ GattReadResult result = co_await selectedCharacteristic.ReadValueAsync(BluetoothCacheMode::Uncached);\r
+ if (result.Status() == GattCommunicationStatus::Success)\r
+ {\r
+ rootPage.NotifyUser(L"Read result: " + FormatValueByPresentation(result.Value(), presentationFormat), NotifyType::StatusMessage);\r
+ }\r
+ else\r
+ {\r
+ rootPage.NotifyUser(L"Read failed: Status = " + to_hstring(result.Status()), NotifyType::ErrorMessage);\r
+ }\r
+ }\r
+\r
+ fire_and_forget Scenario2_Client::CharacteristicWriteButton_Click()\r
+ {\r
+#if 1\r
+ auto lifetime = get_strong();\r
+\r
+ hstring text = CharacteristicWriteValue().Text();\r
+ if (!text.empty())\r
+ {\r
+ std::vector<std::wstring> byteStrings;\r
+ std::wstringstream wss(text.c_str());\r
+ std::wstring byteStr;\r
+ while (wss >> byteStr)\r
+ {\r
+ byteStrings.push_back(byteStr);\r
+ }\r
+\r
+ // 转换并格式化字节为十六进制字符串,添加 "0x" 前缀\r
+ std::vector<uint8_t> bytes;\r
+ std::wstringstream hexStream;\r
+ for (const auto& byteStr : byteStrings)\r
+ {\r
+ uint8_t byteValue = static_cast<uint8_t>(std::stoi(byteStr, nullptr, 16));\r
+ bytes.push_back(byteValue);\r
+ hexStream << L"0x" << std::hex << std::setw(2) << std::setfill(L'0') << static_cast<int>(byteValue) << L", ";\r
+ }\r
+ std::wstring formattedHexStr = hexStream.str();\r
+ // 去除末尾的逗号和空格\r
+ if (!formattedHexStr.empty())\r
+ {\r
+ formattedHexStr.pop_back();\r
+ formattedHexStr.pop_back();\r
+ }\r
+\r
+ // 使用格式化后的十六进制数据\r
+ IBuffer writeBuffer;\r
+ DataWriter writer;\r
+ for (const auto& byte : bytes)\r
+ {\r
+ writer.WriteByte(byte);\r
+ }\r
+ writeBuffer = writer.DetachBuffer();\r
+\r
+ co_await WriteBufferToSelectedCharacteristicAsync(writeBuffer);\r
+ }\r
+ else\r
+ {\r
+ rootPage.NotifyUser(L"No data to write to device", NotifyType::ErrorMessage);\r
+ }\r
+#else\r
+ auto lifetime = get_strong();\r
+\r
+ hstring text = CharacteristicWriteValue().Text();\r
+ if (!text.empty())\r
+ {\r
+ IBuffer writeBuffer = CryptographicBuffer::ConvertStringToBinary(CharacteristicWriteValue().Text(), BinaryStringEncoding::Utf8);\r
+\r
+ co_await WriteBufferToSelectedCharacteristicAsync(writeBuffer);\r
+ }\r
+ else\r
+ {\r
+ rootPage.NotifyUser(L"No data to write to device", NotifyType::ErrorMessage);\r
+ }\r
+#endif\r
+ }\r
+\r
+ fire_and_forget Scenario2_Client::CharacteristicWriteButtonInt_Click()\r
+ {\r
+ auto lifetime = get_strong();\r
+\r
+ int32_t readValue;\r
+ if (TryParseInt(CharacteristicWriteValue().Text().begin(), readValue))\r
+ {\r
+ DataWriter writer;\r
+ writer.ByteOrder(ByteOrder::LittleEndian);\r
+ writer.WriteInt32(readValue);\r
+\r
+ co_await WriteBufferToSelectedCharacteristicAsync(writer.DetachBuffer());\r
+ }\r
+ else\r
+ {\r
+ rootPage.NotifyUser(L"Data to write has to be an int32", NotifyType::ErrorMessage);\r
+ }\r
+ }\r
+\r
+ IAsyncOperation<bool> Scenario2_Client::WriteBufferToSelectedCharacteristicAsync(IBuffer buffer)\r
+ {\r
+ auto lifetime = get_strong();\r
+\r
+ try\r
+ {\r
+ // BT_Code: Writes the value from the buffer to the characteristic.\r
+ GattWriteResult result = co_await selectedCharacteristic.WriteValueWithResultAsync(buffer);\r
+\r
+ if (result.Status() == GattCommunicationStatus::Success)\r
+ {\r
+ rootPage.NotifyUser(L"Successfully wrote value to device", NotifyType::StatusMessage);\r
+ co_return true;\r
+ }\r
+ else\r
+ {\r
+ rootPage.NotifyUser(L"Write failed: Status = " + to_hstring(result.Status()), NotifyType::ErrorMessage);\r
+ co_return false;\r
+ }\r
+ }\r
+ catch (hresult_error& ex)\r
+ {\r
+ if (ex.code() == E_BLUETOOTH_ATT_INVALID_PDU)\r
+ {\r
+ rootPage.NotifyUser(ex.message(), NotifyType::ErrorMessage);\r
+ co_return false;\r
+ }\r
+ if (ex.code() == E_BLUETOOTH_ATT_WRITE_NOT_PERMITTED || ex.code() == E_ACCESSDENIED)\r
+ {\r
+ // This usually happens when a device reports that it support writing, but it actually doesn't.\r
+ rootPage.NotifyUser(ex.message(), NotifyType::ErrorMessage);\r
+ co_return false;\r
+ }\r
+ throw;\r
+ }\r
+ }\r
+\r
+ fire_and_forget Scenario2_Client::ValueChangedSubscribeToggle_Click()\r
+ {\r
+ auto lifetime = get_strong();\r
+\r
+ if (!notificationsToken)\r
+ {\r
+ GattClientCharacteristicConfigurationDescriptorValue cccdValue = GattClientCharacteristicConfigurationDescriptorValue::None;\r
+ if ((selectedCharacteristic.CharacteristicProperties() & GattCharacteristicProperties::Indicate) != GattCharacteristicProperties::None)\r
+ {\r
+ cccdValue = GattClientCharacteristicConfigurationDescriptorValue::Indicate;\r
+ }\r
+\r
+ else if ((selectedCharacteristic.CharacteristicProperties() & GattCharacteristicProperties::Notify) != GattCharacteristicProperties::None)\r
+ {\r
+ cccdValue = GattClientCharacteristicConfigurationDescriptorValue::Notify;\r
+ }\r
+\r
+ try\r
+ {\r
+ // BT_Code: Must write the CCCD in order for server to send indications.\r
+ // We receive them in the ValueChanged event handler.\r
+ GattCommunicationStatus status = co_await selectedCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(cccdValue);\r
+\r
+ if (status == GattCommunicationStatus::Success)\r
+ {\r
+ AddValueChangedHandler();\r
+ rootPage.NotifyUser(L"Successfully subscribed for value changes", NotifyType::StatusMessage);\r
+ }\r
+ else\r
+ {\r
+ rootPage.NotifyUser(L"Error registering for value changes: Status = " + to_hstring(status), NotifyType::ErrorMessage);\r
+ }\r
+ }\r
+ catch (hresult_access_denied& ex)\r
+ {\r
+ // This usually happens when a device reports that it support indicate, but it actually doesn't.\r
+ rootPage.NotifyUser(ex.message(), NotifyType::ErrorMessage);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ try\r
+ {\r
+ // BT_Code: Must write the CCCD in order for server to send notifications.\r
+ // We receive them in the ValueChanged event handler.\r
+ // Note that this sample configures either Indicate or Notify, but not both.\r
+ GattCommunicationStatus result = co_await\r
+ selectedCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(\r
+ GattClientCharacteristicConfigurationDescriptorValue::None);\r
+ if (result == GattCommunicationStatus::Success)\r
+ {\r
+ RemoveValueChangedHandler();\r
+ rootPage.NotifyUser(L"Successfully un-registered for notifications", NotifyType::StatusMessage);\r
+ }\r
+ else\r
+ {\r
+ rootPage.NotifyUser(L"Error un-registering for notifications: Status = " + to_hstring(result), NotifyType::ErrorMessage);\r
+ }\r
+ }\r
+ catch (hresult_access_denied& ex)\r
+ {\r
+ // This usually happens when a device reports that it support notify, but it actually doesn't.\r
+ rootPage.NotifyUser(ex.message(), NotifyType::ErrorMessage);\r
+ }\r
+ }\r
+ }\r
+\r
+ fire_and_forget Scenario2_Client::Characteristic_ValueChanged(GattCharacteristic const&, GattValueChangedEventArgs args)\r
+ {\r
+ auto lifetime = get_strong();\r
+\r
+ // BT_Code: An Indicate or Notify reported that the value has changed.\r
+ // Display the new value with a timestamp.\r
+ hstring newValue = FormatValueByPresentation(args.CharacteristicValue(), presentationFormat);\r
+ std::time_t now = clock::to_time_t(clock::now());\r
+ char buffer[26];\r
+ ctime_s(buffer, ARRAYSIZE(buffer), &now);\r
+ hstring message = L"Value at " + to_hstring(buffer) + L": " + newValue;\r
+ co_await resume_foreground(Dispatcher());\r
+ CharacteristicLatestValue().Text(message);\r
+ }\r
+\r
+ /// <summary>\r
+ /// Process the raw data received from the device into application usable data,\r
+ /// according the the Bluetooth Heart Rate Profile.\r
+ /// https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.heart_rate_measurement.xml&u=org.bluetooth.characteristic.heart_rate_measurement.xml\r
+ /// This function throws an std::out_of_range if the data cannot be parsed.\r
+ /// </summary>\r
+ /// <param name="data">Raw data received from the heart rate monitor.</param>\r
+ /// <returns>The heart rate measurement value.</returns>\r
+ int32_t ParseHeartRateValue(IBuffer const& buffer)\r
+ {\r
+ // Heart Rate profile defined flag values\r
+ const uint8_t heartRateValueFormat = 0x1;\r
+\r
+ com_array<uint8_t> bytes;\r
+ CryptographicBuffer::CopyToByteArray(buffer, bytes);\r
+ \r
+ if (bytes.at(0) & heartRateValueFormat)\r
+ {\r
+ return bytes.at(1) | (bytes.at(2) << 8);\r
+ }\r
+ return bytes.at(1);\r
+ }\r
+\r
+ hstring Scenario2_Client::FormatValueByPresentation(IBuffer const& buffer, GenericAttributeProfile::GattPresentationFormat const& format)\r
+ {\r
+ // BT_Code: For the purpose of this sample, this function converts only UInt32 and\r
+ // UTF-8 buffers to readable text. It can be extended to support other formats if your app needs them.\r
+ if (format != nullptr)\r
+ {\r
+ if (format.FormatType() == GattPresentationFormatTypes::UInt32())\r
+ {\r
+ uint32_t value;\r
+ if (TryExtract(buffer, value))\r
+ {\r
+ return to_hstring(value);\r
+ }\r
+ return L"(error: Invalid UInt32)";\r
+\r
+ }\r
+ else if (format.FormatType() == GattPresentationFormatTypes::Utf8())\r
+ {\r
+ try\r
+ {\r
+ return CryptographicBuffer::ConvertBinaryToString(BinaryStringEncoding::Utf8, buffer);\r
+ }\r
+ catch (hresult_invalid_argument&)\r
+ {\r
+ return L"(error: Invalid UTF-8 string)";\r
+ }\r
+ }\r
+ else\r
+ {\r
+ // Add support for other format types as needed.\r
+ return L"Unsupported format: " + CryptographicBuffer::EncodeToHexString(buffer);\r
+ }\r
+ }\r
+ else if (buffer != nullptr)\r
+ {\r
+ // We don't know what format to use. Let's try some well-known profiles, or default back to UTF-8.\r
+ if (selectedCharacteristic.Uuid() == GattCharacteristicUuids::HeartRateMeasurement())\r
+ {\r
+ try\r
+ {\r
+ return L"Heart Rate: " + to_hstring(ParseHeartRateValue(buffer));\r
+ }\r
+ catch (std::out_of_range&)\r
+ {\r
+ return L"Heart Rate: (unable to parse)";\r
+ }\r
+ }\r
+ else if (selectedCharacteristic.Uuid() == GattCharacteristicUuids::BatteryLevel())\r
+ {\r
+ // battery level is encoded as a percentage value in the first byte according to\r
+ // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.battery_level.xml\r
+ uint8_t percent;\r
+ if (TryExtract(buffer, percent))\r
+ {\r
+ return L"Battery Level: " + to_hstring(percent) + L"%";\r
+ }\r
+ return L"Battery Level: (unable to parse)";\r
+ }\r
+ // This is our custom calc service Result UUID. Format it like an Int\r
+ else if (selectedCharacteristic.Uuid() == Constants::ResultCharacteristicUuid)\r
+ {\r
+ int32_t value;\r
+ if (TryExtract(buffer, value))\r
+ {\r
+ return to_hstring(value);\r
+ }\r
+ return L"Invalid response from calc server";\r
+ }\r
+ else if (NotifyCharacteristic.Uuid() == Constants::MicCharacteristicUuid)\r
+ {\r
+ return L"Mic data: " + CryptographicBuffer::EncodeToHexString(buffer);\r
+ }\r
+ else if (NotifyCharacteristic.Uuid() == Constants::IdentifyCharacteristicUuid)\r
+ {\r
+ com_array<uint8_t> bytes;\r
+ CryptographicBuffer::CopyToByteArray(buffer, bytes);\r
+ stb_app_recv_data_from_device(bytes.data(), static_cast<uint32_t>(bytes.size()));\r
+ return L"Bizbus data: " + CryptographicBuffer::EncodeToHexString(buffer);\r
+ }\r
+ // No guarantees on if a characteristic is registered for notifications.\r
+ else if (registeredCharacteristic != nullptr)\r
+ {\r
+ // This is our custom calc service Result UUID. Format it like an Int\r
+ if (registeredCharacteristic.Uuid() == Constants::ResultCharacteristicUuid)\r
+ {\r
+ int32_t value;\r
+ if (TryExtract(buffer, value))\r
+ {\r
+ return to_hstring(value);\r
+ }\r
+ return L"Invalid response from calc server";\r
+ }\r
+ }\r
+ else\r
+ {\r
+ try\r
+ {\r
+ return L"Unknown format: " + CryptographicBuffer::ConvertBinaryToString(BinaryStringEncoding::Utf8, buffer);\r
+\r
+ }\r
+ catch (hresult_invalid_argument&)\r
+ {\r
+ return L"Unknown format";\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ return L"Empty data received";\r
+ }\r
+ return L"Unknown format";\r
+ }\r
+}\r
+\r
+\r
+\r
18E0C5922D0FF8E30093BA8F /* stb_identify.so in Frameworks */ = {isa = PBXBuildFile; fileRef = 18E0C58F2D0FF8E30093BA8F /* stb_identify.so */; };
18E0C5932D0FF8E40093BA8F /* stb_app.h in Headers */ = {isa = PBXBuildFile; fileRef = 18E0C5902D0FF8E30093BA8F /* stb_app.h */; };
18E0C5942D0FF8E40093BA8F /* stb_identify.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 18E0C5912D0FF8E30093BA8F /* stb_identify.a */; };
- 18E0C5972D1000DF0093BA8F /* ByteDanceSdk.h in Headers */ = {isa = PBXBuildFile; fileRef = 18E0C5952D1000DF0093BA8F /* ByteDanceSdk.h */; };
+ 18E0C5972D1000DF0093BA8F /* ByteDanceSdk.h in Headers */ = {isa = PBXBuildFile; fileRef = 18E0C5952D1000DF0093BA8F /* ByteDanceSdk.h */; settings = {ATTRIBUTES = (Public, ); }; };
18E0C5982D1000DF0093BA8F /* ByteDanceSdk.m in Sources */ = {isa = PBXBuildFile; fileRef = 18E0C5962D1000DF0093BA8F /* ByteDanceSdk.m */; };
18EF7AF92C7603E800AC5223 /* adpcm.h in Headers */ = {isa = PBXBuildFile; fileRef = 18EF7AEA2C7603E800AC5223 /* adpcm.h */; };
18EF7AFA2C7603E800AC5223 /* TlwMouseSdk.m in Sources */ = {isa = PBXBuildFile; fileRef = 18EF7AEB2C7603E800AC5223 /* TlwMouseSdk.m */; };
18EF7B052C7603E800AC5223 /* TlwConnectManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 18EF7AF62C7603E800AC5223 /* TlwConnectManager.h */; };
18FCA3972C7F2AD100C44A37 /* AiMouseAuth.h in Headers */ = {isa = PBXBuildFile; fileRef = 18FCA3952C7F2AD100C44A37 /* AiMouseAuth.h */; };
18FCA3982C7F2AD100C44A37 /* AiMouseAuth.m in Sources */ = {isa = PBXBuildFile; fileRef = 18FCA3962C7F2AD100C44A37 /* AiMouseAuth.m */; };
+ 3FCF534F2D1A5C97007EC52F /* LogManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FCF534E2D1A5C97007EC52F /* LogManager.m */; };
+ 3FCF53502D1A5C97007EC52F /* LogManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FCF534D2D1A5C97007EC52F /* LogManager.h */; };
+ 3FCF53512D1A5C97007EC52F /* LogManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FCF534D2D1A5C97007EC52F /* LogManager.h */; };
+ 3FCF53522D1A5C97007EC52F /* LogManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FCF534E2D1A5C97007EC52F /* LogManager.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
188814BC2C85BB76009299A9 /* AiBkzhAuthManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AiBkzhAuthManager.m; sourceTree = "<group>"; };
188814C02C85C2BA009299A9 /* AESCBCHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AESCBCHelper.h; sourceTree = "<group>"; };
188814C12C85C2BA009299A9 /* AESCBCHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AESCBCHelper.m; sourceTree = "<group>"; };
- 189365512CEB0C3700023B62 /* libAiMouseSdk copy.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = "libAiMouseSdk copy.a"; path = "/Users/apple/Desktop/code/MouseSdk-MacOS/MouseSdk/AiMouseSdk/build/Debug/libAiMouseSdk copy.a"; sourceTree = "<absolute>"; };
189365522CEB115200023B62 /* KeyboardHidManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyboardHidManager.h; sourceTree = "<group>"; };
189365532CEB115200023B62 /* KeyboardHidManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KeyboardHidManager.m; sourceTree = "<group>"; };
189365562CEB153000023B62 /* MSUtilis.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSUtilis.h; sourceTree = "<group>"; };
18EF7AF62C7603E800AC5223 /* TlwConnectManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TlwConnectManager.h; sourceTree = "<group>"; };
18FCA3952C7F2AD100C44A37 /* AiMouseAuth.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AiMouseAuth.h; sourceTree = "<group>"; };
18FCA3962C7F2AD100C44A37 /* AiMouseAuth.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AiMouseAuth.m; sourceTree = "<group>"; };
+ 3FCF534C2D1A4E38007EC52F /* libAiMouseSdk copy.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libAiMouseSdk copy.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 3FCF534D2D1A5C97007EC52F /* LogManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LogManager.h; sourceTree = "<group>"; };
+ 3FCF534E2D1A5C97007EC52F /* LogManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LogManager.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
180E7AA82BD7BB12008558E8 /* AiMouseSdk */,
180E7AA72BD7BB12008558E8 /* Products */,
180E7D092BD8FEB2008558E8 /* Frameworks */,
+ 3FCF534C2D1A4E38007EC52F /* libAiMouseSdk copy.a */,
);
sourceTree = "<group>";
};
1888148D2C85766B009299A9 /* AiDeviceAuthManager.m */,
189365562CEB153000023B62 /* MSUtilis.h */,
189365572CEB153000023B62 /* MSUtilis.m */,
+ 3FCF534D2D1A5C97007EC52F /* LogManager.h */,
+ 3FCF534E2D1A5C97007EC52F /* LogManager.m */,
);
path = Manager;
sourceTree = "<group>";
18EF7B052C7603E800AC5223 /* TlwConnectManager.h in Headers */,
180E7CF92BD8FC4F008558E8 /* dirac.h in Headers */,
18E0C5932D0FF8E40093BA8F /* stb_app.h in Headers */,
+ 3FCF53502D1A5C97007EC52F /* LogManager.h in Headers */,
184A71032BDA4C050025A332 /* AFNetworkReachabilityManager.h in Headers */,
184A71242BDE2DA60025A332 /* AiSecretModel.h in Headers */,
180E7CCF2BD8FC4E008558E8 /* video_enc_params.h in Headers */,
18862B282C806BD900D3564D /* hwcontext_mediacodec.h in Headers */,
18862B292C806BD900D3564D /* AiAudioDecoder.h in Headers */,
18862B2A2C806BD900D3564D /* encryption_info.h in Headers */,
+ 3FCF53512D1A5C97007EC52F /* LogManager.h in Headers */,
18862B2B2C806BD900D3564D /* blowfish.h in Headers */,
18862B2C2C806BD900D3564D /* AiAliAuthManager.h in Headers */,
18862B2D2C806BD900D3564D /* jni.h in Headers */,
);
name = "AiMouseSdk copy";
productName = AiMouseSdk;
- productReference = 189365512CEB0C3700023B62 /* libAiMouseSdk copy.a */;
+ productReference = 3FCF534C2D1A4E38007EC52F /* libAiMouseSdk copy.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
18EF7B042C7603E800AC5223 /* TlwAudioManager.m in Sources */,
18E0C5982D1000DF0093BA8F /* ByteDanceSdk.m in Sources */,
189960112CEAD7B50042505F /* KeyboardSdk.m in Sources */,
+ 3FCF534F2D1A5C97007EC52F /* LogManager.m in Sources */,
180E7BE72BD7BD84008558E8 /* AiAudioManager.m in Sources */,
18EF7AFB2C7603E800AC5223 /* TlwTools.m in Sources */,
18EF7AFA2C7603E800AC5223 /* TlwMouseSdk.m in Sources */,
18862BAF2C806BD900D3564D /* TimerManager.m in Sources */,
18862BB02C806BD900D3564D /* HidManager.m in Sources */,
18862BB22C806BD900D3564D /* AiMouseTools2.m in Sources */,
+ 3FCF53522D1A5C97007EC52F /* LogManager.m in Sources */,
18862BB32C806BD900D3564D /* AiSecretModel.m in Sources */,
18862BB42C806BD900D3564D /* AiSender.m in Sources */,
18862BB52C806BD900D3564D /* AiTrippleModel.m in Sources */,
@end
@implementation AiMouseDeviceInfo
-(NSString *)description{
-// NSString *info = [NSString stringWithFormat:@"\n battery_power = %@\n CPI = %@\n CPI_list = %@\n version = %@\n brand = %@\n sn = %@\n mac = %@\n productKey = %@\n secretKey = %@\n deviceSecret = %@ \n record_mode = %@ \n mouse_mode = %@ \n url = %@ \n urlActive = %@ ",self.battery_power,self.CPI,self.CPI_list,self.version,self.brand,self.sn,self.mac,self.productKey,self.secretKey,self.deviceSecret,self.record_mode,self.mouse_mode,self.url,self.urlActive];
-
NSString *info = [NSString stringWithFormat:@"\n type = %d \n battery_power = %@\n CPI = %@\n CPI_list = %@\n version = %@\n brand = %@\n sn = %@\n mac = %@\n productKey = %@\n secretKey = %@\n deviceSecret = %@ ",self.type,self.battery_power,self.CPI,self.CPI_list,self.version,self.brand,self.sn,self.mac,self.productKey,self.secretKey,self.deviceSecret];
return info;
}
@end
@interface AiMouse()
-@property (nonatomic, assign) AiMouseLogLevel logLevel;
-
-@property (nonatomic, strong) AiAuthManager *authManager;
-@property (nonatomic, strong) AiAliAuthManager *aliAuthManager;
-@property (nonatomic, strong) AiBkzhAuthManager *bkAuthManager;
@property (nonatomic, strong) AiAudioManager *audioManager;
@property (nonatomic, strong) AiRecordManager *recordManager;
@property (nonatomic, strong) AiDeviceInfoManager *deviceInfoManager;
@property (nonatomic, strong) NSString *updateDeviceSecret;//更新的deviceSecret
-@property (nonatomic, assign) BOOL isAuthing;
@end
@implementation AiMouse
-(instancetype)init{
if (self = [super init]) {
- _logLevel = AiMouseLogLevel_none;
_connectType = AiMouseConnectType_bluetooth;
-// NSLog(@"[AiMouseSdk]%@",[NSString stringWithFormat:@"AiMouseSdk_v%@",self.version]);
[self.recordManager checkPermissions];
}
return self;
}
--(NSString *)version{
- return @"1.0.33";
-}
-(AiDeviceInfoManager *)deviceInfoManager{
if (!_deviceInfoManager) {
return _deviceInfoManager;;
}
--(AiAuthManager *)authManager{
- if (!_authManager) {
- _authManager = [[AiAuthManager alloc] init];
- __weak typeof(self) ws = self;
- _authManager.outputLog = ^(NSString * _Nonnull log) {
- [ws showLog:log];
- };
- _authManager.setDeviceSecret = ^(NSString * _Nonnull value, AiCmdFinishBlock _Nonnull finished) {
- [ws setDeviceSecret:value completation:finished];
- };
- _authManager.authCallBack = ^(BOOL isSuccess) {
- [ws authResult:isSuccess];
-// [ws setDeviceSecret:@"" completation:nil];
- };
- }
- return _authManager;
-}
-
--(AiAliAuthManager *)aliAuthManager{
- if (!_aliAuthManager) {
- _aliAuthManager = [[AiAliAuthManager alloc] init];
- __weak typeof(self) ws = self;
- _aliAuthManager.outputLog = ^(NSString * _Nonnull log) {
- [ws showLog:log];
- };
- _aliAuthManager.setDeviceSecret = ^(NSString * _Nonnull value, AiAliCmdFinishBlock _Nonnull finished) {
- [ws setDeviceSecret:value completation:finished];
- };
- _aliAuthManager.authCallBack = ^(BOOL isSuccess) {
- [ws authResult:isSuccess];
-// [ws setDeviceSecret:@"" completation:nil];
- };
- }
- return _aliAuthManager;
-}
--(AiBkzhAuthManager *)bkAuthManager{
- if (!_bkAuthManager) {
- _bkAuthManager = [[AiBkzhAuthManager alloc] init];
- __weak typeof(self) ws = self;
- _bkAuthManager.outputLog = ^(NSString * _Nonnull log) {
- [ws showLog:log];
- };
- _bkAuthManager.setDeviceSecret = ^(NSString * _Nonnull value, AiBkzhCmdFinishBlock _Nonnull finished) {
- [ws setDeviceSecret:value completation:finished];
- };
- _bkAuthManager.authCallBack = ^(BOOL isSuccess) {
- [ws authResult:isSuccess];
- };
- }
- return _bkAuthManager;
-}
-
-(AiAudioManager *)audioManager{
if (!_audioManager) {
_audioManager = [[AiAudioManager alloc] init];
}
#pragma mark - pub Api
-- (void)setLogLevel:(AiMouseLogLevel)level{
- _logLevel = level;
-}
- (void)didDisconnect{
[self stopRecord:true];
// [self.connectManager disConnected];
}
}
}
-//开始鉴权
-- (void)startAuthentication:(AiMouseAuthType)type finished:(void (^)(AiMouseAuthState))complete{
- if (type == AiMouseAuthType_none){
- complete(AiMouseAuthState_Success);
- return;
- }
- [self showLog:@"开始鉴权"];
- self.authBlock = complete;
- __block typeof(self) ws = self;
- [self getDeviceInfo:^(AiMouseDeviceInfo *deviceInfo, NSError *error) {
- if (error ) {
- ws.authBlock(AiMouseAuthState_Failure);
- }
- else{
- if(type == AiMouseAuthType_Ali){
- [ws.aliAuthManager loginWith:deviceInfo];
- }
- else if(type == AiMouseAuthType_BeiKeZhiHui){
- [ws.bkAuthManager loginWith:deviceInfo];
- }
- else{
- [ws.authManager loginWith:deviceInfo];
- }
- }
- }];
-}
- (void)sendAiDataToSdk:(NSData *)data{
// [self showLog:[NSString stringWithFormat:@"[receive][Voice] %@",data]];
[self.deviceInfoManager receiveData:data];
}
-- (void)setDeviceSecret:(NSString *)value completation:(AiCmdFinishBlock)complete{
- self.updateDeviceSecret = value;
- __weak typeof(self) ws = self;
- [self.deviceInfoManager setDeviceSecret:value completation:^(BOOL isSuccess) {
- if (isSuccess) {
- [ws showLog:@"写入deviceSecret成功,查询是否获读取成功..."];
- //更新成功,检查是否读取到
- [ws.deviceInfoManager getDeviceInfo:^(AiMouseDeviceInfo * _Nonnull deviceInfo, NSError * _Nonnull error) {
- if ([deviceInfo.deviceSecret isEqualToString:value]) {
- [ws showLog:@"写入deviceSecret成功,读取成功!"];
- complete(true);
- }
- else{
- //查不到,继续写入
- [ws showLog:@"查询不到deviceSecret,继续写入!!!"];
- [ws setDeviceSecret:ws.updateDeviceSecret completation:complete];
- }
- }];
- }
- else{
- [ws showLog:@"写入deviceSecret失败!"];
- [ws setDeviceSecret:ws.updateDeviceSecret completation:complete];
- }
- }];
-}
+
- (void)getDeviceInfo:(void (^)(AiMouseDeviceInfo *deviceInfo,NSError *error))complete{
__weak typeof(self) ws = self;
}
#pragma mark - other
- (void)sendRecordData:(NSData *)data{
-// if (self.authState != AiMouseAuthState_Success){
-// [self showLog:@"设备还未鉴权!!!"];
-// return;
-// };
// [self showLog:[NSString stringWithFormat:@"[audio] %@",data]];
if (self.delegate) [self.delegate aiMouseSendRecordData:data];
}
- (void)sendCmdData:(NSData *)data{
-// if (self.authState != AiMouseAuthState_Success){
-// [self showLog:@"设备还未鉴权!!!"];
-// return;
-// }
[self showLog:[NSString stringWithFormat:@"[send] %@",data]];
if (self.delegate) [self.delegate aiMouseSendCmdData:data];
}
if (self.delegate && [self.delegate respondsToSelector:@selector(aiMouseAddLog:)]) {
[self.delegate aiMouseAddLog:[NSString stringWithFormat:@"[frk]%@",log]];
}
-// if(self.logLevel == AiMouseLogLevel_info){
-// NSLog(@"[frk]%@",log);
-// }
}
- (void)checkAuthState{
- if (self.isAuthing) {
- return;
- }
- self.isAuthing = true;
- __weak typeof(self) ws = self;
- [self startAuthentication:AiMouseAuthType_none finished:^(AiMouseAuthState state) {
- ws.isAuthing = false;
- [ws showLog:state == AiMouseAuthState_Success? @"鉴权成功":@"鉴权失败"];
- if(ws.delegate) [ws.delegate aiMouseAuthenticationResult:state];
- }];
+ if(self.delegate) [self.delegate aiMouseAuthenticationResult:AiMouseAuthState_Success];
}
#pragma mark - deviceInfo
- (void)startRecord{