using System; using System.Collections.Generic; using System.Linq; using System.Text; using ChamChat.Models; namespace ChamChat { public partial class LHL113_Client : Client { private const Int32 _OptionRange = 3000; private const Int32 _DataTransferTimeOut = 1000; private DateTime _ReadyToSend = DateTime.Now; // Timestamp when client is ready to communicate private const int _RAM = 1; private DateTime _dtTestStart = DateTime.Now; // To do public LHL113_Client(Int32 MIDS, ClientType Type) : base(MIDS, Type) { // Set options available in client _Parameters = new List(); _Parameters.Add(Parameter.T); _Parameters.Add(Parameter.RH); _Parameters.Add(Parameter.RampT); _Parameters.Add(Parameter.RampRH); // Add option range _ClientOptions = new List(); foreach (ProfileOption o in Enum.GetValues(typeof(ProfileOption))) if ((int)o >= _OptionRange && (int)o < _OptionRange+999) _ClientOptions.Add(o); // Set availabel addresses for programming _AvailableRAMs = new List(); for (int i = 1; i < 31; i++) _AvailableRAMs.Add(i); _InterfaceType = InterfaceType.FDTI_USB_COM422; } // To do public override Profile ReadProfile(int RAM, ref System.ComponentModel.BackgroundWorker bgw) { string sAddr = _Address.ToString(); string cmd; string read; Profile profile = new Profile(); try { // Communicate with client cmd = sAddr + ",PRGMREAD,"; DataTransfer(cmd, out read, _DataTransferTimeOut); List steps = new List(); List loops = new List(); List options = new List(); String name = "LHL113_Client"; // Create profile profile = new Profile(name, steps, loops, options); } catch { } return profile; } public override Boolean WriteProfile(Profile profile) { return WriteProfile(profile, _RAM); } public override Boolean WriteProfile(Profile profile, int RAM) { // Only stand alone profiles allowed! if (!IsProgrammable(profile)) return false; string sRAM = String.Format("{0:0}", RAM); string sCmdStart = _Address.ToString() + ", PRGM DATA WRITE, PGM:" + sRAM + ", "; string cmd; string read; // Set to STANDBY if OFF cmd = _Address.ToString() + ", MODE?"; DataTransfer(cmd, out read, _DataTransferTimeOut); if (read.Contains("OFF")) { cmd = _Address.ToString() + ", MODE, STANDBY"; DataTransfer(cmd, out read, _DataTransferTimeOut); } // Communicate with client (page 49) cmd = sCmdStart + "EDIT START"; DataTransfer(cmd, out read, _DataTransferTimeOut); for (int i = 0; i < profile.SerializedStepList.Count; i++) { Step step = profile.SerializedStepList[i]; cmd = sCmdStart; cmd += string.Format("STEP{0:0}, ", i + 1); cmd += string.Format("TEMP{0:00.0}, ", step.T); if (step.RampCtrlT) cmd += "TRAMPON,"; else cmd += "TRAMPOFF,"; cmd += string.Format("HUMI{0:00}, ", step.RH); if (step.RampCtrlRH) cmd += "HRAMPON,"; else cmd += "HRAMPOFF,"; if (step.Hours < 100) cmd += string.Format("TIME{0:00}:{1:00}, ", step.Hours, step.Minutes); else cmd += string.Format("TIME{0:00}:00, ", step.Hours); cmd += "GRANTY OFF, "; DataTransfer(cmd, out read, _DataTransferTimeOut); System.Threading.Thread.Sleep(500); } // End options (off is default) if (profile.Options.Contains(ProfileOption.LHL113_EndModeHold)) cmd = sCmdStart + "END, HOLD"; else cmd = sCmdStart + "END, OFF"; DataTransfer(cmd, out read, _DataTransferTimeOut); // Loop (see page 50) if (profile.Loops.Count == 1) { Loop l = profile.Loops[0]; cmd = sCmdStart + String.Format("COUNT, ({0:0}. {1:0}. {2:0})", l.First, l.Last, l.N); DataTransfer(cmd, out read, _DataTransferTimeOut); } cmd = sCmdStart + "EDIT END"; DataTransfer(cmd, out read, _DataTransferTimeOut); Boolean result = false; if (_Interface.InterfaceStatus == null) result = true; _Profile = profile; return result; } public override Boolean IsProgrammable(Profile profile) { // Profile is programmable if all below applies // Step is at least 3 minutes foreach (Step step in profile.Steps) if (step.DurationMin < 3) return false; // Temperature is limited between 30 & 90 °C foreach (Step step in profile.Steps) if (step.T < 30 || step.T > 90) return false; // RH is limited between 60 & 95 °C foreach (Step step in profile.Steps) if (step.RH < 60 || step.RH > 95) return false; // Only one program of a max of 9 steps and a maximum of 99 repeated steps can be stored at a time (page 44 of user's manual). if (profile.Steps.Count > 9) return false; if (profile.Loops.Count == 1) { if (profile.Loops[0].N > 99) return false; } else { if (profile.SerializedStepList.Count > 9) return false; } return true; } // To do public override Boolean HasAlarm(out List alarms) { alarms = new List(); return true; } public override Boolean IsIdle() { // IsIdle() returns true if status of chamber is 'Standby'. See page 31 MODE?. string sAddr = _Address.ToString(); string cmd; string read; cmd = sAddr + ", MODE?"; DataTransfer(cmd, out read, _DataTransferTimeOut); if (read.Contains("STANDBY") || read.Contains("OFF")) return true; return false; } public override Boolean Start() { if (_Profile == null) return false; string sAddr = _Address.ToString(); string cmd; string read; cmd = sAddr + ", MODE, RUN "+_RAM; // See page 47. DataTransfer(cmd, out read, _DataTransferTimeOut); _dtTestStart = DateTime.Now; return TxRxSucces(cmd, read); } public override Boolean IsFinished() { // Finished() returns true if chamber is not running. See page 34 MODE?. string sAddr = _Address.ToString(); string cmd; string read; cmd = sAddr + ", MODE?"; DataTransfer(cmd, out read, _DataTransferTimeOut); if (read.Contains("OFF") || read.Contains("STANDBY")) return true; return false; } public override Boolean Stop() { string sAddr = _Address.ToString(); string cmd; string read; cmd = sAddr + ", MODE, STANDBY"; // Pg. 47 DataTransfer(cmd, out read, _DataTransferTimeOut); return TxRxSucces(cmd, read); } public override Boolean IsOnline() { try { string sAddr = _Address.ToString(); string cmd; string read; cmd = sAddr + ", ROM?"; // Pg. 27 DataTransfer(cmd, out read, _DataTransferTimeOut); return read.ToLower().Contains("jlc"); } catch { return false; } } public override String Progress() { string sAddr = _Address.ToString(); string cmd; string read; //cmd = sAddr + ", MON?"; // See page 31 //DataTransfer(cmd, out read, _DataTransferTimeOut); //Double T = Double.Parse(read.Split(',')[0]); //Double RH = Double.Parse(read.Split(',')[1]); cmd = sAddr + ", PRGM MON?"; // See page 35 DataTransfer(cmd, out read, _DataTransferTimeOut); int step = Int32.Parse(read.Split(',')[1]) - 1; Double Tset = Double.Parse(read.Split(',')[2]); Double RHset = Double.Parse(read.Split(',')[3]); string time = read.Split(',')[4]; int hrs = Int32.Parse(time.Split(':')[0]); int min = Int32.Parse(time.Split(':')[1]); int cyclesLeft = Int32.Parse(read.Split(',')[5]); double stepTimeLeft = hrs * 60 + min; double stepDuration = _Profile.SerializedStepList[step].DurationMin; double stepRuntime = stepDuration - stepTimeLeft; double pStep = Math.Min(100, Math.Floor(stepRuntime / stepDuration * 100)); double testRunTime = (_dtTestStart - DateTime.Now).TotalMinutes; double pTest = Math.Min(100, Math.Floor(testRunTime / _Profile.DurationMin * 100)); double testTimeRemain = _Profile.DurationMin - testRunTime; double testTimeRemainHrs = Math.Floor(testTimeRemain / 60); double testTimeRemainMin = Math.Floor(testTimeRemain - 60 * testTimeRemainHrs); string progress = String.Format("Step #{0:00}/{1:00} progress {2:0}%, ", step + 1, _Profile.SerializedStepList.Count, pStep); progress += String.Format("remaining step time {0:0}h{1:00}m, remaining cycles {2:0}, ",hrs,min, cyclesLeft); progress += String.Format("test progress {0:0}%, remaining test time {1:0}h{2:00}m", pTest, testTimeRemainHrs,testTimeRemainMin); return progress; } private bool TxRxSucces(string cmd, string read) { // Command not correctly processed if (read.StartsWith("NA:")) return false; // No response received if (read.Trim().Length < 1) return false; // Handle monitoring commands if (cmd.Trim().Contains("?")) { return true; } else { if(read.Trim().Contains("OK:")) return true; } return false; } // Performs transfer and adds interface logs to list in Client parent class private Boolean DataTransfer(string cmd, out string read, int ReturnDataWaitms) { // If no maximum number of attempts is given, it defaults to 3. return DataTransfer(cmd, out read, ReturnDataWaitms, 3); } // Performs transfer and adds interface logs to list in Client parent class private Boolean DataTransfer(string cmd, out string read, int ReturnDataWaitms, int MaxNumOfAttempts) { // Construct command to send cmd += (char)13; // CR cmd += (char)10; // LF cmd = cmd.Replace(" ", ""); // Wait for _ReadyToSend or max 2 seconds DateTime go = DateTime.Now.AddSeconds(2); while (DateTime.Now < _ReadyToSend && DateTime.Now < go) System.Threading.Thread.Sleep(10); read = ""; bool success = false; int attempts = 0; while (!success && attempts <= MaxNumOfAttempts) { DataTransferLog log = _Interface.DataTransfer(cmd, out read, ReturnDataWaitms); success = TxRxSucces(cmd, read); attempts++; // Mask for showing in GUI if (cmd.Contains("MODE?") || cmd.Contains("MON?")) log.ShowInGUI = false; // Notify user via GUI of failed attempts if (attempts > 1) log.Command += string.Format(" [Attempt {0:0}]", attempts); // Add to logs AppendDataTransferLog(log); // Set _ReadyToSend acc. manual specs if (cmd.Contains("?")) _ReadyToSend = DateTime.Now.AddMilliseconds(300); else _ReadyToSend = DateTime.Now.AddMilliseconds(1000); // Sleeps if (!success) System.Threading.Thread.Sleep(3000); // Sleep 3 seconds before resending if failed } return success; } } }