using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Threading;
using System.Timers;
using QCRPG.Framework;
using QCRPG.TSL.BT.Packets;

namespace QCRPG.TSL.BT;

public class BTAPI : CommonAPI, QCRPG.Framework.IObserver<AclData>, QCRPG.Framework.IObserver<SynchronousData>, QCRPG.Framework.IObserver<IsoData>
{
	public class FileTransferQueue
	{
		private Queue<AclData> aclDataQueue = new Queue<AclData>();

		private bool running;

		private Thread aclDataThread;

		private Thread receiveResponseThread;

		private BTAPI btAPI;

		private int maxAvailable;

		private ModeAgnosticDataReceiver modeAgnosticDataReceiver;

		private int currentAvailable;

		private AclData aclDataTemp;

		public int CurrentAvailable => currentAvailable;

		public FileTransferQueue(BTAPI btAPI, ModeAgnosticDataReceiver modeAgnosticDataReceiver)
		{
			this.btAPI = btAPI;
			this.modeAgnosticDataReceiver = modeAgnosticDataReceiver;
		}

		public void SetBufferSize(int freeACLDataBuffer)
		{
			maxAvailable = freeACLDataBuffer;
			currentAvailable = freeACLDataBuffer;
		}

		public void Startup()
		{
			if (!running)
			{
				running = true;
				aclDataThread = new Thread(ACLDataThread);
				aclDataThread.Name = "FileTransferQueue-AclData";
				aclDataThread.IsBackground = true;
				receiveResponseThread = new Thread(ResponseReceiveThread);
				receiveResponseThread.Name = "FileTransferQueue-ReceiveResponse";
				receiveResponseThread.IsBackground = true;
				aclDataThread.Start();
				receiveResponseThread.Start();
			}
		}

		public void Shutdown()
		{
			if (!running)
			{
				return;
			}
			while (running)
			{
				lock (aclDataQueue)
				{
					if (aclDataQueue.Count == 0)
					{
						break;
					}
				}
				Thread.Sleep(100);
			}
			running = false;
			aclDataThread.Join();
			receiveResponseThread.Join();
		}

		public void Enqueue(AclData aclDataPacket)
		{
			if (!running)
			{
				return;
			}
			while (true)
			{
				lock (aclDataQueue)
				{
					if (aclDataQueue.Count < maxAvailable)
					{
						break;
					}
				}
				Thread.Sleep(0);
			}
			lock (aclDataQueue)
			{
				aclDataQueue.Enqueue(aclDataPacket);
			}
		}

		public void Clear()
		{
			if (!running)
			{
				return;
			}
			lock (aclDataQueue)
			{
				aclDataQueue.Clear();
			}
		}

		private void ACLDataThread()
		{
			while (running)
			{
				bool flag = false;
				lock (aclDataQueue)
				{
					if (aclDataQueue.Count > 0 && currentAvailable > 0)
					{
						aclDataTemp = aclDataQueue.Dequeue();
						flag = true;
						currentAvailable--;
						if (currentAvailable < 0)
						{
							currentAvailable = 0;
						}
					}
				}
				if (flag)
				{
					btAPI.Send(aclDataTemp);
				}
			}
		}

		private void ResponseReceiveThread()
		{
			while (running)
			{
				NumberOfCompletedPacketsEvent numberOfCompletedPacketsEvent = (NumberOfCompletedPacketsEvent)modeAgnosticDataReceiver.Receive(typeof(NumberOfCompletedPacketsEvent), 2000);
				int result = 0;
				int.TryParse(numberOfCompletedPacketsEvent.Info.FieldInfoList[2].Value, NumberStyles.HexNumber, null, out result);
				currentAvailable += result;
				if (currentAvailable > maxAvailable)
				{
					currentAvailable = maxAvailable;
				}
			}
		}
	}

	private const int TLV_TYPE_INVALID = 0;

	private const int TLV_TYPE_PATCH = 1;

	private const int TLV_TYPE_NVM_BT = 2;

	private const int TLV_TYPE_NVM_FM = 3;

	private const int TLV_TYPE_NVM_MULTIPLE = 4;

	private const int maxPatchBytesToSendAtOnce = 243;

	private const int skipResponseCheckDelayMs = 50;

	private const int ACLFlagFlushable = 32;

	private const int ACLFlagNonFlushable = 0;

	private const int ACLFlagContinue = 16;

	internal const uint L2CAPHeaderLength = 4u;

	internal const ushort DefaultChannelID = 64;

	internal const uint seqNumLen = 4u;

	private ProtocolHCI protocolHCI;

	private ProtocolDiag protocolDiag;

	private ConnectionSerialPort connectionSerialPort;

	private ConnectionUsbAtheros connectionUsb;

	private ConnectionTCP connectionTCP;

	private int responseWaitTimeMs = 1000;

	private int resetWaitTimeMs = 3000;

	private bool decodePacket = true;

	private bool conciseLogging;

	private bool fullAclLogging;

	private FileTransferQueue fileTransferQueue;

	private PacketDecodeInfo packetDecodeInfo = new PacketDecodeInfo();

	protected SpecificPacketNotifier specificPacketNotifier;

	private QCRPG.Framework.IObserver<PacketBase> packetLogger;

	private string sharedConnectionPortName = "";

	private List<QCRPG.Framework.IObserver<PacketBase>> sendIsoDataPacketObservers = new List<QCRPG.Framework.IObserver<PacketBase>>();

	private List<QCRPG.Framework.IObserver<PacketBase>> receiveIsoDataPacketObservers = new List<QCRPG.Framework.IObserver<PacketBase>>();

	private List<QCRPG.Framework.IObserver<PacketBase>> sendScoDataPacketObservers = new List<QCRPG.Framework.IObserver<PacketBase>>();

	private List<QCRPG.Framework.IObserver<PacketBase>> receiveScoDataPacketObservers = new List<QCRPG.Framework.IObserver<PacketBase>>();

	private List<QCRPG.Framework.IObserver<PacketBase>> sendAclDataPacketObservers = new List<QCRPG.Framework.IObserver<PacketBase>>();

	private List<QCRPG.Framework.IObserver<PacketBase>> receiveAclDataPacketObservers = new List<QCRPG.Framework.IObserver<PacketBase>>();

	private GenericNotifier<TrafficGenInfoBase> trafficGenStatusNotifier = new GenericNotifier<TrafficGenInfoBase>();

	private List<BTTrafficGenInfo> trafficGenInfoList = new List<BTTrafficGenInfo>();

	private System.Timers.Timer receivedTrafficPacketTimer;

	private bool isTrafficCompleted;

	private BTConfigSettings btConfigSettings;

	private string logsDirectory;

	private uint ramDumpTotalLength;

	private uint ramDumpNextFragmentSequenceNumber;

	private List<byte> ramDumpBuffer = new List<byte>();

	private bool processingRamDumpFragments;

	private bool displayEnhLogMessages = true;

	private string tempFileLocation;

	private int scoHandle1;

	private Queue<SynchronousData> scoDataQueue;

	private FileStream scoReceivedFileStream;

	private Queue<SynchronousData> scoReceivedQueue;

	private Thread saveReceivedScoToFileThread;

	private ManualResetEvent saveScoToFileEvent = new ManualResetEvent(initialState: false);

	private BinaryWriter scooHciBinaryWriter;

	private bool scoStart;

	private int scoHCIAmplitude = 8000;

	private int scoHCIFrequency = 1000;

	private int scoHCISampleRate = 16000;

	private int scoDataLength;

	private int lnkHeaderLength;

	private int lnkDataIndex;

	private List<byte>[] lnkGeneratedData;

	private List<byte> lnkSplitData;

	private int lnkTotalAclPacketsReceived;

	private int lnkTotalPacketErrors;

	private int lnkTotalByteErrors;

	public bool FullAclLogging
	{
		get
		{
			return fullAclLogging;
		}
		set
		{
			fullAclLogging = value;
		}
	}

	public GenericNotifier<TrafficGenInfoBase> TrafficGenStatusNotifier
	{
		get
		{
			return trafficGenStatusNotifier;
		}
		set
		{
			trafficGenStatusNotifier = value;
		}
	}

	public List<BTTrafficGenInfo> TrafficGenInfoList
	{
		get
		{
			return trafficGenInfoList;
		}
		set
		{
			trafficGenInfoList = value;
		}
	}

	public string LogsDirectory
	{
		set
		{
			logsDirectory = value;
		}
	}

	public bool ProcessingRamDumpFragments => processingRamDumpFragments;

	public List<byte>[] LnkGeneratedData
	{
		set
		{
			lnkGeneratedData = value;
		}
	}

	public BTAPI(PacketListBase packetList, Logger logger, PacketReceiveMode packetReceiveMode, BTConfigSettings btConfigSettings = null)
		: base(packetList, logger, packetReceiveMode)
	{
		this.btConfigSettings = btConfigSettings;
		protocolHCI = new ProtocolHCI();
		protocolDiag = new ProtocolDiag();
		packetList.Packets.Add(new IsoData());
	}

	public override void AddToSharedSerialConnection(string portName)
	{
		if (connectionSerialPort != null && connectionSerialPort.IsOpen())
		{
			throw new Exception("Serial port connection is open, refusing to add to shared connection");
		}
		if (connectionUsb != null && connectionUsb.IsOpen())
		{
			throw new Exception("USB connection is open, refusing to add to shared connection");
		}
		if (GetSharedConnectionPortName() != "" && GetSharedConnectionPortName() != portName)
		{
			RemoveFromSharedSerialConnection(sharedConnectionPortName);
		}
		ShutdownReceiveDataObservation();
		protocolHCI.UseUARTProtocolID = true;
		protocolHCI.EnableSendModeSwitchNotifications = false;
		protocolHCI.Reset();
		protocolHCI.RegisterReceiveACLDataPacketObserver(this);
		ChangeBottomProtocol(protocolHCI, usePacketDataReceiver: false);
		SetupReceiveDataObservation();
		APIBase.sharedConnectionManager.AddRoute(portName, 1, protocolBottom);
		APIBase.sharedConnectionManager.AddRoute(portName, 2, protocolBottom);
		APIBase.sharedConnectionManager.AddRoute(portName, 3, protocolBottom);
		APIBase.sharedConnectionManager.AddRoute(portName, 4, protocolBottom);
		APIBase.sharedConnectionManager.AddRoute(portName, 5, protocolBottom);
		AddSleepProtocolToSharedConnection(portName);
		protocolHCI.UnregisterSendACLDataObserver(connection);
		ChangeConnection(APIBase.sharedConnectionManager.GetConnection(portName));
		protocolHCI.RegisterSendACLDataObserver(connection);
		protocolHCI.RegisterSendSCODataObserver(connection);
		protocolHCI.RegisterSendISODataObserver(connection);
		logger.NotifyObserver(new LogMessage(LogMessageType.Info, $"Added BT to shared serial connection (portName = {portName})"));
		sharedConnectionPortName = portName;
		APIBase.sharedConnectionClosedMap[portName].Add(delegate
		{
			sharedConnectionPortName = "";
		});
		APIBase.sharedConnectionClosedMap[portName].Add(delegate
		{
			base.CloseConnection();
		});
		if (snoopLog != null)
		{
			snoopLog.DataLink = SnoopLogger.DataLinkType.HCI_UART;
		}
	}

	public override void RemoveFromSharedSerialConnection(string portName)
	{
		if (connectionSerialPort != null && connectionSerialPort.IsOpen())
		{
			throw new Exception("Serial port connection is open, refusing to remove from shared connection");
		}
		if (connectionUsb != null && connectionUsb.IsOpen())
		{
			throw new Exception("USB connection is open, refusing to remove from shared connection");
		}
		APIBase.sharedConnectionManager.RemoveRoute(portName, 1);
		APIBase.sharedConnectionManager.RemoveRoute(portName, 2);
		APIBase.sharedConnectionManager.RemoveRoute(portName, 3);
		APIBase.sharedConnectionManager.RemoveRoute(portName, 4);
		APIBase.sharedConnectionManager.RemoveRoute(portName, 5);
		logger.NotifyObserver(new LogMessage(LogMessageType.Info, $"Removed BT from shared serial connection (portName = {portName})"));
		sharedConnectionPortName = "";
	}

	public string GetSharedConnectionPortName()
	{
		if (sharedConnectionPortName == "")
		{
			return sharedConnectionPortName;
		}
		if (!APIBase.IsSharedConnectionActiveAndOpen(sharedConnectionPortName))
		{
			sharedConnectionPortName = "";
		}
		return sharedConnectionPortName;
	}

	public override void AddToSharedDiagConnection(string portName, string diagType)
	{
		if (connectionSerialPort != null && connectionSerialPort.IsOpen())
		{
			throw new Exception("Serial port connection is open, refusing to add to shared connection");
		}
		if (connectionUsb != null && connectionUsb.IsOpen())
		{
			throw new Exception("USB connection is open, refusing to add to shared connection");
		}
		if (GetSharedConnectionPortName() != "" && GetSharedConnectionPortName() != portName)
		{
			RemoveFromSharedDiagConnection(sharedConnectionPortName);
		}
		ShutdownReceiveDataObservation();
		protocolHCI.UseUARTProtocolID = true;
		protocolHCI.EnableSendModeSwitchNotifications = false;
		protocolHCI.Reset();
		protocolHCI.RegisterReceiveACLDataPacketObserver(this);
		ChangeTopProtocol(protocolHCI);
		protocolHCI.UnregisterSendACLDataObserver(connection);
		ChangeBottomProtocol(protocolDiag, usePacketDataReceiver: false);
		protocolHCI.RegisterSendACLDataObserver(protocolDiag);
		SetupReceiveDataObservation();
		AddSharedDiagConnectionRoutes(portName, protocolDiag.FtmCommandCode, protocolDiag.LogCodes);
		ChangeConnection(APIBase.sharedConnectionManager.GetConnection(portName));
		((ConnectionDiag)connection).ConfigureAsyncReceive(protocolDiag.LogCodes);
		logger.NotifyObserver(new LogMessage(LogMessageType.Info, $"Added BT to shared diag connection (portName = {portName})"));
		sharedConnectionPortName = portName;
		APIBase.sharedConnectionClosedMap[portName].Add(delegate
		{
			sharedConnectionPortName = "";
		});
		if (snoopLog != null)
		{
			snoopLog.DataLink = SnoopLogger.DataLinkType.HCI_UART;
		}
	}

	public void SetDiagLibraryMode(string diagType, string libraryMode)
	{
		if (diagType.Equals("QDL", StringComparison.OrdinalIgnoreCase) || libraryMode.Equals("QPST", StringComparison.OrdinalIgnoreCase))
		{
			protocolDiag.FtmLogCrc = new byte[0];
			protocolDiag.FtmCrcLength = 0;
			return;
		}
		ProtocolDiag obj = protocolDiag;
		byte[] ftmLogCrc = new byte[2];
		obj.FtmLogCrc = ftmLogCrc;
		protocolDiag.FtmCrcLength = 2;
	}

	public override void RemoveFromSharedDiagConnection(string portName)
	{
		if (connectionSerialPort != null && connectionSerialPort.IsOpen())
		{
			throw new Exception("Serial port connection is open, refusing to remove from shared connection");
		}
		if (connectionUsb != null && connectionUsb.IsOpen())
		{
			throw new Exception("USB connection is open, refusing to remove from shared connection");
		}
		RemoveSharedDiagConnectionRoutes(portName, protocolDiag.FtmCommandCode, protocolDiag.LogCodes);
		protocolHCI.UnregisterSendACLDataObserver(protocolDiag);
		logger.NotifyObserver(new LogMessage(LogMessageType.Info, $"Removed BT from shared diag connection (portName = {portName})"));
		sharedConnectionPortName = "";
	}

	protected override void CreateReceivePacketHandler()
	{
		receivePacketHandler = new BTReceivePacketHandler(packetList);
	}

