Skip to content

Commit 05398c3

Browse files
committed
Сhanging the application architecture
2 parents 2f70c72 + 184d938 commit 05398c3

19 files changed

Lines changed: 559 additions & 382 deletions

File tree

GithubResources/Lighthouse.png

440 KB
Loading

GithubResources/instruction.png

151 KB
Loading

LighthouseV2PowerControl/LighthouseV2PowerControl.csproj renamed to LighthousePowerControl/LighthousePowerControl.csproj

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<OutputType>WinExe</OutputType>
54
<TargetFramework>netcoreapp3.1</TargetFramework>
6-
<UseWindowsForms>true</UseWindowsForms>
7-
<ApplicationIcon>newIcon.ico</ApplicationIcon>
8-
<Version>0.0.4</Version>
9-
<Authors>D0rG</Authors>
10-
<StartupObject>LighthouseV2PowerControl.Program</StartupObject>
11-
<AssemblyVersion>0.0.4.0</AssemblyVersion>
125
</PropertyGroup>
136

147
<ItemGroup>
@@ -23,11 +16,14 @@
2316

2417
<ItemGroup>
2518
<None Update="manifest.vrmanifest">
19+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
20+
</None>
21+
<None Update="openvr\manifest.vrmanifest">
2622
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
2723
</None>
2824
<None Update="openvr_api.dll">
29-
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
25+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
3026
</None>
3127
</ItemGroup>
3228

