HamBook – Rev 21

Subversion Repositories:
Rev:
using HamBook.Radios.Generic;
using HamBook.Radios;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Serilog;
using HamBook.Properties;
using Serilog.Events;
using System.Media;
using System.Reflection;
using RJCP.IO.Ports;
using System.Diagnostics;
using System.IO;
using Toasts;
using System.Drawing;
using Configuration;
using System.Security.Cryptography;

namespace HamBook
{
    public class BandScan
    {
        private CancellationTokenSource _scanningCancellationTokenSource;
        private CancellationToken _scanningCancellationToken;

        private CatAssemblies _catAssemblies;
        private int _minFrequency;
        private int _maxFrequency;
        private SerialPortStream _serialPort;
        private Configuration.Configuration _configuration;
        private int _currentFrequency;
        private Task _scanTask;

        private BandScan() 
        {
        }

        public BandScan(CatAssemblies catAssemblies, int min, int max, SerialPortStream serialPort, Configuration.Configuration configuration) : this()
        {
            _catAssemblies = catAssemblies;
            _minFrequency = min;
            _maxFrequency = max;
            _serialPort = serialPort;
            _configuration = configuration;

        }

        public async void Start(int stepFrequency, int pauseTime)
        {
            if(_scanTask != null)
            {
                if (!_scanningCancellationToken.IsCancellationRequested)
                {
                    _scanningCancellationTokenSource.Cancel();
                }

                await _scanTask;
                _scanTask = null;
            }

            _scanningCancellationTokenSource = new CancellationTokenSource();
            _scanningCancellationToken = _scanningCancellationTokenSource.Token;

            _scanTask = Scan(stepFrequency, pauseTime);
        }

        public async void Start(int stepFrequency, int pauseTime, int pauseDetectTime)
        {
            if (_scanTask != null)
            {
                if (!_scanningCancellationToken.IsCancellationRequested)
                {
                    _scanningCancellationTokenSource.Cancel();
                }

                await _scanTask;
                _scanTask = null;
            }

            _scanningCancellationTokenSource = new CancellationTokenSource();
            _scanningCancellationToken = _scanningCancellationTokenSource.Token;

            _scanTask = Scan(stepFrequency, pauseTime, pauseDetectTime);
        }

        public async Task Stop()
        {
            if (_scanTask != null)
            {
                if (!_scanningCancellationToken.IsCancellationRequested)
                {
                    _scanningCancellationTokenSource.Cancel();
                }

                await _scanTask;
                _scanTask = null;
            }
        }

        private async Task Scan(int stepFrequency, int pauseTime)
        {
            if (!_serialPort.IsOpen)
            {
                _serialPort.Open();
            }

            _serialPort.DiscardInBuffer();

            _catAssemblies.CatWrite<InformationState>("AI", new object[] { InformationState.ON });

            try
            {

                _currentFrequency = _minFrequency;

                do
                {
                    var taskCompletionSource = new TaskCompletionSource<bool>();

#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                    Task.Delay(TimeSpan.FromSeconds(pauseTime), _scanningCancellationToken)
                        .ContinueWith(_ => taskCompletionSource.TrySetResult(true), CancellationToken.None);
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed

                    using (var soundPlayer = new SoundPlayer(Assembly.GetExecutingAssembly().GetManifestResourceStream("HamBook.Effects.pot.wav")))
                    {
                        soundPlayer.Play();
                        await _catAssemblies.CatWriteAsync<int>("FA", new object[] { _currentFrequency }, _scanningCancellationToken);
                    }

                    await taskCompletionSource.Task;

                    _currentFrequency = _currentFrequency + stepFrequency;
                    if (_currentFrequency > _maxFrequency)
                    {
                        _currentFrequency = _minFrequency;
                    }
                    if (_currentFrequency < _minFrequency)
                    {
                        _currentFrequency = _minFrequency;
                    }

                } while (!_scanningCancellationToken.IsCancellationRequested);
            }
            catch (Exception exception)
            {
                Log.Error(exception, Resources.Scanning_aborted);
            }
            finally
            {
                _catAssemblies.CatWrite<InformationState>("AI", new object[] { InformationState.OFF });

                if (_serialPort.IsOpen)
                {
                    _serialPort.Close();

                    _serialPort.DiscardInBuffer();
                }
            }
        }