	public override void Send(PacketBase packet)
	{
		if (packet is AclData)
		{
			try
			{
				protocolHCI.Send(packet as AclData);
			}
			catch (Exception ex)
			{
				logger.Enqueue(new LogMessage(LogMessageType.Error, ex));
				throw ex;
			}
			packet.Flags |= 2u;
			{
				foreach (QCRPG.Framework.IObserver<PacketBase> item in sendAclDataPacketObservers.Where((QCRPG.Framework.IObserver<PacketBase> o) => o != null))
				{
					item.NotifyObserver(packet);
				}
				return;
			}
		}
		if (packet is SynchronousData)
		{
			try
			{
				protocolHCI.Send(packet as SynchronousData);
			}
			catch (Exception ex2)
			{
				logger.Enqueue(new LogMessage(LogMessageType.Error, ex2));
				throw ex2;
			}
			packet.Flags |= 2u;
			{
				foreach (QCRPG.Framework.IObserver<PacketBase> item2 in sendScoDataPacketObservers.Where((QCRPG.Framework.IObserver<PacketBase> o) => o != null))
				{
					item2.NotifyObserver(packet);
				}
				return;
			}
		}
		if (packet is IsoData)
		{
			try
			{
				protocolHCI.Send(packet as IsoData);
			}
			catch (Exception ex3)
			{
				logger.Enqueue(new LogMessage(LogMessageType.Error, ex3));
				throw ex3;
			}
			packet.Flags |= 2u;
			{
				foreach (QCRPG.Framework.IObserver<PacketBase> item3 in sendIsoDataPacketObservers.Where((QCRPG.Framework.IObserver<PacketBase> o) => o != null))
				{
					item3.NotifyObserver(packet);
				}
				return;
			}
		}
		BTOutgoingPacketData bTOutgoingPacketData = new BTOutgoingPacketData(packet.ToByteArray());
		if (packet.Type == PacketType.Command)
		{
			bTOutgoingPacketData.btPacketType = BTPacketDataType.Command;
		}
		else if (packet.Type == PacketType.Notification)
		{
			bTOutgoingPacketData.btPacketType = BTPacketDataType.Event;
		}
		else if (packet is SynchronousData)
		{
			bTOutgoingPacketData.btPacketType = BTPacketDataType.SynchronousDataPacket;
		}
		else
		{
			bTOutgoingPacketData.btPacketType = BTPacketDataType.Raw;
		}
		packetDataSender.SendSync(bTOutgoingPacketData);
		packet.Flags |= 2u;
		sendPacketNotifier.NotifyObservers(packet);
	}

	public override void Send(byte[] bytes, int length, bool performValidPacketCheck = false)
	{
		BTOutgoingPacketData bTOutgoingPacketData = new BTOutgoingPacketData(bytes, length);
		packetDataSender.SendSync(bTOutgoingPacketData);
		if (!performValidPacketCheck)
		{
			return;
		}
		try
		{
			PacketBase packetBase = null;
			if (connection is ConnectionSerialPort)
			{
				List<PacketType> list = new List<PacketType>();
				if (bTOutgoingPacketData.bytes[0] <= 1 || bTOutgoingPacketData.bytes[0] > 5)
				{
					list.Add(PacketType.Command);
				}
				else if (bTOutgoingPacketData.bytes[0] == 4)
				{
					list.Add(PacketType.Notification);
				}
				else if (bTOutgoingPacketData.bytes[0] == 2)
				{
					list.Add(PacketType.Data);
					packetBase = new AclData();
					packetBase.FromByteArray(bTOutgoingPacketData.bytes.Skip(1).ToArray());
				}
				else if (bTOutgoingPacketData.bytes[0] == 3)
				{
					list.Add(PacketType.Data);
					packetBase = new SynchronousData();
					packetBase.FromByteArray(bTOutgoingPacketData.bytes.Skip(1).ToArray());
				}
				else if (bTOutgoingPacketData.bytes[0] == 5)
				{
					list.Add(PacketType.Data);
					packetBase = new IsoData();
					packetBase.FromByteArray(bTOutgoingPacketData.bytes.Skip(1).ToArray());
				}
				if (packetBase == null)
				{
					packetBase = packetList.BytesToPacketOfType(bTOutgoingPacketData.bytes.Skip(1).ToArray(), list);
				}
			}
			else
			{
				if (!(connection is ConnectionUsbAtheros))
				{
					return;
				}
				packetBase = packetList.BytesToPacketOfType(bTOutgoingPacketData.bytes, new List<PacketType> { PacketType.Command });
			}
			packetBase.Flags |= 2u;
			sendPacketNotifier.NotifyObservers(packetBase);
		}
		catch (Exception)
		{
		}
	}

	public override void SendAsync(PacketBase packet)
	{
		BTOutgoingPacketData bTOutgoingPacketData = new BTOutgoingPacketData(packet.ToByteArray());
		if (packet.Type == PacketType.Command)
		{
			bTOutgoingPacketData.btPacketType = BTPacketDataType.Command;
		}
		else if (packet.Type == PacketType.Notification)
		{
			bTOutgoingPacketData.btPacketType = BTPacketDataType.Event;
		}
		else if (packet is AclData)
		{
			bTOutgoingPacketData.btPacketType = BTPacketDataType.AclDataPacket;
		}
		else if (packet is SynchronousData)
		{
			bTOutgoingPacketData.btPacketType = BTPacketDataType.SynchronousDataPacket;
		}
		else if (packet is IsoData)
		{
			bTOutgoingPacketData.btPacketType = BTPacketDataType.IsoDataPacket;
		}
		else
		{
			bTOutgoingPacketData.btPacketType = BTPacketDataType.Raw;
		}
		packetDataSender.SendAsync(bTOutgoingPacketData);
		packet.Flags |= 2u;
		sendPacketNotifier.NotifyObservers(packet);
	}

	public override void RegisterSendPacketObserver(QCRPG.Framework.IObserver<PacketBase> observer)
	{
		base.RegisterSendPacketObserver(observer);
		RegisterSendACLDataPacketObserver(observer);
		RegisterSendSCODataPacketObserver(observer);
		RegisterSendISODataPacketObserver(observer);
	}

	public override void UnregisterSendPacketObserver(QCRPG.Framework.IObserver<PacketBase> observer)
	{
		base.UnregisterSendPacketObserver(observer);
		UnregisterSendACLDataPacketObserver(observer);
		UnregisterSendSCODataPacketObserver(observer);
		UnregisterSendISODataPacketObserver(observer);
	}

	public override void RegisterReceivePacketObserver(QCRPG.Framework.IObserver<PacketBase> observer)
	{
		base.RegisterReceivePacketObserver(observer);
		RegisterReceiveACLDataPacketObserver(observer);
		RegisterReceiveSCODataPacketObserver(observer);
		RegisterReceiveISODataPacketObserver(observer);
	}

	public override void UnregisterReceivePacketObserver(QCRPG.Framework.IObserver<PacketBase> observer)
	{
		base.UnregisterReceivePacketObserver(observer);
		UnregisterReceiveACLDataPacketObserver(observer);
		UnregisterReceiveSCODataPacketObserver(observer);
	}

	public void OpenSerialConnection(string portName, int baudRate, Handshake handShake, bool initAt115k = false)
	{
		if (GetSharedConnectionPortName() != "")
		{
			throw new Exception("Already added to shared connection, refusing to try to open");
		}
		CloseConnectionNoLogMessages();
		ShutdownReceiveDataObservation();
		protocolHCI.UseUARTProtocolID = true;
		protocolHCI.EnableSendModeSwitchNotifications = false;
		protocolHCI.Reset();
		protocolHCI.RegisterReceiveACLDataPacketObserver(this);
		protocolHCI.RegisterReceiveSCODataPacketObserver(this);
		protocolHCI.RegisterReceiveISODataPacketObserver(this);
		ChangeBottomProtocol(protocolHCI);
		SetupReceiveDataObservation();
		protocolHCI.UnregisterSendACLDataObserver(connection);
		protocolHCI.UnregisterSendSCODataObserver(connection);
		protocolHCI.UnregisterSendISODataObserver(connection);
		connectionSerialPort = new ConnectionSerialPort();
		connectionSerialPort.RegisterConnectionStateChangeInfoObserver(connectionStateChangeInfoObserver);
		if (snoopLog != null)
		{
			snoopLog.DataLink = SnoopLogger.DataLinkType.HCI_UART;
		}
		if (initAt115k)
		{
			if (btConfigSettings.DefaultBTNVMFile.CompareTo("") == 0)
			{
				throw new Exception("Default BT NVM file is empty! This is required for Initializing the DUT @ 115200bps. Please select NVM on BT Config menu.");
			}
			connectionSerialPort.Open(portName, 115200, handShake);
			ChangeConnection(connectionSerialPort);
			logger.Enqueue(new LogMessage(LogMessageType.Info, $"InitAt115k: Opened BT serial connection (portName = {portName}, dataRate = {115200}, flowControl = {handShake.ToString()})"));
			string arg = ReadBDAddress();
			logger.Enqueue(new LogMessage(LogMessageType.Info, $"Device BDAddr: {arg}"));
			logger.Enqueue(new LogMessage(LogMessageType.Info, $"InitAt115k: Loading NVM (filename = {btConfigSettings.DefaultBTNVMFile})"));
			WriteNVM(btConfigSettings.DefaultBTNVMFile, skipResponseChecks: true);
			Thread.Sleep(100);
			connectionSerialPort.Close();
			logger.Enqueue(new LogMessage(LogMessageType.Info, $"InitAt115k: Close out serial connection (portName = {portName})"));
		}
		connectionSerialPort.Open(portName, baudRate, handShake);
		ChangeConnection(connectionSerialPort);
		protocolHCI.RegisterSendACLDataObserver(connectionSerialPort);
		protocolHCI.RegisterSendSCODataObserver(connectionSerialPort);
		protocolHCI.RegisterSendISODataObserver(connectionSerialPort);
		logger.NotifyObserver(new LogMessage(LogMessageType.Info, $"Opened BT serial connection (portName = {portName}, dataRate = {baudRate}, flowControl = {handShake.ToString()})"));
	}

	public void OpenSerialConnection(string portName, int initialBaudRate, int finalBaudRate, Handshake handShake = Handshake.None, bool hciInit = false)
	{
		if (GetSharedConnectionPortName() != "")
		{
			throw new Exception("Already added to shared connection, refusing to try to open");
		}
		CloseConnectionNoLogMessages();
		ShutdownReceiveDataObservation();
		protocolHCI.UseUARTProtocolID = true;
		protocolHCI.EnableSendModeSwitchNotifications = false;
		protocolHCI.Reset();
		protocolHCI.RegisterReceiveACLDataPacketObserver(this);
		protocolHCI.RegisterReceiveSCODataPacketObserver(this);
		protocolHCI.RegisterReceiveISODataPacketObserver(this);
		ChangeBottomProtocol(protocolHCI);
		SetupReceiveDataObservation();
		protocolHCI.UnregisterSendACLDataObserver(connection);
		protocolHCI.UnregisterSendSCODataObserver(connection);
		protocolHCI.UnregisterSendISODataObserver(connection);
		connectionSerialPort = new ConnectionSerialPort();
		connectionSerialPort.RegisterConnectionStateChangeInfoObserver(connectionStateChangeInfoObserver);
		if (snoopLog != null)
		{
			snoopLog.DataLink = SnoopLogger.DataLinkType.HCI_UART;
		}
		if (hciInit)
		{
			if (btConfigSettings.DefaultBTNVMFile.CompareTo("") == 0)
			{
				throw new Exception("Default BT NVM file is empty! This is required for Initializing the DUT with HCI. Please select NVM on BT Config menu.");
			}
			connectionSerialPort.Open(portName, initialBaudRate, handShake);
			ChangeConnection(connectionSerialPort);
			logger.Enqueue(new LogMessage(LogMessageType.Info, $"HCI_Init: Opened BT serial connection (portName = {portName}, dataRate = {initialBaudRate}, flowControl = {handShake.ToString()})"));
			string arg = ReadBDAddress();
			logger.Enqueue(new LogMessage(LogMessageType.Info, $"Device BDAddr: {arg}"));
			logger.Enqueue(new LogMessage(LogMessageType.Info, $"HCI_Init: Changing baud rate to {finalBaudRate}"));
			SetbaudRate((uint)finalBaudRate);
			connectionSerialPort.Close();
			connectionSerialPort.Open(portName, finalBaudRate, handShake);
			ChangeConnection(connectionSerialPort);
			protocolHCI.RegisterSendACLDataObserver(connectionSerialPort);
			protocolHCI.RegisterSendSCODataObserver(connectionSerialPort);
			protocolHCI.RegisterSendISODataObserver(connectionSerialPort);
			logger.Enqueue(new LogMessage(LogMessageType.Info, $"HCI_Init: Baud rate changed to {finalBaudRate}"));
			logger.Enqueue(new LogMessage(LogMessageType.Info, $"HCI_Init: Loading Patch (filename = {btConfigSettings.DefaultBTPatchFile})"));
			PatchFirmwareTLV(btConfigSettings.DefaultBTPatchFile);
			Thread.Sleep(100);
			logger.Enqueue(new LogMessage(LogMessageType.Info, $"HCI_Init: Loading NVM (filename = {btConfigSettings.DefaultBTNVMFile})"));
			WriteNVM(btConfigSettings.DefaultBTNVMFile);
		}
	}

	public void OpenTCPConnection(string ipAddress, int portNumber, bool performWillsAndDos, bool addProtocolByte)
	{
		if (GetSharedConnectionPortName() != "")
		{
			throw new Exception("Already added to shared connection, refusing to try to open");
		}
		CloseConnectionNoLogMessages();
		ShutdownReceiveDataObservation();
		protocolHCI.UseUARTProtocolID = addProtocolByte;
		protocolHCI.EnableSendModeSwitchNotifications = !addProtocolByte;
		protocolHCI.Reset();
		protocolHCI.RegisterReceiveACLDataPacketObserver(this);
		ChangeBottomProtocol(protocolHCI);
		SetupReceiveDataObservation();
		protocolHCI.UnregisterSendACLDataObserver(connection);
		connectionTCP = new ConnectionTCP();
		connectionTCP.RegisterConnectionStateChangeInfoObserver(connectionStateChangeInfoObserver);
		connectionTCP.Open(ipAddress, portNumber, performWillsAndDos, addProtocolByte);
		if (snoopLog != null)
		{
			snoopLog.DataLink = SnoopLogger.DataLinkType.HCI_UART;
		}
		ChangeConnection(connectionTCP);
		protocolHCI.RegisterSendACLDataObserver(connectionTCP);
		logger.NotifyObserver(new LogMessage(LogMessageType.Info, $"Opened BT TCP connection (IPADDRESS = {ipAddress}, PORT NUMBER = {portNumber})"));
	}

	private string ReadBDAddress()
	{
		ModeAgnosticDataReceiver modeAgnosticDataReceiver = new ModeAgnosticDataReceiver(this);
		modeAgnosticDataReceiver.Startup();
		try
		{
			ReadBdAddr readBdAddr = new ReadBdAddr();
			Send(readBdAddr);
			List<PacketBase> packets = modeAgnosticDataReceiver.ReceiveAll(readBdAddr.ExpectedResponseTypes, responseWaitTimeMs);
			CommandCompleteForReadBdAddr commandCompleteForReadBdAddr = (CommandCompleteForReadBdAddr)PacketHelper.GetPacketTypeFromList(typeof(CommandCompleteForReadBdAddr), packets);
			return "0x" + commandCompleteForReadBdAddr.UserFields.BdAddr.ToString("X12");
		}
		finally
		{
			modeAgnosticDataReceiver.Shutdown();
		}
	}

	private void SetbaudRate(uint baudRate)
	{
		HciVsSetBaudrate hciVsSetBaudrate = new HciVsSetBaudrate();
		string value = "BaudRate_" + baudRate + "_bps";
		hciVsSetBaudrate._UserFields.SetBaudRateAsBaudRateEnum((HciVsSetBaudrate.UserFieldsWrapper.BaudRateEnum)Enum.Parse(typeof(HciVsSetBaudrate.UserFieldsWrapper.BaudRateEnum), value));
		Send(hciVsSetBaudrate);
	}