33-
</Project>
29+
</Project>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
public enum ManifestTask
2+
{
3+
add,
4+
rm
5+
}
6+
7+
public enum TaskResult
8+
{
9+
success,
10+
failure
11+
}
Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
using System;
2+
using System.IO;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
using System.Collections.Generic;
6+
using System.Text.RegularExpressions;
7+
using Windows.Storage.Streams;
8+
using Windows.Devices.Bluetooth;
9+
using Windows.Devices.Enumeration;
10+
using Windows.Devices.Bluetooth.GenericAttributeProfile;
11+
using Valve.VR;
12+
13+
namespace LighthousePowerControl
14+
{
15+
public sealed class LighthouseV2PowerControl
16+
{
17+
private readonly Regex _lighthuiuseRegex = new Regex("^LHB-.{8}");
18+
private readonly Guid _service = Guid.Parse("00001523-1212-efde-1523-785feabcd124");
19+
private readonly Guid _characteristic = Guid.Parse("00001525-1212-efde-1523-785feabcd124");
20+
private readonly byte _activateByte = 0x01;
21+
private readonly byte _deactivateByte = 0x00;
22+
private List<GattCharacteristic> _listGattCharacteristics = new List<GattCharacteristic>();
23+
private CVRSystem _OVRSystem;
24+
private Thread _onQuitThread;
25+
private CancellationTokenSource _cancellationToken = new CancellationTokenSource();
26+
public event Action onAppQuit; //Need 4 quit app with steamvr
27+
28+
#region SteamVR connection
29+
/// <summary>
30+
/// If SteamVR open connetc to steamvr 4 deactivate with VR.
31+
/// </summary>
32+
/// <returns></returns>
33+
public TaskResultAndMessage ConnectToSteamVR()
34+
{
35+
TaskResultAndMessage result;
36+
37+
try
38+
{
39+
EVRInitError error = EVRInitError.None;
40+
_OVRSystem = OpenVR.Init(ref error, EVRApplicationType.VRApplication_Background); //starts and shuts down with SteamVR.
41+
if (error == EVRInitError.Init_NoServerForBackgroundApp || error != EVRInitError.None)
42+
{
43+
result.message = "Init without SteamVR;";
44+
result.result = TaskResult.failure;
45+
}
46+
else
47+
{
48+
result.message = "Init with SteamVR;";
49+
result.result = TaskResult.success;
50+
_onQuitThread = new Thread(new ThreadStart(QuitThreadChecker));
51+
_onQuitThread.Start();
52+
}
53+
}
54+
catch (Exception e)
55+
{
56+
result.result = TaskResult.failure;
57+
result.message = e.Message;
58+
return result;
59+
}
60+
61+
return result;
62+
}
63+
64+
#region Threading
65+
/// <summary>
66+
/// A thread that does not allow the application to close until the base stations are disabled
67+
/// </summary>
68+
private void QuitThreadChecker()
69+
{
70+
while (true && !_cancellationToken.IsCancellationRequested)
71+
{
72+
Thread.Sleep(100);
73+
VREvent_t lastEvent = new VREvent_t();
74+
_OVRSystem.PollNextEvent(ref lastEvent,
75+
(uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(VREvent_t)));
76+
if ((EVREventType)lastEvent.eventType == EVREventType.VREvent_Quit)
77+
{
78+
_OVRSystem.AcknowledgeQuit_Exiting();
79+
SendOnAllLighthouseAsync(_deactivateByte).Wait();
80+
break;
81+
}
82+
}
83+
84+
while (!_cancellationToken.IsCancellationRequested)
85+
{
86+
_OVRSystem.AcknowledgeQuit_Exiting();
87+
Thread.Sleep(100);
88+
}
89+
OpenVR.Shutdown();
90+
onAppQuit?.Invoke();
91+
}
92+
93+
/// <summary>
94+
/// Call it with AppExit
95+
/// </summary>
96+
public void Cancel()
97+
{
98+
_cancellationToken.Cancel();
99+
}
100+
#endregion
101+
102+
#endregion
103+
104+
#region Bluetooth
105+
/// <summary>
106+
/// Call once at startup to get the gatt characteristics of all base stations. taskResults.Count == 0 if Success
107+
/// </summary>
108+
/// <returns></returns>
109+
public async Task<List<TaskResultAndMessage>> UpdateLighthouseListAsync()
110+
{
111+
DeviceInformationCollection GatDevices = await DeviceInformation.FindAllAsync(GattDeviceService.GetDeviceSelectorFromUuid(_service));
112+
List<TaskResultAndMessage> taskResults = new List<TaskResultAndMessage>(GatDevices.Count);
113+
114+
for (int id = 0; id < GatDevices.Count; ++id)
115+
{
116+
if (!_lighthuiuseRegex.IsMatch(GatDevices[id].Name)) continue;
117+
118+
BluetoothLEDevice bluetoothLeDevice = await BluetoothLEDevice.FromIdAsync(GatDevices[id].Id);
119+
GattDeviceServicesResult result = await bluetoothLeDevice.GetGattServicesAsync();
120+
121+
if (result.Status == GattCommunicationStatus.Success)
122+
{
123+
IReadOnlyList<GattDeviceService> serviceList = result.Services;
124+
for (int i = 0; i < serviceList.Count; ++i)
125+
{
126+
if (serviceList[i].Uuid != _service) continue;
127+
GattCharacteristicsResult gattRes;
128+
do
129+
{
130+
gattRes = await serviceList[i].GetCharacteristicsForUuidAsync(_characteristic);
131+
}
132+
while (gattRes.Status == GattCommunicationStatus.AccessDenied);
133+
134+
if (gattRes.Status == GattCommunicationStatus.Success)
135+
{
136+
var openStatus = await serviceList[i].OpenAsync(GattSharingMode.SharedReadAndWrite);
137+
IReadOnlyList<GattCharacteristic> characteristics = gattRes.Characteristics;
138+
for (int j = 0; j < characteristics.Count; ++j)
139+
{
140+
if (characteristics[j].Uuid != _characteristic) continue;
141+
_listGattCharacteristics.Add(characteristics[j]);
142+
}
143+
}
144+
else
145+
{
146+
taskResults.Add(new TaskResultAndMessage
147+
{
148+
result = TaskResult.failure,
149+
message = $"Characteristics {gattRes.Status};"
150+
});
151+
}
152+
}
153+
}
154+
else
155+
{
156+
taskResults.Add(new TaskResultAndMessage
157+
{
158+
result = TaskResult.failure,
159+
message = $"Sevices {result.Status};"
160+
});
161+
}
162+
}
163+
return taskResults;
164+
}
165+
166+
/// <summary>
167+
/// Called to write the value to the characteristic for all found base stations.
168+
/// </summary>
169+
/// <param name="activate"></param>
170+
/// <returns></returns>
171+
private async Task<List<TaskResultAndMessage>> SendOnAllLighthouseAsync(byte byte4send)
172+
{
173+
List<TaskResultAndMessage> taskResults = new List<TaskResultAndMessage>(_listGattCharacteristics.Count);
174+
175+
for (int i = 0; i < _listGattCharacteristics.Count; ++i)
176+
{
177+
TaskResultAndMessage taskResult;
178+
DataWriter writer = new DataWriter();
179+
writer.WriteByte(byte4send);
180+
GattCommunicationStatus resWrite = await _listGattCharacteristics[i].WriteValueAsync(writer.DetachBuffer());
181+
if (resWrite == GattCommunicationStatus.Success)
182+
{
183+
taskResult.result = TaskResult.success;
184+
taskResult.message = $"Lighthouse {i + 1}:" + ((byte4send == _activateByte) ? " has started;" : " stopped;");
185+
}
186+
else
187+
{
188+
taskResult.result = TaskResult.failure;
189+
taskResult.message = $"Lighthouse {i + 1}: {resWrite};";
190+
}
191+
taskResults.Add(taskResult);
192+
}
193+
if (byte4send == _deactivateByte) //Для выхода из треда и корректного отключения.
194+
{
195+
_cancellationToken.Cancel();
196+
}
197+
return taskResults;
198+
}
199+
200+
public async Task<List<TaskResultAndMessage>> ActivateAllLighthouseAsync()
201+
{
202+
return await SendOnAllLighthouseAsync(_activateByte);
203+
}
204+
205+
public async Task<List<TaskResultAndMessage>> DeactivateAllLighthouseAsync()
206+
{
207+
return await SendOnAllLighthouseAsync(_deactivateByte);
208+
}
209+
210+
public TaskResultAndMessage AppManifest(ManifestTask task)
211+
{
212+
TaskResultAndMessage result;
213+
result.result = TaskResult.failure;
214+
EVRInitError evrInitError = EVRInitError.None;
215+
OpenVR.Init(ref evrInitError, EVRApplicationType.VRApplication_Utility);
216+
if (evrInitError != EVRInitError.None)
217+
{
218+
result.message = evrInitError.ToString();
219+
return result;
220+
}
221+
222+
EVRApplicationError applicationError;
223+
string manifestPath = Path.Combine(Directory.GetCurrentDirectory(), "manifest.vrmanifest");
224+
if (task == ManifestTask.add)
225+
{
226+
applicationError = OpenVR.Applications.AddApplicationManifest(manifestPath, false);
227+
}
228+
else
229+
{
230+
applicationError = OpenVR.Applications.RemoveApplicationManifest(manifestPath);
231+
}
232+
233+
if (applicationError != EVRApplicationError.None)
234+
{
235+
result.message = applicationError.ToString();
236+
return result;
237+
}
238+
239+
result.result = TaskResult.success;
240+
result.message = $"Application manifest {((task == ManifestTask.add) ? "registered;" : "removed;")}";
241+
return result;
242+
}
243+
#endregion
244+
}
245+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public struct TaskResultAndMessage
2+
{
3+
public TaskResult result;
4+
public string message;
5+
}

LighthouseV2PowerControl/manifest.vrmanifest renamed to LighthousePowerControl/manifest.vrmanifest

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
2-
"source": "LighthouseV2PowerControl",
2+
"source": "WinAppLighthousePowerControl",
33
"applications": [{
4-
"app_key": "LighthouseV2PowerControl",
4+
"app_key": "WinAppLighthousePowerControl",
55
"launch_type": "binary",
6-
"binary_path_windows": "\\LighthouseV2PowerControl.exe",
6+
"binary_path_windows": "\\WinAppLighthousePowerControl.exe",
77
"is_dashboard_overlay": true,
88

99
"strings": {

LighthouseV2PowerControl.sln

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
3-
# Visual Studio Version 16
4-
VisualStudioVersion = 16.0.31019.35
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.1.32421.90
55
MinimumVisualStudioVersion = 10.0.40219.1
6-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LighthouseV2PowerControl", "LighthouseV2PowerControl\LighthouseV2PowerControl.csproj", "{2CEE8BD4-AF72-4FEF-AE85-25FEC4A0A516}"
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinAppLighthousePowerControl", "WinAppLighthousePowerControl\WinAppLighthousePowerControl.csproj", "{2CEE8BD4-AF72-4FEF-AE85-25FEC4A0A516}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LighthousePowerControl", "LighthousePowerControl\LighthousePowerControl.csproj", "{52512E79-30CD-4357-8DDA-DA066C112C0B}"
79
EndProject
810
Global
911
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -15,6 +17,10 @@ Global
1517
{2CEE8BD4-AF72-4FEF-AE85-25FEC4A0A516}.Debug|Any CPU.Build.0 = Debug|Any CPU
1618
{2CEE8BD4-AF72-4FEF-AE85-25FEC4A0A516}.Release|Any CPU.ActiveCfg = Release|Any CPU
1719
{2CEE8BD4-AF72-4FEF-AE85-25FEC4A0A516}.Release|Any CPU.Build.0 = Release|Any CPU
20+
{52512E79-30CD-4357-8DDA-DA066C112C0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21+
{52512E79-30CD-4357-8DDA-DA066C112C0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
22+
{52512E79-30CD-4357-8DDA-DA066C112C0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
23+
{52512E79-30CD-4357-8DDA-DA066C112C0B}.Release|Any CPU.Build.0 = Release|Any CPU
1824
EndGlobalSection
1925
GlobalSection(SolutionProperties) = preSolution
2026
HideSolutionNode = FALSE

0 commit comments

Comments
 (0)