diff --git a/App/RobobinApp/Platforms/Windows/Package.appxmanifest b/App/RobobinApp/Platforms/Windows/Package.appxmanifest index ed36aaddd37f2d8ffa495a2755eae582495cfc1c..e6b11f6f50b721cd732d8aab5b931bdb74f42fd8 100644 --- a/App/RobobinApp/Platforms/Windows/Package.appxmanifest +++ b/App/RobobinApp/Platforms/Windows/Package.appxmanifest @@ -6,41 +6,45 @@ xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" IgnorableNamespaces="uap rescap"> - <Identity Name="maui-package-name-placeholder" Publisher="CN=User Name" Version="0.0.0.0" /> - - <mp:PhoneIdentity PhoneProductId="8646FF59-A3E1-4276-A8EA-36FBC95CCEAD" PhonePublisherId="00000000-0000-0000-0000-000000000000"/> - - <Properties> - <DisplayName>$placeholder$</DisplayName> - <PublisherDisplayName>User Name</PublisherDisplayName> - <Logo>$placeholder$.png</Logo> - </Properties> - - <Dependencies> - <TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" /> - <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" /> - </Dependencies> - - <Resources> - <Resource Language="x-generate" /> - </Resources> - - <Applications> - <Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="$targetentrypoint$"> - <uap:VisualElements - DisplayName="$placeholder$" - Description="$placeholder$" - Square150x150Logo="$placeholder$.png" - Square44x44Logo="$placeholder$.png" - BackgroundColor="transparent"> - <uap:DefaultTile Square71x71Logo="$placeholder$.png" Wide310x150Logo="$placeholder$.png" Square310x310Logo="$placeholder$.png" /> - <uap:SplashScreen Image="$placeholder$.png" /> - </uap:VisualElements> - </Application> - </Applications> - - <Capabilities> - <rescap:Capability Name="runFullTrust" /> - </Capabilities> + <Identity Name="maui-package-name-placeholder" Publisher="CN=User Name" Version="0.0.0.0" /> + + <mp:PhoneIdentity PhoneProductId="8646FF59-A3E1-4276-A8EA-36FBC95CCEAD" PhonePublisherId="00000000-0000-0000-0000-000000000000"/> + + <Properties> + <DisplayName>$placeholder$</DisplayName> + <PublisherDisplayName>User Name</PublisherDisplayName> + <Logo>$placeholder$.png</Logo> + </Properties> + + <Dependencies> + <TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" /> + <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" /> + </Dependencies> + + <Resources> + <Resource Language="x-generate" /> + </Resources> + + <Applications> + <Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="$targetentrypoint$"> + <uap:VisualElements + DisplayName="$placeholder$" + Description="$placeholder$" + Square150x150Logo="$placeholder$.png" + Square44x44Logo="$placeholder$.png" + BackgroundColor="transparent"> + <uap:DefaultTile Square71x71Logo="$placeholder$.png" Wide310x150Logo="$placeholder$.png" Square310x310Logo="$placeholder$.png" /> + <uap:SplashScreen Image="$placeholder$.png" /> + </uap:VisualElements> + </Application> + </Applications> + + <Capabilities> + <Capability Name="internetClient" /> + <rescap:Capability Name="runFullTrust" /> + <rescap:Capability Name="bluetooth" /> + <rescap:Capability Name="bluetoothGenericAttributeProfile" /> + <rescap:Capability Name="location" /> + </Capabilities> </Package> diff --git a/App/RobobinApp/RobobinApp.csproj.user b/App/RobobinApp/RobobinApp.csproj.user index ed22012985172189459fe0632fc78a258b70b2b4..8a145f6bd6dbb342e247b65713f30a6ea1af444a 100644 --- a/App/RobobinApp/RobobinApp.csproj.user +++ b/App/RobobinApp/RobobinApp.csproj.user @@ -14,6 +14,11 @@ <RuntimeIdentifier>ios-arm64</RuntimeIdentifier> <PlatformTarget>arm64</PlatformTarget> </PropertyGroup> + <ItemGroup> + <AppxManifest Update="Platforms\Windows\Package.appxmanifest"> + <SubType>Designer</SubType> + </AppxManifest> + </ItemGroup> <ItemGroup> <MauiXaml Update="Views\ConnectionPage.xaml"> <SubType>Designer</SubType> diff --git a/App/RobobinApp/ViewModels/ConnectionPageViewModel.cs b/App/RobobinApp/ViewModels/ConnectionPageViewModel.cs index a755d6462cb5d6766238f9556949f72513e3325b..36910486f8f8888c36dfb697132224ccbb97493a 100644 --- a/App/RobobinApp/ViewModels/ConnectionPageViewModel.cs +++ b/App/RobobinApp/ViewModels/ConnectionPageViewModel.cs @@ -57,7 +57,7 @@ namespace RobobinApp.ViewModels { _isConnected = value; OnPropertyChanged(); - OnPropertyChanged(nameof(ConnectButtonText)); + OnPropertyChanged(nameof(ConnectButtonText)); } } private ICharacteristic _readCharacteristic; @@ -111,7 +111,7 @@ namespace RobobinApp.ViewModels public string ConnectButtonText => IsConnected ? "Disconnect" : "Connect"; private bool _isWifiNetworkSelectionVisible; private WifiNetwork _selectedWifiNetwork; - + public bool IsWifiNetworkSelectionVisible { get => _isWifiNetworkSelectionVisible; @@ -154,6 +154,11 @@ namespace RobobinApp.ViewModels { try { + if (SelectedWifiNetwork == null) + { + Debug.WriteLine("No Network Selected"); + return ; + } var SSID = SelectedWifiNetwork.SSID; var result = WriteOperationAsync("CONNECT", SSID + "," + password); @@ -193,7 +198,7 @@ namespace RobobinApp.ViewModels Debug.WriteLine(networks); var delimiter = '\n'; //Test to see if actual SSID has \n, see if it breaks things var networkList = networks.Split(delimiter); - var addedSsids = new HashSet<string>(); + var addedSsids = new HashSet<string>(); foreach (var network in networkList) { @@ -294,7 +299,7 @@ namespace RobobinApp.ViewModels Debug.WriteLine("Starting scanning for devices..."); await _adapter.StartScanningForDevicesAsync(); - + } catch (Exception ex) { @@ -372,66 +377,36 @@ namespace RobobinApp.ViewModels try { - //await _adapter.StopScanningForDevicesAsync(); IsConnected = true; - _connectedDevice = await TryConnectAsync(Guid.Parse(SelectedDevice.MacAddress)); if (_connectedDevice != null) { Debug.WriteLine($"Successfully connected to {SelectedDevice.Name}."); - // var services = await _connectedDevice.GetServicesAsync(); - Debug.WriteLine("Services gotten"); IsWifiNetworkSelectionVisible = true; - // Iterate through the discovered services - //var service = await _connectedDevice.GetServiceAsync(Guid.Parse("00000001-710e-4a5b-8d75-3e5b444bc3cf")); - await Task.Delay(2000); foreach (var service in services) - { - Debug.WriteLine($"Service: ID={service.Id}, Name={service.Name}"); - - if (service.Id.Equals(Guid.Parse("00000001-710e-4a5b-8d75-3e5b444bc3cf")) ) + if (service.Id.Equals(Guid.Parse(SendReceiveServiceUUID))) { - Debug.WriteLine("Found RW service"); + Debug.WriteLine("Found Read/Write service"); ReadWriteService = service; + var characteristics = await ReadWriteService.GetCharacteristicsAsync(); + + ReadCharacteristic = await ReadWriteService.GetCharacteristicAsync(Guid.Parse(rxUUID)); + WriteCharacteristic = await ReadWriteService.GetCharacteristicAsync(Guid.Parse(wxUUID)); + Debug.WriteLine("Characteristics initialized successfully."); ScanForWifiNetworks(); - return; - /***var characteristics = await service.GetCharacteristicsAsync(); - - foreach (var characteristic in characteristics) - { - var descriptors = await characteristic.GetDescriptorsAsync(); - foreach (var descriptor in descriptors) - { - var descriptorValue = await descriptor.ReadAsync(); - var descriptorValueString = Encoding.UTF8.GetString(descriptorValue); - Debug.WriteLine($"Descriptor: {descriptor.Id} | Value: {descriptorValueString}"); - } - - Debug.WriteLine($"{characteristic.Uuid} |{characteristic.Name}"); - if (characteristic.Name.Equals(readCharacteristicName)) - - { - ReadCharacteristic = characteristic; - var result = await ReadOperationAsync(); - - } - else if (characteristic.Name.Equals(writeCharacteristicName)) - { - WriteCharacteristic = characteristic; - const string command = "SCAN"; - //await WriteOperationAsync(command); - ScanForWifiNetworks(); - - } - }**/ + break; } } - + if (ReadWriteService == null || ReadCharacteristic == null || WriteCharacteristic == null) + { + Debug.WriteLine("Failed to initialize BLE service or characteristics."); + OnDisconnect(); + } } else { @@ -443,42 +418,31 @@ namespace RobobinApp.ViewModels { Debug.WriteLine($"Connection error: {ex.Message}"); await Application.Current.MainPage.DisplayAlert("Connection Error", $"Failed to connect: {ex.Message}", "OK"); + OnDisconnect(); } catch (Exception ex) { Debug.WriteLine($"General connection error: {ex.Message}"); await Application.Current.MainPage.DisplayAlert("Connection Error", $"An error occurred: {ex.Message}", "OK"); - } - finally - { - // Ensure we reset connection state - if (_connectedDevice == null) - { - IsConnected = false; - // Consider resetting any other related UI state - } + OnDisconnect(); } } - - - private async Task<string> ReadOperationAsync(int retryCount = 3) { - if (ReadWriteService == null || !IsConnected) + if (ReadCharacteristic == null || !IsConnected) { - Debug.WriteLine("Read characteristic is not set or device is not connected."); + Debug.WriteLine("Read characteristic is not initialized or device is not connected."); return "Failure"; } - ReadCharacteristic = await ReadWriteService.GetCharacteristicAsync(Guid.Parse(rxUUID)); - Debug.WriteLine($"READ COMMAND : {ReadCharacteristic.Uuid}"); + for (int attempt = 1; attempt <= retryCount; attempt++) { try { - Debug.WriteLine($"Attempt {attempt}: Reading from characteristic {ReadCharacteristic.Uuid}"); + Debug.WriteLine($"Attempt {attempt}: Reading from characteristic"); var temperatureData = await ReadCharacteristic.ReadAsync(); - var temperatureValue = System.Text.Encoding.UTF8.GetString(temperatureData.data); + var temperatureValue = Encoding.UTF8.GetString(temperatureData.data); Debug.WriteLine($"Temperature Value: {temperatureValue}"); return temperatureValue; } @@ -487,34 +451,37 @@ namespace RobobinApp.ViewModels Debug.WriteLine($"Read attempt {attempt} failed: {ex.Message}"); if (attempt == retryCount) { - Debug.WriteLine("Max retry attempts reached for reading."); - throw; - } else - { - await Task.Delay(1000); + Debug.WriteLine("Max retry attempts reached for reading. Attempting reconnection..."); + if (await TryReconnect()) + { + Debug.WriteLine("Reconnected successfully. Retrying read operation."); + return await ReadOperationAsync(retryCount); // Retry after reconnection + } + Debug.WriteLine("Reconnection failed. Returning failure."); + return "Failure"; } + await Task.Delay(1000); } } - return "Failure"; + return "Failure"; } - private async Task<string> WriteOperationAsync(string command, string arguments="", int retryCount = 3) + private async Task<string> WriteOperationAsync(string command, string arguments = "", int retryCount = 3) { - if (ReadWriteService == null) + if (WriteCharacteristic == null || !IsConnected) { - Debug.WriteLine("Write characteristic is not set."); + Debug.WriteLine("Write characteristic is not initialized or device is not connected."); return "Failure"; } - //Get Characteristic - WriteCharacteristic = await ReadWriteService.GetCharacteristicAsync(Guid.Parse(wxUUID)); - string joinedData = command + ":" + arguments; - Debug.WriteLine($"WRITE COMMAND {joinedData}, UUID: {WriteCharacteristic}"); - byte[] data = System.Text.Encoding.UTF8.GetBytes(joinedData); + + string joinedData = $"{command}:{arguments}"; + byte[] data = Encoding.UTF8.GetBytes(joinedData); + Debug.WriteLine($"WRITE COMMAND {joinedData}, UUID: {WriteCharacteristic.Uuid}"); for (int attempt = 1; attempt <= retryCount; attempt++) { try - { + { await WriteCharacteristic.WriteAsync(data); Debug.WriteLine("Write operation succeeded."); return "Success"; @@ -524,18 +491,66 @@ namespace RobobinApp.ViewModels Debug.WriteLine($"Write attempt {attempt} failed: {ex.Message}"); if (attempt == retryCount) { - Debug.WriteLine("Max retry attempts reached for writing."); - throw; - } else - { - await Task.Delay(1000); + Debug.WriteLine("Max retry attempts reached for writing. Attempting reconnection..."); + if (await TryReconnect()) + { + Debug.WriteLine("Reconnected successfully. Retrying write operation."); + return await WriteOperationAsync(command, arguments, retryCount); // Retry after reconnection + } + Debug.WriteLine("Reconnection failed. Returning failure."); + return "Failure"; } + await Task.Delay(1000); } } return "Failure"; - } + private async Task<bool> TryReconnect() + { + if (SelectedDevice == null) + { + Debug.WriteLine("No device is selected for reconnection."); + return false; + } + + Debug.WriteLine($"Attempting to reconnect to {SelectedDevice.Name}, MAC Address {SelectedDevice.MacAddress}"); + + try + { + IsConnected = false; + _connectedDevice = await TryConnectAsync(Guid.Parse(SelectedDevice.MacAddress)); + + if (_connectedDevice != null) + { + Debug.WriteLine($"Successfully reconnected to {SelectedDevice.Name}."); + + // Re-initialize services and characteristics + var services = await _connectedDevice.GetServicesAsync(); + ReadWriteService = services.FirstOrDefault(s => s.Id.Equals(Guid.Parse(SendReceiveServiceUUID))); + + if (ReadWriteService != null) + { + ReadCharacteristic = await ReadWriteService.GetCharacteristicAsync(Guid.Parse(rxUUID)); + WriteCharacteristic = await ReadWriteService.GetCharacteristicAsync(Guid.Parse(wxUUID)); + IsConnected = true; + return true; + } + } + else + { + Debug.WriteLine("Failed to reconnect to the device."); + return false; + } + } + catch (Exception ex) + { + Debug.WriteLine($"Reconnection error: {ex.Message}"); + return false; + } + + return false; + } private async void OnDisconnect() { @@ -544,13 +559,9 @@ namespace RobobinApp.ViewModels try { Debug.WriteLine($"Attempting to disconnect from {_connectedDevice.Name}"); - ResetState(); await _adapter.DisconnectDeviceAsync(_connectedDevice); Debug.WriteLine("Disconnected successfully."); - IsWifiNetworkSelectionVisible = false; ResetState(); - IsConnected = false; - ScanDevices(); await Application.Current.MainPage.DisplayAlert("Disconnected", "Device disconnected successfully.", "OK"); } catch (Exception ex) @@ -574,11 +585,11 @@ namespace RobobinApp.ViewModels BluetoothDevices.Clear(); ReadCharacteristic = null; WriteCharacteristic = null; + ReadWriteService = null; IsWifiNetworkSelectionVisible = false; - } - } + } }