	public void OpenUsbConnection(UsbDeviceInfo usbDeviceInfo, bool enableAcl = true)
	{
		ConnectionSpecificProtocolInfo.SleepModeState sleepMode = GetSleepMode();
		if (sleepMode != 0)
		{
			logger.NotifyObserver(new LogMessage(LogMessageType.Error, string.Format("USB connection not supported in sleep mode " + sleepMode.ToString() + ". Set sleep Mode to NONE and try again.")));
			return;
		}
		if (GetSharedConnectionPortName() != "")
		{
			throw new Exception("Already added to shared connection, refusing to try to open");
		}
		CloseConnectionNoLogMessages();
		ShutdownReceiveDataObservation();
		protocolHCI.UseUARTProtocolID = false;
		protocolHCI.EnableSendModeSwitchNotifications = true;
		protocolHCI.Reset();
		protocolHCI.RegisterReceiveACLDataPacketObserver(this);
		ChangeBottomProtocol(protocolHCI);
		SetupReceiveDataObservation();
		protocolHCI.UnregisterSendACLDataObserver(connection);
		if (usbDeviceInfo.connectionClass == typeof(ConnectionUsbAtheros))
		{
			connectionUsb = new ConnectionUsbAtheros(usbDeviceInfo);
			connectionUsb.EnableReceiveModeSwitchNotifications = true;
			connectionUsb.RegisterConnectionStateChangeInfoObserver(connectionStateChangeInfoObserver);
			ChangeConnection(connectionUsb);
			protocolHCI.RegisterSendACLDataObserver(connectionUsb);
			connectionUsb.Open(usbDeviceInfo, enableAcl);
			logger.NotifyObserver(new LogMessage(LogMessageType.Info, $"Opened BT Atheros USB connection (path = {usbDeviceInfo.path})"));
			if (snoopLog != null)
			{
				snoopLog.DataLink = SnoopLogger.DataLinkType.Unencapsulated_HCI;
			}
			return;
		}
		throw new Exception("Unsupported connection class: " + usbDeviceInfo.connectionClass.ToString());
	}

	public override void CloseConnection()
	{
		if (GetSharedConnectionPortName() != "")
		{
			throw new Exception("Already added to shared connection, refusing to try to close");
		}
		if (connectionSerialPort != null)
		{
			connectionSerialPort.Close();
			logger.NotifyObserver(new LogMessage(LogMessageType.Info, "Closed BT serial connection"));
		}
		if (connectionUsb != null)
		{
			connectionUsb.Close();
			logger.NotifyObserver(new LogMessage(LogMessageType.Info, "Closed BT USB connection"));
		}
		if (connectionTCP != null)
		{
			connectionTCP.Close();
			logger.NotifyObserver(new LogMessage(LogMessageType.Info, "Closed BT TCP connection"));
		}
		base.CloseConnection();
	}

	private void CloseConnectionNoLogMessages()
	{
		if (GetSharedConnectionPortName() != "")
		{
			if (protocolBottom is ProtocolDiag)
			{
				RemoveFromSharedDiagConnection(sharedConnectionPortName);
			}
			else
			{
				RemoveFromSharedSerialConnection(sharedConnectionPortName);
			}
		}
		if (connectionSerialPort != null)
		{
			connectionSerialPort.Close();
		}
		if (connectionUsb != null)
		{
			connectionUsb.Close();
		}
	}

	public void EnableDisplayEnhancedLog(bool enable)
	{
		displayEnhLogMessages = enable;
		protocolHCI.DisplayEnhLogGUI = enable;
	}

	public void EnableEnhLogIds(List<uint> LogIds)
	{
		foreach (uint LogId in LogIds)
		{
			protocolHCI.AllowedEnhancedLogIds[LogId] = true;
		}
	}

	public void DisableEnhLogIds(List<uint> LogIds)
	{
		foreach (uint LogId in LogIds)
		{
			protocolHCI.AllowedEnhancedLogIds[LogId] = false;
		}
	}

	public void SetAclDataDisplay()
	{
		ProtocolHCI.AclLogMode aclMode = protocolHCI.AclMode;
		SetAclDataDisplay(aclMode);
	}

	public void SetAclDataDisplay(ProtocolHCI.AclLogMode aclDisplay)
	{
		protocolHCI.AclMode = aclDisplay;
		switch (aclDisplay)
		{
		case ProtocolHCI.AclLogMode.FULL:
			SetDecodePacket(decodePacket: true, packetResponse: false);
			if (packetLogger != null)
			{
				RegisterSendACLDataPacketObserver(packetLogger);
				RegisterReceiveACLDataPacketObserver(packetLogger);
			}
			break;
		case ProtocolHCI.AclLogMode.SUMMARY:
			SetDecodePacket(decodePacket: true, packetResponse: false, conciseLog: true);
			if (packetLogger != null)
			{
				RegisterSendACLDataPacketObserver(packetLogger);
				RegisterReceiveACLDataPacketObserver(packetLogger);
			}
			break;
		case ProtocolHCI.AclLogMode.NONE:
			lock (sendAclDataPacketObservers)
			{
				foreach (QCRPG.Framework.IObserver<PacketBase> item in sendAclDataPacketObservers.Where((QCRPG.Framework.IObserver<PacketBase> o) => o != null))
				{
					if (item.GetType().ToString().Equals("QCRPG.PacketLogger"))
					{
						packetLogger = item;
						UnregisterSendACLDataPacketObserver(packetLogger);
						break;
					}
				}
			}
			lock (receiveAclDataPacketObservers)
			{
				foreach (QCRPG.Framework.IObserver<PacketBase> item2 in receiveAclDataPacketObservers.Where((QCRPG.Framework.IObserver<PacketBase> o) => o != null))
				{
					if (item2.GetType().ToString().Equals("QCRPG.PacketLogger"))
					{
						packetLogger = item2;
						UnregisterReceiveACLDataPacketObserver(packetLogger);
						break;
					}
				}
				break;
			}
		}
	}

	public void SetFullAclDataToLogFile(bool fullAclLogging)
	{
		this.fullAclLogging = fullAclLogging;
		SetDecodePacket(decodePacket: true, packetResponse: false, conciseLogging, fullAclLogging);
	}

	public bool IsConnectionOpen()
	{
		if (string.IsNullOrEmpty(sharedConnectionPortName))
		{
			if (connectionSerialPort != null)
			{
				return connectionSerialPort.IsOpen();
			}
			if (connectionUsb != null)
			{
				return connectionUsb.IsOpen();
			}
			return false;
		}
		return true;
	}

	protected override void SetupReceiveDataObservation()
	{
		if (protocolBottom is ProtocolHCI)
		{
			protocolHCI.RegisterReceiveDataObserverPostProcessing(receiveDataObserver);
		}
		else if (protocolBottom is ProtocolDiag)
		{
			protocolDiag.RegisterReceiveDataObserverPostProcessing(receiveDataObserver);
		}
	}

	protected override void ShutdownReceiveDataObservation()
	{
		if (protocolBottom is ProtocolHCI)
		{
			protocolHCI.UnregisterReceiveDataObserverPostProcessing(receiveDataObserver);
		}
		else if (protocolBottom is ProtocolDiag)
		{
			protocolDiag.UnregisterReceiveDataObserverPostProcessing(receiveDataObserver);
		}
	}

	public void WriteNVM(string filename, bool skipResponseChecks = false, ProtocolHCI.SleepModeState sleepMode = ProtocolHCI.SleepModeState.NONE, bool convertNvmToBin = false, List<string> nvmMessages = null)
	{
		if (Path.GetExtension(filename).ToUpper() == ".NVM")
		{
			WriteNVM_TXT(filename, skipResponseChecks, sleepMode, convertNvmToBin, nvmMessages);
			return;
		}
		if (Path.GetExtension(filename).ToUpper() == ".BIN")
		{
			WriteNVMTLV_BIN(filename, skipResponseChecks, sleepMode);
			return;
		}
		throw new Exception("NVM file type not in the correct format.");
	}

	private byte[] NvmTagsToByteArray(List<NVMTag> nvmTags)
	{
		List<byte> list = new List<byte>();
		list.Add(2);
		int num = 0;
		foreach (NVMTag nvmTag in nvmTags)
		{
			list.Add((byte)nvmTag.tagNumber);
			list.Add((byte)(nvmTag.tagNumber >> 8));
			list.Add((byte)nvmTag.tagLength);
			list.Add((byte)(nvmTag.tagLength >> 8));
			for (int i = 0; i < 8; i++)
			{
				list.Add(0);
			}
			for (int j = 0; j < nvmTag.tagLength; j++)
			{
				list.Add(nvmTag.tagValue[j]);
			}
		}
		num = list.Count - 1;
		list.Insert(1, (byte)num);
		list.Insert(2, (byte)(num >> 8));
		list.Insert(3, (byte)(num >> 16));
		return list.ToArray();
	}

	private void NvmTagDownload(List<NVMTag> nvmTags, bool skipResponseChecks, bool isNewVSC, List<string> nvmMessages = null)
	{
		ModeAgnosticDataReceiver modeAgnosticDataReceiver = new ModeAgnosticDataReceiver(this);
		modeAgnosticDataReceiver.Startup();
		if (nvmMessages == null)
		{
			nvmMessages = new List<string>();
		}
		string text = "";
		try
		{
			List<PacketBase> list = null;
			CommandCompleteForNop commandCompleteForNop = null;
			foreach (NVMTag nvmTag in nvmTags)
			{
				NvmAccessSet nvmAccessSet = new NvmAccessSet();
				nvmAccessSet.UserFields.TagNumber = (uint)nvmTag.tagNumber;
				nvmAccessSet.UserFields.Length = (uint)nvmTag.tagLength;
				for (int i = 0; i < nvmTag.tagLength; i++)
				{
					nvmAccessSet.UserFields.TagValueList[i] = nvmTag.tagValue[i];
				}
				Send(nvmAccessSet);
				if (!skipResponseChecks)
				{
					if (isNewVSC)
					{
						Type[] packetTypes = new Type[1] { typeof(CommandCompleteForNvmAccessSet) };
						list = modeAgnosticDataReceiver.ReceiveAll(packetTypes, responseWaitTimeMs);
						CommandCompleteForNvmAccessSet commandCompleteForNvmAccessSet = (CommandCompleteForNvmAccessSet)PacketHelper.GetPacketTypeFromList(typeof(CommandCompleteForNvmAccessSet), list);
						if (commandCompleteForNvmAccessSet.UserFields.TagNumber != nvmTag.tagNumber)
						{
							text = "Tag Number " + commandCompleteForNvmAccessSet.UserFields.TagNumber + ": Tag number doesn't match in event";
							logger.NotifyObserver(new LogMessage(LogMessageType.Warning, text));
							nvmMessages.Add(text);
						}
						else if (commandCompleteForNvmAccessSet.UserFields.Length != nvmTag.tagLength)
						{
							text = "Tag Number " + commandCompleteForNvmAccessSet.UserFields.TagNumber + ": Tag length doesn't match in event";
							logger.NotifyObserver(new LogMessage(LogMessageType.Warning, text));
							nvmMessages.Add(text);
						}
						else
						{
							for (int j = 0; j < nvmTag.tagLength; j++)
							{
								if (commandCompleteForNvmAccessSet.UserFields.TagValueList[j] != nvmTag.tagValue[j])
								{
									text = "Tag Number " + commandCompleteForNvmAccessSet.UserFields.TagNumber + ": Tag value doesn't match in event";
									logger.NotifyObserver(new LogMessage(LogMessageType.Warning, text));
									nvmMessages.Add(text);
								}
							}
						}
						CheckStatus(commandCompleteForNvmAccessSet);
						continue;
					}
					Type[] packetTypes2 = new Type[2]
					{
						typeof(NvmAccessSetEvent),
						typeof(CommandCompleteForNop)
					};
					list = modeAgnosticDataReceiver.ReceiveAll(packetTypes2, responseWaitTimeMs);
					NvmAccessSetEvent nvmAccessSetEvent = (NvmAccessSetEvent)PacketHelper.GetPacketTypeFromList(typeof(NvmAccessSetEvent), list);
					if (nvmAccessSetEvent.UserFields.TagNumber != nvmTag.tagNumber)
					{
						text = "Tag Number " + nvmAccessSetEvent.UserFields.TagNumber + ": Tag number doesn't match in event";
						logger.NotifyObserver(new LogMessage(LogMessageType.Warning, text));
						nvmMessages.Add(text);
					}
					else if (nvmAccessSetEvent.UserFields.Length != nvmTag.tagLength)
					{
						text = "Tag Number " + nvmAccessSetEvent.UserFields.TagNumber + ": Tag length doesn't match in event";
						logger.NotifyObserver(new LogMessage(LogMessageType.Warning, text));
						nvmMessages.Add(text);
					}
					else
					{
						for (int k = 0; k < nvmTag.tagLength; k++)
						{
							if (nvmAccessSetEvent.UserFields.TagValueList[k] != nvmTag.tagValue[k])
							{
								text = "Tag Number " + nvmAccessSetEvent.UserFields.TagNumber + ": Tag value doesn't match in event";
								logger.NotifyObserver(new LogMessage(LogMessageType.Warning, text));
								nvmMessages.Add(text);
							}
						}
					}
					commandCompleteForNop = (CommandCompleteForNop)PacketHelper.GetPacketTypeFromList(typeof(CommandCompleteForNop), list);
					CheckStatus(commandCompleteForNop);
				}
				else
				{
					Thread.Sleep(50);
				}
			}
		}
		finally
		{
			modeAgnosticDataReceiver.Shutdown();
		}
	}

	public void WriteNVM_TXT(string filename, bool skipResponseChecks = false, ProtocolHCI.SleepModeState sleepMode = ProtocolHCI.SleepModeState.NONE, bool convertNvmToBin = false, List<string> nvmMessages = null)
	{
		logger.NotifyObserver(new LogMessage(LogMessageType.Info, "Starting BT NVM download"));
		NVMFileReader nVMFileReader = new NVMFileReader();
		List<NVMTag> nvmTags = nVMFileReader.ReadTags(filename);
		ModeAgnosticDataReceiver modeAgnosticDataReceiver = new ModeAgnosticDataReceiver(this);
		modeAgnosticDataReceiver.Startup();
		bool isNewVSC = false;
		try
		{
			EdlGetStatusRequest packet = new EdlGetStatusRequest();
			Send(packet);
			List<PacketBase> list = null;
			PacketBase packetBase = null;
			CommandCompleteForNop commandCompleteForNop = null;
			if (!skipResponseChecks)
			{
				packetBase = modeAgnosticDataReceiver.Receive(responseWaitTimeMs);
				if (packetBase is EdlStatusResponse)
				{
					EdlStatusResponse packet2 = (EdlStatusResponse)packetBase;
					CheckStatus(packet2);
					packetBase = modeAgnosticDataReceiver.Receive(responseWaitTimeMs);
					commandCompleteForNop = (CommandCompleteForNop)packetBase;
					CheckStatus(commandCompleteForNop);
				}
				else if (packetBase is CommandCompleteForEdlGetStatusRequest)
				{
					CommandCompleteForEdlGetStatusRequest packet3 = (CommandCompleteForEdlGetStatusRequest)packetBase;
					CheckStatus(packet3);
					isNewVSC = true;
				}
			}
			else
			{
				Thread.Sleep(50);
			}
			if (convertNvmToBin)
			{
				byte[] tlvData = NvmTagsToByteArray(nvmTags);
				TlvDownload(tlvData, skipResponseChecks, isNewVSC);
			}
			else
			{
				NvmTagDownload(nvmTags, skipResponseChecks, isNewVSC, nvmMessages);
			}
			Reset reset = new Reset();
			Send(reset);
			if (sleepMode != 0)
			{
				SetSleepMode(sleepMode);
			}
			if (!skipResponseChecks)
			{
				try
				{
					list = modeAgnosticDataReceiver.ReceiveAll(reset.ExpectedResponseTypes, resetWaitTimeMs);
				}
				catch (TimeoutException innerException)
				{
					throw new TimeoutException("Please check the baudrate. NVM might have changed the target's baudrate.", innerException);
				}
				CommandCompleteForReset packet4 = (CommandCompleteForReset)PacketHelper.GetPacketTypeFromList(typeof(CommandCompleteForReset), list);
				CheckStatus(packet4);
			}
			else
			{
				Thread.Sleep(50);
			}
			logger.NotifyObserver(new LogMessage(LogMessageType.Info, "Finished BT NVM download"));
		}
		finally
		{
			modeAgnosticDataReceiver.Shutdown();
		}
	}

