public void ExecuteSendCommand(object sender, string command, GXPacket packet)
		{
			switch (command)
			{
				case "ReadTableData":
                    Status = 0;
                    Add = 0;
                    Columns = null;
                    GXIEC62056Table table = (GXIEC62056Table)sender;
                    table.ClearRows();
					ReadTableData(sender, packet);
					break;
				case "ReadTableDataNext":
					ReadTableDataNext(sender, packet);
					break;
                case "Connect":
                    GXIEC62056Device dev = GetDevice(sender);
                    Connect(dev.SerialNumber, dev.Password, dev.Mode, dev.GXClient.Media, dev.WaitTime);
					break;
                case "Disconnect":
                    Disconnect(GetDevice(sender), packet);
                    break;
                case "Readout":
					Readout(sender, packet);
					break;
				case "ReadData":
					ReadData(sender, packet);
					break;
                case "KeepAlive":
                    KeepAlive(sender as GXIEC62056Device, packet);
					break;                    
				default:
					throw new Exception("ExecuteCommand failed. Unknown command: " + command);
			}
		}
 /// <summary>
 /// User has reset transaction time so packet is not going old.
 /// </summary>
 /// <param name="packet"></param>
 /// <returns></returns>
 static bool IsTransactionTimeReset(GXPacket packet)
 {
     //Check is user reset packet transaction time.                       
     if ((packet.Status & PacketStates.TransactionTimeReset) != 0)
     {
         packet.Status ^= PacketStates.TransactionTimeReset;
         return true;
     }
     return false;
 }
		public void ExecuteParseCommand(object sender, string command, GXPacket[] packets)
		{
			switch (command)
			{
				case "ReadTableDataReply":
					ReadTableDataReply(sender, packets);
					break;
				case "ReadDataReply":
					ReadDataReply(sender, packets);
					break;
                case "DisconnectReply":
                    DisconnectReply(sender, packets);
					break;
                case "KeepAliveReply":
                    KeepAliveReply(sender as GXIEC62056Device, packets);
					break;
				default:
					throw new Exception("ExecuteCommand failed. Unknown command: " + command);
			}
		}
		public bool IsTransactionComplete(object sender, string command, GXPacket packet)
		{
			try
			{
				switch (command)
				{
					case "IsReadoutComplete":
						return IsReadoutComplete(sender, packet);
					default:
						throw new Exception("IsTransactionComplete failed. Unknown command: " + command);
				}
			}
			catch (Exception ex)
			{
				System.Diagnostics.Debug.WriteLine("IsTransactionComplete Failed: " + ex.Message);
				System.Diagnostics.Debug.Write(ex.StackTrace);
				System.Diagnostics.Debug.WriteLine("------------------------------------------");
				throw;
			}
		}
		public void ExecuteParseCommand(object sender, string command, GXPacket[] packets)
		{
			try
			{
				switch (command)
				{
					case "ReadoutReply":
						ReadoutReply(sender, packets);
						break;
					default:
						throw new Exception("ExecuteCommand failed. Unknown command: " + command);
				}
			}
			catch (Exception ex)
			{
				System.Diagnostics.Debug.WriteLine("ExecuteParseCommand Failed: " + ex.Message);
				System.Diagnostics.Debug.Write(ex.StackTrace);
				System.Diagnostics.Debug.WriteLine("------------------------------------------");
				throw;
			}
		}
        /////////////////////////////////////////////////////////////////////////////
        // Should packet try to resend one more time...
        /////////////////////////////////////////////////////////////////////////////
        static bool GetResend(GXPacket packet)
        {
            bool bReSend = ++packet.SendCount <= packet.ResendCount;
            if (!bReSend)
            {
				if (packet.Sender != null && packet.Sender.Trace >= System.Diagnostics.TraceLevel.Error)
				{
                    string str = Resources.FailedToSendPacket + packet.Id + ", delay " + (DateTime.Now - packet.SendTime).TotalMilliseconds.ToString();
                    packet.Sender.NotifyVerbose(packet.Sender, str);
					Gurux.Common.GXCommon.TraceWriteLine(str);
				}
            }
            else
            {
				if (packet.Sender != null && packet.Sender.Trace >= System.Diagnostics.TraceLevel.Info)
				{
                    string str = "Try to resend packet " + packet.Id.ToString() + " (" + packet.SendCount.ToString() + "/" + (packet.ResendCount + 1).ToString() + ")";
                    packet.Sender.NotifyVerbose(packet.Sender, str);
                    Gurux.Common.GXCommon.TraceWriteLine(str);					
				}
            }
            return bReSend;
        }
        /// <summary>
        /// Sends the packet.
        /// </summary>
        /// <param name="packet">Data packet to be sent.</param>
        /// <param name="synchronous">If True, synchronous sending mode is used. If False, asynchronous mode is used.</param>
        /// <remarks>
        /// If GXPacket is sent synchronously, GXCom fills the sent packet with information of the received packet, 
        /// so data can be used instantly after the Send call. If GXPacket is sent asynchronously, 
        /// data is received through Received method.
        /// </remarks>        
        /// <seealso cref="OnReceived">OnReceived</seealso>
        public void Send(GXPacket packet, bool synchronous)
        {
            if (m_Server == null)
            {
                throw new Exception(Resources.ServerNotCreatedCallAssignMediaFirst);
            }
            if (packet.ByteOrder != this.ByteOrder)
            {
                throw new Exception(Resources.PacketSByteOrderIsNotSameAsClientS);
            }
            if (packet.WaitTime == 0 && packet.ResendCount != -1)
            {
                throw new Exception(Resources.PacketSWaitTimeCanTBeZero);
            }
            if (m_Server.m_SendPackets.Count > 0)
            {
                return;
            }            
            packet.Sender = this;
            ++Statistics.PacketsSend;
            NotifyBeforeSend(packet);
            m_replyEvent.Reset();
            m_Server.Send(packet);
            //Wait until reply is received or packet is old...
			if (synchronous && packet.ResendCount != -1)
            {
                m_replyEvent.WaitOne();
            }
            if ((packet.Status & PacketStates.SendFailed) != 0 && packet.SenderInfo != null)
            {
                string str = packet.SenderInfo;
                packet.SenderInfo = null;
                throw new Exception(str);
            }            
        }
		private bool IsTableRead(object sender, GXPacket packet)
		{
			if ((sender as GXIEC62056Table).ReadMode == 6)
			{
                GXIEC62056Table table = (GXIEC62056Table)sender;
                object[][] rows = Parser.IEC62056Parser.ParseTableData(packet.ExtractPacket(), ref Columns, ref Status, ref Time, ref Add, table.Data);
                System.Diagnostics.Debug.WriteLine("Mikko " + rows.Length);
                table.AddRows(table.RowCount, new List<object[]>(rows), false);                
            }            
            return (byte) packet.Eop != 0x4;
		}
        /// <summary>
        /// Creates default packet with client settings.
        /// </summary>
        /// <returns>New packet with client settings.</returns>        
        public GXPacket CreatePacket()
        {
            GXPacket packet;
            lock (PacketsSync)
            {
                if (Packets.Count != 0)
                {
                    packet = Packets.Pop();
                }
                else
                {
                    packet = new GXPacket();
                }
            }
            packet.Sender = this;
            packet.WaitTime = this.WaitTime;
            packet.ResendCount = this.ResendCount;
            packet.SendCount = 0;
            packet.Bop = this.Bop;
            packet.Eop = this.Eop;
            packet.ByteOrder = this.ByteOrder;
            packet.MinimumSize = this.MinimumSize;
            packet.ChecksumSettings.Copy(this.ChecksumSettings);
            return packet;

        }
		public bool IsTransactionComplete(object sender, string command, GXPacket packet)
		{
			switch (command)
			{
				case "IsTableRead":
				return IsTableRead(sender, packet);
				default:
					throw new Exception("IsTransactionComplete failed. Unknown command: " + command);
			}
		}
		private void ReadTableDataReply(object sender, GXPacket[] packets)
		{
            if ((sender as GXIEC62056Table).ReadMode != 6)
            {
                GXIEC62056Table table = (GXIEC62056Table)sender;
                object[][] rows = Parser.IEC62056Parser.ParseTableData(packets[packets.Length - 1].ExtractPacket(), ref Columns, ref Status, ref Time, ref Add, table.Data);
                table.AddRows(table.RowCount, new List<object[]>(rows), false);
            }
		}
		private void ParseReadoutReply(GXPacket packet, GXMBusCategory category)
		{
			List<byte> dataBuff = new List<byte>();
			dataBuff.Add((byte)packet.Bop);
			dataBuff.AddRange((byte[])packet.ExtractData(typeof(byte[]), 0, -1));
			dataBuff.Add((byte)packet.Checksum);
			dataBuff.Add((byte)packet.Eop);
			List<MBusRegister> registers = MBus.ParseReadReply(dataBuff.ToArray());
			for (int pos = 0; pos < registers.Count; ++pos)
			{
                foreach (GXMBusProperty it in category.Properties)
                {
                    if (it.Ordinal == pos)
                    {
                        it.SetValue(registers[pos].Value, false, PropertyStates.ValueChangedByDevice);
                        break;
                    }
                }				
			}
		}
		private void Readout(object sender, GXPacket packet)
		{			
			GXMBusDevice device = (GXMBusDevice)GetDeviceFromSender(sender);
			IGXMedia media = (IGXMedia)device.GXClient.Media;

			bool isSerial = device.GXClient.MediaType == "Serial";
			if (isSerial)
			{
				((Gurux.Serial.GXSerial)media).BaudRate = 2400;
				((Gurux.Serial.GXSerial)media).DataBits = 8;
				((Gurux.Serial.GXSerial)media).Parity = System.IO.Ports.Parity.Even;
				((Gurux.Serial.GXSerial)media).StopBits = System.IO.Ports.StopBits.One;
			}


			List<byte> buff = new List<byte>(new byte[] {0x10, 0x40, device.DeviceAddress});
			buff.Add(CountShortFrameChecksum(buff.ToArray()));
			buff.Add(0x16);

			ReceiveParameters<byte[]> recParams = new ReceiveParameters<byte[]>();			
			lock (media.Synchronous)
			{
				recParams.AllData = true;
				recParams.Count = 1;
				recParams.Peek = false;
				recParams.Eop = null;
				recParams.Reply = null;
				recParams.WaitTime = device.WaitTime;

				media.Send(buff.ToArray(), null);
				if (!media.Receive(recParams))
				{
					throw new Exception("Handshake timeout.");
				}
			}
			System.Threading.Thread.Sleep(2000);

			if (!(recParams.Reply.Length > 0 && recParams.Reply[0] == 0xE5))
			{
				throw new Exception("Invalid handshake response.");
			}

			packet.Bop = (byte)0x10;
			packet.Eop = (byte)0x16;
			packet.ChecksumSettings.Position = -2;
            packet.ChecksumSettings.Type = ChecksumType.Sum8Bit;
			packet.ChecksumSettings.Start = 1;
			packet.ChecksumSettings.Count = -2;
			packet.AppendData((byte)0x5B);
			packet.AppendData(device.DeviceAddress);

			m_PreviousFCB = -1;
		}
		private void ReadoutReply(object sender, GXPacket[] packets)
		{
			List<byte> fullData = new List<byte>();
			foreach (GXPacket packet in packets)
			{
				object tmp = null;
				tmp = packet.ExtractData(typeof(byte[]), 0, -1);
				if (tmp is byte[])
				{
					fullData.AddRange(tmp as byte[]);
				}
			}
		}
 internal void AddPacketToReceivedBuffer(GXPacket packet)
 {
     lock (m_ReceicedPackets.SyncRoot)
     {
         m_ReceicedPackets.Add(packet);
         m_ReceicedPacketsAdded.Set();
     }
 }
		private void ReadDataReply(object sender, GXPacket[] packets)
		{
			if (sender is GXIEC62056Property)
			{
				GXIEC62056Property prop = sender as GXIEC62056Property;
				List<byte> fullData = new List<byte>();
				foreach (GXPacket packet in packets)
				{
					object tmp = null;
					tmp = packet.ExtractData(typeof(byte[]), 0, -1);
					if (tmp is byte[])
					{
						fullData.AddRange(tmp as byte[]);
					}
				}

				string val = ASCIIEncoding.ASCII.GetString(fullData.ToArray());
                int start = val.IndexOf('(');
                int end = val.LastIndexOf(')');
                if (start != -1 && end != -1)
                {
                    val = val.Substring(start + 1, end - start - 1);
                }
                prop.ReadTime = DateTime.Now;
				prop.SetValue(val, false, PropertyStates.ValueChangedByDevice);                
			}
		}
		private void Readout(object sender, GXPacket packet)
		{
			GXDevice dev = null;
			if (sender is GXDevice)
			{
				dev = sender as GXDevice;
			}
			else if (sender is GXTable)
			{
				dev = (sender as GXTable).Device;
			}
			else if (sender is GXCategory)
			{
				dev = (sender as GXCategory).Device;
			}
			else if (sender is GXProperty)
			{
				dev = (sender as GXProperty).Device;
			}
			else
			{
				throw new Exception("Readout failed. Unknown sender: " + sender.ToString());
			}
            /* TODO: Readout
			List<byte> readoutBytes = Handshake(sender, packet, true);
			List<Parser.IECDataObject> items = Parser.IEC62056Parser.ParseReadout(readoutBytes);
            foreach (Parser.IECDataObject it in items)
            {
                if (!it.Address.Contains("*"))
                {
                    List<object> results = new List<object>();
                    dev.FindByPropertyValue("OBISCode", it.Address, results);
                    if (results.Count > 0)
                    {
                        GXProperty prop = results[0] as GXProperty;
                        prop.ReadTime = DateTime.Now;
                        prop.SetValue(it.Value, false, PropertyStates.ValueChangedByDevice);
                    }
                }
            }
             * */
		}
		private void ReadData(object sender, GXPacket packet)
		{
			if (!(sender is GXIEC62056Property))
			{
				return;
			}
            GXIEC62056Property prop = sender as GXIEC62056Property;
            packet.AppendData("R" + prop.ReadMode.ToString());
            packet.AppendData((byte)2);
            packet.AppendData(prop.Data + "(" + prop.Parameters + ")");
		}
        private void KeepAliveReply(GXIEC62056Device sender, GXPacket[] packets)
        {
            List<byte> fullData = new List<byte>();
            foreach (GXPacket packet in packets)
            {
                object tmp = null;
                tmp = packet.ExtractData(typeof(byte[]), 0, -1);
                if (tmp is byte[])
                {
                    fullData.AddRange(tmp as byte[]);
                }
            }

            string val = ASCIIEncoding.ASCII.GetString(fullData.ToArray());
            int start = val.IndexOf('(');
            int end = val.LastIndexOf(')');
            if (start != -1 && end != -1)
            {
                val = val.Substring(start + 1, end - start - 1);
            }
        }
 private void KeepAlive(GXIEC62056Device device, GXPacket packet)
 {
     if (device.AliveMode == 0)
     {
         packet.AppendData("R2");
         packet.AppendData((byte)2);
         packet.AppendData("0.0.0()");
     }
     else
     {
         packet.AppendData("R" + device.AliveMode.ToString());
         packet.AppendData((byte)2);
         packet.AppendData(device.AliveData + "(" + device.AliveParameters + ")");
     }
 }
		private bool IsReadoutComplete(object sender, GXPacket packet)
		{
			byte cField = (byte)packet.ExtractData(typeof(System.Byte), 3, 1);
			byte fcv = (byte) (cField & MASK_FCV);
			byte fcb = (byte) (cField & MASK_FCB);

			if (sender is GXMBusCategory)
			{
				ParseReadoutReply(packet, sender as GXMBusCategory);
			}
			else
			{
				//This should never happen
				throw new Exception("Unknown parameter \"sender\" in IsReadoutComplete.");
			}
			packet.Clear();
			if (fcv == 0)
			{
				return true;
			}
			else
			{
				m_PreviousFCB = fcb;
				return false;
			}
		}
 /// <summary>
 /// Releases packet so it can be recycled.
 /// </summary>
 /// <param name="packet">Released packet.</param>
 public void ReleasePacket(GXPacket packet)
 {
     lock (PacketsSync)
     {
         if (Packets.Count < 100)
         {
             packet.Clear();
             Packets.Push(packet);
         }
     }
 }
		private void ReadoutReply(object sender, GXPacket[] packets)
		{
			//Do nothing, parsing is done in IsReadoutComplete
		}
        private void DisconnectReply(object sender, GXPacket[] packets)
		{
            string header, data;
            List<byte> buff = new List<byte>(packets[0].ExtractPacket());            
            IEC62056Parser.GetPacket(buff, true, out header, out data);        
        }
		private void ReadMoreData(object sender, GXPacket packet)
		{
			GXMBusDevice dev = (GXMBusDevice)GetDeviceFromSender(sender);
			packet.AppendData((byte)0x5B);
			packet.AppendData(dev.DeviceAddress);
		}
		private void ReadTableData(object sender, GXPacket packet)
		{
            GXIEC62056Table table = sender as GXIEC62056Table;		            
			DateTime start, end;
            (sender as IGXPartialRead).GetStartEndTime(out start, out end);
            packet.AppendData(IEC62056Parser.GenerateReadTable(table.Data, start, end, table.Parameters, table.ReadMode, table.ReadCount));
		}
		private void ReadTableDataNext(object sender, GXPacket packet)
		{
			packet.Bop = null;
			packet.Eop = null;
			packet.ChecksumSettings.Type = ChecksumType.None;
			packet.AppendData((byte)0x06);
		}
        internal void Send(GXPacket packet)
        {
            lock (m_SendPackets.SyncRoot)
            {
				if (packet.Sender == null)
				{
					throw new Exception(Resources.InvalidSender);
				}
                packet.Id = ++m_PacketIdCounter;
                //If packet is send asyncronously.
                if (packet.ResendCount == -1)
                {
                    byte[] buff = packet.ExtractPacket();
                    packet.Sender.NotifyVerbose(packet.Sender, TraceTypes.Sent, buff);
                    Media.Send(buff, packet.SenderInfo);
                }
                else
                {
                    m_SendPackets.Add(packet);
                    m_SendPacketsAdded.Set();
                }
            }
        }
		/// <summary>
		/// Create a copy of the GXPacket.
		/// </summary>
        public void Copy(GXPacket source)
        {
            Clear();
            lock (source.SyncRoot)
            {
                AppendData(source.ExtractData(typeof(byte[]), 0, -1));
                this.Bop = source.Bop;
                this.Eop = source.Eop;
                this.ChecksumSettings.Copy(source.ChecksumSettings);
				this.Sender = source.Sender;
            }
        }
        private void Disconnect(object sender, GXPacket packet)
		{
			GXIEC62056Device dev = null;
			if (sender is GXIEC62056Device)
			{
				dev = sender as GXIEC62056Device;
			}
			else if (sender is GXProperty)
			{
				dev = (sender as GXProperty).Device as GXIEC62056Device;
			}
			else
			{
				throw new Exception("InitRead failed. Unknown sender: " + sender.ToString());
			}
			if (dev.Mode != Protocol.ModeA)
			{
                packet.ResendCount = -1;
                packet.Eop = null;
                packet.ChecksumSettings.Position = -3;
                packet.ChecksumSettings.Count = -3;
                packet.AppendData("B0");
                packet.AppendData((byte) 3);
			}
		}