HamBook – Blame information for rev 58
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
54 | office | 1 | using System; |
1 | office | 2 | using System.Collections.Concurrent; |
3 | using System.Collections.Generic; |
||
4 | using System.Linq; |
||
5 | using System.Reflection; |
||
6 | using System.Runtime.CompilerServices; |
||
7 | using System.Threading; |
||
8 | using System.Threading.Tasks; |
||
54 | office | 9 | using HamBook.Properties; |
10 | using RJCP.IO.Ports; |
||
11 | using Serilog; |
||
1 | office | 12 | |
13 | namespace HamBook.Radios |
||
14 | { |
||
15 | public class CatAssemblies : IDisposable |
||
16 | { |
||
54 | office | 17 | private readonly ConcurrentDictionary<string, Cat> _catCommands; |
18 | private readonly string _radio; |
||
19 | private readonly SemaphoreSlim _semaphoreSlim; |
||
20 | private readonly SerialPortStream _serialPort; |
||
1 | office | 21 | |
22 | private int _count; |
||
23 | |||
24 | private CatAssemblies() |
||
25 | { |
||
26 | _catCommands = new ConcurrentDictionary<string, Cat>(); |
||
26 | office | 27 | _semaphoreSlim = new SemaphoreSlim(1, 1); |
1 | office | 28 | } |
29 | |||
9 | office | 30 | public CatAssemblies(SerialPortStream serialPort, string radio) : this() |
1 | office | 31 | { |
32 | _serialPort = serialPort; |
||
33 | _radio = radio; |
||
34 | |||
35 | Load(_radio); |
||
36 | } |
||
54 | office | 37 | |
38 | public int Count => _count; |
||
39 | |||
1 | office | 40 | public void Dispose() |
41 | { |
||
42 | Unload(); |
||
43 | } |
||
44 | |||
45 | private void Load(string radio) |
||
46 | { |
||
47 | Interlocked.Exchange(ref _count, 0); |
||
48 | |||
49 | foreach (var type in Assembly.GetExecutingAssembly() |
||
54 | office | 50 | .GetTypes() |
51 | .Where(type => type.IsSubclassOf(typeof(Cat))) |
||
52 | .Where(type => |
||
53 | type.GetCustomAttribute<RadioAttribute>() != null && |
||
54 | type.GetCustomAttribute<RadioAttribute>().Radio == radio)) |
||
1 | office | 55 | try |
56 | { |
||
57 | var catCommand = (Cat)type |
||
58 | office | 58 | .GetConstructor(new[] { typeof(SerialPortStream) })?.Invoke(new object[] { _serialPort }); |
1 | office | 59 | |
54 | office | 60 | if (catCommand == null) throw new ArgumentException(Resources.Could_not_create_assembly); |
1 | office | 61 | |
62 | if (!_catCommands.TryAdd(catCommand.Name, catCommand)) |
||
63 | { |
||
64 | Log.Warning(Resources.Unable_to_register_assembly, catCommand.Name); |
||
65 | |||
66 | catCommand.Dispose(); |
||
67 | |||
68 | continue; |
||
69 | } |
||
70 | |||
71 | //BindEventHandlers(command); |
||
72 | Interlocked.Increment(ref _count); |
||
73 | } |
||
74 | catch (Exception exception) |
||
75 | { |
||
76 | Log.Error(exception, Resources.Could_not_instantiate_assembly, type); |
||
77 | } |
||
78 | |||
79 | Log.Information(Resources.Registering_commands, Count); |
||
80 | } |
||
81 | |||
82 | private void Unload() |
||
83 | { |
||
84 | // Dispose all command assemblies. |
||
85 | var list = new List<Cat>(_catCommands.Values); |
||
86 | |||
87 | for (var i = 0; i < list.Count; ++i) |
||
88 | try |
||
89 | { |
||
90 | //UnbindEventHandlers(list[i]); |
||
91 | if (list[i] != null) |
||
92 | { |
||
93 | Log.Debug(Resources.Disposing_assembly, list[i].GetType().Name); |
||
94 | |||
95 | list[i] |
||
96 | .Dispose(); |
||
97 | |||
98 | list[i] = null; |
||
99 | } |
||
100 | } |
||
101 | catch (NullReferenceException) |
||
102 | { |
||
103 | // Already removed. |
||
104 | } |
||
105 | catch (ObjectDisposedException) |
||
106 | { |
||
107 | list[i] = null; |
||
108 | } |
||
109 | catch (Exception exception) |
||
110 | { |
||
111 | Log.Error(exception, Resources.Error_encountered_while_disposing_object); |
||
112 | } |
||
113 | |||
114 | _catCommands.Clear(); |
||
115 | } |
||
116 | |||
58 | office | 117 | public bool CatParse<T>(string command, object[] param, out T output) |
1 | office | 118 | { |
58 | office | 119 | if (!_catCommands.TryGetValue(command, out var catCommand)) |
120 | throw new CatCommandException(Resources.CAT_command_not_found, command); |
||
121 | |||
122 | var methodInfo = catCommand.GetType().GetMethod("Parse"); |
||
123 | if (methodInfo == null) |
||
3 | office | 124 | { |
26 | office | 125 | throw new CatCommandException(Resources.CAT_command_method_not_found, command, "Parse"); |
58 | office | 126 | |
3 | office | 127 | } |
128 | |||
58 | office | 129 | output = default; |
130 | try |
||
131 | { |
||
132 | output = (T)methodInfo.Invoke(catCommand, param); |
||
133 | } |
||
134 | catch |
||
135 | { |
||
136 | return false; |
||
137 | } |
||
138 | |||
139 | return true; |
||
26 | office | 140 | } |
141 | |||
142 | public T CatGetDefault<T>(string command, object[] param) |
||
143 | { |
||
144 | _semaphoreSlim.Wait(); |
||
145 | |||
1 | office | 146 | try |
147 | { |
||
54 | office | 148 | if (!_serialPort.IsOpen) _serialPort.Open(); |
26 | office | 149 | |
58 | office | 150 | if (_catCommands.TryGetValue(command, out var catCommand)) |
26 | office | 151 | { |
58 | office | 152 | var methodInfo = catCommand.GetType().GetMethod("GetDefault"); |
153 | |||
154 | if (methodInfo != null) |
||
1 | office | 155 | { |
58 | office | 156 | return (T)methodInfo.Invoke(catCommand, param); |
1 | office | 157 | } |
158 | } |
||
159 | } |
||
160 | finally |
||
161 | { |
||
58 | office | 162 | if (_serialPort.IsOpen) |
163 | { |
||
164 | _serialPort.Flush(); |
||
165 | _serialPort.Close(); |
||
166 | } |
||
167 | |||
26 | office | 168 | _semaphoreSlim.Release(); |
1 | office | 169 | } |
9 | office | 170 | |
171 | return default; |
||
1 | office | 172 | } |
173 | |||
58 | office | 174 | public void CatSet(string command, object[] param) |
9 | office | 175 | { |
26 | office | 176 | _semaphoreSlim.Wait(); |
177 | try |
||
9 | office | 178 | { |
54 | office | 179 | if (!_serialPort.IsOpen) _serialPort.Open(); |
11 | office | 180 | |
58 | office | 181 | if (!_catCommands.TryGetValue(command, out var catCommand)) |
182 | throw new CatCommandException(Resources.CAT_command_not_found, command); |
||
9 | office | 183 | |
58 | office | 184 | var methodInfo = catCommand.GetType().GetMethod("Set") ?? |
185 | throw new CatCommandException(Resources.CAT_command_method_not_found, command, "Set"); |
||
9 | office | 186 | |
58 | office | 187 | methodInfo.Invoke(catCommand, param); |
1 | office | 188 | } |
189 | finally |
||
190 | { |
||
58 | office | 191 | if (_serialPort.IsOpen) |
192 | { |
||
193 | _serialPort.Flush(); |
||
194 | _serialPort.Close(); |
||
195 | } |
||
196 | |||
26 | office | 197 | _semaphoreSlim.Release(); |
1 | office | 198 | } |
199 | } |
||
200 | |||
54 | office | 201 | public async Task<TU> CatSetAsync<T, TU>(string command, object[] param, CancellationToken cancellationToken) |
3 | office | 202 | { |
26 | office | 203 | await _semaphoreSlim.WaitAsync(cancellationToken); |
3 | office | 204 | |
205 | try |
||
206 | { |
||
54 | office | 207 | if (!_serialPort.IsOpen) _serialPort.Open(); |
26 | office | 208 | |
58 | office | 209 | if (!_catCommands.TryGetValue(command, out var catCommand)) |
210 | throw new CatCommandException(Resources.CAT_command_not_found, command); |
||
9 | office | 211 | |
58 | office | 212 | var methodInfo = catCommand.GetType().GetMethod("SetAsync") ?? |
213 | throw new CatCommandException(Resources.CAT_command_method_not_found, command, "SetAsync"); |
||
11 | office | 214 | |
58 | office | 215 | if (methodInfo.GetCustomAttribute<AsyncStateMachineAttribute>() == null) |
216 | throw new CatCommandException(Resources.CAT_command_method_not_found, command, "SetAsync"); |
||
54 | office | 217 | |
58 | office | 218 | var parameters = new List<object>(); |
219 | parameters.AddRange(param); |
||
220 | parameters.Add(cancellationToken); |
||
26 | office | 221 | |
58 | office | 222 | var result = await (Task<TU>)methodInfo.Invoke(catCommand, parameters.ToArray()); |
223 | |||
224 | return result; |
||
3 | office | 225 | } |
226 | finally |
||
227 | { |
||
58 | office | 228 | if (_serialPort.IsOpen) |
229 | { |
||
230 | await _serialPort.FlushAsync(cancellationToken); |
||
231 | _serialPort.Close(); |
||
232 | } |
||
233 | |||
26 | office | 234 | _semaphoreSlim.Release(); |
3 | office | 235 | } |
9 | office | 236 | } |
3 | office | 237 | |
9 | office | 238 | public void CatWrite<T>(string command, object[] param) |
239 | { |
||
26 | office | 240 | _semaphoreSlim.Wait(); |
9 | office | 241 | |
242 | try |
||
243 | { |
||
54 | office | 244 | if (!_serialPort.IsOpen) _serialPort.Open(); |
26 | office | 245 | |
58 | office | 246 | if (!_catCommands.TryGetValue(command, out var catCommand)) |
247 | throw new CatCommandException(Resources.CAT_command_not_found, command); |
||
11 | office | 248 | |
58 | office | 249 | var methodInfo = catCommand.GetType().GetMethod("Write") ?? |
250 | throw new CatCommandException(Resources.CAT_command_method_not_found, command, "Write"); |
||
26 | office | 251 | |
58 | office | 252 | methodInfo.Invoke(catCommand, param); |
9 | office | 253 | } |
254 | finally |
||
255 | { |
||
58 | office | 256 | if (_serialPort.IsOpen) |
257 | { |
||
258 | _serialPort.Flush(); |
||
259 | _serialPort.Close(); |
||
260 | } |
||
261 | |||
26 | office | 262 | _semaphoreSlim.Release(); |
9 | office | 263 | } |
3 | office | 264 | } |
265 | |||
9 | office | 266 | public async Task CatWriteAsync<T>(string command, object[] param, CancellationToken cancellationToken) |
3 | office | 267 | { |
26 | office | 268 | await _semaphoreSlim.WaitAsync(cancellationToken); |
3 | office | 269 | |
270 | try |
||
271 | { |
||
54 | office | 272 | if (!_serialPort.IsOpen) _serialPort.Open(); |
26 | office | 273 | |
58 | office | 274 | if (!_catCommands.TryGetValue(command, out var catCommand)) |
275 | throw new CatCommandException(Resources.CAT_command_not_found, command); |
||
9 | office | 276 | |
58 | office | 277 | var methodInfo = catCommand.GetType().GetMethod("WriteAsync") ?? |
278 | throw new CatCommandException(Resources.CAT_command_method_not_found, command, "WriteAsync"); |
||
11 | office | 279 | |
58 | office | 280 | if (methodInfo.GetCustomAttribute<AsyncStateMachineAttribute>() == null) |
281 | throw new CatCommandException(Resources.CAT_command_method_not_found, command, "WriteAsync"); |
||
26 | office | 282 | |
58 | office | 283 | var parameters = new List<object>(); |
284 | parameters.AddRange(param); |
||
285 | parameters.Add(cancellationToken); |
||
11 | office | 286 | |
58 | office | 287 | await (Task)methodInfo.Invoke(catCommand, parameters.ToArray()); |
288 | } |
||
289 | finally |
||
290 | { |
||
291 | if (_serialPort.IsOpen) |
||
26 | office | 292 | { |
58 | office | 293 | await _serialPort.FlushAsync(cancellationToken); |
294 | _serialPort.Close(); |
||
26 | office | 295 | } |
58 | office | 296 | |
297 | _semaphoreSlim.Release(); |
||
3 | office | 298 | } |
58 | office | 299 | } |
300 | |||
301 | public async Task CatWriteAsyncManual<T>(string command, object[] param, CancellationToken cancellationToken) |
||
302 | { |
||
303 | await _semaphoreSlim.WaitAsync(cancellationToken); |
||
304 | |||
305 | try |
||
306 | { |
||
307 | if (!_serialPort.IsOpen) _serialPort.Open(); |
||
308 | |||
309 | if (!_catCommands.TryGetValue(command, out var catCommand)) |
||
310 | throw new CatCommandException(Resources.CAT_command_not_found, command); |
||
311 | |||
312 | var methodInfo = catCommand.GetType().GetMethod("WriteAsync") ?? |
||
313 | throw new CatCommandException(Resources.CAT_command_method_not_found, command, "WriteAsync"); |
||
314 | |||
315 | if (methodInfo.GetCustomAttribute<AsyncStateMachineAttribute>() == null) |
||
316 | throw new CatCommandException(Resources.CAT_command_method_not_found, command, "WriteAsync"); |
||
317 | |||
318 | var parameters = new List<object>(); |
||
319 | parameters.AddRange(param); |
||
320 | parameters.Add(cancellationToken); |
||
321 | |||
322 | await (Task)methodInfo.Invoke(catCommand, parameters.ToArray()); |
||
323 | } |
||
3 | office | 324 | finally |
325 | { |
||
58 | office | 326 | if (_serialPort.IsOpen) |
327 | { |
||
328 | await _serialPort.FlushAsync(cancellationToken); |
||
329 | } |
||
330 | |||
26 | office | 331 | _semaphoreSlim.Release(); |
3 | office | 332 | } |
333 | } |
||
334 | |||
38 | office | 335 | public async Task CatWriteAsync(string command, object[] param, CancellationToken cancellationToken) |
336 | { |
||
337 | await _semaphoreSlim.WaitAsync(cancellationToken); |
||
338 | |||
339 | try |
||
340 | { |
||
54 | office | 341 | if (!_serialPort.IsOpen) _serialPort.Open(); |
38 | office | 342 | |
58 | office | 343 | if (!_catCommands.TryGetValue(command, out var catCommand)) |
344 | throw new CatCommandException(Resources.CAT_command_not_found, command); |
||
38 | office | 345 | |
58 | office | 346 | var methodInfo = catCommand.GetType().GetMethod("WriteAsync") ?? |
347 | throw new CatCommandException(Resources.CAT_command_method_not_found, command, "WriteAsync"); |
||
38 | office | 348 | |
58 | office | 349 | if (methodInfo.GetCustomAttribute<AsyncStateMachineAttribute>() == null) |
350 | throw new CatCommandException(Resources.CAT_command_method_not_found, command, "WriteAsync"); |
||
38 | office | 351 | |
58 | office | 352 | var parameters = new List<object>(); |
353 | parameters.AddRange(param); |
||
354 | parameters.Add(cancellationToken); |
||
38 | office | 355 | |
58 | office | 356 | await (Task)methodInfo.Invoke(catCommand, parameters.ToArray()); |
38 | office | 357 | } |
358 | finally |
||
359 | { |
||
58 | office | 360 | if (_serialPort.IsOpen) |
361 | { |
||
362 | await _serialPort.FlushAsync(cancellationToken); |
||
363 | _serialPort.Close(); |
||
364 | } |
||
365 | |||
38 | office | 366 | _semaphoreSlim.Release(); |
367 | } |
||
368 | } |
||
369 | |||
1 | office | 370 | public T CatRead<T>(string command, object[] param) |
371 | { |
||
26 | office | 372 | _semaphoreSlim.Wait(); |
3 | office | 373 | |
1 | office | 374 | try |
375 | { |
||
54 | office | 376 | if (!_serialPort.IsOpen) _serialPort.Open(); |
26 | office | 377 | |
58 | office | 378 | if (!_catCommands.TryGetValue(command, out var catCommand)) |
379 | throw new CatCommandException(Resources.CAT_command_not_found, command); |
||
26 | office | 380 | |
58 | office | 381 | var methodInfo = catCommand.GetType().GetMethod("Read"); |
382 | if (methodInfo != null) return (T)methodInfo.Invoke(catCommand, param); |
||
11 | office | 383 | |
58 | office | 384 | throw new CatCommandException(Resources.CAT_command_method_not_found, command, "Read"); |
1 | office | 385 | } |
386 | finally |
||
387 | { |
||
58 | office | 388 | if (_serialPort.IsOpen) |
389 | { |
||
390 | _serialPort.Flush(); |
||
391 | _serialPort.Close(); |
||
392 | } |
||
393 | |||
26 | office | 394 | _semaphoreSlim.Release(); |
1 | office | 395 | } |
396 | } |
||
397 | |||
9 | office | 398 | public async Task<T> CatReadAsync<T>(string command, object[] param, CancellationToken cancellationToken) |
1 | office | 399 | { |
26 | office | 400 | await _semaphoreSlim.WaitAsync(cancellationToken); |
3 | office | 401 | |
1 | office | 402 | try |
403 | { |
||
54 | office | 404 | if (!_serialPort.IsOpen) _serialPort.Open(); |
26 | office | 405 | |
58 | office | 406 | if (_catCommands.TryGetValue(command, out var catCommand)) |
26 | office | 407 | { |
58 | office | 408 | var methodInfo = catCommand.GetType().GetMethod("ReadAsync") ?? |
409 | throw new CatCommandException(Resources.CAT_command_method_not_found, command, "ReadAsync"); |
||
9 | office | 410 | |
58 | office | 411 | if (methodInfo.GetCustomAttribute<AsyncStateMachineAttribute>() == null) |
412 | throw new CatCommandException(Resources.CAT_command_method_not_found, command, "ReadAsync"); |
||
27 | office | 413 | |
58 | office | 414 | var parameters = new List<object>(); |
415 | parameters.AddRange(param); |
||
416 | parameters.Add(cancellationToken); |
||
26 | office | 417 | |
58 | office | 418 | var result = await (Task<T>)methodInfo.Invoke(catCommand, parameters.ToArray()); |
11 | office | 419 | |
58 | office | 420 | return result; |
421 | |||
1 | office | 422 | } |
58 | office | 423 | |
424 | throw new CatCommandException(Resources.CAT_command_not_found, command); |
||
1 | office | 425 | } |
426 | finally |
||
427 | { |
||
58 | office | 428 | if (_serialPort.IsOpen) |
429 | { |
||
430 | await _serialPort.FlushAsync(cancellationToken); |
||
431 | _serialPort.Close(); |
||
432 | } |
||
433 | |||
26 | office | 434 | _semaphoreSlim.Release(); |
1 | office | 435 | } |
436 | } |
||
437 | } |
||
54 | office | 438 | } |