namespace Common.Hardware.SIRT.Tasks { using Common.Hardware.SIRT.Parameters; using System; using System.Collections.Generic; public class WritePamTask : SIRTTask { private event Action AKNReceived; private event Action BUPReceived; private event Action LATReceived; private event Action DEBUGReceived; private event Action SEMIReceived; private event Action UnknownReceived; protected P811 p811; protected bool latReceived; protected bool debugReceived; public WritePamTask() { this.p811 = this.request.P1; this.request.Command = SIRTConstants.W_PAM; this.MessageSent += this.OnMessageSent; this.AKNReceived += this.OnAKNReceived; this.BUPReceived += this.OnBUPReceived; this.LATReceived += this.OnLATReceived; this.DEBUGReceived += this.OnDEBUGReceived; this.SEMIReceived += this.OnSEMIReceived; this.UnknownReceived += this.OnUnknownReceived; this.RequireLAT = true; this.PamStatusIX = 11; this.DebugLength = 52; this.SemiLength = 91; } public event Action MessageSent; public event Action MessageReceived; public bool RequireLAT { get; set; } public bool RequireDEBUG { get; set; } public bool IsEncrypted { get; set; } public byte[] EncryptionKeyI { get; set; } private byte[] encryptionKeyII; public byte[] EncryptionKeyII { get => this.encryptionKeyII; set { this.encryptionKeyII = value; this.IsEncrypted = true; } } public bool WakeUpModul { get => this.p811.WakeUpModul; set => this.SetP811(x => x.WakeUpModul = value); } public bool WakeUpCmd { get => this.p811.WakeUpCmd; set => this.SetP811(x => x.WakeUpCmd = value); } public bool IgnoreTimeout { get => this.p811.IgnoreTimeout; set => this.SetP811(x => x.IgnoreTimeout = value); } public bool DelPamSemi { get => this.p811.DelPamSemi; set => this.SetP811(x => x.DelPamSemi = value); } public bool DelPamTx { get => this.p811.DelPamTx; set => this.SetP811(x => x.DelPamTx = value); } public bool DelPamAdr { get => this.p811.DelPamAdr; set => this.SetP811(x => x.DelPamAdr = value); } public bool DelPamAll { get => this.p811.DelPamAll; set => this.SetP811(x => x.DelPamAll = value); } public byte[] Data { get => this.request.Payload; set => this.request.Payload = value; } public byte DebugLength { get; set; } public byte SemiLength { get; set; } public byte PamStatusIX { get; set; } public bool AnyTelegramReceived { get; set; } public Queue MessageQueue { get; set; } = new Queue(); public override void Receive(SIRTMessage response) { if (this.UseEncryption(response)) { this.DecriptResponse(response); } this.MessageQueue.Enqueue(response); if (response.Command == SIRTConstants.ACKN_ANSW) { this.AKNReceived?.Invoke(response); } else if (response.Command == SIRTConstants.FROM_AIR) { var payload = response?.Payload; if (payload != null && payload.Length > 0) { var type = payload[0]; if (type == SIRTConstants.BUP) { this.AnyTelegramReceived = true; this.BUPReceived?.Invoke(response); } else if (type == SIRTConstants.LAT) { this.latReceived = true; this.AnyTelegramReceived = true; this.LATReceived?.Invoke(response); } else if (type == SIRTConstants.DEBUG) { this.debugReceived = true; this.AnyTelegramReceived = true; this.DEBUGReceived?.Invoke(response); } else if (type == SIRTConstants.SEMI) { this.AnyTelegramReceived = true; this.SEMIReceived?.Invoke(response); } else { this.UnknownReceived?.Invoke(response); } } else { this.UnknownReceived?.Invoke(response); } } else { this.UnknownReceived?.Invoke(response); } this.MessageReceived?.Invoke(response); } public override byte[] Start() { this.latReceived = false; this.debugReceived = false; var payload = this.EncryptRequest(); var message = new SIRTMessage { Direction = this.request.Direction, Command = this.request.Command, P1 = this.request.P1, P2 = this.request.P2, Address = this.request.Address, Payload = payload, Frequency = this.Frequency, SirtId = this.SirtId, }; this.MessageSent?.Invoke(this.request); this.SetRunning(); return message.GetBytes(); } protected virtual void OnMessageSent(SIRTMessage request) { } protected virtual void OnAKNReceived(SIRTMessage akn) { } protected virtual void OnBUPReceived(SIRTMessage bup) { } protected virtual void OnLATReceived(SIRTMessage lat) { this.latReceived = true; } protected virtual void OnDEBUGReceived(SIRTMessage debug) { this.debugReceived = true; if (this.RequireLAT && !this.latReceived) { this.SetPending(); } } protected virtual void OnSEMIReceived(SIRTMessage semi) { if ((this.RequireLAT && !this.latReceived) || (this.RequireDEBUG && !this.debugReceived) || semi.Payload[this.PamStatusIX] != 0) { this.SetPending(); } else { this.SetCompleted(); } } protected virtual void OnUnknownReceived(SIRTMessage unknown) { } protected virtual bool UseEncryption(SIRTMessage response) { if (response is null || this.EncryptionKeyI is null) { return false; } var payload = response.Payload; if (payload is null) { return false; } var length = payload.Length; if (length <= 0) { this.IsEncrypted = false; } else if (length >= this.SemiLength) { this.IsEncrypted = length > this.SemiLength; } else if (length >= this.DebugLength) { this.IsEncrypted = length > this.DebugLength; } else { this.IsEncrypted = payload.GetCrc() != 0; } return this.IsEncrypted; } private byte[] EncryptRequest() { var requestPayload = this.request.Payload; var payloadLength = requestPayload.Length; var payload = new byte[payloadLength]; if (payloadLength > 0) { Array.Copy(requestPayload, 0, payload, 0, payloadLength); if (this.IsEncrypted) { payload = payload.EncryptRequest(this.EncryptionKeyI, this.RequestAddress); } } return payload; } private void DecriptResponse(SIRTMessage response) { var payloadLength = response.Length; if (payloadLength <= 0) { return; } var payload = new byte[payloadLength]; Array.Copy(response.Payload, 0, payload, 0, payloadLength); if (this.IsEncrypted) { response.Payload = payload.DecryptResponse(this.EncryptionKeyI); // Check if SEMI received if (payloadLength > this.SemiLength) { var pamStatus = new PAMStatus(response.Payload[this.PamStatusIX]); // when pam status > 31 - try decrypt with the other key if (!pamStatus.IsValid && this.EncryptionKeyII != null) { var _payload = payload.DecryptResponse(this.EncryptionKeyII); pamStatus = new PAMStatus(_payload[this.PamStatusIX]); // when pam status OK then switch the keys if (pamStatus == PAMStatus.OK) { response.Payload = _payload; var _encryptionKey = this.EncryptionKeyI; this.EncryptionKeyI = this.encryptionKeyII; this.encryptionKeyII = _encryptionKey; } } } } } private void SetP811(Action p811Setter) { p811Setter.Invoke(this.p811); this.request.P1 = this.p811; } } }