	public void PatchFirmware(string filename, bool skipResponseChecks = false)
	{
		logger.NotifyObserver(new LogMessage(LogMessageType.Info, "Starting BT Firmware Patching"));
		byte[] array = File.ReadAllBytes(filename);
		int num = 0;
		int num2 = array.Length;
		ModeAgnosticDataReceiver modeAgnosticDataReceiver = new ModeAgnosticDataReceiver(this);
		modeAgnosticDataReceiver.Startup();
		try
		{
			EdlPatchDetachRequest packet = new EdlPatchDetachRequest();
			Send(packet);
			List<PacketBase> packets = null;
			PacketBase packetBase = null;
			CommandCompleteForNop commandCompleteForNop = null;
			EdlStatusResponse edlStatusResponse = null;
			bool flag = false;
			if (!skipResponseChecks)
			{
				packetBase = modeAgnosticDataReceiver.Receive(resetWaitTimeMs);
				if (packetBase is EdlStatusResponse)
				{
					edlStatusResponse = (EdlStatusResponse)packetBase;
					CheckStatus(edlStatusResponse);
					packetBase = modeAgnosticDataReceiver.Receive(resetWaitTimeMs);
					commandCompleteForNop = (CommandCompleteForNop)packetBase;
					CheckStatus(commandCompleteForNop);
				}
				else
				{
					CommandCompleteForEdlPatchDetachRequest packet2 = (CommandCompleteForEdlPatchDetachRequest)packetBase;
					CheckStatus(packet2);
					flag = true;
				}
			}
			else
			{
				Thread.Sleep(50);
			}
			EdlSetPatchHeaderRequest edlSetPatchHeaderRequest = new EdlSetPatchHeaderRequest();
			edlSetPatchHeaderRequest.UserFields.ProductId = Conversions.ByteArrayToUint(array, num, 4, elementZeroIsMsb: false);
			num += 4;
			num2 -= 4;
			edlSetPatchHeaderRequest.UserFields.BuildVersion = Conversions.ByteArrayToUint(array, num, 4, elementZeroIsMsb: false);
			num += 4;
			num2 -= 4;
			edlSetPatchHeaderRequest.UserFields.BaseAddress = Conversions.ByteArrayToUint(array, num, 4, elementZeroIsMsb: false);
			num += 4;
			num2 -= 4;
			edlSetPatchHeaderRequest.UserFields.EntryAddress = Conversions.ByteArrayToUint(array, num, 4, elementZeroIsMsb: false);
			num += 4;
			num2 -= 4;
			edlSetPatchHeaderRequest.UserFields.Length = Conversions.ByteArrayToUint(array, num, 4, elementZeroIsMsb: false);
			num += 4;
			num2 -= 4;
			edlSetPatchHeaderRequest.UserFields.Crc = Conversions.ByteArrayToUint(array, num, 4, elementZeroIsMsb: false);
			num += 4;
			num2 -= 4;
			edlSetPatchHeaderRequest.UserFields.ControlBits = Conversions.ByteArrayToUint(array, num, 4, elementZeroIsMsb: false);
			num += 4;
			num2 -= 4;
			Send(edlSetPatchHeaderRequest);
			if (!skipResponseChecks)
			{
				if (flag)
				{
					Type[] packetTypes = new Type[1] { typeof(CommandCompleteForEdlSetPatchHeaderRequest) };
					packets = modeAgnosticDataReceiver.ReceiveAll(packetTypes, resetWaitTimeMs);
					CommandCompleteForEdlSetPatchHeaderRequest packet3 = (CommandCompleteForEdlSetPatchHeaderRequest)PacketHelper.GetPacketTypeFromList(typeof(CommandCompleteForEdlSetPatchHeaderRequest), packets);
					CheckStatus(packet3);
				}
				else
				{
					Type[] packetTypes2 = new Type[2]
					{
						typeof(EdlStatusResponse),
						typeof(CommandCompleteForNop)
					};
					packets = modeAgnosticDataReceiver.ReceiveAll(packetTypes2, resetWaitTimeMs);
					edlStatusResponse = (EdlStatusResponse)PacketHelper.GetPacketTypeFromList(typeof(EdlStatusResponse), packets);
					CheckStatus(edlStatusResponse);
					commandCompleteForNop = (CommandCompleteForNop)PacketHelper.GetPacketTypeFromList(typeof(CommandCompleteForNop), packets);
					CheckStatus(commandCompleteForNop);
				}
			}
			else
			{
				Thread.Sleep(50);
			}
			uint num3 = edlSetPatchHeaderRequest.UserFields.BaseAddress;
			while (num2 > 0)
			{
				int num4 = num2;
				if (num4 > 239)
				{
					num4 = 239;
				}
				EdlPoke8Request edlPoke8Request = new EdlPoke8Request();
				edlPoke8Request.UserFields.DataLength = (uint)num4;
				edlPoke8Request.UserFields.Address = num3;
				for (int i = 0; i < num4; i++)
				{
					edlPoke8Request.UserFields.DataList[i] = array[num++];
				}
				num2 -= num4;
				num3 += (uint)num4;
				Send(edlPoke8Request);
				if (!skipResponseChecks)
				{
					packets = modeAgnosticDataReceiver.ReceiveAll(edlPoke8Request.ExpectedResponseTypes, resetWaitTimeMs);
					edlStatusResponse = (EdlStatusResponse)PacketHelper.GetPacketTypeFromList(typeof(EdlStatusResponse), packets);
					CheckStatus(edlStatusResponse);
					commandCompleteForNop = (CommandCompleteForNop)PacketHelper.GetPacketTypeFromList(typeof(CommandCompleteForNop), packets);
					CheckStatus(commandCompleteForNop);
				}
				else
				{
					Thread.Sleep(50);
				}
			}
			EdlPatchAttachRequest packet4 = new EdlPatchAttachRequest();
			Send(packet4);
			if (!skipResponseChecks)
			{
				if (flag)
				{
					packetBase = modeAgnosticDataReceiver.Receive(resetWaitTimeMs);
					CommandCompleteForEdlPatchAttachRequest packet5 = (CommandCompleteForEdlPatchAttachRequest)PacketHelper.GetPacketTypeFromList(typeof(CommandCompleteForEdlPatchAttachRequest), packets);
					CheckStatus(packet5);
				}
				else
				{
					Type[] packetTypes3 = new Type[2]
					{
						typeof(EdlStatusResponse),
						typeof(CommandCompleteForNop)
					};
					packets = modeAgnosticDataReceiver.ReceiveAll(packetTypes3, responseWaitTimeMs);
					edlStatusResponse = (EdlStatusResponse)PacketHelper.GetPacketTypeFromList(typeof(EdlStatusResponse), packets);
					CheckStatus(edlStatusResponse);
					commandCompleteForNop = (CommandCompleteForNop)PacketHelper.GetPacketTypeFromList(typeof(CommandCompleteForNop), packets);
					CheckStatus(commandCompleteForNop);
				}
			}
			else
			{
				Thread.Sleep(50);
			}
			EdlResetRequest packet6 = new EdlResetRequest();
			Send(packet6);
			Thread.Sleep(500);
			try
			{
				EdlGetAppVerRequest packet7 = new EdlGetAppVerRequest();
				Send(packet7);
				if (!skipResponseChecks)
				{
					if (flag)
					{
						Type[] packetTypes4 = new Type[1] { typeof(CommandCompleteForEdlGetAppVerRequest) };
						packets = modeAgnosticDataReceiver.ReceiveAll(packetTypes4, resetWaitTimeMs);
						CommandCompleteForEdlGetAppVerRequest packet8 = (CommandCompleteForEdlGetAppVerRequest)PacketHelper.GetPacketTypeFromList(typeof(CommandCompleteForEdlGetAppVerRequest), packets);
						CheckStatus(packet8);
					}
					else
					{
						Type[] packetTypes5 = new Type[2]
						{
							typeof(EdlGetAppVerResponse),
							typeof(CommandCompleteForNop)
						};
						packets = modeAgnosticDataReceiver.ReceiveAll(packetTypes5, responseWaitTimeMs);
						commandCompleteForNop = (CommandCompleteForNop)PacketHelper.GetPacketTypeFromList(typeof(CommandCompleteForNop), packets);
						CheckStatus(commandCompleteForNop);
					}
				}
				else
				{
					Thread.Sleep(50);
				}
			}
			catch (TimeoutException)
			{
				logger.NotifyObserver(new LogMessage(LogMessageType.Warning, "Timeout getting app version, retrying"));
				EdlGetAppVerRequest packet9 = new EdlGetAppVerRequest();
				Send(packet9);
				if (!skipResponseChecks)
				{
					if (flag)
					{
						packetBase = modeAgnosticDataReceiver.Receive(responseWaitTimeMs);
						CommandCompleteForEdlGetAppVerRequest packet10 = (CommandCompleteForEdlGetAppVerRequest)packetBase;
						CheckStatus(packet10);
					}
					else
					{
						Type[] packetTypes6 = new Type[2]
						{
							typeof(EdlGetAppVerResponse),
							typeof(CommandCompleteForNop)
						};
						packets = modeAgnosticDataReceiver.ReceiveAll(packetTypes6, responseWaitTimeMs);
						commandCompleteForNop = (CommandCompleteForNop)PacketHelper.GetPacketTypeFromList(typeof(CommandCompleteForNop), packets);
						CheckStatus(commandCompleteForNop);
					}
				}
				else
				{
					Thread.Sleep(50);
				}
			}
			logger.NotifyObserver(new LogMessage(LogMessageType.Info, "Finished BT Firmware Patching"));
		}
		finally
		{
			modeAgnosticDataReceiver.Shutdown();
		}
	}

	public void PatchFirmwareTLV(string filename, bool skipResponseChecks = false)
	{
		logger.NotifyObserver(new LogMessage(LogMessageType.Info, "Starting BT Firmware TLV Patching"));
		byte[] array = File.ReadAllBytes(filename);
		int num = 0;
		bool flag = false;
		bool flag2 = false;
		if (!skipResponseChecks && array.Length > 14)
		{
			num = array[14];
			logger.NotifyObserver(new LogMessage(LogMessageType.Info, "Patch download configuration: skipVendorStatusEventCheck = " + ((num & 1) == 1) + ", skipCCEventCheck = " + ((num & 2) == 2)));
		}
		ModeAgnosticDataReceiver modeAgnosticDataReceiver = new ModeAgnosticDataReceiver(this);
		modeAgnosticDataReceiver.Startup();
		if (array[0] != 1)
		{
			logger.NotifyObserver(new LogMessage(LogMessageType.Error, "Incorrect TLV file format"));
			logger.NotifyObserver(new LogMessage(LogMessageType.Error, "Failed to finish BT Firmware TLV Patching"));
			return;
		}
		try
		{
			PatchVerRequest packet = new PatchVerRequest();
			Send(packet);
			PacketBase packetBase = null;
			List<PacketBase> list = null;
			CommandCompleteForPatchVerRequest commandCompleteForPatchVerRequest = null;
			bool flag3 = false;
			if (!skipResponseChecks)
			{
				packetBase = modeAgnosticDataReceiver.Receive(resetWaitTimeMs);
				if (packetBase is PatchVerResponse)
				{
					_ = (PatchVerResponse)packetBase;
					packetBase = modeAgnosticDataReceiver.Receive(typeof(CommandCompleteForNop), resetWaitTimeMs);
				}
				else
				{
					flag3 = true;
					commandCompleteForPatchVerRequest = (CommandCompleteForPatchVerRequest)packetBase;
					CheckStatus(commandCompleteForPatchVerRequest);
				}
			}
			else
			{
				Thread.Sleep(50);
			}
			TlvDownload(array, skipResponseChecks, flag3, num);
			Thread.Sleep(50);
			Reset packet2 = new Reset();
			Send(packet2);
			if (!skipResponseChecks)
			{
				List<Type> expectedResponseList = new List<Type>();
				string errorCodeType = "";
				if (num != 0)
				{
					if (flag3)
					{
						expectedResponseList.AddRange(new Type[1] { typeof(CommandCompleteForTlvDownloadRequest) });
						errorCodeType = "TlvDownloadResponseErrorCodeEnum";
					}
					else
					{
						expectedResponseList.AddRange(new Type[1] { typeof(TlvDownloadResponse) });
						errorCodeType = "EdlErrorCodeEnum";
					}
				}
				expectedResponseList.AddRange(new Type[1] { typeof(CommandCompleteForReset) });
				list = modeAgnosticDataReceiver.ReceiveAll(expectedResponseList.ToArray(), resetWaitTimeMs);
				PacketBase packet3 = list.FindLast((PacketBase packetResponse) => packetResponse.GetType() == expectedResponseList[0]);
				CheckStatus(packet3, errorCodeType);
				CommandCompleteForReset packet4 = (CommandCompleteForReset)PacketHelper.GetPacketTypeFromList(typeof(CommandCompleteForReset), list);
				CheckStatus(packet4);
			}
			Send(packet);
			if (!skipResponseChecks)
			{
				packetBase = modeAgnosticDataReceiver.Receive(resetWaitTimeMs);
				if (packetBase is CommandCompleteForPatchVerRequest)
				{
					commandCompleteForPatchVerRequest = (CommandCompleteForPatchVerRequest)packetBase;
					CheckStatus(commandCompleteForPatchVerRequest);
				}
				else if (packetBase is PatchVerResponse)
				{
					_ = (PatchVerResponse)packetBase;
					packetBase = modeAgnosticDataReceiver.Receive(typeof(CommandCompleteForNop), resetWaitTimeMs);
				}
			}
			logger.NotifyObserver(new LogMessage(LogMessageType.Info, "Finished BT Firmware Patching"));
		}
		finally
		{
			modeAgnosticDataReceiver.Shutdown();
		}
	}

	private void WriteCombinedNVMTLV_BIN(byte[] tlvData, bool skipResponseChecks = false)
	{
		int num = 0;
		int num2 = tlvData.Length;
		int num3 = 0;
		int num4 = 0;
		int num5 = 0;
		ModeAgnosticDataReceiver modeAgnosticDataReceiver = new ModeAgnosticDataReceiver(this);
		modeAgnosticDataReceiver.Startup();
		int num6 = tlvData[num4++];
		if (num6 != 4)
		{
			throw new Exception("File type does not match combined NVM bin type. First byte is 0x" + num6.ToString("X"));
		}
		num2 = tlvData[num4++];
		num2 += tlvData[num4++] << 8;
		num4++;
		try
		{
			PacketBase packetBase = null;
			while (num4 < num2)
			{
				num5 = tlvData[num4];
				if (num5 != 2 && num5 != 3)
				{
					throw new Exception("NVM bin file malformed. Byte 0x" + num5.ToString("X2"));
				}
				num3 = tlvData[num4 + 1];
				num3 += tlvData[num4 + 2] << 8;
				num = num3 + 4;
				while (num > 0)
				{
					int num7 = num;
					if (num7 > 243)
					{
						num7 = 243;
					}
					TlvDownloadRequest tlvDownloadRequest = new TlvDownloadRequest();
					tlvDownloadRequest.UserFields.TlvSegmentLength = (uint)num7;
					for (int i = 0; i < num7; i++)
					{
						tlvDownloadRequest.UserFields.DataList[i] = tlvData[num4++];
					}
					num -= num7;
					Send(tlvDownloadRequest);
					if (num == 0)
					{
						skipResponseChecks = true;
					}
					packetBase = null;
					if (!skipResponseChecks)
					{
						packetBase = modeAgnosticDataReceiver.Receive(new Type[2]
						{
							typeof(TlvDownloadResponse),
							typeof(CommandCompleteForTlvDownloadRequest)
						}, resetWaitTimeMs);
						if (packetBase is TlvDownloadResponse)
						{
							TlvDownloadResponse packet = (TlvDownloadResponse)packetBase;
							CheckStatus(packet, "EdlErrorCodeEnum");
							packetBase = modeAgnosticDataReceiver.Receive(new Type[1] { typeof(CommandCompleteForNop) }, resetWaitTimeMs);
						}
						else if (packetBase is CommandCompleteForTlvDownloadRequest)
						{
							CommandCompleteForTlvDownloadRequest packet2 = (CommandCompleteForTlvDownloadRequest)packetBase;
							CheckStatus(packet2, "TlvDownloadResponseErrorCodeEnum");
						}
					}
					else
					{
						Thread.Sleep(50);
					}
					if (num == 0)
					{
						int millisecondsTimeout = 500;
						Thread.Sleep(millisecondsTimeout);
					}
				}
			}
			Thread.Sleep(50);
			logger.NotifyObserver(new LogMessage(LogMessageType.Info, "Finished BT NVM download"));
			Reset reset = new Reset();
			Send(reset);
			if (!skipResponseChecks)
			{
				PacketBase packet3 = modeAgnosticDataReceiver.Receive(reset.ExpectedResponseTypes, resetWaitTimeMs);
				CheckStatus(packet3);
			}
		}
		catch (Exception ex)
		{
			logger.NotifyObserver(new LogMessage(LogMessageType.Error, "Failed Combined NVM download"));
			throw ex;
		}
		finally
		{
			modeAgnosticDataReceiver.Startup();
		}
	}

