Initial commit: FieldLogger MAUI app with Maglink BLE support
Added Maglink RTK GNSS receiver integration with correct BLE UUIDs and device name filtering (ML-* prefix). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
107
FieldLogger/ViewModels/DeviceScanViewModel.cs
Normal file
107
FieldLogger/ViewModels/DeviceScanViewModel.cs
Normal file
@@ -0,0 +1,107 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using FieldLogger.Models;
|
||||
using FieldLogger.Services;
|
||||
using FieldLogger.Services.Ble;
|
||||
|
||||
namespace FieldLogger.ViewModels;
|
||||
|
||||
[QueryProperty(nameof(KindName), "kind")]
|
||||
public sealed partial class DeviceScanViewModel : ObservableObject
|
||||
{
|
||||
private readonly BleScanner _scanner;
|
||||
private readonly DeviceConnectionManager _manager;
|
||||
private CancellationTokenSource? _scanCts;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _kindName = nameof(DeviceKind.Locator);
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(ScanButtonText))]
|
||||
private bool _isScanning;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _title = "Select Device";
|
||||
|
||||
[ObservableProperty]
|
||||
private string _hint = "";
|
||||
|
||||
public ObservableCollection<DiscoveredDevice> Devices { get; } = new();
|
||||
|
||||
public DeviceKind Kind => Enum.TryParse<DeviceKind>(KindName, out var k) ? k : DeviceKind.Locator;
|
||||
|
||||
public string ScanButtonText => IsScanning ? "Scanning…" : "Scan Again";
|
||||
|
||||
public DeviceScanViewModel(BleScanner scanner, DeviceConnectionManager manager)
|
||||
{
|
||||
_scanner = scanner;
|
||||
_manager = manager;
|
||||
_scanner.DeviceDiscovered += OnDeviceDiscovered;
|
||||
}
|
||||
|
||||
partial void OnKindNameChanged(string value)
|
||||
{
|
||||
Title = Kind == DeviceKind.Locator ? "Select Locating Receiver" : "Select RTK GPS Receiver";
|
||||
Hint = Kind == DeviceKind.Locator
|
||||
? "Looking for UM receivers (UMRX / DT100). Make sure Bluetooth is enabled on the receiver."
|
||||
: "Looking for Maglink RTK receivers. Make sure the receiver is powered on.";
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public async Task ScanAsync()
|
||||
{
|
||||
if (IsScanning)
|
||||
return;
|
||||
|
||||
Devices.Clear();
|
||||
IsScanning = true;
|
||||
_scanCts = new CancellationTokenSource();
|
||||
try
|
||||
{
|
||||
await _scanner.ScanAsync(TimeSpan.FromSeconds(12), _scanCts.Token);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Shell.Current.DisplayAlert("Scan Failed", ex.Message, "OK");
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsScanning = false;
|
||||
_scanCts?.Dispose();
|
||||
_scanCts = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void StopScan() => _scanCts?.Cancel();
|
||||
|
||||
[RelayCommand]
|
||||
private async Task SelectAsync(DiscoveredDevice device)
|
||||
{
|
||||
StopScan();
|
||||
await _manager.UseDeviceAsync(Kind, device.Id, device.Name);
|
||||
await Shell.Current.GoToAsync("..");
|
||||
}
|
||||
|
||||
private void OnDeviceDiscovered(object? sender, DiscoveredDevice device)
|
||||
{
|
||||
// Filter by device name prefix based on device type.
|
||||
if (Kind == DeviceKind.Locator && !UmReceiverService.IsUmReceiverName(device.Name))
|
||||
return;
|
||||
if (Kind == DeviceKind.Maglink && !MaglinkService.IsMaglinkName(device.Name))
|
||||
return;
|
||||
|
||||
MainThread.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
var existing = Devices.FirstOrDefault(d => d.Id == device.Id);
|
||||
if (existing is not null)
|
||||
Devices.Remove(existing);
|
||||
|
||||
// Keep the list sorted by signal strength.
|
||||
var index = 0;
|
||||
while (index < Devices.Count && Devices[index].Rssi >= device.Rssi)
|
||||
index++;
|
||||
Devices.Insert(index, device);
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user