HamBook – Blame information for rev 54
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
54 | office | 1 | using System; |
2 | using System.IO; |
||
3 | using System.Media; |
||
4 | using System.Reflection; |
||
3 | office | 5 | using System.Text; |
6 | using System.Threading; |
||
7 | using System.Threading.Tasks; |
||
54 | office | 8 | using Configuration; |
3 | office | 9 | using HamBook.Properties; |
54 | office | 10 | using HamBook.Radios; |
11 | using HamBook.Radios.Generic; |
||
9 | office | 12 | using RJCP.IO.Ports; |
54 | office | 13 | using Serilog; |
12 | office | 14 | using Toasts; |
3 | office | 15 | |
16 | namespace HamBook |
||
17 | { |
||
18 | public class BandScan |
||
19 | { |
||
54 | office | 20 | private readonly CatAssemblies _catAssemblies; |
21 | private readonly Configuration.Configuration _configuration; |
||
22 | private readonly int _maxFrequency; |
||
23 | private readonly int _minFrequency; |
||
24 | private readonly SerialPortStream _serialPort; |
||
25 | private int _currentFrequency; |
||
26 | private CancellationToken _scanningCancellationToken; |
||
3 | office | 27 | private CancellationTokenSource _scanningCancellationTokenSource; |
36 | office | 28 | private Thread _scanThread; |
3 | office | 29 | |
54 | office | 30 | private BandScan() |
3 | office | 31 | { |
32 | } |
||
33 | |||
54 | office | 34 | public BandScan(CatAssemblies catAssemblies, int min, int max, SerialPortStream serialPort, |
35 | Configuration.Configuration configuration) : this() |
||
3 | office | 36 | { |
37 | _catAssemblies = catAssemblies; |
||
38 | _minFrequency = min; |
||
39 | _maxFrequency = max; |
||
40 | _serialPort = serialPort; |
||
12 | office | 41 | _configuration = configuration; |
3 | office | 42 | } |
43 | |||
36 | office | 44 | public void Start(int stepFrequency, int pauseTime, int pauseDetectTime, bool autoTune = false) |
3 | office | 45 | { |
36 | office | 46 | if (_scanThread != null) |
21 | office | 47 | { |
54 | office | 48 | if (!_scanningCancellationToken.IsCancellationRequested) _scanningCancellationTokenSource.Cancel(); |
21 | office | 49 | |
36 | office | 50 | _scanThread.Join(); |
51 | _scanThread = null; |
||
21 | office | 52 | } |
53 | |||
3 | office | 54 | _scanningCancellationTokenSource = new CancellationTokenSource(); |
55 | _scanningCancellationToken = _scanningCancellationTokenSource.Token; |
||
5 | office | 56 | |
54 | office | 57 | _scanThread = new Thread(Scan); |
36 | office | 58 | _scanThread.Start(new BandScanParameters(stepFrequency, pauseTime, pauseDetectTime, autoTune)); |
3 | office | 59 | } |
60 | |||
39 | office | 61 | public void Stop() |
3 | office | 62 | { |
36 | office | 63 | if (_scanThread != null) |
3 | office | 64 | { |
54 | office | 65 | if (!_scanningCancellationToken.IsCancellationRequested) _scanningCancellationTokenSource.Cancel(); |
21 | office | 66 | |
36 | office | 67 | _scanThread.Join(); |
68 | _scanThread = null; |
||
3 | office | 69 | } |
21 | office | 70 | } |
71 | |||
36 | office | 72 | private async void Scan(object obj) |
21 | office | 73 | { |
36 | office | 74 | var bandScanParameters = (BandScanParameters)obj; |
21 | office | 75 | |
54 | office | 76 | if (!_serialPort.IsOpen) _serialPort.Open(); |
9 | office | 77 | |
78 | _serialPort.DiscardInBuffer(); |
||
79 | |||
3 | office | 80 | try |
81 | { |
||
5 | office | 82 | _currentFrequency = _minFrequency; |
3 | office | 83 | |
84 | do |
||
85 | { |
||
5 | office | 86 | var taskCompletionSource = new TaskCompletionSource<bool>(); |
3 | office | 87 | |
54 | office | 88 | using (var soundPlayer = new SoundPlayer(Assembly.GetExecutingAssembly() |
89 | .GetManifestResourceStream("HamBook.Effects.pot.wav"))) |
||
7 | office | 90 | { |
91 | soundPlayer.Play(); |
||
39 | office | 92 | |
54 | office | 93 | await _catAssemblies.CatWriteAsync<int>("FA", new object[] { _currentFrequency }, |
94 | _scanningCancellationToken); |
||
7 | office | 95 | } |
5 | office | 96 | |
36 | office | 97 | if (bandScanParameters.AutoTune) |
23 | office | 98 | { |
54 | office | 99 | await _catAssemblies.CatWriteAsync<TunerState>("AC", new object[] { TunerState.TUNER_ON }, |
100 | _scanningCancellationToken); |
||
23 | office | 101 | |
39 | office | 102 | do |
103 | { |
||
104 | await Task.Delay(TimeSpan.FromSeconds(1), _scanningCancellationToken); |
||
105 | |||
106 | try |
||
107 | { |
||
54 | office | 108 | var tuneState = await _catAssemblies.CatReadAsync<TunerState>("AC", new object[] { }, |
109 | _scanningCancellationToken); |
||
39 | office | 110 | |
54 | office | 111 | if (tuneState != TunerState.TUNER_ON) break; |
39 | office | 112 | } |
113 | catch (Exception) |
||
114 | { |
||
115 | // retry |
||
116 | } |
||
117 | } while (!_scanningCancellationToken.IsCancellationRequested); |
||
118 | |||
54 | office | 119 | await _catAssemblies.CatWriteAsync<TunerState>("AC", new object[] { TunerState.TUNING_START }, |
120 | _scanningCancellationToken); |
||
23 | office | 121 | |
36 | office | 122 | do |
123 | { |
||
124 | await Task.Delay(TimeSpan.FromSeconds(1), _scanningCancellationToken); |
||
21 | office | 125 | |
36 | office | 126 | try |
127 | { |
||
54 | office | 128 | var tuneState = await _catAssemblies.CatReadAsync<TunerState>("AC", new object[] { }, |
129 | _scanningCancellationToken); |
||
39 | office | 130 | |
54 | office | 131 | if (tuneState != TunerState.TUNING_START) break; |
36 | office | 132 | } |
133 | catch (Exception) |
||
134 | { |
||
135 | // retry |
||
136 | } |
||
137 | } while (!_scanningCancellationToken.IsCancellationRequested); |
||
21 | office | 138 | } |
139 | |||
36 | office | 140 | _catAssemblies.CatWrite<InformationState>("AI", new object[] { InformationState.ON }); |
21 | office | 141 | |
36 | office | 142 | try |
143 | { |
||
144 | using (var memoryStream = new MemoryStream()) |
||
145 | { |
||
21 | office | 146 | #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed |
36 | office | 147 | Task.Delay(TimeSpan.FromSeconds(bandScanParameters.PauseTime), _scanningCancellationToken) |
148 | .ContinueWith(_ => taskCompletionSource.TrySetResult(true), CancellationToken.None); |
||
21 | office | 149 | #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed |
150 | |||
36 | office | 151 | await taskCompletionSource.Task; |
21 | office | 152 | |
54 | office | 153 | await _serialPort.CopyToAsync(memoryStream, _serialPort.BytesToRead, |
154 | _scanningCancellationToken); |
||
23 | office | 155 | |
36 | office | 156 | memoryStream.Position = 0L; |
28 | office | 157 | |
36 | office | 158 | var result = Encoding.ASCII.GetString(memoryStream.ToArray()); |
28 | office | 159 | |
54 | office | 160 | Parallel.ForEach(result.Split(Radios.Yaesu.FT_891.Constants.Eot), |
161 | new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }, |
||
162 | async (split, state) => |
||
36 | office | 163 | { |
54 | office | 164 | if (string.IsNullOrEmpty(split)) state.Stop(); |
28 | office | 165 | |
54 | office | 166 | try |
28 | office | 167 | { |
54 | office | 168 | switch (_catAssemblies.CatParse<BusyState>("BY", |
169 | new object[] { $"{split}{Radios.Yaesu.FT_891.Constants.Eot}" })) |
||
170 | { |
||
171 | case BusyState.ON: |
||
172 | if (_configuration.Notifications.TryGetNotificationState( |
||
173 | NotificationType.SignalScanDetect, out var notificationState)) |
||
174 | state.Stop(); |
||
36 | office | 175 | |
54 | office | 176 | var toastFrom = new ToastForm( |
177 | $"{Resources.Signal_detected_during_scan}", |
||
178 | $"{Resources.Frequency}: {_currentFrequency}Hz", |
||
179 | notificationState.LingerTime, |
||
180 | Constants.AssemblyIcon); |
||
36 | office | 181 | |
54 | office | 182 | toastFrom.Show(); |
36 | office | 183 | |
54 | office | 184 | await Task.Delay( |
185 | TimeSpan.FromSeconds(bandScanParameters.PauseDetectTime), |
||
186 | _scanningCancellationToken); |
||
187 | state.Stop(); |
||
188 | break; |
||
189 | } |
||
28 | office | 190 | } |
54 | office | 191 | catch (TargetInvocationException exception) when |
192 | (exception.InnerException is UnmatchedRadioResponseException) |
||
193 | { |
||
194 | // suppress |
||
195 | } |
||
196 | catch (Exception exception) |
||
197 | { |
||
198 | Log.Warning(exception, Resources.Error_encountered_while_scanning_for_signal); |
||
199 | } |
||
200 | }); |
||
9 | office | 201 | } |
202 | } |
||
54 | office | 203 | catch (Exception exception) |
36 | office | 204 | { |
205 | Log.Warning(exception, Resources.Error_encountered_while_scanning_for_signal); |
||
206 | } |
||
207 | finally |
||
208 | { |
||
209 | _catAssemblies.CatWrite<InformationState>("AI", new object[] { InformationState.OFF }); |
||
210 | } |
||
9 | office | 211 | |
36 | office | 212 | _currentFrequency = _currentFrequency + bandScanParameters.StepFrequency; |
54 | office | 213 | if (_currentFrequency > _maxFrequency) _currentFrequency = _minFrequency; |
214 | if (_currentFrequency < _minFrequency) _currentFrequency = _minFrequency; |
||
36 | office | 215 | } while (!_scanningCancellationToken.IsCancellationRequested); |
3 | office | 216 | } |
36 | office | 217 | catch (Exception exception) |
3 | office | 218 | { |
219 | Log.Error(exception, Resources.Scanning_aborted); |
||
220 | } |
||
9 | office | 221 | finally |
222 | { |
||
223 | if (_serialPort.IsOpen) |
||
224 | { |
||
225 | _serialPort.Close(); |
||
226 | |||
227 | _serialPort.DiscardInBuffer(); |
||
228 | } |
||
229 | } |
||
3 | office | 230 | } |
231 | } |
||
54 | office | 232 | } |