using Aitex.Core.Common.DeviceData; using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Device; using Aitex.Core.RT.Log; using Aitex.Core.RT.OperationCenter; using Aitex.Core.RT.SCCore; using Aitex.Core.RT.Tolerance; using Aitex.Core.UI.Control; using Aitex.Core.Util; using CommunityToolkit.HighPerformance.Buffers; using MECF.Framework.Common.Communications; using MECF.Framework.Common.DataCenter; using MECF.Framework.Common.Device.Bases; using MECF.Framework.Common.Equipment; using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.ServiceModel.Channels; using Venus_Core; namespace Venus_RT.Devices { public class TruPlasmaRF : RfPowerBase { private readonly AsyncSerialPort _serial; private List buffer = new List(4096); public TruPlasmaRF(ModuleName mod, VenusDevice device) : base(mod.ToString(), device.ToString()) { this.Status = GeneratorStatus.Unknown; var portNum = SC.GetStringValue(device == VenusDevice.Rf ? $"{mod}.Rf.Port" : $"{mod}.BiasRf.Port"); _serial = new AsyncSerialPort(portNum, 9600, 8, System.IO.Ports.Parity.None, System.IO.Ports.StopBits.One, "/r", false); } public override bool Initialize() { base.Initialize(); DATA.Subscribe($"{Module}.{Name}.DeviceData", () => DeviceData); if (_serial.Open()) { _serial.OnBinaryDataChanged += SerialPortDataReceived; _serial.OnErrorHappened += SerialPortErrorOccurred; ResetCommand(); getcontrol(); SetPulseMode(false); } else { LOG.Write(eEvent.ERR_RF, Module, "Tru 射频发生器串口无法打开"); return false; } return true; } public new AITRfData DeviceData => new AITRfData { Module = Module, DeviceName = Name, ScalePower = ScalePower, ForwardPower = ForwardPower, ReflectPower = ReflectPower, IsRfOn = IsPowerOn, PowerSetPoint = PowerSetPoint, }; private void SerialPortDataReceived(byte[] rawMessage) { try { buffer.AddRange(rawMessage); while (buffer.Count >= 18) //至少包含ACK帧头(1字节)、长度、校验位(17或12字节) { //2.1 查找数据头 if (buffer[0] == 0x06) //传输数据有帧头,用于判断 { //得到完整的数据,复制到ReceiveBytes中进行校验 byte[] ReceiveBytes = new byte[13]; byte[] ReadReceiveBytes = new byte[18]; buffer.CopyTo(0, ReceiveBytes, 0, 13); buffer.CopyTo(0, ReadReceiveBytes, 0, 18); if ((ReceiveBytes[12] == 0x55) && (ReceiveBytes[1] == 0xAA)) //校验,最后一个字节是校验位 { parsecmd(ReceiveBytes); buffer.RemoveRange(0, 13); } else if ((ReadReceiveBytes[17] == 0x55) && (ReceiveBytes[1] == 0xAA)) { parsecmd(ReadReceiveBytes); buffer.RemoveRange(0, 18); } else { buffer.Clear(); LOG.Write(eEvent.ERR_RF, Module, $"rf通讯错误"); } } else //帧头不正确时,记得清除 { //buffer.RemoveAt(0); } } } catch (Exception ex) { buffer.Clear(); LOG.WriteExeption(ex); } } public GeneratorStatus Status { get; set; } private float _forwardPower; public override float ForwardPower { get { return _forwardPower; } set { _forwardPower = CalibrationData(value, false); } } private bool GetBitValue(byte value, int bit) { return (value & (byte)Math.Pow(2, bit)) > 0 ? true : false; } public override bool ReConnect() { return _serial.ReConnect(); } public override bool IsPowerOn { get => Status == GeneratorStatus.ON; set { } } public void parsecmd(byte[] message) { try { IsPowerOn = GetBitValue(message[4], 4); if (GetBitValue(message[4], 4)) { Status = GeneratorStatus.ON; } else { Status = GeneratorStatus.OFF; } switch (message[5]) { case 0x01://ParamRead if (message.Length == 18 && message[6] == 0x14) { int DataValue = BitConverter.ToInt32(new byte[] { message[11], message[12], message[13], message[14] }, 0); ReflectPower = DataValue; } else if (message.Length == 18 && message[6] == 0x12) { int DataValue1 = BitConverter.ToInt32(new byte[] { message[11], message[12], message[13], message[14] }, 0); ForwardPower = DataValue1; } break; case 0x02://ParamWrite break; case 0xFE://TelegramError LOG.Write(eEvent.ERR_RF, Module, "Telegram structure is not correct"); break; default: // 默认代码块 break; } switch (message[9]) { case 0x26: Status = GeneratorStatus.OFF; IsPowerOn = false; break; case 0x24: LOG.Write(eEvent.ERR_RF, Module, "Telegram structure is not correct"); break; default: // 默认代码块 break; } } catch (Exception ex) { LOG.WriteExeption(ex); } } private void SerialPortErrorOccurred(string obj) { LOG.Write(eEvent.ERR_RF, Module, $"Tru 射频串口出错, [{obj}]"); } public override void SetPower(float val) { List baseBytes = new List() { 0xAA, 0x02, 0x0B, 0x00, 0x02, 0x06, 0x00, 0x01, 0x00, 0x04 }; byte[] valueBytes = BitConverter.GetBytes((int)val); baseBytes.AddRange(valueBytes); baseBytes = CRC16(baseBytes.ToArray()); baseBytes.Add(0x55); _serial.Write(baseBytes.ToArray()); } public override void Monitor() { readpi(); readpr(); } public void getcontrol() { byte[] getincontrol = new byte[] { 0xAA, 0x02, 0x06, 0x00, 0x05, 0x01, 0x00, 0x00, 0xFF, 0x34, 0x8A, 0x55 }; _serial.Write(getincontrol.ToArray()); } public void releasecontrol() { byte[] getincontrol = new byte[] { 0xAA, 0x02, 0x06, 0x00, 0x05, 0x02, 0x00, 0x00, 0xFF, 0xE8, 0x11, 0x55 }; _serial.Write(getincontrol.ToArray()); } public void readpr()//reflect { byte[] getincontrol = new byte[] { 0xAA, 0x02, 0x06, 0x00, 0x01, 0x14, 0x00, 0x01, 0xFF, 0xE1, 0x97, 0x55 }; _serial.Write(getincontrol.ToArray()); } public void readpi()//forward { byte[] getincontrola = new byte[] { 0xAA, 0x02, 0x06, 0x00, 0x01, 0x12, 0x00, 0x01, 0xFF, 0x78, 0xB0, 0x55 }; _serial.Write(getincontrola.ToArray()); } public void ResetCommand() { LOG.Write(eEvent.ERR_RF, Module, $"Send rest"); byte[] getincontrol = new byte[] { 0xAA, 0x02, 0x0B, 0x00, 0x02, 0x4D, 0x00, 0x01, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x30, 0x72, 0x55 }; _serial.Write(getincontrol.ToArray()); } public override void Reset() { byte[] getincontrol = new byte[] { 0xAA, 0x02, 0x0B, 0x00, 0x02, 0x4D, 0x00, 0x01, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x30, 0x72, 0x55 }; _serial.Write(getincontrol.ToArray()); } public override bool SetPowerOnOff(bool on, out string str) { str = ""; var _chamber = DEVICE.GetDevice(Module); if (on && !_chamber.CheckGeneratorAndHVInterlock(VenusDevice.Rf)) { return false; } getcontrol(); List baseBytes = new List() { 0xAA, 0x02, 0x0B, 0x00, 0x02, 0x6F, 0x00, 0x01, 0x00, 0x07 }; if (on == true) { baseBytes.AddRange(new List { 0x01, 0x00, 0x00, 0x00 }); } else { baseBytes.AddRange(new List { 0x00, 0x00, 0x00, 0x00 }); } baseBytes = CRC16(baseBytes.ToArray()); baseBytes.Add(0x55); _serial.Write(baseBytes.ToArray()); if (on == false) { releasecontrol(); } return true; } public override void SetPulseMode(bool on) { List baseBytes = new List() { 0xAA, 0x02, 0x0B, 0x00, 0x02, 0x6A, 0x01, 0x01, 0x00, 0x04 }; if (on == true) { baseBytes.AddRange(new List { 0x01, 0x00, 0x00, 0x00 }); } else { baseBytes.AddRange(new List { 0x00, 0x00, 0x00, 0x00 }); } baseBytes = CRC16(baseBytes.ToArray()); baseBytes.Add(0x55); _serial.Write(baseBytes.ToArray()); } public override void SetPulseRateFreq(int nFreq) { if (nFreq > 0) { List baseBytes = new List() { 0xAA, 0x02, 0x0B, 0x00, 0x02, 0x6C, 0x01, 0x01, 0x00, 0x04 }; byte[] valueBytes = BitConverter.GetBytes(nFreq); baseBytes.AddRange(valueBytes); baseBytes = CRC16(baseBytes.ToArray()); baseBytes.Add(0x55); _serial.Write(baseBytes.ToArray()); } else { LOG.Write(eEvent.ERR_RF, Module, $"{Name},SetPulseRateFreq() parameter error: {nFreq}"); } } public override void SetPulseDutyCycle(int percentage) { if (percentage >= 10 && percentage <= 90) { List baseBytes = new List() { 0xAA, 0x02, 0x0B, 0x00, 0x02, 0x6D, 0x01, 0x01, 0x00, 0x04 }; byte[] valueBytes = BitConverter.GetBytes(percentage); baseBytes.AddRange(valueBytes); baseBytes = CRC16(baseBytes.ToArray()); baseBytes.Add(0x55); _serial.Write(baseBytes.ToArray()); } else { LOG.Write(eEvent.ERR_RF, Module, $"{Name},SetPulseDutyCycle() parameter error: {percentage}"); } } #region 霍廷格RF协议crc-16/CCITT-FALSE校验 private bool CRC16(byte[] buffer, ref byte[] ResCRC16) // crc-16/CCITT-FALSE,判断校验 { bool status = false; ushort crc = 0xFFFF; int size = buffer.Length; //计算待计算的数据长度 int i = 0; if (size > 0) { while (size-- > 0) { crc = (ushort)((crc >> 8) | (crc << 8)); crc ^= buffer[i++]; crc ^= (ushort)(((byte)crc) >> 4); crc ^= (ushort)(crc << 12); crc ^= (ushort)((crc & 0xff) << 5); } } //判断输入的ResCRC16与计算出来的是否一致 if (ResCRC16[0] == (byte)((crc >> 8) & 0xff) && ResCRC16[1] == (byte)(crc & 0xff)) { status = true; } return status; } private List CRC16(byte[] buffer) // crc-16/CCITT-FALSE,补全两个字节 { ushort crc = 0xFFFF; int size = buffer.Length; //计算待计算的数据长度 int i = 0; if (size > 0) { while (size-- > 0) { crc = (ushort)((crc >> 8) | (crc << 8)); crc ^= buffer[i++]; crc ^= (ushort)(((byte)crc) >> 4); crc ^= (ushort)(crc << 12); crc ^= (ushort)((crc & 0xff) << 5); } } var byteList = buffer.ToList(); byteList.Add((byte)(crc & 0xff)); byteList.Add((byte)((crc >> 8) & 0xff)); return byteList; } #endregion } class TruPlasmaMatch : RfMatchBase { private readonly AsyncSerialPort _serial; private const ushort S3_HEAD_LENGTH = 2; private readonly DeviceTimer _timerQueryStatus = new DeviceTimer(); private int QUERY_INTERVAL = 1000; private List buffer = new List(4096); [Subscription("MatchWorkMode")] public EnumRfMatchTuneMode WorkMode { get; set; } public float C1 { get; set; } public float C2 { get; set; } //[Subscription("VPP")] public ushort VPP { get; set; } public new AITMatchData DeviceData { get { return new AITMatchData { Module = Module, DeviceName = Name, WorkMode = WorkMode.ToString(), C1 = TunePosition1, C2 = TunePosition2, VPP = "", DCBias = DCBias.ToString() }; } } public TruPlasmaMatch(ModuleName mod, VenusDevice device) : base(mod.ToString(), device.ToString()) { var portNum = SC.GetStringValue($"{mod}.{device}.Port"); _serial = new AsyncSerialPort(portNum, 9600, 8, System.IO.Ports.Parity.None, System.IO.Ports.StopBits.One, "/r", false); intervalTime = 100; } ~TruPlasmaMatch() { _serial?.Close(); } public override bool Initialize() { base.Initialize(); preset(50,50); if (_serial.Open()) { _serial.OnBinaryDataChanged += SerialBinaryPortDataReceived; _serial.OnErrorHappened += SerialPortErrorOccurred; } else { LOG.Write(eEvent.ERR_RF, Module, "Match 串口无法打开"); return false; } DATA.Subscribe($"{Module}.{Name}.C1", () => TunePosition1); DATA.Subscribe($"{Module}.{Name}.C2", () => TunePosition2); DATA.Subscribe($"{Module}.{Name}.WorkMode", () => WorkMode.ToString()); OP.Subscribe($"{Module}.{Name}.SetC1", (func, args) => { return true; }); OP.Subscribe($"{Module}.{Name}.SetC2", (func, args) => { return true; }); OP.Subscribe($"{Module}.{Name}.{AITRfOperation.SetMatchPositionC1}", (out string reason, int time, object[] param) => { SetMatchPositionC1((float)Convert.ToDouble(param[0]), out reason); return true; }); OP.Subscribe($"{Module}.{Name}.{AITRfOperation.SetMatchPositionC2}", (out string reason, int time, object[] param) => { SetMatchPositionC2((float)Convert.ToDouble(param[0]), out reason); return true; }); OP.Subscribe($"{Module}.{Name}.{AITRfOperation.SetMatchPosition}", (out string reason, int time, object[] param) => { SetMatchPosition((float)Convert.ToDouble(param[0]), (float)Convert.ToDouble(param[1]), out reason); return true; }); OP.Subscribe($"{Module}.{Name}.{AITRfOperation.SetMatchProcessMode}", (out string reason, int time, object[] param) => { SetMatchMode((string)param[0] == "Auto" ? EnumRfMatchTuneMode.Auto : EnumRfMatchTuneMode.Manual, out reason); return true; }); return true; } public void readc1() { byte[] readc1 = new byte[] { 0x0C, 0xF3, 0x00, 0x02, 0x00, 0x01, 0x61, 0x42, 0x79, 0x18, 0x01, 0x37 }; _serial.Write(readc1.ToArray()); } public void readc2() { byte[] readc1 = new byte[] { 0x0C, 0xF3, 0x00, 0x02, 0x00, 0x01, 0x61, 0x42, 0x79, 0x19, 0x01, 0x38 }; _serial.Write(readc1.ToArray()); } public override void Monitor() { //ReadPosition(50,50);//0x10 (present mode)CMD 可实现任意模式下只读不设值,0x08(auto then manual)在auto模式下可实现相同功能 readc1(); readc2(); } public override void Terminate() { } public override void Reset() { preset(50, 50); } /// /// /// /// 百分比数字 /// /// private void executeMatchPostion(float c1, float c2) { SetPositionManualAuto(c1, c2); } public override void SetMatchPosition(float c1, float c2, out string reason) { executeMatchPostion(c1, c2); reason = ""; } public void SetPresetMode(RfMatchPresetMode mode) { } // -----------------------Private Method------------------------- // private void SerialBinaryPortDataReceived(byte[] message) { if (message.Count() < 18) { string hexString = BitConverter.ToString(message.ToArray()).Replace("-", " "); //LOG.Write(eEvent.ERR_MATCH, Module, hexString); //LOG.Write(eEvent.ERR_RF, Module, "收到 Match 数据格式不正确"); } else { try { buffer.AddRange(message); while (buffer.Count >= 18) //至少包含帧头(1字节)、长度(1字节)、其余27字节 { //2.1 查找数据头 if (buffer[0] == 0x1D && buffer[1] == 0xE2) //传输数据有帧头,用于判断 { //得到完整的数据,复制到ReceiveBytes中进行校验 byte[] ReceiveBytes = new byte[29]; buffer.CopyTo(0, ReceiveBytes, 0, 29); TunePosition1 = BitConverter.ToSingle(new byte[] { ReceiveBytes[10], ReceiveBytes[11], ReceiveBytes[12], ReceiveBytes[13] }, 0) * 100; TunePosition2 = BitConverter.ToSingle(new byte[] { ReceiveBytes[14], ReceiveBytes[15], ReceiveBytes[16], ReceiveBytes[17] }, 0) * 100; buffer.RemoveRange(0, 29); switch (ReceiveBytes[19]) { case 0x01: this.WorkMode = EnumRfMatchTuneMode.Manual; break; case 0x02: this.WorkMode = EnumRfMatchTuneMode.Auto; break; case 0x20: this.WorkMode = EnumRfMatchTuneMode.Undefined; break; default: break; } } else if (buffer[0] == 0x12 && buffer[1] == 0xED) { byte[] ReceiveBytes18 = new byte[18]; buffer.CopyTo(0, ReceiveBytes18, 0, 18); if (ReceiveBytes18[10] == 0x79 && ReceiveBytes18[11] == 0x18) { TunePosition1 = BitConverter.ToSingle(new byte[] { ReceiveBytes18[12], ReceiveBytes18[13], ReceiveBytes18[14], ReceiveBytes18[15] }, 0) * 100; }else if (ReceiveBytes18[10] == 0x79 && ReceiveBytes18[11] == 0x19) { TunePosition2 = BitConverter.ToSingle(new byte[] { ReceiveBytes18[12], ReceiveBytes18[13], ReceiveBytes18[14], ReceiveBytes18[15] }, 0) * 100; } buffer.RemoveRange(0, 18); } else //帧头不正确时,记得清除 { buffer.Clear(); LOG.Write(eEvent.ERR_MATCH, Module, $"Match通讯错误"); } } } catch (Exception ex) { buffer.Clear(); LOG.WriteExeption(ex); } } } private void SerialPortErrorOccurred(string str) { LOG.Write(eEvent.ERR_RF, Module, $"AdTec Match error [{str}]"); } private void SetPositionManualAuto(float c1val, float c2val) { List Len = new List() { 0x16, 0xE9 }; List DstSrc = new List() { 0x00, 0x02, 0x00, 0x01 }; List Cmd = new List { 0x60, 0x40 }; byte[] val1Bytes = BitConverter.GetBytes(c1val / 100); byte[] val2Bytes = BitConverter.GetBytes(c2val / 100); List Act = new List() { 0x00 }; List Ctr123 = new List { 0x08, 0x00, 0x00 }; List baseBytes = new List() { }; baseBytes.AddRange(Len); baseBytes.AddRange(DstSrc); baseBytes.AddRange(Cmd); baseBytes.AddRange(val1Bytes); baseBytes.AddRange(val2Bytes); baseBytes.AddRange(Act); baseBytes.AddRange(Ctr123); int a = 0; for (int i = 2; i < baseBytes.Count; i++) { a += (Int16)baseBytes[i]; } byte[] ackture = new byte[2]; byte[] ackbyte = BitConverter.GetBytes(a); ackture[0] = ackbyte[1]; ackture[1] = ackbyte[0]; baseBytes.AddRange(ackture); _serial.Write(baseBytes.ToArray()); } private void preset(float c1val, float c2val) { List Len = new List() { 0x16, 0xE9 }; List DstSrc = new List() { 0x00, 0x02, 0x00, 0x01 }; List Cmd = new List { 0x60, 0x40 }; byte[] val1Bytes = BitConverter.GetBytes(c1val / 100); byte[] val2Bytes = BitConverter.GetBytes(c2val / 100); List Act = new List() { 0x00 }; List Ctr123 = new List { 0x04, 0x10, 0x80 }; List baseBytes = new List() { }; baseBytes.AddRange(Len); baseBytes.AddRange(DstSrc); baseBytes.AddRange(Cmd); baseBytes.AddRange(val1Bytes); baseBytes.AddRange(val2Bytes); baseBytes.AddRange(Act); baseBytes.AddRange(Ctr123); int a = 0; for (int i = 2; i < baseBytes.Count; i++) { a += (Int16)baseBytes[i]; } byte[] ackture = new byte[2]; byte[] ackbyte = BitConverter.GetBytes(a); ackture[0] = ackbyte[1]; ackture[1] = ackbyte[0]; baseBytes.AddRange(ackture); _serial.Write(baseBytes.ToArray()); } public override bool SetMatchMode(EnumRfMatchTuneMode enumRfMatchTuneMode, out string reason) { reason = string.Empty; return true; } public override bool ReConnect() { return _serial.ReConnect(); } private void SetWorkMode(EnumRfMatchTuneMode mode) { } private void SetPresetMemory(byte gear) { } } }