        private async Task Scan(int stepFrequency, int pauseTime, int pauseDetectTime)
        {
            if (!_serialPort.IsOpen)
            {
                _serialPort.Open();
            }

            _serialPort.DiscardInBuffer();

            _catAssemblies.CatWrite<InformationState>("AI", new object[] { InformationState.ON });

            try
            {

                _currentFrequency = _minFrequency;

                do
                {
                    var taskCompletionSource = new TaskCompletionSource<bool>();

#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                    Task.Delay(TimeSpan.FromSeconds(pauseTime), _scanningCancellationToken)
                        .ContinueWith(_ => taskCompletionSource.TrySetResult(true), CancellationToken.None);
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed

                    using (var soundPlayer = new SoundPlayer(Assembly.GetExecutingAssembly().GetManifestResourceStream("HamBook.Effects.pot.wav")))
                    {
                        soundPlayer.Play();
                        await _catAssemblies.CatWriteAsync<int>("FA", new object[] { _currentFrequency }, _scanningCancellationToken);
                    }

                    using (var memoryStream = new MemoryStream())
                    {
                        _serialPort.DiscardInBuffer();

                        await taskCompletionSource.Task;

                        var count = _serialPort.BaudRate / sizeof(byte) * pauseTime;
                        await _serialPort.CopyToAsync(memoryStream, count, _scanningCancellationToken);

                        memoryStream.Position = 0L;

                        // TODO: radios
                        var result = Encoding.ASCII.GetString(memoryStream.ToArray());
                        foreach (var split in result.Split(Radios.Generic.Constants.EOT))
                        {
                            if(string.IsNullOrEmpty(split))
                            {
                                continue;
                            }

                            try
                            {
                                switch (_catAssemblies.CatParse<BusyState>("BY", new object[] { $"{split}{Radios.Generic.Constants.EOT}" }))
                                {
                                    case BusyState.ON:
                                        if (_configuration.Notifications.TryGetNotificationState(NotificationType.SignalScanDetect, out var notificationState))
                                        {
                                            continue;
                                        }

                                        var toastFrom = new ToastForm(
                                            $"{Resources.Signal_detected_during_scan}",
                                            $"{Resources.Frequency}: {_currentFrequency}Hz",
                                            notificationState.LingerTime,
                                            Constants.AssemblyIcon);

                                        toastFrom.Show();

                                        await Task.Delay(TimeSpan.FromSeconds(pauseDetectTime), _scanningCancellationToken);
                                        continue;
                                }
                            }
                            catch (TargetInvocationException exception) when (exception.InnerException is UnmatchedRadioResponseException)
                            {
                                // suppress
                            }
                            catch (Exception exception)
                            {
                                Log.Warning(exception, Resources.Unexpected_failure_while_scanning);
                            }
                        }
                    }

                    _currentFrequency = _currentFrequency + stepFrequency;
                    if(_currentFrequency > _maxFrequency)
                    {
                        _currentFrequency = _minFrequency;
                    }
                    if(_currentFrequency < _minFrequency)
                    {
                        _currentFrequency = _minFrequency;
                    }

                } while(!_scanningCancellationToken.IsCancellationRequested);
            }
            catch(Exception exception)
            {
                Log.Error(exception, Resources.Scanning_aborted);
            }
            finally
            {
                _catAssemblies.CatWrite<InformationState>("AI", new object[] { InformationState.OFF });

                if (_serialPort.IsOpen)
                {
                    _serialPort.Close();

                    _serialPort.DiscardInBuffer();
                }
            }
        }
    }
}