	private void TlvDownload(byte[] tlvData, bool skipResponseChecks = false, bool isNewVSC = false, int downloadConfig = 0)
	{
		int num = 0;
		int num2 = tlvData.Length;
		bool flag = (downloadConfig & 1) == 1;
		bool flag2 = (downloadConfig & 2) == 2;
		ModeAgnosticDataReceiver modeAgnosticDataReceiver = new ModeAgnosticDataReceiver(this);
		modeAgnosticDataReceiver.Startup();
		List<Type> list = new List<Type>();
		if (!skipResponseChecks)
		{
			if (isNewVSC)
			{
				if (!flag && !flag2)
				{
					list.Add(typeof(CommandCompleteForTlvDownloadRequest));
				}
			}
			else if (!flag)
			{
				list.Add(typeof(TlvDownloadResponse));
			}
			else if (!flag2)
			{
				list.Add(typeof(CommandCompleteForNop));
			}
		}
		try
		{
			while (num2 > 0)
			{
				int num3 = num2;
				if (num3 > 243)
				{
					num3 = 243;
				}
				TlvDownloadRequest tlvDownloadRequest = new TlvDownloadRequest();
				tlvDownloadRequest.UserFields.TlvSegmentLength = (uint)num3;
				for (int i = 0; i < num3; i++)
				{
					tlvDownloadRequest.UserFields.DataList[i] = tlvData[num++];
				}
				num2 -= num3;
				Send(tlvDownloadRequest);
				PacketBase packetBase = null;
				if (!skipResponseChecks && list.Count != 0)
				{
					packetBase = modeAgnosticDataReceiver.Receive(list.ToArray(), resetWaitTimeMs);
					if (packetBase is TlvDownloadResponse)
					{
						TlvDownloadResponse packet = (TlvDownloadResponse)packetBase;
						CheckStatus(packet, "EdlErrorCodeEnum");
						if (!flag2 && num2 != 0)
						{
							_ = (CommandCompleteForNop)modeAgnosticDataReceiver.Receive(new Type[1] { typeof(CommandCompleteForNop) }, resetWaitTimeMs);
						}
					}
					else if (packetBase is CommandCompleteForTlvDownloadRequest)
					{
						CommandCompleteForTlvDownloadRequest packet2 = (CommandCompleteForTlvDownloadRequest)packetBase;
						CheckStatus(packet2, "TlvDownloadResponseErrorCodeEnum");
					}
					else if (!(packetBase is CommandCompleteForNop))
					{
					}
				}
				else
				{
					Thread.Sleep(50);
				}
				if (num2 == 0)
				{
					int millisecondsTimeout = 500;
					Thread.Sleep(millisecondsTimeout);
				}
			}
		}
		catch (Exception ex)
		{
			logger.NotifyObserver(new LogMessage(LogMessageType.Error, "Failed TLV download"));
			throw ex;
		}
		finally
		{
			modeAgnosticDataReceiver.Shutdown();
		}
	}

	public void WriteNVMTLV_BIN(string filename, bool skipResponseChecks = false, ProtocolHCI.SleepModeState sleepMode = ProtocolHCI.SleepModeState.NONE)
	{
		logger.NotifyObserver(new LogMessage(LogMessageType.Info, "Starting BT NVM download BIN/TLV format"));
		byte[] array = File.ReadAllBytes(filename);
		ModeAgnosticDataReceiver modeAgnosticDataReceiver = new ModeAgnosticDataReceiver(this);
		modeAgnosticDataReceiver.Startup();
		if (array[0] == 4)
		{
			WriteCombinedNVMTLV_BIN(array, skipResponseChecks);
			return;
		}
		if (array[0] != 2)
		{
			logger.NotifyObserver(new LogMessage(LogMessageType.Error, "Incorrect BIN/TLV file format"));
			logger.NotifyObserver(new LogMessage(LogMessageType.Error, "Failed to finish BT NVM download"));
			throw new Exception("Incorrect BIN/TLV file format");
		}
		PatchVerRequest packet = new PatchVerRequest();
		Send(packet);
		PacketBase packetBase = null;
		bool isNewVSC = false;
		if (!skipResponseChecks)
		{
			packetBase = modeAgnosticDataReceiver.Receive(resetWaitTimeMs);
			if (packetBase is PatchVerResponse)
			{
				packetBase = modeAgnosticDataReceiver.Receive(typeof(CommandCompleteForNop), resetWaitTimeMs);
			}
			else
			{
				isNewVSC = true;
				PacketBase packet2 = (CommandCompleteForPatchVerRequest)packetBase;
				CheckStatus(packet2);
			}
		}
		try
		{
			TlvDownload(array, skipResponseChecks, isNewVSC);
			Thread.Sleep(50);
			logger.NotifyObserver(new LogMessage(LogMessageType.Info, "Finished BT NVM BIN download"));
			Reset reset = new Reset();
			Send(reset);
			if (sleepMode != 0)
			{
				SetSleepMode(sleepMode);
			}
			List<PacketBase> packets = modeAgnosticDataReceiver.ReceiveAll(reset.ExpectedResponseTypes, resetWaitTimeMs);
			CommandCompleteForReset packet3 = (CommandCompleteForReset)PacketHelper.GetPacketTypeFromList(typeof(CommandCompleteForReset), packets);
			CheckStatus(packet3);
		}
		finally
		{
			modeAgnosticDataReceiver.Shutdown();
		}
	}

	public void InitTrafficGenL2CAP(BTTrafficGenInfo trafficGenInfo, QCRPG.Framework.IObserver<TrafficGenInfoBase> observer)
	{
		trafficGenInfo.stop = false;
		trafficGenInfo.numCompletedAclPackets = (trafficGenInfo.completedByteCount = (trafficGenInfo.l2capSentPacketCount = (trafficGenInfo.l2capReceivedPacketCount = 0u)));
		if (trafficGenInfo.l2capPacketLength > 65539)
		{
			logger.Enqueue(new LogMessage(LogMessageType.Warning, $"Maximum value for L2CAP packet length is {65539u}"));
			trafficGenInfo.l2capPacketLength = 65539u;
		}
		lock (trafficGenInfoList)
		{
			trafficGenInfoList.Add(trafficGenInfo);
		}
		RegisterTrafficGenStatusObserver(observer);
		receivedTrafficPacketTimer = new System.Timers.Timer();
		receivedTrafficPacketTimer.Interval = TrafficGenInfoBase.timeoutPerPacket * 1000;
		receivedTrafficPacketTimer.AutoReset = false;
		receivedTrafficPacketTimer.Enabled = false;
		receivedTrafficPacketTimer.Elapsed += delegate
		{
			receiveTrafficGenTimer_Elapsed(trafficGenInfo);
		};
	}

	private void receiveTrafficGenTimer_Elapsed(BTTrafficGenInfo trafficGenInfo)
	{
		logger.Enqueue(new LogMessage(LogMessageType.Info, "Timeout Per Packet ( " + receivedTrafficPacketTimer.Interval + " msec) expired."));
		receivedTrafficPacketTimer.Stop();
		NotifyTrafficGenStatus(TrafficGenStatus.Fail, trafficGenInfo);
	}

	public void RunTrafficGenL2CAP(BTTrafficGenInfo trafficGenInfo)
	{
		uint num = 0u;
		trafficGenInfo.stop = false;
		trafficGenInfo.numCompletedAclPackets = 0u;
		trafficGenInfo.completedByteCount = 0u;
		trafficGenInfo.l2capSentPacketCount = 0u;
		trafficGenInfo.l2capSentDataCount = 0u;
		trafficGenInfo.l2capSendDataLength = trafficGenInfo.l2capPacketLength - 4;
		trafficGenInfo.startTime = DateTime.Now;
		byte generatedData = trafficGenInfo.txSeed;
		receivedTrafficPacketTimer.Enabled = false;
		while (trafficGenInfo.l2capSentPacketCount < trafficGenInfo.numL2CAPPackets && !trafficGenInfo.stop)
		{
			try
			{
				generatedData = ACLDataTransferFromTrafficGenInfo(trafficGenInfo, 64, generatedData);
			}
			catch (ThreadAbortException)
			{
				Thread.ResetAbort();
				break;
			}
			num++;
			if (trafficGenInfo.l2capSentDataCount == trafficGenInfo.l2capSendDataLength)
			{
				trafficGenInfo.l2capSentDataCount = 0u;
				if (++trafficGenInfo.l2capSentPacketCount == trafficGenInfo.numL2CAPPackets)
				{
					break;
				}
			}
		}
		trafficGenInfo.stopTime = DateTime.Now;
		TimeSpan timeSpan = trafficGenInfo.stopTime - trafficGenInfo.startTime;
		while (trafficGenInfo.numCompletedAclPackets < num)
		{
			Thread.Yield();
			trafficGenInfo.stopTime = DateTime.Now;
			timeSpan = trafficGenInfo.stopTime - trafficGenInfo.startTime;
			if (timeSpan.TotalSeconds > (double)TrafficGenInfoBase.timeoutPeriod)
			{
				logger.Enqueue(new LogMessage(LogMessageType.Error, $"After {timeSpan}, Number of completed packets = {trafficGenInfo.numCompletedAclPackets} < {num}"));
				NotifyTrafficGenStatus(TrafficGenStatus.Fail, trafficGenInfo);
				return;
			}
		}
		NotifyTrafficGenStatus(trafficGenInfo.stop ? TrafficGenStatus.Fail : TrafficGenStatus.Success, trafficGenInfo);
		logger.Enqueue(new LogMessage(LogMessageType.Error, string.Format("Notify traffic gen status {1} received = {0}", trafficGenInfo.l2capReceivedPacketCount, trafficGenInfo.stop)));
	}

	internal static byte ACLDataTransferFromTrafficGenInfo(BTTrafficGenInfo trafficGenInfo, ushort channelID, byte generatedData)
	{
		List<byte> list = new List<byte>();
		uint num = 0u;
		byte b = 0;
		if (trafficGenInfo.l2capSentDataCount == 0)
		{
			b = (byte)(trafficGenInfo.flushable ? 32u : 0u);
			switch (trafficGenInfo.trafficGenMode)
			{
			case BTTrafficGenMode.Fixed:
				generatedData = trafficGenInfo.txSeed;
				break;
			default:
				generatedData = trafficGenInfo.txSeed++;
				break;
			case BTTrafficGenMode.MinToMax:
				generatedData = 0;
				break;
			case BTTrafficGenMode.Sweep:
				break;
			}
			list.Add((byte)(trafficGenInfo.l2capSendDataLength & 0xFFu));
			list.Add((byte)(trafficGenInfo.l2capSendDataLength >> 8));
			list.Add((byte)(channelID & 0xFFu));
			list.Add((byte)(channelID >> 8));
			if (trafficGenInfo.enableSeqNum)
			{
				for (int i = 0; (long)i < 4L; i++)
				{
					list.Add((byte)((trafficGenInfo.seqNum >> 8 * (4 - i - 1)) & 0xFFu));
				}
				num = trafficGenInfo.aclDataLength - 4 - 4;
				trafficGenInfo.seqNum++;
				trafficGenInfo.l2capSentDataCount += 4u;
			}
			else
			{
				num = trafficGenInfo.aclDataLength - 4;
			}
		}
		else
		{
			b = 16;
			num = trafficGenInfo.aclDataLength;
		}
		for (int j = 0; j < num; j++)
		{
			list.Add(generatedData);
			if (trafficGenInfo.trafficGenMode != 0)
			{
				generatedData = (byte)((generatedData != byte.MaxValue) ? (++generatedData) : 0);
			}
			trafficGenInfo.l2capSentDataCount++;
			if (trafficGenInfo.l2capSentDataCount == trafficGenInfo.l2capSendDataLength)
			{
				break;
			}
		}
		byte[] array = list.ToArray();
		AclData aclData = new AclData();
		aclData.UserFields.Handle = trafficGenInfo.connectionHandle;
		aclData.UserFields.Flags = b;
		aclData.UserFields.DataLength = (uint)array.Length;
		for (int k = 0; k < array.Length; k++)
		{
			aclData.UserFields.DataList[k] = array[k];
		}
		trafficGenInfo.aclDataQueue.Enqueue(aclData);
		return generatedData;
	}

	public void UpdateTrafficGenNumberOfCompletedPackets(PacketBase packet)
	{
		if (packet is NumberOfCompletedPacketsEvent)
		{
			NumberOfCompletedPacketsEvent numberOfCompletedPacketsEvent = (NumberOfCompletedPacketsEvent)packet;
			BTTrafficGenInfo bTTrafficGenInfo = trafficGenInfoList.Find((BTTrafficGenInfo info) => info.connectionHandle == numberOfCompletedPacketsEvent.UserFields.ConnectionHandle && info.endType == TrafficEndType.Source);
			if (bTTrafficGenInfo == null)
			{
				logger.Enqueue(new LogMessage(LogMessageType.Warning, "Unexpected Number of Completed Packets event"));
			}
			else
			{
				bTTrafficGenInfo.numCompletedAclPackets += numberOfCompletedPacketsEvent.UserFields.HcNumOfCompletedPackets;
			}
		}
	}

