HamBook – Blame information for rev 14

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