/// <summary>
        /// Issues Phase Diagnostic call for meter
        /// </summary>
        /// <returns>Boolean indicating success of Phase Diagnostic call</returns>
        private string Process()
        {
            CancellationToken token = _cts.Token;
            var task = _serial.PhaseDiagnostic(token);

            // Waits X seconds for Phase Diagnostic call to finish execution if not then display
            // modal to user and attempt to reconnect
            int timeout = _serial.NewFirmware ? 7000 : 5000;

            if (!task.Wait(timeout, token))
            {
                // Create thread that launches modal window for user and continues to poll
                // original process to determine if it has completed
                Thread t = new Thread(new ThreadStart(() =>
                {
                    InfoView info      = null;
                    InfoViewModel ifvm = new InfoViewModel(task, _cts, "Serial Connection Lost", "Attempting to Reconnect");

                    Application.Current.Dispatcher.Invoke(() =>
                    {
                        info = new InfoView
                        {
                            Owner = Application.Current.MainWindow,
                            WindowStartupLocation = WindowStartupLocation.CenterOwner,
                            DataContext           = ifvm
                        };

                        info.Show();
                    });

                    var monitor = ifvm.Poll();
                    if (monitor)
                    {
                        // Close the window if the program has successfully re-established communication
                        Application.Current.Dispatcher.Invoke(() =>
                        {
                            ifvm.UserClosedWindow = false;
                            info.Close();
                        });
                    }
                    else
                    {
                        // Wait for the task to complete
                        while (task.Status != TaskStatus.RanToCompletion)
                        {
                        }

                        // exit this function
                        return;
                    }
                }));

                t.SetApartmentState(ApartmentState.STA);
                t.IsBackground = true;
                t.Start();
                t.Join();
            }

            // Iterate over each line and extract the voltage, current and kW for each channel and phase of the meter
            string buffer      = task.Result;
            int    meter       = 0;
            bool   phase1      = true;
            int    lineNumber  = 0;
            bool   corrupted   = false;
            float  voltageASum = 0.0f;
            float  voltageBSum = 0.0f;
            float  voltageCSum = 0.0f;
            float  voltageANum = 0;
            float  voltageBNum = 0;
            float  voltageCNum = 0;

            foreach (string s in buffer.Split(new char[] { '\n', '\r' }, System.StringSplitOptions.RemoveEmptyEntries))
            {
                string[] cols = s.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);

                // if not data row continue to next line
                if (s.Contains("Amps") || (!_serial.NewFirmware && cols.Length != 10) || (_serial.NewFirmware && cols.Length != 9))
                {
                    continue;
                }

                if (!_serial.NewFirmware)
                {
                    if (Regex.IsMatch(cols[0], "^(3[2-9]|4[0-3])$") && Regex.IsMatch(cols[3], "^[12]$") && Convert.ToInt32(cols[0]) - 32 == lineNumber / 2)
                    {
                        meter  = Convert.ToInt32(cols[0]) - 32;
                        phase1 = cols[3] == "1" ? true : false;

                        if (phase1)
                        {
                            if (Regex.IsMatch(cols[6], @"^\d*\.\d*$"))
                            {
                                Phase1Text[meter, 0] = float.Parse(cols[6]).ToString("0.00");
                            }
                            else
                            {
                                Phase1Text[meter, 0] = "--";
                                corrupted            = true;
                            }

                            if (Regex.IsMatch(cols[8], @"^\d*\.\d*$"))
                            {
                                float watts = float.Parse(cols[8]);
                                Phase1Text[meter, 1] = (watts / 1000).ToString("0.00");

                                if (Regex.IsMatch(cols[9], @"^\d*\.\d*$"))
                                {
                                    double temp = Math.Atan2(float.Parse(cols[9]), watts);

                                    if (double.IsNaN(temp))
                                    {
                                        Phase1Text[meter, 2] = "--";
                                    }
                                    else
                                    {
                                        Phase1Text[meter, 2] = temp.ToString("0.00");
                                    }
                                }
                                else
                                {
                                    Phase1Text[meter, 2] = "--";
                                    corrupted            = true;
                                }
                            }
                            else
                            {
                                Phase1Text[meter, 1] = "--";
                                Phase1Text[meter, 2] = "--";
                                corrupted            = true;
                            }

                            // Set the voltages for the Meter Information box
                            if (Regex.IsMatch(cols[7], @"^\d*\.\d*$"))
                            {
                                if (Phase1Text[meter, 4] == "A")
                                {
                                    voltageASum += float.Parse(cols[7]);
                                    voltageANum++;
                                }
                                else if (Phase1Text[meter, 4] == "B")
                                {
                                    voltageBSum += float.Parse(cols[7]);
                                    voltageBNum++;
                                }
                                else if (Phase1Text[meter, 4] == "C")
                                {
                                    voltageCSum += float.Parse(cols[7]);
                                    voltageCNum++;
                                }
                            }
                            else
                            {
                                corrupted = true;
                            }
                        }
                        else
                        {
                            if (Regex.IsMatch(cols[6], @"^\d*\.\d*$"))
                            {
                                Phase2Text[meter, 0] = float.Parse(cols[6]).ToString("0.00");
                            }
                            else
                            {
                                Phase2Text[meter, 0] = "--";
                                corrupted            = true;
                            }

                            if (Regex.IsMatch(cols[8], @"^\d*\.\d*$"))
                            {
                                float watts = float.Parse(cols[8]);
                                Phase2Text[meter, 1] = (watts / 1000).ToString("0.00");

                                if (Regex.IsMatch(cols[9], @"^\d*\.\d*$"))
                                {
                                    double temp = Math.Atan2(float.Parse(cols[9]), watts);

                                    if (double.IsNaN(temp))
                                    {
                                        Phase2Text[meter, 2] = "--";
                                    }
                                    else
                                    {
                                        Phase2Text[meter, 2] = temp.ToString("0.00");
                                    }
                                }
                                else
                                {
                                    Phase2Text[meter, 2] = "--";
                                    corrupted            = true;
                                }
                            }
                            else
                            {
                                Phase2Text[meter, 1] = "--";
                                Phase2Text[meter, 2] = "--";
                                corrupted            = true;
                            }

                            // Set the voltages for the Meter Information box
                            if (Regex.IsMatch(cols[7], @"^\d*\.\d*$"))
                            {
                                if (Phase2Text[meter, 4] == "A")
                                {
                                    voltageASum += float.Parse(cols[7]);
                                    voltageANum++;
                                }
                                else if (Phase2Text[meter, 4] == "B")
                                {
                                    voltageBSum += float.Parse(cols[7]);
                                    voltageBNum++;
                                }
                                else if (Phase2Text[meter, 4] == "C")
                                {
                                    voltageCSum += float.Parse(cols[7]);
                                    voltageCNum++;
                                }
                            }
                            else
                            {
                                corrupted = true;
                            }
                        }
                    }
                    else
                    {
                        if (lineNumber % 2 == 0)
                        {
                            Phase1Text[lineNumber / 2, 0] = "--";   // Amps
                            Phase1Text[lineNumber / 2, 1] = "--";   // Watts
                            Phase1Text[lineNumber / 2, 2] = "--";   // PF
                        }
                        else
                        {
                            Phase2Text[lineNumber / 2, 0] = "--";   // Amps
                            Phase2Text[lineNumber / 2, 1] = "--";   // Watts
                            Phase2Text[lineNumber / 2, 2] = "--";   // PF
                        }

                        corrupted = true;
                    }
                }
                else
                {
                    if (Regex.IsMatch(cols[0], "^[12]$"))
                    {
                        phase1 = cols[0] == "1" ? true : false;

                        if (phase1)
                        {
                            if (Regex.IsMatch(cols[3], @"^\d*\.\d*$"))
                            {
                                Phase1Text[meter, 0] = float.Parse(cols[3]).ToString("0.00");
                            }
                            else
                            {
                                Phase1Text[meter, 0] = "--";
                                corrupted            = true;
                            }

                            if (Regex.IsMatch(cols[5], @"^\d*\.\d*$"))
                            {
                                float watts = float.Parse(cols[5]);
                                Phase1Text[meter, 1] = (watts / 1000).ToString("0.00");

                                if (Regex.IsMatch(cols[6], @"^\d*\.\d*$"))
                                {
                                    double temp = Math.Atan2(float.Parse(cols[6]), watts);
                                    if (double.IsNaN(temp))
                                    {
                                        Phase1Text[meter, 2] = "--";
                                    }
                                    else
                                    {
                                        Phase1Text[meter, 2] = temp.ToString("0.00");
                                    }
                                }
                                else
                                {
                                    Phase1Text[meter, 2] = "--";
                                    corrupted            = true;
                                }
                            }
                            else
                            {
                                Phase1Text[meter, 1] = "--";
                                Phase1Text[meter, 2] = "--";
                                corrupted            = true;
                            }

                            // Set the voltages for the Meter Information box
                            if (Regex.IsMatch(cols[4], @"^\d*\.\d*$"))
                            {
                                if (Phase1Text[meter, 4] == "A")
                                {
                                    voltageASum += float.Parse(cols[4]);
                                    voltageANum++;
                                }
                                else if (Phase1Text[meter, 4] == "B")
                                {
                                    voltageBSum += float.Parse(cols[4]);
                                    voltageBNum++;
                                }
                                else if (Phase1Text[meter, 4] == "C")
                                {
                                    voltageCSum += float.Parse(cols[4]);
                                    voltageCNum++;
                                }
                            }
                            else
                            {
                                corrupted = true;
                            }
                        }
                        else
                        {
                            if (Regex.IsMatch(cols[3], @"^\d*\.\d*$"))
                            {
                                Phase2Text[meter, 0] = float.Parse(cols[3]).ToString("0.00");
                            }
                            else
                            {
                                Phase2Text[meter, 0] = "--";
                                corrupted            = true;
                            }

                            if (Regex.IsMatch(cols[5], @"^\d*\.\d*$"))
                            {
                                float watts = float.Parse(cols[5]);
                                Phase2Text[meter, 1] = (watts / 1000).ToString("0.00");

                                if (Regex.IsMatch(cols[6], @"^\d*\.\d*$"))
                                {
                                    double temp = Math.Atan2(float.Parse(cols[6]), watts);
                                    if (double.IsNaN(temp))
                                    {
                                        Phase2Text[meter, 2] = "--";
                                    }
                                    else
                                    {
                                        Phase2Text[meter, 2] = temp.ToString("0.00");
                                    }
                                }
                                else
                                {
                                    Phase2Text[meter, 2] = "--";
                                    corrupted            = true;
                                }
                            }
                            else
                            {
                                Phase2Text[meter, 1] = "--";
                                Phase2Text[meter, 2] = "--";
                                corrupted            = true;
                            }

                            // Set the voltages for the Meter Information box
                            if (Regex.IsMatch(cols[4], @"^\d*\.\d*$"))
                            {
                                if (Phase2Text[meter, 4] == "A")
                                {
                                    voltageASum += float.Parse(cols[4]);
                                    voltageANum++;
                                }
                                else if (Phase2Text[meter, 4] == "B")
                                {
                                    voltageBSum += float.Parse(cols[4]);
                                    voltageBNum++;
                                }
                                else if (Phase2Text[meter, 4] == "C")
                                {
                                    voltageCSum += float.Parse(cols[4]);
                                    voltageCNum++;
                                }
                            }
                            else
                            {
                                corrupted = true;
                            }

                            meter++;
                        }
                    }
                    else
                    {
                        if (lineNumber % 2 == 0)
                        {
                            Phase1Text[lineNumber / 2, 0] = "--";   // Amps
                            Phase1Text[lineNumber / 2, 1] = "--";   // Watts
                            Phase1Text[lineNumber / 2, 2] = "--";   // PF
                        }
                        else
                        {
                            Phase2Text[lineNumber / 2, 0] = "--";   // Amps
                            Phase2Text[lineNumber / 2, 1] = "--";   // Watts
                            Phase2Text[lineNumber / 2, 2] = "--";   // PF
                        }

                        corrupted = true;
                    }
                }

                lineNumber++;
            }

            // Display average of Voltages instead of last voltage received
            // aids in troubleshooting
            VoltageA = (voltageASum / voltageANum).ToString("0.00") + " V";
            VoltageB = (voltageBSum / voltageBNum).ToString("0.00") + " V";
            VoltageC = (voltageCSum / voltageCNum).ToString("0.00") + " V";

            OnPropertyChanged(nameof(Phase1Text));
            OnPropertyChanged(nameof(Phase2Text));

            // If present data is corrupted, increment corrupted counter
            if (corrupted)
            {
                _numCorrupted++;
            }
            // Reset corrupted counter if data isn't corrupt
            else
            {
                _numCorrupted = 0;
            }

            // If data is corrupt, 3 times in a row
            // display modal to user and stop reading
            if (_numCorrupted == 3)
            {
                InfoView      info = null;
                InfoViewModel ifvm = new InfoViewModel("Corrupted Data", "Corrupted Data has been received multiple times. Please check set up. Pausing serial port reads.");

                Application.Current.Dispatcher.Invoke(() =>
                {
                    info = new InfoView
                    {
                        Owner = Application.Current.MainWindow,
                        WindowStartupLocation = WindowStartupLocation.CenterOwner,
                        DataContext           = ifvm
                    };

                    info.Show();
                });

                // Stops async processes and closes serial port
                // but leaves current tab open
                _break = true;
                _serial.Close();
            }

            return(buffer);
        }
        /// <summary>
        /// Connects a serial port to a meter and creates a new meter object, progressing user to next page
        /// </summary>
        /// <returns></returns>
        private async Task OpenSerial()
        {
            try
            {
                var tokenSource         = new CancellationTokenSource();
                CancellationToken token = tokenSource.Token;
                var task = EstablishSerial(token);

                // Waits 5 seconds for Phase Diagnostic call to finish execution if not then display
                // modal to user and attempt to reconnect
                if (!task.Wait(500, token))
                {
                    // Create thread that launches modal window for user and continues to poll
                    // original process to determine if it has completed
                    Thread t = new Thread(new ThreadStart(async() =>
                    {
                        InfoView info      = null;
                        InfoViewModel ifvm = new InfoViewModel(task, tokenSource, "Meter Serial Connection", "Connecting to Meter");

                        Application.Current.Dispatcher.Invoke(() =>
                        {
                            info = new InfoView
                            {
                                Owner = Application.Current.MainWindow,
                                WindowStartupLocation = WindowStartupLocation.CenterOwner,
                                DataContext           = ifvm
                            };

                            info.Show();
                        });

                        var monitor = ifvm.Poll();
                        if (monitor)
                        {
                            // Close the window if the program has successfully re-established communication
                            Application.Current.Dispatcher.Invoke(() =>
                            {
                                ifvm.UserClosedWindow = false;
                                info.Close();
                            });
                        }
                        else
                        {
                            // Wait for the task to complete
                            while (task.Status != TaskStatus.RanToCompletion)
                            {
                            }

                            // exit this function
                            return;
                        }
                    }));

                    t.SetApartmentState(ApartmentState.STA);
                    t.IsBackground = true;
                    t.Start();
                    t.Join();
                }
            }
            catch
            {
            }
            finally
            {
                IsBusy  = false;
                COMPORT = "          ";
            }
        }