	public void CompareTrafficL2CAP(PacketBase packet)
	{
		if (!(packet is AclData))
		{
			return;
		}
		AclData aclData = (AclData)packet;
		uint connectionHandle = ((aclData.UserFields.Flags << 8) | aclData.UserFields.Handle) & 0xFFFu;
		if (connectionHandle == 3804)
		{
			return;
		}
		BTTrafficGenInfo bTTrafficGenInfo = null;
		lock (trafficGenInfoList)
		{
			bTTrafficGenInfo = trafficGenInfoList.Find((BTTrafficGenInfo info) => info.connectionHandle == connectionHandle && info.endType == TrafficEndType.Destination);
		}
		if (bTTrafficGenInfo == null)
		{
			logger.Enqueue(new LogMessage(LogMessageType.Warning, "Unexpected ACL data packet"));
			return;
		}
		if (bTTrafficGenInfo.l2capReceivedPacketCount == 0 && bTTrafficGenInfo.l2capReceivedHeaderCount == 0)
		{
			bTTrafficGenInfo.startTime = DateTime.Now;
		}
		bTTrafficGenInfo.stopTime = DateTime.Now;
		bTTrafficGenInfo.completedByteCount += aclData.UserFields.DataLength;
		if (bTTrafficGenInfo.stop)
		{
			logger.Enqueue(new LogMessage(LogMessageType.Warning, "Removing stopped BTTrafficGenInfo and ignoring ACL data packet"));
			lock (trafficGenInfoList)
			{
				trafficGenInfoList.Remove(bTTrafficGenInfo);
				return;
			}
		}
		receivedTrafficPacketTimer.Stop();
		int i = 0;
		if (bTTrafficGenInfo.l2capReceivedHeaderCount < 4)
		{
			if (bTTrafficGenInfo.l2capReceivedHeaderCount == 0)
			{
				if (aclData.UserFields.Flags != 32 && aclData.UserFields.Flags != 0)
				{
					lock (trafficGenInfoList)
					{
						trafficGenInfoList.Remove(bTTrafficGenInfo);
					}
					logger.Enqueue(new LogMessage(LogMessageType.Error, $"Expected Flags = {32}, Received {aclData.UserFields.Flags}"));
					bTTrafficGenInfo.status = TrafficGenStatus.Fail;
					trafficGenStatusNotifier.NotifyObservers(bTTrafficGenInfo);
					return;
				}
			}
			else if (aclData.UserFields.Flags != 16)
			{
				lock (trafficGenInfoList)
				{
					trafficGenInfoList.Remove(bTTrafficGenInfo);
				}
				logger.Enqueue(new LogMessage(LogMessageType.Error, $"Expected Flags = {16}, Received {aclData.UserFields.Flags}"));
				bTTrafficGenInfo.status = TrafficGenStatus.Fail;
				trafficGenStatusNotifier.NotifyObservers(bTTrafficGenInfo);
				return;
			}
			uint num = Math.Min(aclData.UserFields.DataLength, 4 - bTTrafficGenInfo.l2capReceivedHeaderCount);
			int num2 = (int)bTTrafficGenInfo.l2capReceivedHeaderCount;
			i = 0;
			while (i < aclData.UserFields.DataLength && num2 < 2)
			{
				bTTrafficGenInfo.l2capReceiveDataLength += aclData.UserFields.DataList[i] << 8 * num2;
				i++;
				num2++;
			}
			num2 -= 2;
			while (i < aclData.UserFields.DataLength && num2 < 2)
			{
				bTTrafficGenInfo.l2capReceivedChannelId += aclData.UserFields.DataList[i] << 8 * num2;
				i++;
				num2++;
			}
			bTTrafficGenInfo.l2capReceivedHeaderCount += num;
			if (bTTrafficGenInfo.l2capReceivedHeaderCount == 4)
			{
				if (bTTrafficGenInfo.l2capReceivedChannelId != 64)
				{
					bTTrafficGenInfo.l2capReceivedHeaderCount -= num;
					bTTrafficGenInfo.l2capReceivedChannelId = (bTTrafficGenInfo.l2capReceiveDataLength = 0u);
					logger.Enqueue(new LogMessage(LogMessageType.Warning, "Unexpected ACL data packet"));
					return;
				}
				if (bTTrafficGenInfo.l2capReceiveDataLength != bTTrafficGenInfo.l2capPacketLength - 4)
				{
					lock (trafficGenInfoList)
					{
						trafficGenInfoList.Remove(bTTrafficGenInfo);
					}
					logger.Enqueue(new LogMessage(LogMessageType.Error, $"Expected L2CAP data length = {bTTrafficGenInfo.l2capPacketLength - 4}, Received {bTTrafficGenInfo.l2capReceiveDataLength}"));
					bTTrafficGenInfo.status = TrafficGenStatus.Fail;
					trafficGenStatusNotifier.NotifyObservers(bTTrafficGenInfo);
					return;
				}
				switch (bTTrafficGenInfo.trafficGenMode)
				{
				case BTTrafficGenMode.Fixed:
					bTTrafficGenInfo.expectedData = bTTrafficGenInfo.rxSeed;
					break;
				default:
					bTTrafficGenInfo.expectedData = bTTrafficGenInfo.rxSeed++;
					break;
				case BTTrafficGenMode.MinToMax:
					bTTrafficGenInfo.expectedData = 0;
					break;
				case BTTrafficGenMode.Sweep:
					break;
				}
			}
			bTTrafficGenInfo.l2capReceivedDataCount += aclData.UserFields.DataLength - num;
			if (bTTrafficGenInfo.enableSeqNum)
			{
				_ = aclData.UserFields.DataList;
				uint num3 = 0u;
				int num4 = 0;
				while (i < aclData.UserFields.DataLength && (long)num4 < 4L)
				{
					num3 += aclData.UserFields.DataList[i] << 8 * (4 - num4 - 1);
					i++;
					num4++;
				}
				if (num3 != bTTrafficGenInfo.seqNum)
				{
					lock (trafficGenInfoList)
					{
						trafficGenInfoList.Remove(bTTrafficGenInfo);
					}
					logger.Enqueue(new LogMessage(LogMessageType.Error, $"Expected SeqNum = {bTTrafficGenInfo.seqNum}, Received SeqNum = {num3}"));
					bTTrafficGenInfo.status = TrafficGenStatus.Fail;
					trafficGenStatusNotifier.NotifyObservers(bTTrafficGenInfo);
					return;
				}
				bTTrafficGenInfo.seqNum++;
			}
		}
		else
		{
			if (aclData.UserFields.Flags != 16)
			{
				lock (trafficGenInfoList)
				{
					trafficGenInfoList.Remove(bTTrafficGenInfo);
				}
				logger.Enqueue(new LogMessage(LogMessageType.Error, $"Expected Flags = {16}, Received {aclData.UserFields.Flags}"));
				bTTrafficGenInfo.status = TrafficGenStatus.Fail;
				trafficGenStatusNotifier.NotifyObservers(bTTrafficGenInfo);
				return;
			}
			bTTrafficGenInfo.l2capReceivedDataCount += aclData.UserFields.DataLength;
		}
		List<uint> dataList = aclData.UserFields.DataList;
		for (int count = dataList.Count; i < count; i++)
		{
			if (dataList[i] != bTTrafficGenInfo.expectedData)
			{
				logger.Enqueue(new LogMessage(LogMessageType.Error, $"CompareTrafficL2CAP Expected Data = {bTTrafficGenInfo.expectedData:X}, Received {dataList[i]:X} at index = {i}"));
				logger.Enqueue(new LogMessage(LogMessageType.Error, $"CompareTrafficL2CAP Data received on integrity failure: {aclData.Info.FieldInfoList[3].Value}"));
				NotifyTrafficGenStatus(TrafficGenStatus.Fail, bTTrafficGenInfo);
				return;
			}
			if (bTTrafficGenInfo.trafficGenMode != 0)
			{
				bTTrafficGenInfo.expectedData = (byte)((bTTrafficGenInfo.expectedData != byte.MaxValue) ? (++bTTrafficGenInfo.expectedData) : 0);
			}
		}
		if (bTTrafficGenInfo.l2capReceivedDataCount == bTTrafficGenInfo.l2capReceiveDataLength)
		{
			bTTrafficGenInfo.l2capReceivedPacketCount++;
			if (bTTrafficGenInfo.l2capReceivedPacketCount == bTTrafficGenInfo.numL2CAPPackets)
			{
				NotifyTrafficGenStatus(TrafficGenStatus.Success, bTTrafficGenInfo);
			}
			bTTrafficGenInfo.l2capReceivedHeaderCount = (bTTrafficGenInfo.l2capReceivedDataCount = 0u);
			bTTrafficGenInfo.l2capReceivedChannelId = (bTTrafficGenInfo.l2capReceiveDataLength = 0u);
		}
		if (!isTrafficCompleted)
		{
			receivedTrafficPacketTimer.Start();
		}
	}

	public void NotifyTrafficGenStatus(TrafficGenStatus trafficGenStatus, BTTrafficGenInfo trafficGenInfo)
	{
		isTrafficCompleted = true;
		receivedTrafficPacketTimer.Stop();
		logger.Enqueue(new LogMessage(LogMessageType.Error, $"Removing traffic gen. Status = {trafficGenStatus.ToString()}"));
		lock (trafficGenInfoList)
		{
			trafficGenInfoList.Remove(trafficGenInfo);
		}
		trafficGenInfo.status = trafficGenStatus;
		trafficGenStatusNotifier.NotifyObservers(trafficGenInfo);
	}

	public void RegisterTrafficGenStatusObserver(QCRPG.Framework.IObserver<TrafficGenInfoBase> observer)
	{
		trafficGenStatusNotifier.RegisterObserver(observer);
	}

	public void UnregisterTrafficGenStatusObserver(QCRPG.Framework.IObserver<TrafficGenInfoBase> observer)
	{
		trafficGenStatusNotifier.UnregisterObserver(observer);
	}

	public void ClearTrafficGen()
	{
		trafficGenInfoList.Clear();
	}

	internal static byte ISODataTransferFromTrafficGenInfo(CISTrafficGenInfo trafficGenInfo, byte generatedData)
	{
		List<byte> list = new List<byte>();
		uint num = 0u;
		switch (trafficGenInfo.trafficGenMode)
		{
		case BTTrafficGenMode.Fixed:
			generatedData = trafficGenInfo.txSeed;
			break;
		default:
			generatedData = trafficGenInfo.txSeed++;
			break;
		case BTTrafficGenMode.MinToMax:
			generatedData = 0;
			break;
		case BTTrafficGenMode.Sweep:
			break;
		}
		num = trafficGenInfo.aclDataLength;
		for (int i = 0; i < num; i++)
		{
			list.Add(generatedData);
			if (trafficGenInfo.trafficGenMode != 0)
			{
				generatedData = (byte)((generatedData != byte.MaxValue) ? (++generatedData) : 0);
			}
		}
		byte[] array = list.ToArray();
		SynchronousData synchronousData = new SynchronousData();
		synchronousData.UserFields.Handle = trafficGenInfo.connectionHandle;
		synchronousData.UserFields.Flags = 0u;
		synchronousData.UserFields.DataLength = (uint)array.Length;
		for (int j = 0; j < array.Length; j++)
		{
			synchronousData.UserFields.DataList[j] = array[j];
		}
		trafficGenInfo.isoDataQueue.Enqueue(synchronousData);
		return generatedData;
	}

	public void RunCisDataTrafficGen(CISTrafficGenInfo trafficGenInfo)
	{
		trafficGenInfo.stop = false;
		trafficGenInfo.numCompletedAclPackets = 0u;
		trafficGenInfo.completedByteCount = 0u;
		trafficGenInfo.l2capSentPacketCount = 0u;
		trafficGenInfo.l2capSentDataCount = 0u;
		trafficGenInfo.startTime = DateTime.Now;
		byte generatedData = trafficGenInfo.txSeed;
		while (trafficGenInfo.l2capSentPacketCount < trafficGenInfo.numL2CAPPackets && !trafficGenInfo.stop)
		{
			try
			{
				generatedData = ISODataTransferFromTrafficGenInfo(trafficGenInfo, generatedData);
			}
			catch (ThreadAbortException)
			{
				Thread.ResetAbort();
				break;
			}
			trafficGenInfo.l2capSentPacketCount++;
		}
		if (trafficGenInfo.isoDataQueue.FlowControl)
		{
			while (trafficGenInfo.numCompletedAclPackets < trafficGenInfo.l2capSentPacketCount)
			{
				Thread.Yield();
			}
		}
	}

	public void CheckLnkIntegrity(PacketBase packet)
	{
		if (!(packet is AclData))
		{
			return;
		}
		AclData aclData = (AclData)packet;
		lnkTotalAclPacketsReceived++;
		int num = 0;
		while (lnkHeaderLength == 0 && num < aclData._UserFields.DataLength - 1)
		{
			for (int i = 0; i < lnkGeneratedData.Length; i++)
			{
				lnkSplitData = lnkGeneratedData[i];
				if (aclData._UserFields.DataList[num] == lnkSplitData[0] && aclData._UserFields.DataList[num + 1] == lnkSplitData[1])
				{
					lnkHeaderLength = num;
					logger.Enqueue(new LogMessage(LogMessageType.Info, "Using LNKData " + i.ToString() + " " + lnkSplitData[0] + lnkSplitData[1]));
					break;
				}
			}
			num++;
		}
		List<uint> dataList = aclData.UserFields.DataList;
		int j = lnkHeaderLength;
		if (lnkDataIndex != 0 && lnkTotalAclPacketsReceived > 1)
		{
			j = 0;
		}
		bool flag = false;
		for (int count = dataList.Count; j < count; j++)
		{
			if (dataList[j] != lnkSplitData[lnkDataIndex])
			{
				logger.Enqueue(new LogMessage(LogMessageType.Warning, $"CheckLnkIntegrity Expected Data = {lnkSplitData[lnkDataIndex]:X}, Received {dataList[j]:X} at index = {j}"));
				lnkTotalByteErrors++;
				if (!flag)
				{
					lnkTotalPacketErrors++;
					flag = true;
				}
			}
			lnkDataIndex++;
			if (lnkDataIndex >= lnkSplitData.Count)
			{
				lnkDataIndex = 0;
			}
		}
	}

	public void GetLnKIntegrityStatistics()
	{
		PrintLnKStatistics();
	}

	public void GetLnKIntegrityStatistics(out int totalReceivedPackets, out int totalPacketErrors, out int totalByteErrors)
	{
		totalReceivedPackets = lnkTotalAclPacketsReceived;
		totalPacketErrors = lnkTotalPacketErrors;
		totalByteErrors = lnkTotalByteErrors;
		PrintLnKStatistics();
	}

	private void PrintLnKStatistics()
	{
		logger.Enqueue(new LogMessage(LogMessageType.Info, "========== LNK Integrity check statistics =========="));
		logger.Enqueue(new LogMessage(LogMessageType.Info, "Total ACL Data Packets received = " + lnkTotalAclPacketsReceived));
		logger.Enqueue(new LogMessage(LogMessageType.Info, "Total Packets received in error = " + lnkTotalPacketErrors));
		logger.Enqueue(new LogMessage(LogMessageType.Info, "Total Bytes received in error = " + lnkTotalByteErrors));
		logger.Enqueue(new LogMessage(LogMessageType.Info, "LNK Header length in ACL packet = " + lnkHeaderLength));
	}

	private void CheckStatus(PacketBase packet)
	{
		foreach (PacketFieldInfo fieldInfo in packet.Info.FieldInfoList)
		{
			if (fieldInfo.ParameterName == "Status")
			{
				ErrorCodeEnum errorCodeEnum = ErrorCodeInfo.ValueToErrorCode(Convert.ToUInt32(fieldInfo.Value, 16));
				if (errorCodeEnum != 0)
				{
					throw new Exception("Status field indicates error: " + errorCodeEnum);
				}
				return;
			}
		}
		throw new Exception("Packet type doesn't have a status field: " + packet.GetType().ToString());
	}

	private void CheckStatus(PacketBase packet, string ErrorCodeType, uint successCode = 0u)
	{
		foreach (PacketFieldInfo fieldInfo in packet.Info.FieldInfoList)
		{
			if (!(fieldInfo.ParameterName == "Status"))
			{
				continue;
			}
			uint num = Convert.ToUInt32(fieldInfo.Value, 16);
			if (num != successCode)
			{
				string text = "";
				if (Type.GetType("QCRPG.TSL.BT.Packets." + ErrorCodeType) != null && Type.GetType("QCRPG.TSL.BT.Packets." + ErrorCodeType).IsEnum)
				{
					text = Enum.GetName(Type.GetType("QCRPG.TSL.BT.Packets." + ErrorCodeType), num);
				}
				else
				{
					text = Enum.GetName(typeof(ErrorCodeEnum), num);
					logger.Enqueue(new LogMessage(LogMessageType.Warning, "Error Code mapping not found: " + ErrorCodeType + ". Using default Error Code."));
				}
				if (text != null)
				{
					throw new Exception("Status field indicates error: " + text + " (0x" + num.ToString("X") + ")");
				}
				throw new Exception("Status field indicates error: 0x" + num.ToString("X") + " (Invalid status byte)");
			}
			return;
		}
		throw new Exception("Packet type doesn't have a status field: " + packet.GetType().ToString());
	}

	public void SetSleepMode(ProtocolHCI.SleepModeState sleepMode)
	{
		ConnectionSpecificProtocolInfo.SleepModeState sleepMode2 = (ConnectionSpecificProtocolInfo.SleepModeState)Enum.Parse(typeof(ConnectionSpecificProtocolInfo.SleepModeState), sleepMode.ToString());
		SetSleepMode(sleepMode2);
	}

