/// <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 = " "; } }