diff --git a/ExtLibs/Xamarin/Xamarin.Android/BTDevice.cs b/ExtLibs/Xamarin/Xamarin.Android/BTDevice.cs index 971fe4e338..af6b189396 100644 --- a/ExtLibs/Xamarin/Xamarin.Android/BTDevice.cs +++ b/ExtLibs/Xamarin/Xamarin.Android/BTDevice.cs @@ -1,14 +1,21 @@ using System; using System.Collections.Generic; +using System.Drawing.Drawing2D; using System.IO; +using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using Android.Bluetooth; +using Android.Bluetooth.LE; +using Android.Runtime; using Android.Util; +using BruTile.Wms; +using Java.Nio; using Java.Util; using MissionPlanner.ArduPilot; using MissionPlanner.Comms; +using static Android.Renderscripts.Sampler; namespace Xamarin.Droid { @@ -20,7 +27,7 @@ public async Task> GetDeviceInfoList() // Get the local Bluetooth adapter var btAdapter = BluetoothAdapter.DefaultAdapter; - if (btAdapter != null) + if (btAdapter != null && btAdapter.IsEnabled) { // Get a set of currently paired devices var pairedDevices = btAdapter.BondedDevices; @@ -33,7 +40,10 @@ public async Task> GetDeviceInfoList() Log.Info("MP", "{0} {1} {2} {3} {4}", device.Name, device.Address, device.Type, device.Class, device.BondState); if (device.Type == BluetoothDeviceType.Le) + { + result.Add(new DeviceInfo() { board = "BLE_" + device.Name, hardwareid = device.Address}); continue; + } result.Add(new DeviceInfo() {board = "BT_" + device.Name, hardwareid = device.Address}); } } @@ -44,7 +54,322 @@ public async Task> GetDeviceInfoList() public async Task GetBT(DeviceInfo first) { - return new BTSerial(first); + if (first.board.StartsWith("BLE_")) + { + return new BTSerialBLE(first); + } + else + { + return new BTSerial(first); + } + } + } + + public class BTSerialBLE : Stream, ICommsSerial + { + MemoryStream readbuffer = new MemoryStream(1024 * 10); + + // nordic uart + public static UUID CCCD = UUID.FromString("00002902-0000-1000-8000-00805f9b34fb"); + public static UUID RX_SERVICE_UUID = UUID.FromString("6e400001-b5a3-f393-e0a9-e50e24dcca9e"); + public static UUID RX_CHAR_UUID = UUID.FromString("6e400002-b5a3-f393-e0a9-e50e24dcca9e"); + public static UUID TX_CHAR_UUID = UUID.FromString("6e400003-b5a3-f393-e0a9-e50e24dcca9e"); + + public BTSerialBLE(DeviceInfo first) + { + _first = first; + PortName = first.name; + } + + public Stream BaseStream => this; + + public int BaudRate { get; set; } + + public int BytesToRead { get; set; } + + public int BytesToWrite { get; set; } + + public int DataBits { get; set; } + public bool DtrEnable { get; set; } + + private BluetoothGatt mBluetoothGatt; + + public bool IsOpen { get; private set; } + + private DeviceInfo _first; + + public string PortName { get; set; } + public int ReadBufferSize { get; set; } + public bool RtsEnable { get; set; } + public int WriteBufferSize { get; set; } + + public override bool CanRead => true; + + public override bool CanSeek => false; + + public override bool CanWrite => true; + + public override long Length { get; } + + public override long Position {get;set; } + public int ReadTimeout { get; set; } + public int WriteTimeout { get; set; } + + public void DiscardInBuffer() + { + + } + + public override void Flush() + { + + } + + public void Open() + { + Log.Info("MP", "Open {0} {1}", _first.name, _first.hardwareid); + BluetoothAdapter bluetoothAdapter = BluetoothAdapter.DefaultAdapter; + BluetoothDevice device = bluetoothAdapter.GetRemoteDevice(_first.hardwareid); + + mBluetoothGatt = device.ConnectGatt(null, false, new BluetoothGattCallback(this)); + + Thread.Sleep(1000); + + IsOpen = true; + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (buffer == null) throw new ArgumentNullException(nameof(buffer)); + if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset)); + if (count < 0) throw new ArgumentOutOfRangeException(nameof(count)); + + var deadline = DateTime.Now.AddMilliseconds(ReadTimeout); + while (BytesToRead < count && DateTime.Now < deadline) + { + Thread.Sleep(1); + } + + if (ReadTimeout > 0 && BytesToRead == 0) + { + throw new TimeoutException("No data in serial buffer"); + } + + var read = Math.Min(count, BytesToRead); + + lock (readbuffer) + { + read = readbuffer.Read(buffer, offset, read); + BytesToRead -= read; + } + + return read; + } + + public override int ReadByte() + { + var ans = new byte[] { 0 }; + var count = Read(ans, 0, 1); + return count > 0 ? ans[0] : -1; + } + + public int ReadChar() + { + return ReadByte(); + } + + public string ReadExisting() + { + StringBuilder build = new StringBuilder(); + for (int a = 0; a < BytesToRead; a++) + build.Append((char)ReadByte()); + return build.ToString(); + } + + public string ReadLine() + { + var temp = new byte[4000]; + var count = 0; + var timeout = 0; + + while (timeout <= 100) + { + if (!IsOpen) break; + if (BytesToRead > 0) + { + var letter = (byte)ReadByte(); + + temp[count] = letter; + + if (letter == '\n') // normal line + break; + + count++; + if (count == temp.Length) + break; + timeout = 0; + } + else + { + timeout++; + Thread.Sleep(5); + } + } + + return Encoding.ASCII.GetString(temp, 0, count + 1); + } + + + public override long Seek(long offset, SeekOrigin origin) + { + return BaseStream.Seek(offset, origin); + } + + public override void SetLength(long value) + { + BaseStream.SetLength(value); + } + + public void toggleDTR() + { + + } + + + public override void Write(byte[] buffer, int offset, int count) + { + // rx from nordic side + BluetoothGattService RxService = mBluetoothGatt.GetService(RX_SERVICE_UUID); + BluetoothGattCharacteristic RxChar = RxService.GetCharacteristic(RX_CHAR_UUID); + + RxChar.SetValue(buffer.Skip(offset).Take(count).ToArray()); + bool status = mBluetoothGatt.WriteCharacteristic(RxChar); + + Log.Debug("MP", "Write {0} {1} {2}", status, buffer.Length, count); + } + + public void Write(string text) + { + Write(ASCIIEncoding.ASCII.GetBytes(text), 0, text.Length); + } + + public void WriteLine(string text) + { + text += '\n'; + Write(ASCIIEncoding.ASCII.GetBytes(text), 0, text.Length); + } + + public void Close() + { + mBluetoothGatt?.Close(); + } + + public void Dispose() + { + Close(); + } + + private class BluetoothGattCallback : global::Android.Bluetooth.BluetoothGattCallback + { + public BTSerialBLE BTSerialBLE { get; } + + public BluetoothGattCallback(BTSerialBLE bTSerialBLE) + { + BTSerialBLE = bTSerialBLE; + } + + public override void OnConnectionStateChange(BluetoothGatt gatt, [GeneratedEnum] GattStatus status, [GeneratedEnum] ProfileState newState) + { + Log.Info("MP", "OnConnectionStateChange {0} - {1}", newState, status); + base.OnConnectionStateChange(gatt, status, newState); + + if (newState == ProfileState.Connected) + { + gatt.DiscoverServices(); + } + else if (newState == ProfileState.Disconnected) + { + BTSerialBLE.IsOpen = false; + } + } + + public override void OnServicesDiscovered(BluetoothGatt gatt, [GeneratedEnum] GattStatus status) + { + Log.Info("MP", "OnServicesDiscovered {0}", status); + base.OnServicesDiscovered(gatt, status); + + BluetoothGattService RxService = BTSerialBLE.mBluetoothGatt.GetService(RX_SERVICE_UUID); + if (RxService != null) + { + BluetoothGattCharacteristic TxChar = RxService.GetCharacteristic(TX_CHAR_UUID); + if (TxChar != null) + { + BTSerialBLE.mBluetoothGatt.SetCharacteristicNotification(TxChar, true); + BluetoothGattDescriptor descriptor = TxChar.GetDescriptor(CCCD); + descriptor.SetValue(BluetoothGattDescriptor.EnableNotificationValue.ToArray()); + BTSerialBLE.mBluetoothGatt.WriteDescriptor(descriptor); + } + else + Log.Info("MP", "OnServicesDiscovered GetService fail"); + } + else + Log.Info("MP", "OnServicesDiscovered GetCharacteristic fail"); + + Log.Info("MP", "OnServicesDiscovered Done"); + } + + public override void OnCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, [GeneratedEnum] GattStatus status) + { + Log.Info("MP", "OnCharacteristicRead {0} {1}", characteristic.Uuid, status); + base.OnCharacteristicRead(gatt, characteristic, status); + + update(characteristic); + } + + private void update(BluetoothGattCharacteristic characteristic) + { + Log.Debug("MP", "update {0} {1}", characteristic.Uuid, TX_CHAR_UUID.Equals(characteristic.Uuid)); + if (TX_CHAR_UUID.Equals(characteristic.Uuid)) + { + lock (BTSerialBLE.readbuffer) + { + var buffer = characteristic.GetValue(); + var len = buffer.Length; + if (BTSerialBLE.readbuffer.Position == BTSerialBLE.readbuffer.Length && BTSerialBLE.readbuffer.Length > 0) + { + //clear it + BTSerialBLE.readbuffer.SetLength(0); + // add data + BTSerialBLE.readbuffer.Write(buffer, 0, len); + // set readback start point + BTSerialBLE.readbuffer.Position = 0; + // update toread + BTSerialBLE.BytesToRead += len; + Log.Debug("BTSerial", "BytesToRead1 " + BTSerialBLE.BytesToRead); + } + else + { + var pos = BTSerialBLE.readbuffer.Position; + // goto end + BTSerialBLE.readbuffer.Seek(0, SeekOrigin.End); + //write + BTSerialBLE.readbuffer.Write(buffer, 0, len); + // seek back to readpos + BTSerialBLE.readbuffer.Seek(pos, SeekOrigin.Begin); + BTSerialBLE.BytesToRead += len; + Log.Debug("BTSerial", "BytesToRead2 " + BTSerialBLE.BytesToRead); + } + } + } + } + + public override void OnCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) + { + Log.Info("MP", "OnCharacteristicChanged {0}", characteristic.Uuid); + base.OnCharacteristicChanged(gatt, characteristic); + + update(characteristic); + } } } diff --git a/ExtLibs/Xamarin/Xamarin/GCSViews/WinForms.xaml.cs b/ExtLibs/Xamarin/Xamarin/GCSViews/WinForms.xaml.cs index e321366e91..15fc8d7a73 100644 --- a/ExtLibs/Xamarin/Xamarin/GCSViews/WinForms.xaml.cs +++ b/ExtLibs/Xamarin/Xamarin/GCSViews/WinForms.xaml.cs @@ -109,7 +109,7 @@ public WinForms() } else { - if (s.StartsWith("BT_")) + if (s.StartsWith("BT_") || s.StartsWith("BLE_")) { var bt = await Test.BlueToothDevice.GetDeviceInfoList(); diff --git a/ExtLibs/Xamarin/Xamarin/Maps/MyImageCache.cs b/ExtLibs/Xamarin/Xamarin/Maps/MyImageCache.cs index 6049e41d59..5404ddec05 100644 --- a/ExtLibs/Xamarin/Xamarin/Maps/MyImageCache.cs +++ b/ExtLibs/Xamarin/Xamarin/Maps/MyImageCache.cs @@ -183,6 +183,37 @@ int PureImageCache.DeleteOlderThan(DateTime date, int? type) return affectedRows; } + public bool CheckImageFromCache(int type, GPoint pos, int zoom) + { + bool ret = false; + if (Created) + { + try + { + string file = CacheLocation + Path.DirectorySeparatorChar + GMapProviders.TryGetProvider(type).Name + + Path.DirectorySeparatorChar + zoom + Path.DirectorySeparatorChar + pos.Y + + Path.DirectorySeparatorChar + pos.X + ".jpg"; + if (File.Exists(file)) + { + ret = true; + } + else + { + ret = false; + } + } + catch (Exception ex) + { +#if MONO + Console.WriteLine("CheckImageFromCache: " + ex.ToString()); +#endif + Debug.WriteLine("CheckImageFromCache: " + ex.ToString()); + ret = false; + } + } + return ret; + } + #endregion } } \ No newline at end of file diff --git a/MissionPlannerLib.csproj b/MissionPlannerLib.csproj index 39e4512bba..10203fab69 100644 --- a/MissionPlannerLib.csproj +++ b/MissionPlannerLib.csproj @@ -79,6 +79,7 @@ + @@ -175,6 +176,7 @@ + @@ -270,6 +272,7 @@ +