	public void ACLDataPacketTransferViaFile(uint connectionHandle, string filename)
	{
		ModeAgnosticDataReceiver modeAgnosticDataReceiver = new ModeAgnosticDataReceiver(this);
		int num = 1021;
		uint flags = 32u;
		uint flags2 = 16u;
		try
		{
			logger.NotifyObserver(new LogMessage(LogMessageType.Info, $"Starting ACL data transfer for {filename}"));
			byte[] array = File.ReadAllBytes(filename);
			AclData aclData = new AclData();
			aclData.UserFields.Handle = connectionHandle;
			modeAgnosticDataReceiver.Startup();
			if (array.Length <= num)
			{
				aclData.UserFields.Flags = flags;
				List<uint> list = new List<uint>();
				for (int i = 0; i < array.Length; i++)
				{
					list.Add(array[i]);
				}
				aclData.UserFields.DataList.AddRange(list);
				aclData.UserFields.DataLength = (uint)array.Length;
				SendAndCheckACLPacket(modeAgnosticDataReceiver, aclData);
				return;
			}
			int num2 = array.Length;
			int num3 = num;
			bool flag = true;
			while (num2 > 0)
			{
				int num4 = num2;
				if (num4 > num3)
				{
					num4 = num3;
				}
				List<uint> list2 = new List<uint>();
				for (int j = 0; j < num4; j++)
				{
					list2.Add(array[j]);
				}
				if (flag)
				{
					aclData.UserFields.Flags = flags;
					flag = false;
				}
				else
				{
					aclData.UserFields.Flags = flags2;
				}
				aclData.UserFields.DataList.AddRange(list2);
				aclData.UserFields.DataLength = (uint)num4;
				num2 -= num4;
				SendAndCheckACLPacket(modeAgnosticDataReceiver, aclData);
			}
			logger.NotifyObserver(new LogMessage(LogMessageType.Info, "Finished sending ACL packets"));
		}
		catch (Exception ex)
		{
			logger.NotifyObserver(new LogMessage(LogMessageType.Error, "Failed to send ACL data"));
			throw ex;
		}
		finally
		{
			modeAgnosticDataReceiver.Shutdown();
		}
	}

	private void SendAndCheckACLPacket(ModeAgnosticDataReceiver modeAgnosticDataReceiver, AclData aclDataPacket)
	{
		Send(aclDataPacket);
		NumberOfCompletedPacketsEvent numberOfCompletedPacketsEvent = new NumberOfCompletedPacketsEvent();
		Type[] packetTypes = new Type[1] { numberOfCompletedPacketsEvent.GetType() };
		List<PacketBase> list = null;
		list = modeAgnosticDataReceiver.ReceiveAll(packetTypes, resetWaitTimeMs);
		bool flag = false;
		foreach (PacketBase item in list)
		{
			if (item.GetType().Name == "NumberOfCompletedPacketsEvent")
			{
				flag = true;
				break;
			}
		}
		if (!flag)
		{
			logger.NotifyObserver(new LogMessage(LogMessageType.Error, "Failed to receive NumberOfCompletedPacketsEvent"));
			throw new Exception("Failed to receive NumberOfCompletedPacketsEvent");
		}
	}

	public void ACLDataPacketFileTransfer(uint connectionHandle, string filename)
	{
		ModeAgnosticDataReceiver modeAgnosticDataReceiver = new ModeAgnosticDataReceiver(this);
		List<PacketBase> list = null;
		modeAgnosticDataReceiver.Startup();
		ReadBufferSize readBufferSize = new ReadBufferSize();
		int num = 0;
		try
		{
			Send(readBufferSize);
			list = modeAgnosticDataReceiver.ReceiveAll(readBufferSize.ExpectedResponseTypes, responseWaitTimeMs);
			CommandCompleteForReadBufferSize commandCompleteForReadBufferSize = (CommandCompleteForReadBufferSize)PacketHelper.GetPacketTypeFromList(typeof(CommandCompleteForReadBufferSize), list);
			if (!CheckStatusForPacket(commandCompleteForReadBufferSize, readBufferSize.GetType().ToString()))
			{
				throw new Exception("Read buffer size fails.");
			}
			Convert.ToInt32(commandCompleteForReadBufferSize.UserFields.HcAclDataPacketLength);
			Convert.ToInt32(commandCompleteForReadBufferSize.UserFields.HcSynchronousDataPacketLength);
			num = Convert.ToInt32(commandCompleteForReadBufferSize.UserFields.HcTotalNumAclDataPackets);
			Convert.ToInt32(commandCompleteForReadBufferSize.UserFields.HcTotalNumSynchronousDataPackets);
			fileTransferQueue = new FileTransferQueue(this, modeAgnosticDataReceiver);
			fileTransferQueue.SetBufferSize(num);
			fileTransferQueue.Startup();
			fileTransferQueue.Clear();
			AclData aclData = FileNameACLDataPacket(connectionHandle, filename);
			if (aclData == null)
			{
				throw new Exception("file name is not valid.");
			}
			fileTransferQueue.Enqueue(aclData);
			AssembleFilePacketDataInFileTransfer(connectionHandle, filename);
		}
		catch (Exception ex)
		{
			string text = string.Format("File can not be opened for reading: " + ex);
			logger.Enqueue(new LogMessage(LogMessageType.Error, text));
		}
		finally
		{
			fileTransferQueue.Shutdown();
			modeAgnosticDataReceiver.Shutdown();
		}
	}

	private bool CheckStatusForPacket(PacketBase packet, string packetName)
	{
		foreach (PacketFieldInfo fieldInfo in packet.Info.FieldInfoList)
		{
			if (fieldInfo.ParameterName == "Status")
			{
				ErrorCodeEnum errorCodeEnum = ErrorCodeInfo.ValueToErrorCode(Convert.ToUInt32(fieldInfo.Value, 16));
				if (errorCodeEnum != 0)
				{
					logger.Enqueue(new LogMessage(LogMessageType.Error, packetName + " status field indicates error: " + errorCodeEnum));
				}
				return true;
			}
		}
		logger.Enqueue(new LogMessage(LogMessageType.Error, "Packet type doesn't have a status field: " + packetName));
		return false;
	}

	private AclData FileNameACLDataPacket(uint connectionhandler, string filename)
	{
		FileInfo fileInfo = new FileInfo(filename);
		long length = fileInfo.Length;
		if (length > uint.MaxValue)
		{
			logger.Enqueue(new LogMessage(LogMessageType.Error, "File is bigger than supported, the biggest file supported is 4G"));
			return null;
		}
		string name = fileInfo.Name;
		List<byte> list = new List<byte>();
		List<byte> list2 = new List<byte>();
		list2.Add(218);
		list2.Add(218);
		list2.Add((byte)(length & 0xFF));
		list2.Add((byte)((length >> 8) & 0xFF));
		list2.Add((byte)((length >> 16) & 0xFF));
		list2.Add((byte)((length >> 24) & 0xFF));
		char[] array = name.ToCharArray();
		try
		{
			for (int i = 0; i < array.Length; i++)
			{
				list2.Add(Convert.ToByte(array[i]));
			}
		}
		catch (Exception ex)
		{
			logger.Enqueue(new LogMessage(LogMessageType.Error, "File name contains illegal character. " + ex));
			return null;
		}
		list2.Add(0);
		int num = list2.Count - 2;
		list.Add((byte)((uint)num & 0xFFu));
		list.Add((byte)(num >> 8));
		list.AddRange(list2);
		byte[] array2 = list.ToArray();
		AclData aclData = new AclData();
		aclData.UserFields.Handle = connectionhandler;
		aclData.UserFields.Flags = 32u;
		aclData.UserFields.DataLength = (uint)array2.Length;
		for (int j = 0; j < array2.Length; j++)
		{
			aclData.UserFields.DataList[j] = array2[j];
		}
		return aclData;
	}

	private void AssembleFilePacketDataInFileTransfer(uint connectionhandler, string filename)
	{
		BinaryReader binaryReader = null;
		try
		{
			FileInfo fileInfo = new FileInfo(filename);
			long num = fileInfo.Length;
			if (num > uint.MaxValue)
			{
				logger.Enqueue(new LogMessage(LogMessageType.Error, "File is bigger than supported, the biggest file supported is 4G"));
				return;
			}
			try
			{
				binaryReader = new BinaryReader(File.Open(filename, FileMode.Open));
			}
			catch (Exception ex)
			{
				string text = string.Format("File can not be opened for reading: " + ex);
				logger.Enqueue(new LogMessage(LogMessageType.Error, text));
				return;
			}
			int num2 = (int)(num / 65531);
			long num3 = 0L;
			for (int i = 0; i <= num2; i++)
			{
				int num4 = 0;
				int num5 = 0;
				if (num > 65531)
				{
					num4 = 63;
					num5 = 65531;
				}
				else
				{
					num4 = (int)((num + 4) / 1024);
					num5 = (int)num;
				}
				int num6 = num5;
				int num7 = 0;
				for (int j = 0; j <= num4; j++)
				{
					List<byte> list = new List<byte>();
					List<byte> list2 = new List<byte>();
					int num8 = 0;
					num8 = ((num6 <= 1024) ? num6 : 1024);
					if (j == 0 && num6 > 1020)
					{
						num8 = 1020;
					}
					num7 = num8;
					if (j == 0)
					{
						list.Add(218);
						list.Add(218);
						binaryReader.BaseStream.Seek(num3, SeekOrigin.Begin);
						byte[] collection = binaryReader.ReadBytes(num7);
						list.AddRange(collection);
						list2.Add((byte)((uint)num5 & 0xFFu));
						list2.Add((byte)(num5 >> 8));
						list2.AddRange(list);
					}
					else
					{
						binaryReader.BaseStream.Seek(num3, SeekOrigin.Begin);
						byte[] collection2 = binaryReader.ReadBytes(num7);
						list.AddRange(collection2);
						list2.AddRange(list);
					}
					byte[] array = list2.ToArray();
					AclData aclData = new AclData();
					aclData.UserFields.Handle = connectionhandler;
					if (j == 0)
					{
						aclData.UserFields.Flags = 32u;
						if (num6 > 1020)
						{
							aclData.UserFields.DataLength = 1024u;
						}
						else
						{
							aclData.UserFields.DataLength = (uint)array.Length;
						}
					}
					else
					{
						aclData.UserFields.Flags = 16u;
						aclData.UserFields.DataLength = (uint)array.Length;
					}
					for (int k = 0; k < array.Length; k++)
					{
						aclData.UserFields.DataList[k] = array[k];
					}
					fileTransferQueue.Enqueue(aclData);
					num3 += num8;
					num6 -= num8;
				}
				num -= num5;
			}
		}
		finally
		{
			binaryReader?.Close();
		}
	}

	internal void SendSleepByteAfterDataTransfer()
	{
		protocolHCI.PutDeviceToSleepIfNeeded();
	}

	public void Poke16(int Address, byte[] Data)
	{
		EdlPoke16Request edlPoke16Request = new EdlPoke16Request();
		edlPoke16Request.UserFields.Address = (uint)Address;
		edlPoke16Request.UserFields.DataLength = (uint)Data.Length;
		Array.Reverse(Data);
		for (int i = 0; i < Data.Length; i++)
		{
			edlPoke16Request.UserFields.DataList[i] = Data[i];
		}
		logger.NotifyObserver(new LogMessage(LogMessageType.Info, "Starting Poke16"));
		ModeAgnosticDataReceiver modeAgnosticDataReceiver = new ModeAgnosticDataReceiver(this);
		modeAgnosticDataReceiver.Startup();
		try
		{
			Send(edlPoke16Request);
			PacketBase packetBase = null;
			Type[] packetTypes = new Type[2]
			{
				typeof(EdlStatusResponse),
				typeof(CommandCompleteForEdlPoke16Request)
			};
			packetBase = modeAgnosticDataReceiver.Receive(packetTypes, resetWaitTimeMs);
			if (packetBase is EdlStatusResponse)
			{
				CommandCompleteForNop commandCompleteForNop = null;
				packetBase = modeAgnosticDataReceiver.Receive(resetWaitTimeMs);
				commandCompleteForNop = (CommandCompleteForNop)packetBase;
				CheckStatus(commandCompleteForNop);
			}
			else
			{
				CommandCompleteForEdlPoke16Request packet = (CommandCompleteForEdlPoke16Request)packetBase;
				CheckStatus(packet);
			}
		}
		finally
		{
			modeAgnosticDataReceiver.Shutdown();
		}
	}

	public void Poke32(int Address, byte[] Data)
	{
		EdlPoke32Request edlPoke32Request = new EdlPoke32Request();
		edlPoke32Request.UserFields.Address = (uint)Address;
		edlPoke32Request.UserFields.DataLength = (uint)Data.Length;
		Array.Reverse(Data);
		for (int i = 0; i < Data.Length; i++)
		{
			edlPoke32Request.UserFields.DataList[i] = Data[i];
		}
		logger.NotifyObserver(new LogMessage(LogMessageType.Info, "Starting Poke32"));
		ModeAgnosticDataReceiver modeAgnosticDataReceiver = new ModeAgnosticDataReceiver(this);
		modeAgnosticDataReceiver.Startup();
		try
		{
			Send(edlPoke32Request);
			PacketBase packetBase = null;
			CommandCompleteForNop commandCompleteForNop = null;
			Type[] packetTypes = new Type[2]
			{
				typeof(EdlStatusResponse),
				typeof(CommandCompleteForEdlPoke32Request)
			};
			packetBase = modeAgnosticDataReceiver.Receive(packetTypes, resetWaitTimeMs);
			if (packetBase is EdlStatusResponse)
			{
				EdlStatusResponse edlStatusResponse = (EdlStatusResponse)packetBase;
				if (edlStatusResponse.UserFields.GetEdlAppTypeAsEdlAppTypeEnum() != EdlStatusResponse.UserFieldsWrapper.EdlAppTypeEnum.BOOT)
				{
					commandCompleteForNop = (CommandCompleteForNop)modeAgnosticDataReceiver.Receive(typeof(CommandCompleteForNop), resetWaitTimeMs);
					CheckStatus(commandCompleteForNop);
				}
				else
				{
					CheckStatus(edlStatusResponse);
				}
			}
			else
			{
				CommandCompleteForEdlPoke32Request packet = (CommandCompleteForEdlPoke32Request)packetBase;
				CheckStatus(packet);
			}
		}
		finally
		{
			modeAgnosticDataReceiver.Shutdown();
		}
	}

	public void SendGenericCommand(ushort OpCode, int Length, byte[] Data)
	{
		GenericCommand genericCommand = new GenericCommand();
		genericCommand.UserFields.Opcode = OpCode;
		genericCommand.UserFields.PayloadLength = (uint)Length;
		for (int i = 0; i < Data.Length; i++)
		{
			genericCommand.UserFields.PayloadList[i] = Data[i];
		}
		logger.NotifyObserver(new LogMessage(LogMessageType.Info, "Start Sending Generic Command"));
		try
		{
			Send(genericCommand);
		}
		catch (Exception ex)
		{
			string text = string.Format("Send Error. " + ex);
			logger.NotifyObserver(new LogMessage(LogMessageType.Error, text));
		}
	}

	public void ACLData(int connectionHandle, int Flags, int dataLength, byte[] Data)
	{
		AclData aclData = new AclData();
		aclData.UserFields.Handle = (uint)connectionHandle;
		aclData.UserFields.Flags = (uint)Flags;
		aclData.UserFields.DataLength = (uint)dataLength;
		for (int i = 0; i < dataLength; i++)
		{
			aclData.UserFields.DataList[i] = Data[i];
		}
		logger.NotifyObserver(new LogMessage(LogMessageType.Info, "Starting ACL Data"));
		ModeAgnosticDataReceiver modeAgnosticDataReceiver = new ModeAgnosticDataReceiver(this);
		modeAgnosticDataReceiver.Startup();
		try
		{
			Send(aclData);
		}
		finally
		{
			modeAgnosticDataReceiver.Shutdown();
		}
	}

	public void RegisterSendACLDataPacketObserver(QCRPG.Framework.IObserver<PacketBase> observer)
	{
		GC.KeepAlive(sendAclDataPacketObservers);
		lock (sendAclDataPacketObservers)
		{
			if (sendAclDataPacketObservers.Contains(observer))
			{
				return;
			}
			sendAclDataPacketObservers.Add(observer);
		}
		GC.KeepAlive(sendAclDataPacketObservers);
	}

