-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathProgram.cs
More file actions
175 lines (147 loc) · 6.43 KB
/
Program.cs
File metadata and controls
175 lines (147 loc) · 6.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
using System.ComponentModel.DataAnnotations;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Crosswind;
using CommandLine;
/// This is the main part of Crosswind. All it really does:
/// - Load up the telemetry service selected by the user. Such as FSUIPC.
/// - Load up the EFB receiver service selected by the user. Such as Simlink
/// - Every second (or other interval selected by user)
/// - Read the telemetry from the telemetry interface.
/// - Send the telemetry to the EFB
///
/// The design is a bit over-engineering. It was just an exercise to learn some
/// of the paradigms that are common with C#.
///
/// TODO: Requires cleanup and documentation.
sealed class Options
{
public enum ServiceType { FSUIPC }
public enum ReceiverType { Simlink }
[Option('v', "versose",
HelpText = "Make output more verbose")]
public bool Verbose { get; set; }
[Option('s', "interval",
Required = true,
HelpText = "Refresh interval in seconds.")]
public int interval { get; set; }
[Option('i', "interface",
Required = true,
MetaValue = "<SERVICE>",
HelpText = "Flight Simulator Interface. Supported: FSUIPC."
)]
public ServiceType Service { get; set; }
[Option('t', "target",
Required = true,
MetaValue = "<RECEIVER>",
HelpText = "Electronic Flight Bag Target. Supported: Simlink."
)]
public ReceiverType Receiver { get; set; }}
class Program
{
private static ILogger<Program> logger;
static async Task<int> Main(string[] args)
{
Console.WriteLine("Welcome To Crosswind!");
Console.WriteLine("Licensed under the MIT License. See LICENSE file for details.");
var result = ParseArgs(args);
if (result.Errors.Any())
{
return 1;
}
var services = PrepareServices(result);
var provider = services.BuildServiceProvider();
ITelemetryService<FSUIPCTelemetry> telemetryService = GetTelemetryService(provider, result);
var telemetryReceiver = GetTelemetryReceiver(provider, result);
logger.LogInformation($"Connecting to telemetry service {telemetryService.GetType()}...");
if (telemetryService.Connect() == false)
{
logger.LogError($"Failed to connect to telemetry service {telemetryService.GetType()}!");
return 1;
}
logger.LogInformation($"Starting to receiver service {telemetryReceiver.GetType()}...");
if (telemetryReceiver.Start() == false)
{
logger.LogError($"Failed to connect to receiver service {telemetryReceiver.GetType()}!");
return 1;
}
using var cts = new CancellationTokenSource();
Console.CancelKeyPress += (_, e) =>
{
e.Cancel = true;
logger.LogInformation("Cancellation Requested.");
cts.Cancel();
};
while (cts.IsCancellationRequested == false)
{
logger.LogTrace($"Querying telemetry service...");
if (telemetryService.Refresh() == false)
{
logger.LogError($"Failed to refresh telemetry {telemetryService.GetType()}!");
return 1;
}
if (telemetryReceiver is IFSUIPCReceiver fsuipcReceiver)
{
logger.LogTrace($"Getting telemetry from FSUIPC...");
FSUIPCTelemetry telemetry = telemetryService.GetTelemetry();
logger.LogTrace($"Sending telemetry to {telemetryReceiver.GetType()}...");
if (fsuipcReceiver.Send(telemetry) == false)
{
logger.LogError($"Failed to send to receiver service {telemetryService.GetType()}!");
return 1;
}
}
await Task.Delay(result.Value.interval * 1000);
}
logger.LogInformation($"Disconnecting from telemetry service {telemetryService.GetType()}!");
if (telemetryService.Disconnect() == false)
{
logger.LogError($"Failed to disconnect from telemetry service {telemetryService.GetType()}!");
return 1;
}
logger.LogInformation($"Disconnecting from receiver service {telemetryReceiver.GetType()}...");
if (telemetryReceiver.Stop() == false)
{
logger.LogError($"Failed to stop receiver service {telemetryReceiver.GetType()}!");
return 1;
};
return 0;
}
private static ITelemetryReceiver GetTelemetryReceiver(ServiceProvider provider, ParserResult<Options> result)
{
logger.LogInformation("Retrieving receiver services...");
ITelemetryReceiver telemetryReceiver =
provider.GetRequiredKeyedService<ITelemetryReceiver>(result.Value.Receiver);
return telemetryReceiver;
}
private static ITelemetryService<FSUIPCTelemetry> GetTelemetryService(ServiceProvider provider, ParserResult<Options> result)
{
logger.LogInformation("Retrieving FSUIPC telemetry services...");
return provider.GetRequiredKeyedService<ITelemetryService<FSUIPCTelemetry>>(result.Value.Service);
}
private static ServiceCollection PrepareServices(ParserResult<Options> result)
{
var services = new ServiceCollection();
services.AddLogging(b => b.AddSimpleConsole().SetMinimumLevel(result.Value.Verbose ? LogLevel.Trace : LogLevel.Information));
logger = services.BuildServiceProvider().GetRequiredService<ILogger<Program>>();
logger.LogInformation("Logger prepared...");
logger.LogInformation("Adding services...");
services.AddKeyedTransient<ITelemetryService<FSUIPCTelemetry>, FSUIPCService>(Options.ServiceType.FSUIPC);
services.AddKeyedTransient<ITelemetryReceiver, SimlinkReceiver>(Options.ReceiverType.Simlink);
logger.LogInformation("Services added successfully...");
return services;
}
private static ParserResult<Options> ParseArgs(string[] args)
{
var parser = new Parser(cfg =>
{
cfg.HelpWriter = Console.Out;
cfg.AutoHelp = true;
cfg.AutoVersion = true;
cfg.CaseInsensitiveEnumValues = true;
});
var result = parser.ParseArguments<Options>(args);
return result;
}
}