HamBook – Blame information for rev 11

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 using HamBook.Radios;
2 using HamBook.Utilities;
3 using HamBook.Utilities.Serialization;
4 using NetSparkleUpdater.Enums;
5 using NetSparkleUpdater.SignatureVerifiers;
6 using NetSparkleUpdater.UI.WinForms;
7 using NetSparkleUpdater;
8 using Serilog;
9 using System;
10 using System.ComponentModel;
11 using System.Drawing;
12 using System.IO;
13 using System.IO.Ports;
14 using System.Reflection;
15 using System.Threading;
16 using System.Threading.Tasks;
17 using System.Windows.Forms;
18 using HamBook.Properties;
19 using HamBook.Radios.Generic;
20 using PowerState = HamBook.Radios.Generic.PowerState;
5 office 21 using System.Media;
7 office 22 using HamBook.Utilities.Controls;
9 office 23 using RJCP.IO.Ports;
24 using System.Text;
1 office 25  
26 namespace HamBook
27 {
28 public partial class Form1 : Form
29 {
30 private ScheduledContinuation _changedConfigurationContinuation;
31 private Configuration.Configuration Configuration { get; set; }
9 office 32 private SerialPortStream _serialPort;
1 office 33 private LogMemorySink _memorySink;
34 private ViewLogsForm _viewLogsForm;
35 private AboutForm _aboutForm;
36 private SettingsForm _settingsForm;
37 private SparkleUpdater _sparkle;
38 private readonly CancellationToken _cancellationToken;
39 private readonly CancellationTokenSource _cancellationTokenSource;
40 private CatAssemblies _catAssemblies;
3 office 41 private BandScan _bandScan;
10 office 42 private SpectrogramForm _spectrogramForm;
1 office 43  
44 public bool MemorySinkEnabled { get; set; }
45  
46 private Form1()
47 {
48 _cancellationTokenSource = new CancellationTokenSource();
49 _cancellationToken = _cancellationTokenSource.Token;
50  
51 _changedConfigurationContinuation = new ScheduledContinuation();
3 office 52  
1 office 53 }
54  
55 public Form1(Mutex mutex) : this()
56 {
57 InitializeComponent();
58  
59 _memorySink = new LogMemorySink();
60  
61 Log.Logger = new LoggerConfiguration()
62 .MinimumLevel.Debug()
63 .WriteTo.Conditional(condition => MemorySinkEnabled, configureSink => configureSink.Sink(_memorySink))
64 .WriteTo.File(Path.Combine(Constants.UserApplicationDirectory, "Logs", $"{Constants.AssemblyName}.log"),
65 rollingInterval: RollingInterval.Day)
66 .CreateLogger();
67  
68 // Start application update.
69 var manifestModuleName = Assembly.GetEntryAssembly().ManifestModule.FullyQualifiedName;
70 var icon = Icon.ExtractAssociatedIcon(manifestModuleName);
71  
72 _sparkle = new SparkleUpdater("https://hambook.grimore.org/update/appcast.xml",
73 new Ed25519Checker(SecurityMode.Strict, "LonrgxVjSF0GnY4hzwlRJnLkaxnDn2ikdmOifILzLJY="))
74 {
75 UIFactory = new UIFactory(icon),
76 RelaunchAfterUpdate = true
77 };
78 _sparkle.StartLoop(true, true);
79 }
80  
81 private async void Form1_Load(object sender, EventArgs e)
82 {
83 Configuration = await LoadConfiguration();
84  
7 office 85 _serialPort = InitializeSerialPort(Configuration);
1 office 86  
7 office 87 _catAssemblies = InitializeAssemblies(_serialPort);
1 office 88  
89 try
90 {
9 office 91 switch (await _catAssemblies.CatReadAsync<PowerState>("PS", new object[] { }, _cancellationToken))
1 office 92 {
93 case PowerState.ON:
7 office 94 Log.Information(Resources.Attempting_to_initialize_radio);
9 office 95 if(!await InitializeRadio())
7 office 96 {
97 return;
98 }
99  
100 Log.Information(Resources.Initializing_GUI);
1 office 101 break;
102 }
103 }
104 catch(Exception exception)
105 {
106 Log.Error(exception, Resources.Failed_to_read_power_state);
107 }
108 }
109  
9 office 110 private async void quitToolStripMenuItem_Click(object sender, EventArgs e)
1 office 111 {
9 office 112 if(_bandScan != null)
113 {
114 await _bandScan.Stop();
115 _bandScan = null;
116 }
117  
1 office 118 Close();
119 }
120  
121 private void viewLogsToolStripMenuItem_Click(object sender, EventArgs e)
122 {
123 if (_viewLogsForm != null)
124 {
125 return;
126 }
127  
128 _viewLogsForm = new ViewLogsForm(this, _memorySink, _cancellationToken);
129 _viewLogsForm.Closing += ViewLogsForm_Closing;
130 _viewLogsForm.Show();
131 }
132  
133 private void ViewLogsForm_Closing(object sender, CancelEventArgs e)
134 {
135 if (_viewLogsForm == null)
136 {
137 return;
138 }
139  
140 _viewLogsForm.Closing -= ViewLogsForm_Closing;
141 _viewLogsForm.Close();
142 _viewLogsForm = null;
143 }
144  
145 private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
146 {
147 if (_aboutForm != null)
148 {
149 return;
150 }
151  
152 _aboutForm = new AboutForm(_cancellationToken);
153 _aboutForm.Closing += AboutForm_Closing;
154 _aboutForm.Show();
155 }
156  
157 private void AboutForm_Closing(object sender, CancelEventArgs e)
158 {
159 if (_aboutForm == null)
160 {
161 return;
162 }
163  
164 _aboutForm.Dispose();
165 _aboutForm = null;
166 }
167  
168 private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
169 {
170 if (_settingsForm != null)
171 {
172 return;
173 }
174  
175 _settingsForm = new SettingsForm(Configuration, _cancellationToken);
176 _settingsForm.Closing += SettingsForm_Closing;
177 _settingsForm.Show();
178 }
179  
180 private void SettingsForm_Closing(object sender, CancelEventArgs e)
181 {
182 if (_settingsForm == null)
183 {
184 return;
185 }
186  
187 if(_settingsForm.SaveOnClose)
188 {
189 // Commit the configuration.
190 _changedConfigurationContinuation.Schedule(TimeSpan.FromSeconds(1),
191 async () => {
192 await SaveConfiguration();
193  
11 office 194 if(_bandScan != null)
195 {
196 await _bandScan.Stop();
197 _bandScan = null;
198 }
199  
200  
1 office 201 Miscellaneous.LaunchOnBootSet(Configuration.LaunchOnBoot);
202  
7 office 203 _serialPort = InitializeSerialPort(Configuration);
1 office 204  
7 office 205 _catAssemblies = InitializeAssemblies(_serialPort);
206  
207 try
208 {
9 office 209 switch (await _catAssemblies.CatReadAsync<PowerState>("PS", new object[] { }, _cancellationToken))
7 office 210 {
211 case PowerState.ON:
212 Log.Information(Resources.Attempting_to_initialize_radio);
9 office 213 if (!await InitializeRadio())
7 office 214 {
215 return;
216 }
217 Log.Information(Resources.Initializing_GUI);
218 break;
219 }
220 }
221 catch (Exception exception)
222 {
223 Log.Error(exception, Resources.Failed_to_read_power_state);
224 }
225  
1 office 226 }, _cancellationToken);
227 }
228  
229 _settingsForm.Dispose();
230 _settingsForm = null;
231 }
232  
233 public async Task SaveConfiguration()
234 {
235 if (!Directory.Exists(Constants.UserApplicationDirectory))
236 {
237 Directory.CreateDirectory(Constants.UserApplicationDirectory);
238 }
239  
240 switch (await Serialization.Serialize(Configuration, Constants.ConfigurationFile, "Configuration",
241 "<!ATTLIST Configuration xmlns:xsi CDATA #IMPLIED xsi:noNamespaceSchemaLocation CDATA #IMPLIED>",
242 CancellationToken.None))
243 {
3 office 244 case SerializationSuccess<Configuration.Configuration> configuration:
1 office 245 Log.Information("Serialized configuration.");
246 break;
247 case SerializationFailure serializationFailure:
248 Log.Warning(serializationFailure.Exception.Message, "Failed to serialize configuration.");
249 break;
250 }
251 }
252  
253 public static async Task<Configuration.Configuration> LoadConfiguration()
254 {
255 if (!Directory.Exists(Constants.UserApplicationDirectory))
256 {
257 Directory.CreateDirectory(Constants.UserApplicationDirectory);
258 }
259  
260 var deserializationResult =
261 await Serialization.Deserialize<Configuration.Configuration>(Constants.ConfigurationFile,
262 Constants.ConfigurationNamespace, Constants.ConfigurationXsd, CancellationToken.None);
263  
264 switch (deserializationResult)
265 {
266 case SerializationSuccess<Configuration.Configuration> serializationSuccess:
267 return serializationSuccess.Result;
268 case SerializationFailure serializationFailure:
269 Log.Warning(serializationFailure.Exception, "Failed to load configuration.");
270 return new Configuration.Configuration();
271 default:
272 return new Configuration.Configuration();
273 }
274 }
275  
9 office 276 private async Task<bool> InitializeRadio()
1 office 277 {
278 try
279 {
9 office 280 await _catAssemblies.CatWriteAsync<InformationState>("AI", new object[] { InformationState.OFF }, _cancellationToken);
281  
11 office 282 return await _catAssemblies.CatReadAsync<bool>("ID", new object[] { }, _cancellationToken);
1 office 283 }
284 catch(Exception exception)
285 {
7 office 286 Log.Error(exception, Resources.Unable_to_initialize_radio);
11 office 287  
7 office 288 return false;
1 office 289 }
7 office 290 }
291  
9 office 292 private CatAssemblies InitializeAssemblies(SerialPortStream serialPort)
7 office 293 {
294 if(_catAssemblies != null)
1 office 295 {
7 office 296 _catAssemblies.Dispose();
297 _catAssemblies = null;
1 office 298 }
299  
7 office 300 return new CatAssemblies(serialPort, Configuration.Radio);
301 }
302  
9 office 303 private SerialPortStream InitializeSerialPort(Configuration.Configuration configuration)
7 office 304 {
305 if (_serialPort != null)
1 office 306 {
7 office 307 if (_serialPort.IsOpen)
308 {
309 _serialPort.Close();
310 }
311 _serialPort.Dispose();
312 _serialPort = null;
1 office 313 }
314  
7 office 315 // Set up serial connection.
9 office 316 var serialPort = new SerialPortStream(configuration.Port, configuration.Speed, configuration.DataBits, configuration.Parity, configuration.StopBits);
7 office 317 serialPort.ReadTimeout = configuration.SerialPortTimeout.Read;
318 serialPort.WriteTimeout = configuration.SerialPortTimeout.Write;
319 serialPort.Handshake = configuration.Handshake;
9 office 320 serialPort.Encoding = Encoding.ASCII;
1 office 321  
7 office 322 Log.Information($"{Resources.Initialized_serial_port} {configuration.Port} {configuration.Speed} {configuration.Parity} {configuration.DataBits} {configuration.StopBits}");
323  
324 return serialPort;
1 office 325 }
326  
327 private async void updateToolStripMenuItem_Click(object sender, EventArgs e)
328 {
329 // Manually check for updates, this will not show a ui
330 var result = await _sparkle.CheckForUpdatesQuietly();
331 if (result.Status == NetSparkleUpdater.Enums.UpdateStatus.UpdateAvailable)
332 {
333 // if update(s) are found, then we have to trigger the UI to show it gracefully
334 _sparkle.ShowUpdateNeededUI();
335 return;
336 }
337  
338 MessageBox.Show(Resources.No_updates_available_at_this_time, Resources.HamBook, MessageBoxButtons.OK,
339 MessageBoxIcon.Asterisk,
340 MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly, false);
341 }
342  
9 office 343 private async void toolStripComboBox1_SelectedIndexChanged(object sender, EventArgs e)
1 office 344 {
345 var toolStripComboBox = (ToolStripComboBox)sender;
3 office 346 if(RadioMode.TryParse(toolStripComboBox.Text, out var radioMode))
1 office 347 {
3 office 348 try
1 office 349 {
9 office 350 await _catAssemblies.CatSetAsync<RadioMode>("MD", new object[] { radioMode }, _cancellationToken);
1 office 351 }
3 office 352 catch (Exception exception)
353 {
354 Log.Error(exception, Resources.Failed_to_set_radio_mode, radioMode);
355 }
1 office 356 }
357 }
358  
359 private async void onToolStripMenuItem_Click(object sender, EventArgs e)
360 {
361 try
362 {
9 office 363 await _catAssemblies.CatSetAsync<PowerState>("PS", new object[] { PowerState.ON }, _cancellationToken);
1 office 364 }
365 catch(Exception exception)
366 {
367 Log.Error(exception, Resources.Failed_to_set_power_state);
368 }
369 }
370  
371 private async void offToolStripMenuItem_Click(object sender, EventArgs e)
372 {
373 try
374 {
9 office 375 await _catAssemblies.CatSetAsync<PowerState>("PS", new object[] { PowerState.OFF }, _cancellationToken);
1 office 376 }
377 catch(Exception exception)
378 {
379 Log.Error(exception, Resources.Failed_to_set_power_state);
380 }
381 }
382  
9 office 383 private async void toolStripComboBox2_MouseWheel(object sender, MouseEventArgs e)
1 office 384 {
5 office 385 using (var soundPlayer = new SoundPlayer(Assembly.GetExecutingAssembly().GetManifestResourceStream("HamBook.Effects.pot.wav")))
1 office 386 {
7 office 387 var toolStripComboBox = (ScrollableToolStripComboBox)sender;
5 office 388 if (int.TryParse(toolStripComboBox.Text, out var frequency))
3 office 389 {
5 office 390 switch (Math.Sign(e.Delta))
391 {
392 case -1:
393 frequency = frequency - 100;
394 break;
395 case 1:
396 frequency = frequency + 100;
397 break;
398 }
399  
400 soundPlayer.Play();
401  
402 try
403 {
9 office 404 await _catAssemblies.CatSetAsync<int>("FA", new object[] { frequency }, _cancellationToken);
5 office 405 toolStripComboBox.Text = $"{frequency}";
7 office 406  
407 Log.Information($"{Resources.Set_VFO_A_frequency} {frequency}Hz");
5 office 408 }
409 catch (Exception exception)
410 {
411 Log.Error(exception, Resources.Failed_to_set_VFO_A_frequency);
412 }
3 office 413 }
1 office 414 }
415 }
416  
9 office 417 private async void scrollableToolStripComboBox1_MouseWheel(object sender, MouseEventArgs e)
1 office 418 {
5 office 419 using (var soundPlayer = new SoundPlayer(Assembly.GetExecutingAssembly().GetManifestResourceStream("HamBook.Effects.pot.wav")))
1 office 420 {
7 office 421 var toolStripComboBox = (ScrollableToolStripComboBox)sender;
5 office 422 if (int.TryParse(toolStripComboBox.Text, out var frequency))
3 office 423 {
5 office 424 switch (Math.Sign(e.Delta))
425 {
426 case -1:
427 frequency = frequency - 100;
428 break;
429 case 1:
430 frequency = frequency + 100;
431 break;
432 }
3 office 433  
6 office 434 soundPlayer.Play();
435  
5 office 436 try
437 {
9 office 438 await _catAssemblies.CatSetAsync<int>("FB", new object[] { frequency }, _cancellationToken);
5 office 439 toolStripComboBox.Text = $"{frequency}";
7 office 440  
441 Log.Information($"{Resources.Set_VFO_B_frequency} {frequency}Hz");
5 office 442 }
443 catch (Exception exception)
444 {
445 Log.Error(exception, Resources.Failed_to_set_VFO_B_frequency);
446 }
1 office 447 }
448 }
449 }
450  
9 office 451 private async void scrollableToolStripComboBox1_TextChanged(object sender, EventArgs e)
1 office 452 {
3 office 453 var toolStripComboBox = (ToolStripComboBox)sender;
454 if (int.TryParse(toolStripComboBox.Text, out var frequency))
1 office 455 {
3 office 456 try
457 {
9 office 458 await _catAssemblies.CatSetAsync<int>("FA", new object[] { frequency }, _cancellationToken);
3 office 459 }
460 catch (Exception exception)
461 {
462 Log.Error(exception, Resources.Failed_to_set_VFO_A_frequency);
463 }
1 office 464 }
465 }
466  
9 office 467 private async void scrollableToolStripComboBox2_TextChanged(object sender, EventArgs e)
1 office 468 {
3 office 469 var toolStripComboBox = (ToolStripComboBox)sender;
470 if (int.TryParse(toolStripComboBox.Text, out var frequency))
1 office 471 {
472 try
473 {
9 office 474 await _catAssemblies.CatSetAsync<int>("FB", new object[] { frequency }, _cancellationToken);
1 office 475 }
476 catch (Exception exception)
477 {
478 Log.Error(exception, Resources.Failed_to_set_VFO_B_frequency);
479 }
3 office 480 }
481 }
482  
9 office 483 private async void toolStripMenuItem1_Click(object sender, EventArgs e)
3 office 484 {
485 if (_bandScan == null)
486 {
1 office 487 return;
488 }
489  
9 office 490 await _bandScan.Stop();
3 office 491 _bandScan = null;
1 office 492 }
3 office 493  
9 office 494 private async void scanToolStripMenuItem_Click(object sender, EventArgs e)
3 office 495 {
5 office 496 if (!(sender is ToolStripMenuItem toolStripMenuItem) ||
497 !int.TryParse(toolStripMenuItem.Tag.ToString(), out var meters))
3 office 498 {
5 office 499 return;
3 office 500 }
501  
5 office 502 if (!int.TryParse(scrollableToolStripComboBox3.Text, out var pause))
3 office 503 {
5 office 504 pause = 5;
3 office 505 }
506  
5 office 507 if(!int.TryParse(scrollableToolStripComboBox4.Text, out var step))
3 office 508 {
5 office 509 step = 5000;
3 office 510 }
511  
5 office 512 if (!Configuration.Definitions.TryGetBand(meters, out var band))
3 office 513 {
5 office 514 return;
3 office 515 }
516  
517 if (_bandScan != null)
518 {
9 office 519 await _bandScan.Stop();
520 _bandScan = null;
3 office 521 }
522  
5 office 523 _bandScan = new BandScan(_catAssemblies, band.Min, band.Max, _serialPort);
9 office 524  
5 office 525 #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
9 office 526 _bandScan.Start(step, pause, Configuration.ScanDetectPause);
5 office 527 #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
3 office 528 }
529  
11 office 530 private void modeToolStripMenuItem_DropDownOpened(object sender, EventArgs e)
3 office 531 {
11 office 532 Task.Delay(TimeSpan.FromSeconds(1), _cancellationToken).ContinueWith(async task =>
7 office 533 {
11 office 534 try
535 {
536 var mode = await _catAssemblies.CatReadAsync<RadioMode>("MD", new object[] { }, _cancellationToken);
7 office 537  
11 office 538 contextMenuStrip1.InvokeIfRequired(contextMenuStrip =>
539 {
540 toolStripComboBox1.Text = mode;
541 });
542 }
543 catch (Exception exception)
544 {
545 Log.Error(exception, Resources.Failed_to_read_radio_mode);
546 }
7 office 547  
11 office 548 try
549 {
550 var fa = await _catAssemblies.CatReadAsync<int>("FA", new object[] { }, _cancellationToken);
7 office 551  
11 office 552 contextMenuStrip1.InvokeIfRequired(contextMenuStrip =>
553 {
554 scrollableToolStripComboBox1.Text = $"{fa}";
555  
556 });
557  
558 }
559 catch (Exception exception)
560 {
561 Log.Error(exception, Resources.Failed_to_read_VFO_A);
562 }
563  
564 try
565 {
566 var fb = await _catAssemblies.CatReadAsync<int>("FB", new object[] { }, _cancellationToken);
567  
568 contextMenuStrip1.InvokeIfRequired(contextMenuStrip =>
569 {
570 scrollableToolStripComboBox2.Text = $"{fb}";
571  
572 });
573 }
574 catch (Exception exception)
575 {
576 Log.Error(exception, Resources.Failed_to_read_VFO_B);
577 }
578 }, _cancellationToken);
3 office 579 }
10 office 580  
581 private void spectrogramToolStripMenuItem_Click(object sender, EventArgs e)
582 {
583 if (_spectrogramForm != null)
584 {
585 return;
586 }
587  
588 _spectrogramForm = new SpectrogramForm(Configuration, _cancellationToken);
589 _spectrogramForm.Closing += SpectrogramForm_Closing;
590 _spectrogramForm.Show();
591 }
592  
593 private void SpectrogramForm_Closing(object sender, CancelEventArgs e)
594 {
595 if (_spectrogramForm == null)
596 {
597 return;
598 }
599  
600 _spectrogramForm.Dispose();
601 _spectrogramForm = null;
602 }
1 office 603 }
604 }