385 lines
12 KiB
C#
385 lines
12 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using ChamChat.Models;
|
|
|
|
namespace ChamChat
|
|
{
|
|
public partial class PLxKPH_Client : Client
|
|
{
|
|
private const Int32 _OptionRange = 2000;
|
|
private const int _RAM = 1;
|
|
private const Int32 _ReturnDataWaitms = 300; // Time out for client to prepare and return data
|
|
private DateTime _ReadyToSend = DateTime.Now; // Timestamp when client is ready to communicate
|
|
|
|
|
|
public PLxKPH_Client(Int32 MIDS, ClientType Type)
|
|
: base(MIDS, Type)
|
|
{
|
|
|
|
// Set options available in client
|
|
_Parameters = new List<Parameter>();
|
|
_Parameters.Add(Parameter.T);
|
|
_Parameters.Add(Parameter.RH);
|
|
_Parameters.Add(Parameter.RampT);
|
|
_Parameters.Add(Parameter.RampRH);
|
|
|
|
|
|
// Add option range
|
|
_ClientOptions = new List<ProfileOption>();
|
|
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<int>();
|
|
for (int i = 1; i < 21; i++)
|
|
_AvailableRAMs.Add(i);
|
|
|
|
_InterfaceType = InterfaceType.FDTI_USB_COM422;
|
|
}
|
|
|
|
|
|
|
|
|
|
// To do
|
|
public override Profile ReadProfile(int RAM, ref System.ComponentModel.BackgroundWorker bgw)
|
|
{
|
|
Profile profile = new Profile();
|
|
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 title = profile.Title.Substring(0, (int)Math.Min(14, profile.Title.Length)).Trim();
|
|
|
|
string sRAM = string.Format("{0:0}", RAM);
|
|
|
|
string sAddr = _Address.ToString();
|
|
string cmd;
|
|
string read;
|
|
string cmd_pre = sAddr + ", PRGM DATA WRITE, PGM" + sRAM + ", ";
|
|
|
|
|
|
|
|
// Cancel RAM program editing
|
|
cmd = cmd_pre + "EDIT CANCEL";
|
|
DataTransfer(cmd, out read, _ReturnDataWaitms,1);
|
|
if( !read.Contains("ERR-3"))
|
|
DataTransfer(cmd, out read, _ReturnDataWaitms, 3);
|
|
|
|
|
|
|
|
// Open RAM program
|
|
cmd = cmd_pre + "EDIT START";
|
|
DataTransfer(cmd,out read, _ReturnDataWaitms);
|
|
|
|
|
|
// Steps
|
|
try
|
|
{
|
|
for (int i = 0; i < profile.Steps.Count; i++)
|
|
{
|
|
Step step = profile.Steps[i];
|
|
cmd = cmd_pre;
|
|
cmd += String.Format("STEP{0:0}, ", i + 1);
|
|
cmd += String.Format("TEMP{0:0.0}, ", step.T);
|
|
cmd += step.RampCtrlT ? "TRAMPON, " : "TRAMPOFF, ";
|
|
cmd += step.HasRH ? String.Format("HUMI{0:0}, ", step.RH) : "HUMI OFF, ";
|
|
cmd += step.RampCtrlRH ? "HRAMPON, " : "HRAMPOFF, ";
|
|
cmd += String.Format("TIME{0:00}:{1:00}, ", step.Hours, step.Minutes);
|
|
cmd += "GRANTY OFF, ";
|
|
cmd += "PAUSE OFF";
|
|
DataTransfer(cmd, out read, _ReturnDataWaitms);
|
|
}
|
|
}
|
|
catch (Exception ex) { throw new Exception("writing steps - " + ex.Message); }
|
|
|
|
|
|
try
|
|
{
|
|
|
|
// Loops
|
|
if (profile.Loops.Count > 0)
|
|
{
|
|
Loop loop = profile.Loops[0];
|
|
cmd = cmd_pre;
|
|
cmd += String.Format("COUNT, A({0}.{1}.{2})", loop.N - 1, loop.Last + 1, loop.First + 1);
|
|
|
|
if (profile.Loops.Count > 1)
|
|
{
|
|
loop = profile.Loops[1];
|
|
cmd += String.Format(", B({0}.{1}.{2})", loop.N - 1, loop.Last + 1, loop.First + 1);
|
|
}
|
|
DataTransfer(cmd, out read, _ReturnDataWaitms);
|
|
}
|
|
}
|
|
catch (Exception ex) { throw new Exception("writing loops - " + ex.Message); }
|
|
|
|
|
|
|
|
// End mode
|
|
try
|
|
{
|
|
cmd = profile.Options.Contains(ProfileOption.PLxKPH_EndModeHold) ? cmd_pre + "END, HOLD" : cmd_pre + "END, OFF";
|
|
DataTransfer(cmd, out read, _ReturnDataWaitms);
|
|
}
|
|
catch (Exception ex) { throw new Exception("writing end mode - " + ex.Message); }
|
|
|
|
|
|
|
|
// Name of program
|
|
cmd = cmd_pre + "NAME, " + title;
|
|
DataTransfer(cmd, out read, _ReturnDataWaitms);
|
|
|
|
|
|
// Close and save RAM program
|
|
cmd = cmd_pre + "EDIT END";
|
|
DataTransfer(cmd, out read, _ReturnDataWaitms);
|
|
|
|
// Wait 3 seconds to close program
|
|
System.Threading.Thread.Sleep(3000);
|
|
|
|
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
|
|
// number of profile steps 99
|
|
// number of loops < 3
|
|
// -40 < t < 150
|
|
|
|
if(profile.Steps.Count > 99)
|
|
return false;
|
|
|
|
if (profile.Loops.Count > 2)
|
|
return false;
|
|
|
|
foreach (Loop loop in profile.Loops)
|
|
if (loop.N > 99 || loop.N < 2)
|
|
return false;
|
|
|
|
foreach (Step step in profile.Steps)
|
|
{
|
|
if (step.T < -40 || step.T > 150)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
public override Boolean HasAlarm(out List<Alarm> alarms)
|
|
{
|
|
alarms = new List<Alarm>();
|
|
return true;
|
|
}
|
|
|
|
|
|
public override Boolean IsIdle()
|
|
{
|
|
// IsIdle() returns true if status of chamber is 'Standby'. See page 36 MODE?.
|
|
|
|
string sAddr = _Address.ToString();
|
|
string cmd;
|
|
string read;
|
|
|
|
cmd = sAddr + ", MODE?";
|
|
DataTransfer(cmd,out read, _ReturnDataWaitms);
|
|
|
|
if (read.Contains("STANDBY"))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
public override Boolean Start()
|
|
{
|
|
if (_Profile == null)
|
|
return false;
|
|
|
|
string sAddr = _Address.ToString();
|
|
string cmd;
|
|
string read;
|
|
|
|
cmd = sAddr + ", PRGM, RUN, RAM:" + _RAM+", STEP1"; // See page 56
|
|
|
|
return DataTransfer(cmd,out read, _ReturnDataWaitms);
|
|
}
|
|
|
|
|
|
public override Boolean IsFinished()
|
|
{
|
|
// Finished() returns true if chamber is not running. See page 36 MODE?.
|
|
string sAddr = _Address.ToString();
|
|
string cmd;
|
|
string read;
|
|
|
|
cmd = sAddr + ", MON?";
|
|
DataTransfer(cmd, out read, _ReturnDataWaitms);
|
|
|
|
try
|
|
{
|
|
double t = Double.Parse(read.Split(',')[0]);
|
|
double RH = Double.Parse(read.Split(',')[1]);
|
|
_Progress = String.Format("Current conditions are {0:0.0} °C and {1:0} %rh", t, RH);
|
|
_LastProgressUpdate = DateTime.Now;
|
|
}
|
|
catch { _Progress = DateTime.Now.ToString("yyyy-MM-dd @ hh:mm"); }
|
|
|
|
|
|
if (read.Contains("STANDBY"))
|
|
return true;
|
|
|
|
if (read.Contains("OFF"))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
public override Boolean Stop()
|
|
{
|
|
string sAddr = _Address.ToString();
|
|
string cmd;
|
|
string read;
|
|
cmd = sAddr + ", MODE, STANDBY";
|
|
return DataTransfer(cmd, out read, _ReturnDataWaitms);
|
|
}
|
|
|
|
|
|
public override Boolean IsOnline()
|
|
{
|
|
try
|
|
{
|
|
string sAddr = _Address.ToString();
|
|
string cmd;
|
|
string read;
|
|
cmd = sAddr + ", TYPE?";
|
|
DataTransfer(cmd, out read, _ReturnDataWaitms);
|
|
return (read.ToLower().Contains("scp220") );
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private string _Progress = "";
|
|
private DateTime _LastProgressUpdate = DateTime.Now;
|
|
public override String Progress()
|
|
{
|
|
if(_LastProgressUpdate.AddMinutes(3) < DateTime.Now)
|
|
IsFinished();
|
|
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().StartsWith("OK:"))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
private Boolean DataTransfer(string cmd, out string read, int ReturnDataWaitms)
|
|
{
|
|
// If no maximum number of attempts is given, it defaults to 4.
|
|
return DataTransfer(cmd, out read, ReturnDataWaitms,4);
|
|
}
|
|
|
|
|
|
|
|
// 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 1 seconds
|
|
DateTime go = DateTime.Now.AddSeconds(1);
|
|
while (DateTime.Now < _ReadyToSend && DateTime.Now < go)
|
|
System.Threading.Thread.Sleep(10);
|
|
|
|
read = "";
|
|
bool success = false;
|
|
int attempt = 0;
|
|
while (!success && attempt < MaxNumOfAttempts)
|
|
{
|
|
DataTransferLog log = _Interface.DataTransfer(cmd, out read, ReturnDataWaitms);
|
|
success = TxRxSucces(cmd, read);
|
|
attempt++;
|
|
|
|
// Mask for showing in GUI
|
|
if (cmd.Contains("MON?") || cmd.Contains("EDIT CANCEL") || cmd.Contains("EDITCANCEL"))
|
|
log.ShowInGUI = false;
|
|
|
|
|
|
// Notify user via GUI of failed attempts
|
|
if (attempt > 1)
|
|
log.Command += string.Format(" [Attempt {0:0}]", attempt);
|
|
|
|
// Add to logs
|
|
AppendDataTransferLog(log);
|
|
|
|
|
|
// Set _ReadyToSend acc. manual specs
|
|
if (cmd.Contains("?"))
|
|
_ReadyToSend = DateTime.Now.AddMilliseconds(500);
|
|
else
|
|
_ReadyToSend = DateTime.Now.AddMilliseconds(1200);
|
|
|
|
|
|
// Sleeps
|
|
if (!success)
|
|
System.Threading.Thread.Sleep(5000); // Sleep 5 seconds before resending if failed
|
|
}
|
|
return success;
|
|
}
|
|
}
|
|
}
|