Skip to content

Commit b39a91f

Browse files
authored
Merge pull request #178 from ShimmerEngineering/DEV-268
DEV-268
2 parents 09905a1 + bfad7c4 commit b39a91f

File tree

126 files changed

+2398
-14
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

126 files changed

+2398
-14
lines changed
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
using shimmer.Communications;
2+
using System;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using Plugin.BLE;
6+
using Plugin.BLE.Abstractions.Contracts;
7+
using Plugin.BLE.Abstractions.EventArgs;
8+
using System.Threading;
9+
10+
namespace ShimmerBLEMauiAPI.Communications
11+
{
12+
internal class RadioPluginBLEv3 : IVerisenseByteCommunication
13+
{
14+
15+
16+
private IBluetoothLE bluetoothLE = CrossBluetoothLE.Current; // ✅ Should now work
17+
public static bool ShowRXB = false;
18+
19+
public Guid Asm_uuid { get; set; }
20+
21+
public event EventHandler<ByteLevelCommunicationEvent> CommunicationEvent;
22+
23+
private IAdapter _adapter;
24+
private IDevice _device;
25+
private IService _serviceTXRX;
26+
private ICharacteristic _uartTX;
27+
private ICharacteristic _uartRX;
28+
29+
private ConnectivityState State = ConnectivityState.Unknown;
30+
private TaskCompletionSource<bool> ConnectionStatusTCS;
31+
32+
private readonly IBluetoothLE _bluetoothLE;
33+
34+
public RadioPluginBLEv3()
35+
{
36+
_bluetoothLE = CrossBluetoothLE.Current;
37+
_adapter = CrossBluetoothLE.Current.Adapter;
38+
}
39+
40+
public async Task<ConnectivityState> Connect()
41+
{
42+
try
43+
{
44+
ConnectionStatusTCS = new TaskCompletionSource<bool>();
45+
46+
var knownDevices = _adapter.GetSystemConnectedOrPairedDevices(new Guid[] { Asm_uuid });
47+
48+
_device = knownDevices.FirstOrDefault(d => d.Id == Asm_uuid);
49+
if (_device == null)
50+
{
51+
State = ConnectivityState.Disconnected;
52+
return State;
53+
}
54+
55+
// With this corrected implementation:
56+
_adapter.DeviceDisconnected += Device_Disconnected;
57+
58+
await _adapter.ConnectToDeviceAsync(_device);
59+
60+
var services = await _device.GetServicesAsync();
61+
_serviceTXRX = services.FirstOrDefault(s => s.Id == new Guid("6E400001-B5A3-F393-E0A9-E50E24DCCA9E"));
62+
if (_serviceTXRX == null)
63+
{
64+
throw new Exception("TXRX Service not found");
65+
}
66+
67+
_uartTX = (await _serviceTXRX.GetCharacteristicsAsync())
68+
.FirstOrDefault(c => c.Id == new Guid("6E400002-B5A3-F393-E0A9-E50E24DCCA9E"));
69+
70+
_uartRX = (await _serviceTXRX.GetCharacteristicsAsync())
71+
.FirstOrDefault(c => c.Id == new Guid("6E400003-B5A3-F393-E0A9-E50E24DCCA9E"));
72+
73+
if (_uartRX != null)
74+
{
75+
_uartRX.ValueUpdated += UartRX_ValueUpdated;
76+
await _uartRX.StartUpdatesAsync();
77+
}
78+
79+
State = ConnectivityState.Connected;
80+
return State;
81+
}
82+
catch (Exception ex)
83+
{
84+
Console.WriteLine("RadioPluginBLE Connection Error: " + ex.Message);
85+
Disconnect();
86+
return ConnectivityState.Disconnected;
87+
}
88+
}
89+
90+
public async Task<ConnectivityState> Disconnect()
91+
{
92+
try
93+
{
94+
if (_uartRX != null)
95+
{
96+
_uartRX.ValueUpdated -= UartRX_ValueUpdated;
97+
await _uartRX.StopUpdatesAsync();
98+
}
99+
100+
if (_device != null)
101+
{
102+
// With this corrected implementation:
103+
_adapter.DeviceDisconnected += Device_Disconnected;
104+
await _adapter.DisconnectDeviceAsync(_device);
105+
}
106+
107+
_uartTX = null;
108+
_uartRX = null;
109+
_serviceTXRX = null;
110+
_device = null;
111+
112+
State = ConnectivityState.Disconnected;
113+
GC.Collect();
114+
Thread.Sleep(3000);
115+
}
116+
catch (Exception ex)
117+
{
118+
Console.WriteLine("Error during Disconnect: " + ex.Message);
119+
}
120+
121+
return State;
122+
}
123+
124+
private void Device_Disconnected(object sender, DeviceEventArgs e)
125+
{
126+
State = ConnectivityState.Disconnected;
127+
CommunicationEvent?.Invoke(this, new ByteLevelCommunicationEvent
128+
{
129+
Event = ByteLevelCommunicationEvent.CommEvent.Disconnected
130+
});
131+
ConnectionStatusTCS?.TrySetResult(true);
132+
}
133+
134+
public ConnectivityState GetConnectivityState()
135+
{
136+
return State;
137+
}
138+
139+
public async Task<bool> WriteBytes(byte[] bytes)
140+
{
141+
if (_uartTX != null)
142+
{
143+
// Replace WriteWithoutResponseAsync with WriteAsync as per the ICharacteristic interface
144+
await _uartTX.WriteAsync(bytes);
145+
return true;
146+
}
147+
148+
return false;
149+
}
150+
151+
private void UartRX_ValueUpdated(object sender, CharacteristicUpdatedEventArgs e)
152+
{
153+
if (ShowRXB)
154+
{
155+
Console.WriteLine("RXB:" + BitConverter.ToString(e.Characteristic.Value).Replace("-", ""));
156+
}
157+
158+
CommunicationEvent?.Invoke(this, new ByteLevelCommunicationEvent
159+
{
160+
Bytes = e.Characteristic.Value,
161+
Event = ByteLevelCommunicationEvent.CommEvent.NewBytes
162+
});
163+
}
164+
}
165+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using shimmer.Communications;
2+
using ShimmerBLEAPI.Devices;
3+
using ShimmerBLEMauiAPI.Communications;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
10+
namespace ShimmerBLEMauiAPI.Devices
11+
{
12+
public class VerisensePluginBLEDevice : VerisenseBLEDevice
13+
{
14+
public static string path;
15+
public VerisensePluginBLEDevice(string uuid, string name, string comport, CommunicationType commtype) : base(uuid, name)
16+
{
17+
ComPort = comport;
18+
CommType = commtype;
19+
}
20+
21+
public VerisensePluginBLEDevice(string uuid, string name) : base(uuid, name)
22+
{
23+
24+
}
25+
26+
protected override void InitializeRadio()
27+
{
28+
if (BLERadio != null)
29+
BLERadio.CommunicationEvent -= UartRX_ValueUpdated;
30+
if (CommType == CommunicationType.BLE)
31+
{
32+
BLERadio = new RadioPluginBLEv3();
33+
}
34+
35+
}
36+
}
37+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net8.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<ProjectReference Include="..\..\ShimmerBLEAPI\ShimmerBLEAPI.csproj" />
11+
</ItemGroup>
12+
13+
<ItemGroup>
14+
<PackageReference Include="Plugin.BLE" Version="3.1.0" />
15+
</ItemGroup>
16+
17+
</Project>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Passkey Configuration App
2+
3+
This App allows you to set the passkey options for bonding/pairing with the Verisense device. There are three options
4+
- No Passkey
5+
- Default Passkey
6+
- Clinical Passkey
7+
8+
The API has a fully configurable advertising ids, passkey ids, and passkey values, but for the purpose of limiting user error, the App is limited to the above. It will not be Shimmers responsibility should you use a configuration that ends up bricking the Verisense sensor.
9+
10+
The following steps are how to configure the device
11+
1) Pair the Verisense device (if required)
12+
2) Scan
13+
3) Pick Verisense device from the list of scanned devices
14+
4) Connect
15+
5) Select the passkey configuration from the list of choices
16+
6) Click Write Passkey
17+
7) Disconnect
18+
8) Power cycle the Verisense device and unpair it
19+
20+
is an example of changing the sensor to default passkey from clinical passkey, note that the sensor has to be paired prior. Once the settings have been changed remember to power cycle and unpair --> pair the device.
21+
We are defaulting to the following for the advertising ID, and we would recommend customers do the same. In particular paying attention to the Passkey ID definitions below
22+
23+
Verisense-00-XXXXXXXXXXXX : No Passkey
24+
25+
Verisense-01-XXXXXXXXXXXX : Default Passkey (123456)
26+
27+
Verisense-XXXXXXXXXXXX : Clinical Passkey
28+
29+
Verisense-02-XXXXXXXXXXXX : Clinical Passkey (reserved for future if required)
30+
31+
The Clinical Passkey can be retrieved by contacting Shimmer if required.
32+
33+
_Note: Scanning can take a moment, and there are currently no UI indicators that it is indeed scanning_
34+
35+
## Requirements
36+
Verisense FW Version >=1.2.99, using an incorrect version will lead to an error being displayed.
37+
If you require updating the firmware on your Verisense device, please contact Shimmer.
38+
66.5 KB
Binary file not shown.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.companyname.verisensepasskey" android:versionCode="1" android:versionName="1.0">
3+
<application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:label="@string/app_name" android:supportsRtl="true"></application>
4+
<uses-permission android:name="android.permission.INTERNET" />
5+
<uses-permission android:name="android.permission.INTERNET" />
6+
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
7+
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
8+
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
9+
</manifest>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Any raw assets you want to be deployed with your application can be placed in
2+
this directory (and child directories) and given a Build Action of "AndroidAsset".
3+
4+
These files will be deployed with your package and will be accessible using Android's
5+
AssetManager, like this:
6+
7+
public class ReadAsset : Activity
8+
{
9+
protected override void OnCreate (Bundle bundle)
10+
{
11+
base.OnCreate (bundle);
12+
13+
InputStream input = Assets.Open ("my_asset.txt");
14+
}
15+
}
16+
17+
Additionally, some Android functions will automatically load asset files:
18+
19+
Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using Android.App;
2+
using Android.Content.PM;
3+
using Android.OS;
4+
5+
namespace VerisensePasskey.Droid
6+
{
7+
[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
8+
public class MainActivity : MauiAppCompatActivity
9+
{
10+
}
11+
12+
13+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using Android.App;
2+
using Android.Runtime;
3+
4+
namespace VerisensePasskey.Droid
5+
{
6+
[Application]
7+
public class MainApplication : MauiApplication
8+
{
9+
public MainApplication(IntPtr handle, JniHandleOwnership ownership)
10+
: base(handle, ownership)
11+
{
12+
}
13+
14+
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
15+
}
16+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace VerisensePasskey.Droid
2+
{
3+
public static class MauiProgram
4+
{
5+
public static MauiApp CreateMauiApp()
6+
{
7+
var builder = MauiApp.CreateBuilder();
8+
9+
builder
10+
.UseSharedMauiApp();
11+
12+
return builder.Build();
13+
}
14+
}
15+
}

0 commit comments

Comments
 (0)