using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO.Ports; using XYLEM.Communication; using System.Xml.Linq; using XYLEM.Base; using XYLEM.Communication.ValueEncoders; using System.Linq.Expressions; using System.Threading; using MagFlux6200_metrology_reg_list; using XYLEM.Device; using static modbus_master_csharp.Program; using System.Diagnostics.Contracts; using System.Security.Policy; using System.IO; using System.Diagnostics; using System.Xml.Schema; using System.Net.NetworkInformation; namespace modbus_master_csharp { internal class Program { /*For testing directly to metrology */ static string[] argsDefault1 = new string[] { "TEST", "COM200", "115200", "N" }; /*For metrology RS485 when transparent to metrology*/ static string[] argsDefault2 = new string[] { "SAVE_CAL", "COM38" }; static string[] argsDefault2b = new string[] { "SAVE_CAL", "COM200", "115200", "N" }; static string[] argsDefault2c = new string[] { "SAVE_CAL", "COM200", "COM200", "115200", "N" }; // Having more ports static string[] argsDefault3 = new string[] { "TEST", "COM38", "COM200" }; /*For metrology RS485 when transparent to metrology*/ static string[] argsDefault4 = new string[] { "LOAD_CAL=\"0_sensor_cal_for_testing.xml\"", "COM38" }; /*For metrology RS485 when transparent to metrology*/ static string[] argsDefault5 = new string[] { "SET_DN_SN=25,999999", "COM38" }; /*For metrology RS485 when transparent to metrology*/ static string[] argsDebugLiveRun = new string[] { "TEST", "COM200" }; /*For metrology RS485 when transparent to metrology*/ static string[] args_ExAbortCal = new string[] { "ABORT_CAL", "COM200" }; #if (DEBUG) static bool LIVE_RUN = true; // Default = "true" to run with DUT communication or "false" to run without any DUT for communication and mock values /* Preload with program argument used for debugging*/ static bool MAIN_ARGS_OVERWRITE = true; // true to overwrite run with "argsDebugLiveRun" [Default = false] static string[] MAIN_ARGS_OVERWRITE_WITH = argsDebugLiveRun; //testing arguments in debug Default = "argsDebugLiveRun" #else static bool LIVE_RUN = true; // #endif private static string GetArgHelpMessage(bool isArgErrorMessage, string[] args) { var name_exe = System.AppDomain.CurrentDomain.FriendlyName; var message = $@" Example of from command line: Save calibrations only include COMx to use standard baudrate and parity setup: ""{name_exe} {argsDefault2.ToSingleString(false)}"" or run functional test for 2 MagFlux ""{name_exe} {argsDefault3.ToSingleString(false)}"" To run functional test and configure both COMx, baudrate, parity. (Used for com directly to Metrology) ""{name_exe} {argsDefault1.ToSingleString(false)}"" To Load calibrations only include COMx to use standard baudrate and parity setup: ""{name_exe} {argsDefault4.ToSingleString(false)}"" To Set DN [mm] and Sensor Serial number, only include COMx to use standard baudrate and parity setup: ""{name_exe} {argsDefault5.ToSingleString(false)}"" To Abort calibrations only include COMx to use standard baudrate and parity setup: ""{name_exe} {args_ExAbortCal.ToSingleString(false)}"" "; if (isArgErrorMessage) { var argsTxt = args != null ? args.ToSingleString(" ") : ""; message = $"{new string('!', 50)}\nThere is errors in the Arguments list!\n{new string('!', 50)}\nWas: {name_exe} {argsTxt}\n" + message; } return message; } #region Reused functions for testing private static bool GetDeviceHealthy(IMagFluxRequestProtocol dut) { var name = nameof(dut.GetDeviceHealthy); var isOkay = dut.GetDeviceHealthy(); var message = $"{name}: {(isOkay ? "Is okay" : "Has errors")}"; if (!isOkay) { if (dut.GetDeviceErrorMessages(out var errorList)) { Console.WriteLine(message + "\nError List:\n" + errorList.ToSingleString(false)); } else { Console.WriteLine(message); } } return isOkay; } private static void GetBasicDeviceInfo(IMagFluxRequestProtocol dut) { { var name = nameof(dut.GetFwGitHash); var isOkay = dut.GetFwGitHash(out var value_out); var message = $"{name}: {(isOkay ? value_out : "!Read failed!")}"; Console.WriteLine(message); if (!isOkay) { throw new Exception(message); } } { var name = nameof(dut.GetSensorSerialNo); var isOkay = dut.GetSensorSerialNo(out var value_out); var message = $"{name}: {(isOkay ? value_out : "!Read failed!")}"; Console.WriteLine(message); if (!isOkay) { throw new Exception(message); } } { var name = nameof(dut.GetUniqueId); var isOkay = dut.GetUniqueId(out var value_out); var message = $"{name}: {(isOkay ? value_out : "!Read failed!")}"; Console.WriteLine(message); if (!isOkay) { throw new Exception(message); } } { var name = nameof(dut.GetFirmwareVersion); var isOkay = dut.GetFirmwareVersion(out var value_out); var message = $"{name}: {(isOkay ? value_out : "!Read failed!")}"; Console.WriteLine(message); if (!isOkay) { throw new Exception(message); } } { var name = nameof(dut.GetFwBuildDate); var isOkay = dut.GetFwBuildDate(out var value_out); var message = $"{name}: {(isOkay ? value_out : "!Read failed!")}"; Console.WriteLine(message); if (!isOkay) { throw new Exception(message); } } } private static void GetBasicSensorInfo(IMagFluxRequestProtocol dut) { { var name = nameof(dut.GetDn_mm); var isOkay = dut.GetDn_mm(out var dn_mm_out); var message = $"{name}: {(isOkay ? $"{dn_mm_out}mm" : "!Read failed!")}"; Console.WriteLine(message); if (!isOkay) { throw new Exception(message); } } { GetDeviceHealthy(dut); } } private static void AbortDeviceCalibration(IMagFluxRequestProtocol dut) { { var name = nameof(dut.AbortDeviceForCalibration); var isOkay = dut.AbortDeviceForCalibration(); var message = $"{name}: {(isOkay ? "Done" : "!Abort failed!")}"; Console.WriteLine(message); if (!isOkay) { throw new Exception(message); } } } private static bool GetCalibrationPoints(IMagFluxRequestProtocol dut, out CalibrationPoints value_out, bool printoutPoints) { var name = nameof(dut.GetCalibrationPoints); var isOkay = dut.GetCalibrationPoints(out value_out); if (printoutPoints) { Console.WriteLine($"{name}: Read points-> {(isOkay ? "\n"+value_out.ToString() : "!Read failed!")}"); } else { Console.WriteLine($"{name}: Reading calibration points {(isOkay ? "Okay" : "!Read failed!")}"); } return isOkay; } private static bool SetCalibrationPoints(IMagFluxRequestProtocol dut, CalibrationPoints new_calibration_points) { var isOkay = dut.SetCalibrationPoints(new_calibration_points); Console.WriteLine($"{nameof(dut.SetCalibrationPoints)}: {(isOkay ? "Okay" : "Failed")}\n{new_calibration_points}"); return isOkay; } private static bool PrepareDeviceForCalibration(IMagFluxRequestProtocol dut) { { // --- Test setting the device ready for the first measurement used for calibrations --- { var isOkay = dut.PrepareDeviceForCalibration(); Console.WriteLine($"{nameof(dut.PrepareDeviceForCalibration)}: {(isOkay ? "Okay" : "Failed")}"); if (!isOkay || !GetCalibrationPoints(dut, out var value_out, true/*printout points*/)) { GetDeviceHealthy(dut); throw new Exception("Failed Setting device up for calibration"); } return isOkay; } } } private static void RunTestCalibrationPoints(IMagFluxRequestProtocol dut, CalibrationPoints new_calibration_points) { { // Write calibrations var isOkay = SetCalibrationPoints(dut, new_calibration_points); if (!isOkay) { GetDeviceHealthy(dut); throw new Exception("Failed writing the calibration to device"); } } { // Get calibrations and check it if (!GetCalibrationPoints(dut, out var value_out, false/*Don't printout*/) || (new_calibration_points != value_out)) { GetDeviceHealthy(dut); var msg = $"Failed! Calibration is not the same read as written to device\nWritten:\n{new_calibration_points}\nRead:\n{value_out}"; Console.WriteLine(msg); throw new Exception(msg); } } } /// /// Read Sensor serial number /// /// /// Return the Serial number /// Will throw an exception if failing private static UInt32 GetSensorSerialNo(IMagFluxRequestProtocol dut) { var isOkay = dut.GetSensorSerialNo(out var read_out); UInt32 ret = 0; if (isOkay) { isOkay = UInt32.TryParse(read_out, out var passed); ret = passed; } { // Handle result var name = nameof(dut.GetSensorSerialNo); var message = $"Read {name}: {(isOkay ? ret.ToString() : "!failed!")}"; Console.WriteLine(message); if (!isOkay) { throw new Exception(message); } } return ret; } /// /// Write Sensor serial number (Also check with a read back) /// /// what dut to write to /// New serial number /// Will throw an exception if failing private static void SetSensorSerialNo(IMagFluxRequestProtocol dut, UInt32 new_SN) { var name = nameof(dut.SetSensorSerialNo); Console.WriteLine($"Write of {name}: {new_SN.ToString()}"); var isOkay = dut.SetSensorSerialNo(new_SN); var read = GetSensorSerialNo(dut); isOkay &= (read == new_SN); // Is the same as read ? // Handle result if (!isOkay) { var message = $"Write of {name}:!failed!"; Console.WriteLine(message); throw new Exception(message); } } /// /// Read Sensor DN /// /// /// Return DN [mm] /// Will throw an exception if failing private static UInt16 GetDn_mm(IMagFluxRequestProtocol dut) { var isOkay = dut.GetDn_mm(out var read_out); UInt16 ret = 0; if (isOkay) { isOkay = UInt16.TryParse(read_out.ToString(), out var passed); ret = passed; } { // Handle result var name = nameof(dut.GetDn_mm); var message = $"Read {name}: {(isOkay ? ret.ToString() : "!failed!")}"; Console.WriteLine(message); if (!isOkay) { throw new Exception(message); } } return ret; } /// /// Write Sensor DN size (Also check with a read back) /// /// what dut to write to /// New DN [mm] /// Will throw an exception if failing private static void SetDn_mm(IMagFluxRequestProtocol dut, UInt16 new_DN_mm) { var name = nameof(dut.SetDn_mm); Console.WriteLine($"Write of {name}: {new_DN_mm.ToString()}"); var isOkay = dut.SetDn_mm(new_DN_mm); var read = GetDn_mm(dut); isOkay &= (read == new_DN_mm); // Is the same as read ? // Handle result if (!isOkay) { var message = $"Write of {name}:!failed!"; Console.WriteLine(message); throw new Exception(message); } } /// /// save and load what is read from device /// /// /// private static void SaveCalPointsToTempFolder(IMagFluxRequestProtocol dut, CalibrationPoints value_out) { var tempSaveFolder = Environment.GetEnvironmentVariable("USERPROFILE")+@"\Downloads\"; if (dut.GetSensorSerialNo(out var sensorSerial)) { dut.GetUniqueId(out var id); var sensor_cal_file = tempSaveFolder+$"{sensorSerial}_sensor_cal_id_{id}_{DateTime.Now.ToFileTimeTxt()}.xml"; Console.WriteLine($"Save to:\n{sensor_cal_file}"); value_out.SaveToFile(sensor_cal_file); // Check saved data var to_saved_points = value_out.calibrations.ToArray(); value_out.LoadFromFile(sensor_cal_file); var loaded_points = value_out.calibrations.ToArray(); if (!to_saved_points.SequenceEqual(loaded_points)) { var msg = $"Failed save of calibrations\nSaved:\n{to_saved_points}\nLoaded:\n{loaded_points}"; Console.WriteLine(msg); throw new Exception(msg); } } } private static void SAVE_CAL(List duts) { { // Check Save all calibrations one DUT at a time for (var dutIdx = 0; dutIdx < duts.Count(); dutIdx++) { var dut = duts[dutIdx]; Console.WriteLine($"------------------- DUT{dutIdx+1} --------------------"); try { GetBasicDeviceInfo(dut); GetBasicSensorInfo(dut); if (!GetCalibrationPoints(dut, out var value_out, true/*printout points*/)) { GetDeviceHealthy(dut); throw new Exception("Failed saving device calibration"); } else { // save and load what is read from device SaveCalPointsToTempFolder(dut, value_out); } } catch (Exception ex) { dut.OpenLogFile(); throw ex; } } } } private static void ABORT_CAL(List duts) { { // Check Save all calibrations one DUT at a time for (var dutIdx = 0; dutIdx < duts.Count(); dutIdx++) { var dut = duts[dutIdx]; Console.WriteLine($"------------------- DUT{dutIdx+1} --------------------"); try { GetBasicDeviceInfo(dut); AbortDeviceCalibration(dut); GetBasicSensorInfo(dut); if (!GetCalibrationPoints(dut, out var value_out, true/*printout points*/)) { if (!PrepareDeviceForCalibration(dut)) { throw new Exception("Failed abort of device calibration"); } } } catch (Exception ex) { dut.OpenLogFile(); throw ex; } } } } /// /// Load Calibrations /// /// /// private static void LOAD_CAL(List duts, List loadedCalibrations) { { // Check all Values one by one a DUT at a time if (duts.Count() != loadedCalibrations.Count()) { throw new Exception("The number of calibrations is not the same as DUT's to load it in"); } Console.WriteLine("\nSave Calibrations before starting writing new calibrations\n"); SAVE_CAL(duts); Console.WriteLine("\nStarting writing new calibrations\n"); for (var dutIdx = 0; dutIdx < duts.Count(); dutIdx++) { var dut = duts[dutIdx]; Console.WriteLine($"------------------- DUT{dutIdx+1} --------------------"); try { var new_calibration_points = loadedCalibrations[dutIdx]; var isOkay = SetCalibrationPoints(dut, new_calibration_points); if (!isOkay) { throw new Exception($"Writing calibration Fail!\n{new_calibration_points}"); } } catch (Exception ex) { dut.OpenLogFile(); throw ex; } } } } /// /// Set DN and SN in device /// /// Device to write it to /// DN size in [mm] /// Sensor serial number static void SET_DN_SN(IMagFluxRequestProtocol dut, UInt16 DN_mm, UInt32 sensor_sn) { Console.WriteLine($"------------------- Read current DUT Sensor DN and SN --------------------"); try { GetDn_mm(dut); GetSensorSerialNo(dut); } catch (Exception ex) { dut.OpenLogFile(); throw ex; } Console.WriteLine($"------------------- Set DUT Sensor DN and SN --------------------"); try { SetDn_mm(dut, DN_mm); SetSensorSerialNo(dut, sensor_sn); } catch (Exception ex) { dut.OpenLogFile(); throw ex; } } static void TEST(List duts) { { // Check all Values one by one a DUT at a time for (var dutIdx = 0; dutIdx < duts.Count(); dutIdx++) { Console.WriteLine($"------------------- DUT{dutIdx+1} --------------------"); var dut = duts[dutIdx]; try { //if (false) // Don't do basic reads if (true) // Do basic read test { GetBasicDeviceInfo(dut); { var name = nameof(dut.GetFlowRate_lps); var isOkay = dut.GetFlowRate_lps(out var value_out); var message = $"{name}: {(isOkay ? $"{value_out} l/s or {value_out*3.6} m3/h" : "!Read failed!")}"; Console.WriteLine(message); if (!isOkay) { throw new Exception(message); } } GetBasicSensorInfo(dut); { // Always check that GetDeviceErrorMessages() even when there is not error, to test function // Is only run in GetBasicSensorInfo() when there is an error var name = nameof(dut.GetDeviceErrorMessages); var isOkay = dut.GetDeviceErrorMessages(out var value_out); var message = $"{name}: \n{(isOkay ? String.Join("\n", value_out) : "!Read failed!")}"; Console.WriteLine(message); if (!isOkay) { throw new Exception(message); } } AbortDeviceCalibration(dut); { if (!GetCalibrationPoints(dut, out var value_out, true/*printout points*/)) { GetDeviceHealthy(dut); } else { // save and load what is read from device SaveCalPointsToTempFolder(dut, value_out); } } } //if (false) // Do not execute calibration test if (LIVE_RUN && true) // execute calibration test { // A single calibration Test PrepareDeviceForCalibration(dut); { // --- Do a simple 2 point calibration with zero --- var new_calibration_points = new CalibrationPoints( new List { new CalibrationPoint(0,0.001f), // 0 new CalibrationPoint(1,1.002f), // 1 new CalibrationPoint(2,2.003f), // 2 }, dut.CalibrationPointsMax // Extend to ); RunTestCalibrationPoints(dut, new_calibration_points); } { // --- Do a 6 point calibration with negative zero --- var new_calibration_points = new CalibrationPoints( new List { new CalibrationPoint(0,-0.001f), // 0 new CalibrationPoint(1,1.002f), // 1 new CalibrationPoint(2,2.003f), // 2 new CalibrationPoint(3,3.004f), // 3 new CalibrationPoint(4,4.005f), // 4 new CalibrationPoint(5,5.006f), // 5 }, dut.CalibrationPointsMax // Extend to ); RunTestCalibrationPoints(dut, new_calibration_points); // save and load what is read from device SaveCalPointsToTempFolder(dut, new_calibration_points); } { // --- Do a check of write of calibrations points that is not ordered correct --- Console.WriteLine($"Test writing calibration in wrong order is failing and Background check service is running"); { var new_calibration_points = new CalibrationPoints( new List { new CalibrationPoint(0,-0.001f), // 0 new CalibrationPoint(3,3.002f), // 1 Error this an error in order and need to brake calibrations new CalibrationPoint(2,2.003f), // 2 }, dut.CalibrationPointsMax // Extend to ); var isOkay = SetCalibrationPoints(dut, new_calibration_points); if (isOkay) { throw new Exception($"Writing calibration in wrong order needs to Fail!\n{new_calibration_points}"); } int maxWait_s = 5; while (maxWait_s-- > 0) { Console.Write($"\rWait timer out in {maxWait_s}s for getting Device Healthy is returning showing error: "); if (!dut.GetFlowRate_lps(out var value_out)) { throw new Exception($"read of flow failed during polling Device Healthy!"); } if (!GetDeviceHealthy(dut)) { Console.WriteLine($"\nGot correct replay that is Device healthy is \"false\""); break; // Exit } Task.Delay(1000).GetAwaiter().GetResult(); } if (maxWait_s <= 0) { throw new Exception($"Device Healthy was returning \"false\" when calibration was failing!\n{new_calibration_points}"); } } {// Cleanup by returning calibration to default var isOkay = dut.PrepareDeviceForCalibration(); if (!isOkay) { throw new Exception("Failing returning calibration to default!"); } } } { // --- Test Sensor new_SN test --- Console.WriteLine($"--- Test Write a changed Sensor SN ---"); // Read Sensor new_SN Console.WriteLine($"1)Read current Sensor SN"); UInt32 current = GetSensorSerialNo(dut); // Create a new Sensor new_SN var write_new = current + 1; // Write function also check with a read and throw exception if failed Console.WriteLine($"2)Change Sensor SN to {write_new}"); SetSensorSerialNo(dut, write_new); // Restore Sensor new_SN Console.WriteLine($"3)Restore Sensor SN to {write_new}"); SetSensorSerialNo(dut, current); Console.WriteLine($"--- Finish Test ---"); } { // --- Test Sensor DN test --- Console.WriteLine($"--- Test Write a changed Sensor DN Size ---"); // SetDn_mm(dut, 20); // Insure a valid DN UInt16[] tests_dn_mm = { 50, 100 }; // Read Sensor DN Console.WriteLine($"1)Read current Sensor DN Size"); UInt16 current = GetDn_mm(dut); // Create a new Sensor DN var write_new = tests_dn_mm.FirstOrDefault(dn => dn != current); // Write function also check with a read and throw exception if failed Console.WriteLine($"2)Change Sensor DN Size as {write_new}"); SetDn_mm(dut, write_new); // Restore Sensor DN Console.WriteLine($"3)Restore original Sensor DN Size as {current}"); SetDn_mm(dut, current); Console.WriteLine($"--- Finish Test ---"); } } } catch (Exception ex) { dut.OpenLogFile(); throw ex; } } } } #endregion enum RUN_ACTION { UNKNOWN, TEST, SAVE_CAL, LOAD_CAL, ABORT_CAL, SET_DN_SN, SHOW_HELP, } class args_inputs { public List comports; public int? baudrate; public Parity? parity; public List loadedCalibrations; public UInt16? DN_mm; public UInt32? sensor_sn; public args_inputs() { comports = new List(); baudrate = null; parity = null; loadedCalibrations = new List(); sensor_sn = null; } } #region Handle if arguments static RUN_ACTION parse_arguments(string[] args, ref args_inputs ret_args_input) { bool gotArgs = (args.Length >= 1); var run_task = RUN_ACTION.UNKNOWN; var argErrors = gotArgs ? false : true; // Use Default connection if nothing is provided by arguments var arg_offset = 0; if (args.Length > arg_offset) { { /*--------- Parse What task to do ---------*/ if (args.Length > arg_offset) { if ("-H" == args[arg_offset].ToUpper()) { run_task = RUN_ACTION.SHOW_HELP; } else if ("TEST" == args[arg_offset].ToUpper()) { run_task = RUN_ACTION.TEST; } else if ("SAVE_CAL" == args[arg_offset].ToUpper()) { run_task = RUN_ACTION.SAVE_CAL; } else if ("ABORT_CAL" == args[arg_offset].ToUpper()) { run_task = RUN_ACTION.ABORT_CAL; } else if (args[arg_offset].ToUpper().StartsWith("SET_DN_SN=")) { run_task = RUN_ACTION.SET_DN_SN; var values_as_txt = args[arg_offset].Split('=').Last().Split(','); int value_offset = 0; { // parse DN var dn_mm_txt = values_as_txt[value_offset++]; if (!UInt16.TryParse(dn_mm_txt, out var dn_mm)) { throw new InvalidDataException($"Error parsing DN \n{dn_mm_txt} as [mm]\n{GetArgHelpMessage(true, args)}"); } if ((dn_mm < 3) || (dn_mm > 3000)) { throw new InvalidDataException($"Error parsing DN \n{dn_mm}[mm] only 3 - 3000mm is allowed\n{GetArgHelpMessage(true, args)}"); } // Is okay ret_args_input.DN_mm = dn_mm; } { // parse Sensor SN var sn_txt = values_as_txt[value_offset++]; if (!UInt32.TryParse(sn_txt, out var SN)) { throw new InvalidDataException($"Error parsing Sensor SN \n{sn_txt}\n{GetArgHelpMessage(true, args)}"); } // Is okay ret_args_input.sensor_sn = SN; } } else if (args[arg_offset].ToUpper().StartsWith("LOAD_CAL=")) { run_task = RUN_ACTION.LOAD_CAL; var calFilePath = args[arg_offset].Split('=').Last(); var cal = new CalibrationPoints(); if (!File.Exists(calFilePath) || !cal.LoadFromFile(calFilePath)) { throw new InvalidDataException($"Error load calibrations from\n {calFilePath}\n{GetArgHelpMessage(true, args)}"); } ret_args_input.loadedCalibrations.Add(cal); } else { throw new NotImplementedException($"Missing support for parameter {args[arg_offset]}\n{GetArgHelpMessage(true, args)}"); } } } arg_offset++; // Check next argument { /*--------- Parse com port / ports ---------*/ var exit = false; var com_check_arg_offset = arg_offset; while (!exit) { if (args.Length > com_check_arg_offset) { var arg = args[com_check_arg_offset].ToUpper(); if ("COM" == arg.Remove(3)) { ret_args_input.comports.Add(arg); arg_offset = com_check_arg_offset; // Save ret location for last added com } else if (ret_args_input.comports.Count <= 0) { Console.WriteLine($"Com port {arg} not understood."); argErrors = true; exit = true; } else { exit = true; // No more com to connect to } com_check_arg_offset++; // Check next argument } else { exit = true; // No more com to connect to } } } arg_offset++; // Check next argument { /*--------- Parse Baud rate ---------*/ if (args.Length > arg_offset) { var arg = args[arg_offset].ToUpper(); var allowed_baudrate = new string[] { "9600", "19200", "38400", "57600", "115200", "230400" }; if (allowed_baudrate.Contains(arg)) { ret_args_input.baudrate = int.Parse(arg); } else { Console.WriteLine($"Baud rate {arg} not known."); ret_args_input.baudrate = -1; argErrors = true; } } } arg_offset++; // Check next argument { /*--------- Parse Parity ---------*/ if (args.Length > arg_offset) { var arg = args[arg_offset].ToUpper(); if (arg == "E") { ret_args_input.parity = Parity.Even; } else if (arg == "N") { ret_args_input.parity = Parity.None; } else if (arg == "O") { ret_args_input.parity = Parity.Odd; } else { Console.WriteLine($"Parity {arg} not known."); ret_args_input.parity = Parity.None; argErrors = true; } } } } if (argErrors) { string message = GetArgHelpMessage(argErrors, args); Console.WriteLine(message); if (argErrors) { throw new Exception(message); // exit main } } return run_task; } #endregion /// /// For unit testing setup /// /// static void Main(string[] args) { int ret_error = 0; // Is okay List duts = new List(); try { var runMode = RUN_TYPE.Mock; if (LIVE_RUN) { runMode = RUN_TYPE.Normal; } // Just for internal testing #if (DEBUG) if (args.Length <= 0) { if (MAIN_ARGS_OVERWRITE) { args = MAIN_ARGS_OVERWRITE_WITH; //testing directly to metrology } } #endif var run_task = RUN_ACTION.UNKNOWN; bool gotArgs = ((args != null) && (args.Length >= 1)); var inputs = new args_inputs(); if (gotArgs) { run_task = parse_arguments(args, ref inputs); } else { run_task = RUN_ACTION.SHOW_HELP; } if (run_task == RUN_ACTION.SHOW_HELP) { string message = GetArgHelpMessage(false, null); Console.WriteLine(message); return; } // Set window to max size to better fit content // Not needed for now! Console.SetWindowSize(Console.LargestWindowWidth, Console.LargestWindowHeight); #region Setup Communication to dut's foreach (var comport in inputs.comports) { if (runMode != RUN_TYPE.Normal) { Console.WriteLine($"{new string('!', 50)}\n Warning is in running in {runMode} mode\n{new string('!', 50)}"); } MagFlux6200 dut = null; try { // Set up on DUT dut = new MagFlux6200(runMode); var log_path = Environment.GetEnvironmentVariable("USERPROFILE")+@"\Downloads\"; var isOkay = dut.SetLogLocation(log_path, "logs_"+comport); Console.WriteLine($"Using program log path:\n{log_path}"); isOkay &=gotArgs; if (isOkay) { // Use standard and just setup as port if (inputs.baudrate == null) { isOkay &=dut.Connect(comport); } else if ((inputs.baudrate != null) && (inputs.parity != null)) { isOkay &=dut.Connect(comport, inputs.baudrate.Value, inputs.parity.Value); } else { isOkay = false; // Error in settings } } if (isOkay) { duts.Add(dut); } else { var port = comport; if (String.IsNullOrEmpty(port)) { port = "COM ?"; } throw new Exception($"Fail to setup device for {port}"); } } catch (Exception ex) { if (dut!=null) { dut.OpenLogFile(); } throw ex; } } #endregion //#region Setup Communication to dut's switch (run_task) { case RUN_ACTION.TEST: TEST(duts); break; case RUN_ACTION.SAVE_CAL: { SAVE_CAL(duts); } break; case RUN_ACTION.SET_DN_SN: { if(duts.Count() > 1) { throw new InvalidDataException($"Error support only a single device for setting DN and SN \n{GetArgHelpMessage(true, args)}"); } SET_DN_SN(duts.First(), inputs.DN_mm.Value, inputs.sensor_sn.Value); int wait_ms = 15000; Console.WriteLine($"Wait {wait_ms/1000} for device to reset after a possible DN change"); Task.Delay(15000).GetAwaiter().GetResult(); } break; case RUN_ACTION.LOAD_CAL: { LOAD_CAL(duts, inputs.loadedCalibrations); } break; case RUN_ACTION.ABORT_CAL: { ABORT_CAL(duts); } break; default: { throw new NotImplementedException($"Missing support run mode {run_task}"); } } Console.WriteLine("finished functional testing"); // Is set to true when the monitoring values also needs to stop bool exitMonitoringLoop = false, pauseMonitoringLoop = false, _LastPauseMonitoringLoop = false; // Start a task for monitoring a key for exit Console.WriteLine("Press key 'x' exit, 'p' for pause read, 'c' continue read"); Task.Run(() => { ConsoleKeyInfo keyinfo; do { keyinfo = Console.ReadKey(); if (keyinfo.Key == ConsoleKey.P) { pauseMonitoringLoop = true; } else if (keyinfo.Key == ConsoleKey.C) { pauseMonitoringLoop = false; } else { Console.WriteLine($"\n{keyinfo.Key} was pressed. Press key 'x' exit"); } } while (keyinfo.Key != ConsoleKey.X); exitMonitoringLoop = true; }); // Just read flow and other values for testing general measurement int count = 0; // "Structure of an interpolated string" // https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated while (!exitMonitoringLoop) { if (!pauseMonitoringLoop) { var message = "\r"; var dutNum = 1; foreach (var dut in duts) { { // Read Flow var isOkay = dut.GetFlowRate_lps(out var value_out); if (dutNum > 1) { message += " | "; } message += $"DUT{dutNum++}: "; if (!dut.GetDeviceHealthy()) { message += $"Error:"; if (dut.GetDeviceErrorMessages(out var errorList)) { message += $"{errorList.ToSingleString(false)} "; } else { message += $"No Text to display!"; } } else { const int w = 9; message += $"{(isOkay ? $"{value_out*3.6,w:F3} m3/h" : $"!Read failed!")} {dut.GetComCounters()}\t"; if (!isOkay) { throw new Exception(message); } } } } Console.Write(message + $" msg={++count}\t"); } { // Print out if paused read if (_LastPauseMonitoringLoop != pauseMonitoringLoop) { _LastPauseMonitoringLoop = pauseMonitoringLoop; if (pauseMonitoringLoop) { Console.Write("\rRead is Paused!\t\t\t\t\t\t\t\t"); } } } } } catch (Exception ex) { var name_exe = System.AppDomain.CurrentDomain.FriendlyName; AppConst.Logger.AddFuncLog(true, name_exe, "main()", ex); AppConst.Logger.OpenProgramLogFile(); ret_error = -1; //https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes } finally { // Close connection before exit try { if (duts.Count != 0) { foreach (var dut in duts) { dut.CloseConnection(); } } } catch { } Environment.Exit(ret_error); //https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes } } } }