Files
newfolder/ChamChat/Client_PLxKPH/Client.PLxKPH.cs
Wesley Hofman 2f1f4199ad first commit
2025-09-18 14:23:18 +02:00

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;
}
}
}