<#
  .SYNOPSIS
  Executes full-duplex test of FreeDV.

  .DESCRIPTION
  This script starts FreeDV in full-duplex mode for approximately 60 seconds using an autogenerated configuration file
  that will access the audio devices passed in. After 60 seconds, FreeDV will terminate and this script will examine
  the output to determine the number of times that it went into and out of sync. If it detects that FreeDV went out
  of sync during the test, the test is marked as having failed.

  .INPUTS
  None. You can't pipe objects to this script.

  .OUTPUTS
  The script outputs the mode tested as well as the number of passed/failed tests to the console.

  .EXAMPLE
  PS> .\TestFreeDVFullDuplex.ps1 -ModeToTest RADE -RadioToComputerDevice "Microphone (USB Audio CODEC)" -ComputerToRadioDevice "Speakers (USB Audio CODEC)" -ComputerToSpeakerDevice "Speakers (Realtek High Definition Audio(SST))" -MicrophoneToComputerDevice "Microphone Array (Realtek High Definition Audio(SST))"

#>

param (
    [Parameter(Mandatory = $true)]
    [ValidateNotNullOrEmpty()]
    [string] 
    # The sound device to receive RX audio from.
    $RadioToComputerDevice, 

    [Parameter(Mandatory = $true)]
    [ValidateNotNullOrEmpty()]
    [string] 
    # The sound device to emit decoded audio to.
    $ComputerToSpeakerDevice, 

    [Parameter(Mandatory = $true)]
    [ValidateNotNullOrEmpty()]
    [string] 
    # The sound device to receive analog audio from.
    $MicrophoneToComputerDevice, 

    [Parameter(Mandatory = $true)]
    [ValidateNotNullOrEmpty()]
    [string] 
    # The sound device to emit TX audio to.
    $ComputerToRadioDevice,
    
    [ValidateSet("RADEV1", "700D", "700E", "1600")]
    [ValidateNotNullOrEmpty()]
    [string]
    # The FreeDV mode to use for testing.
    $ModeToTest="RADEV1", 

    [int] 
    # The number of times to execute the test.
    $NumberOfRuns=10)


<#
    .Description
    Performs the actual test with FreeDV by generating the needed configuration file, starting FreeDV and then examining the output.
#>
function Test-FreeDV {
    param (
        $ModeToTest,
        $RadioToComputerDevice,
        $ComputerToSpeakerDevice,
        $MicrophoneToComputerDevice,
        $ComputerToRadioDevice
    )

    $current_loc = Get-Location

    # Generate new conf 
    $conf_tmpl = Get-Content "$current_loc\freedv-ctest-fullduplex.conf.tmpl"
    $conf_tmpl = $conf_tmpl.Replace("@FREEDV_RADIO_TO_COMPUTER_DEVICE@", $RadioToComputerDevice)
    $conf_tmpl = $conf_tmpl.Replace("@FREEDV_COMPUTER_TO_RADIO_DEVICE@", $ComputerToRadioDevice)
    $conf_tmpl = $conf_tmpl.Replace("@FREEDV_MICROPHONE_TO_COMPUTER_DEVICE@", $MicrophoneToComputerDevice)
    $conf_tmpl = $conf_tmpl.Replace("@FREEDV_COMPUTER_TO_SPEAKER_DEVICE@", $ComputerToSpeakerDevice)
    $tmp_file = New-TemporaryFile
    $conf_tmpl | Set-Content -Path $tmp_file.FullName

    # Start freedv.exe
    $psi = New-Object System.Diagnostics.ProcessStartInfo
    $psi.CreateNoWindow = $true
    $psi.UseShellExecute = $false
    $psi.RedirectStandardError = $true
    $psi.RedirectStandardOutput = $true
    $psi.FileName = "$current_loc\freedv.exe"
    $psi.WorkingDirectory = $current_loc
    $quoted_tmp_filename = "`"" + $tmp_file.FullName + "`""
    $psi.Arguments = @("/f $quoted_tmp_filename /ut txrx /utmode $ModeToTest")

    $process = New-Object System.Diagnostics.Process
    $process.StartInfo = $psi
    [void]$process.Start()

    # Read output from process
    $err_output = $process.StandardError.ReadToEnd();
    $output = $process.StandardOutput.ReadToEnd();
    $process.WaitForExit()

    Write-Host "$err_output"

    $syncs = $err_output.Split([Environment]::NewLine) | Where { $_.Contains("Sync changed") }
    if ($syncs.Count -eq 1) {
        return $true
    }
    return $false
}

$passes = 0
$fails = 0

for (($i = 0); $i -lt $NumberOfRuns; $i++)
{
    $result = Test-FreeDV `
        -ModeToTest $ModeToTest `
        -RadioToComputerDevice $RadioToComputerDevice `
        -ComputerToSpeakerDevice $ComputerToSpeakerDevice `
        -MicrophoneToComputerDevice $MicrophoneToComputerDevice `
        -ComputerToRadioDevice $ComputerToRadioDevice
    if ($result -eq $true)
    {
        $passes++
    }
    else
    {
        $fails++
    }
}

Write-Host "Mode: $ModeToTest, Total Runs: $NumberOfRuns, Passed: $passes, Failures: $fails"

if ($fails -gt 0) {
    throw "Test failed"
    exit 1
}