	public void UnregisterSendACLDataPacketObserver(QCRPG.Framework.IObserver<PacketBase> observer)
	{
		GC.KeepAlive(sendAclDataPacketObservers);
		lock (sendAclDataPacketObservers)
		{
			if (!sendAclDataPacketObservers.Contains(observer))
			{
				return;
			}
			sendAclDataPacketObservers.Remove(observer);
		}
		GC.KeepAlive(sendAclDataPacketObservers);
	}

	public void RegisterReceiveACLDataPacketObserver(QCRPG.Framework.IObserver<PacketBase> observer)
	{
		GC.KeepAlive(receiveAclDataPacketObservers);
		lock (receiveAclDataPacketObservers)
		{
			if (receiveAclDataPacketObservers.Contains(observer))
			{
				return;
			}
			receiveAclDataPacketObservers.Add(observer);
		}
		GC.KeepAlive(receiveAclDataPacketObservers);
	}

	public void UnregisterReceiveACLDataPacketObserver(QCRPG.Framework.IObserver<PacketBase> observer)
	{
		GC.KeepAlive(receiveAclDataPacketObservers);
		lock (receiveAclDataPacketObservers)
		{
			if (!receiveAclDataPacketObservers.Contains(observer))
			{
				return;
			}
			receiveAclDataPacketObservers.Remove(observer);
		}
		GC.KeepAlive(receiveAclDataPacketObservers);
	}

	public void NotifyObserver(AclData aclData)
	{
		lock (receiveAclDataPacketObservers)
		{
			foreach (QCRPG.Framework.IObserver<PacketBase> item in receiveAclDataPacketObservers.Where((QCRPG.Framework.IObserver<PacketBase> o) => o != null))
			{
				if (item.GetType().FullName == "QCRPG.PacketLogger" && !displayEnhLogMessages)
				{
					uint num = ((aclData.UserFields.Flags << 8) | aclData.UserFields.Handle) & 0xFFFu;
					if (num == 3804)
					{
						break;
					}
				}
				item.NotifyObserver(aclData);
			}
		}
	}

	public void RegisterSendSCODataPacketObserver(QCRPG.Framework.IObserver<PacketBase> observer)
	{
		GC.KeepAlive(sendScoDataPacketObservers);
		lock (sendScoDataPacketObservers)
		{
			if (sendScoDataPacketObservers.Contains(observer))
			{
				return;
			}
			sendScoDataPacketObservers.Add(observer);
		}
		GC.KeepAlive(sendScoDataPacketObservers);
	}

	public void UnregisterSendSCODataPacketObserver(QCRPG.Framework.IObserver<PacketBase> observer)
	{
		GC.KeepAlive(sendScoDataPacketObservers);
		lock (sendScoDataPacketObservers)
		{
			if (!sendScoDataPacketObservers.Contains(observer))
			{
				return;
			}
			sendScoDataPacketObservers.Remove(observer);
		}
		GC.KeepAlive(sendScoDataPacketObservers);
	}

	public void RegisterReceiveSCODataPacketObserver(QCRPG.Framework.IObserver<PacketBase> observer)
	{
		GC.KeepAlive(receiveScoDataPacketObservers);
		lock (receiveScoDataPacketObservers)
		{
			if (receiveScoDataPacketObservers.Contains(observer))
			{
				return;
			}
			receiveScoDataPacketObservers.Add(observer);
		}
		GC.KeepAlive(receiveScoDataPacketObservers);
	}

	public void UnregisterReceiveSCODataPacketObserver(QCRPG.Framework.IObserver<PacketBase> observer)
	{
		GC.KeepAlive(receiveScoDataPacketObservers);
		lock (receiveScoDataPacketObservers)
		{
			if (!receiveScoDataPacketObservers.Contains(observer))
			{
				return;
			}
			receiveScoDataPacketObservers.Remove(observer);
		}
		GC.KeepAlive(receiveScoDataPacketObservers);
	}

	public void NotifyObserver(SynchronousData scoData)
	{
		lock (receiveScoDataPacketObservers)
		{
			foreach (QCRPG.Framework.IObserver<PacketBase> item in receiveScoDataPacketObservers.Where((QCRPG.Framework.IObserver<PacketBase> o) => o != null))
			{
				item.NotifyObserver(scoData);
			}
		}
	}

	public void RegisterSendISODataPacketObserver(QCRPG.Framework.IObserver<PacketBase> observer)
	{
		GC.KeepAlive(sendIsoDataPacketObservers);
		lock (sendIsoDataPacketObservers)
		{
			if (sendIsoDataPacketObservers.Contains(observer))
			{
				return;
			}
			sendIsoDataPacketObservers.Add(observer);
		}
		GC.KeepAlive(sendIsoDataPacketObservers);
	}

	public void UnregisterSendISODataPacketObserver(QCRPG.Framework.IObserver<PacketBase> observer)
	{
		GC.KeepAlive(sendIsoDataPacketObservers);
		lock (sendIsoDataPacketObservers)
		{
			if (!sendIsoDataPacketObservers.Contains(observer))
			{
				return;
			}
			sendIsoDataPacketObservers.Remove(observer);
		}
		GC.KeepAlive(sendIsoDataPacketObservers);
	}

	public void RegisterReceiveISODataPacketObserver(QCRPG.Framework.IObserver<PacketBase> observer)
	{
		GC.KeepAlive(receiveIsoDataPacketObservers);
		lock (receiveScoDataPacketObservers)
		{
			if (receiveIsoDataPacketObservers.Contains(observer))
			{
				return;
			}
			receiveIsoDataPacketObservers.Add(observer);
		}
		GC.KeepAlive(receiveIsoDataPacketObservers);
	}

	public void UnregisterReceiveISODataPacketObserver(QCRPG.Framework.IObserver<PacketBase> observer)
	{
		GC.KeepAlive(receiveIsoDataPacketObservers);
		lock (receiveScoDataPacketObservers)
		{
			if (!receiveIsoDataPacketObservers.Contains(observer))
			{
				return;
			}
			receiveIsoDataPacketObservers.Remove(observer);
		}
		GC.KeepAlive(receiveIsoDataPacketObservers);
	}

	public void NotifyObserver(IsoData isoData)
	{
		lock (receiveIsoDataPacketObservers)
		{
			foreach (QCRPG.Framework.IObserver<PacketBase> item in receiveIsoDataPacketObservers.Where((QCRPG.Framework.IObserver<PacketBase> o) => o != null))
			{
				item.NotifyObserver(isoData);
			}
		}
	}

	public void FlowControl(bool flowControl)
	{
		WriteScoFlowControlEnable writeScoFlowControlEnable = new WriteScoFlowControlEnable();
		writeScoFlowControlEnable.UserFields.SynchronousFlowControlEnable = (flowControl ? 1u : 0u);
		logger.NotifyObserver(new LogMessage(LogMessageType.Info, "Starting Flow Control"));
		ModeAgnosticDataReceiver modeAgnosticDataReceiver = new ModeAgnosticDataReceiver(this);
		modeAgnosticDataReceiver.Startup();
		try
		{
			Send(writeScoFlowControlEnable);
		}
		finally
		{
			modeAgnosticDataReceiver.Shutdown();
		}
	}

	public override void Decode(PacketBase packet)
	{
		BTOutgoingPacketData bTOutgoingPacketData = new BTOutgoingPacketData(packet.ToByteArray());
		if (packet.Type == PacketType.Command)
		{
			bTOutgoingPacketData.btPacketType = BTPacketDataType.Command;
		}
		else if (packet.Type == PacketType.Notification)
		{
			bTOutgoingPacketData.btPacketType = BTPacketDataType.Event;
		}
		else if (packet is AclData)
		{
			bTOutgoingPacketData.btPacketType = BTPacketDataType.AclDataPacket;
		}
		else if (packet is SynchronousData)
		{
			bTOutgoingPacketData.btPacketType = BTPacketDataType.SynchronousDataPacket;
		}
		else
		{
			bTOutgoingPacketData.btPacketType = BTPacketDataType.Raw;
		}
		packetDecodeInfo.PacketDecode = true;
		packetDecodeInfo.PacketResponse = true;
		packetDecodeNotifier.NotifyObservers(packetDecodeInfo);
		packet.Flags |= 2u;
		sendPacketNotifier.NotifyObservers(packet);
		SetDecodePacket(decodePacket, packetResponse: false);
	}

	public void SetDecodePacket(bool decodePacket, bool packetResponse, bool conciseLog, bool fullAclLogging)
	{
		this.fullAclLogging = fullAclLogging;
		SetDecodePacket(decodePacket, packetResponse, conciseLog);
	}

	public void SetDecodePacket(bool decodePacket, bool packetResponse, bool conciseLog = false)
	{
		this.decodePacket = decodePacket;
		conciseLogging = conciseLog;
		packetDecodeInfo.PacketDecode = decodePacket;
		packetDecodeInfo.PacketResponse = packetResponse;
		packetDecodeInfo.FullAclLog = fullAclLogging;
		packetDecodeInfo.ConciseLog = conciseLog;
		packetDecodeNotifier.NotifyObservers(packetDecodeInfo);
	}

	public override void EnableBTSnoopLogging(bool enable, bool messagePopUp = true)
	{
		if (enable)
		{
			if (connectionUsb != null && connectionUsb.IsOpen())
			{
				snoopLog.DataLink = SnoopLogger.DataLinkType.Unencapsulated_HCI;
			}
			else if ((connectionSerialPort != null && connectionSerialPort.IsOpen()) || !string.IsNullOrEmpty(sharedConnectionPortName))
			{
				snoopLog.DataLink = SnoopLogger.DataLinkType.HCI_UART;
			}
			else if ((connectionTCP != null && connectionTCP.IsOpen()) || !string.IsNullOrEmpty(sharedConnectionPortName))
			{
				snoopLog.DataLink = SnoopLogger.DataLinkType.HCI_UART;
			}
			protocolHCI.RegisterSendACLDataObserver(snoopLog);
			protocolHCI.RegisterSendSCODataObserver(snoopLog);
			protocolHCI.RegisterSendISODataObserver(snoopLog);
			protocolHCI.RegisterReceiveACLDataObserver(snoopLog);
			protocolHCI.RegisterReceiveSCODataObserver(snoopLog);
			protocolHCI.RegisterReceiveISODataObserver(snoopLog);
			protocolHCI.RegisterReceiveDataObserverPostProcessing(snoopLog);
			protocolHCI.RegisterSendDataObserver(snoopLog);
		}
		else
		{
			protocolHCI.UnregisterSendACLDataObserver(snoopLog);
			protocolHCI.UnregisterSendSCODataObserver(snoopLog);
			protocolHCI.UnregisterSendISODataObserver(snoopLog);
			protocolHCI.UnregisterReceiveACLDataObserver(snoopLog);
			protocolHCI.UnregisterReceiveSCODataObserver(snoopLog);
			protocolHCI.UnregisterReceiveISODataObserver(snoopLog);
			protocolHCI.UnregisterReceiveDataObserverPostProcessing(snoopLog);
			protocolHCI.UnregisterSendDataObserver(snoopLog);
		}
	}

	public override bool SaveBTSnoopLogs(string filename)
	{
		if (snoopLog != null)
		{
			return snoopLog.SaveLogs(filename);
		}
		return false;
	}

	public override void ClearBTSnoopLogs()
	{
		if (snoopLog != null)
		{
			snoopLog.ClearLogMessages();
		}
	}

	public override void EnableBTSnoopLiveLogging(bool enable, string liveImportDllPath, string liveImportIniPath)
	{
		if (enable)
		{
			protocolHCI.RegisterSendACLDataObserver(snoopLiveLog);
			protocolHCI.RegisterSendSCODataObserver(snoopLiveLog);
			protocolHCI.RegisterSendISODataObserver(snoopLiveLog);
			protocolHCI.RegisterReceiveACLDataObserver(snoopLiveLog);
			protocolHCI.RegisterReceiveSCODataObserver(snoopLiveLog);
			protocolHCI.RegisterReceiveISODataObserver(snoopLiveLog);
			protocolHCI.RegisterReceiveDataObserverPostProcessing(snoopLiveLog);
			protocolHCI.RegisterSendDataObserver(snoopLiveLog);
		}
		else
		{
			snoopLiveLog.DisableBTLiveLogging();
			protocolHCI.UnregisterSendACLDataObserver(snoopLiveLog);
			protocolHCI.UnregisterSendSCODataObserver(snoopLiveLog);
			protocolHCI.UnregisterSendISODataObserver(snoopLiveLog);
			protocolHCI.UnregisterReceiveACLDataObserver(snoopLiveLog);
			protocolHCI.UnregisterReceiveSCODataObserver(snoopLiveLog);
			protocolHCI.UnregisterReceiveISODataObserver(snoopLiveLog);
			protocolHCI.UnregisterReceiveDataObserverPostProcessing(snoopLiveLog);
			protocolHCI.UnregisterSendDataObserver(snoopLiveLog);
		}
	}

	public void BufferRAMDumpFragment(PacketBase packet)
	{
		if (!(packet is RamDumpFragment))
		{
			return;
		}
		RamDumpFragment ramDumpFragment = (RamDumpFragment)packet;
		uint sequenceNumber = ramDumpFragment.UserFields.SequenceNumber;
		ramDumpBuffer.AddRange(Conversions.UintListToByteArray(ramDumpFragment.UserFields.DumpFragmentList));
		switch (sequenceNumber)
		{
		case 0u:
			ramDumpTotalLength = Conversions.UintListToUint(ramDumpFragment.UserFields.TotalLengthList);
			ramDumpNextFragmentSequenceNumber = 1u;
			processingRamDumpFragments = true;
			break;
		case 65535u:
		{
			if (ramDumpBuffer.Count == ramDumpTotalLength)
			{
				logger.Enqueue(new LogMessage(LogMessageType.Error, "Device crashed! RAM Dump received successfully."));
			}
			else
			{
				logger.Enqueue(new LogMessage(LogMessageType.Error, $"Device crashed! RAM dump length does not match, expected length {ramDumpTotalLength}, received length {ramDumpBuffer.Count}"));
			}
			string text = Path.GetDirectoryName(GetType().Assembly.Location) + "\\Logs\\";
			if (!string.IsNullOrEmpty(logsDirectory))
			{
				text = logsDirectory;
			}
			string text2 = text + "RAMDump_" + logger.DutName + DateTime.Now.ToString("_yyyyMMdd_HHmmss_fff") + ".bin";
			using (BinaryWriter binaryWriter = new BinaryWriter(File.OpenWrite(text2)))
			{
				binaryWriter.Write(ramDumpBuffer.ToArray());
				ramDumpBuffer.Clear();
			}
			logger.Enqueue(new LogMessage(LogMessageType.Info, "RAM Dump saved to " + text2));
			processingRamDumpFragments = false;
			ramDumpNextFragmentSequenceNumber = 0u;
			break;
		}
		default:
			if (sequenceNumber != ramDumpNextFragmentSequenceNumber)
			{
				processingRamDumpFragments = false;
				logger.Enqueue(new LogMessage(LogMessageType.Error, $"Missing RAM dump fragments, expected sequence number {ramDumpNextFragmentSequenceNumber}, received sequence number {sequenceNumber}"));
			}
			ramDumpNextFragmentSequenceNumber = sequenceNumber + 1;
			break;
		}
	}

	public void WriteMiniDump(PacketBase packet)
	{
		WriteMiniDump(packet as DumpInformationVse);
	}

	public void WriteMiniDump(DumpInformationVse packet)
	{
		if (packet == null)
		{
			return;
		}
		string path = ((!string.IsNullOrEmpty(logsDirectory)) ? logsDirectory : Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), "Logs"));
		string path2 = "MiniDump_" + logger.DutName + DateTime.Now.ToString("_yyyyMMdd_HHmmss_fff") + ".bin";
		string path3 = Path.Combine(path, path2);
		using BinaryWriter binaryWriter = new BinaryWriter(File.OpenWrite(path3));
		byte[] array = packet.ToByteArray();
		byte[] array2 = new byte[array.Length - 4];
		Array.Copy(array, 4, array2, 0, array.Length - 4);
		binaryWriter.Write(array2);
	}

	public void UpdateEventTimeout(int eventTimeout)
	{
		responseWaitTimeMs = eventTimeout;
		resetWaitTimeMs = eventTimeout;
	}
}
