public static Packet ReadPacket(Stream stream)
        {
            var headerBuffer = new byte[1];
            var bytesRead = stream.Read(headerBuffer, 0, 1);
            if (bytesRead == 0)
            {
                return null;
            }

            var headerVal = (byte)(headerBuffer[0] >> 4);
            var payloadLength = (headerBuffer[0] & 0x0F);

            var packet = new Packet((PacketHeaderType)Enum.Parse(typeof(PacketHeaderType), headerVal.ToString()));

            var bytesRemaining = payloadLength;
            var offset = 0;

            if (payloadLength > 0)
            {
                var payloadBytes = new byte[payloadLength];
                do
                {
                    bytesRead = stream.Read(payloadBytes, offset, bytesRemaining);
                    if (bytesRead == 0)
                    {
                        throw new XpressNetProtocolViolationException("Unexpected end of stream");
                    }
                    bytesRemaining -= bytesRead;
                    offset += bytesRead;
                } while (bytesRemaining > 0);
                packet.Payload.AddRange(payloadBytes);

                // .ToString() is relatively expensive, so only do it if we're logging
                if (XpressNetConstants.XpressNetTraceSource.Switch.ShouldTrace(TraceEventType.Verbose))
                {
                    XpressNetConstants.XpressNetTraceSource.TraceEvent(TraceEventType.Verbose, 0, "Received Packet: {0}", packet.ToString());
                }
                if (Debugger.IsAttached)
                {
                    Console.Out.WriteLineAsync(string.Format("Received Packet: {0}", packet));
                }
            }

            //check the xor matches
            var xorByte = new byte[1];
            stream.Read(xorByte, 0, 1);
            if (xorByte[0] != packet.GetXoredByte())
                throw new XpressNetProtocolViolationException("Packet checksum is invalid");


            PacketReceived(packet, stream);

            return packet;
        }
 protected override bool ValidResponse(Packet packet)
 {
     if (packet.Header == PacketHeaderType.LocomotiveFunction) //TODO: unit test to check this works
     {
         ResponseData = new LocoInfoResp_NormalResp(); //TODO: if the loco is in a dh or mu it may return a different resp?! (it is probably better to modify the response to make it generic!
         return true;
     }
     else
     {
         return false;
     }
 }
 protected override bool ValidResponse(Packet packet)
 {
     if (packet.Header == PacketHeaderType.LocomotiveFunction && (packet.Payload[0] > 0x80 && packet.Payload[0] < 0x89)) //TODO: unit test to check this works
     {
         ResponseData = new SetMultiUnitOrDoubleHeaderErrorResp();
         return true;
     }
     else
     {
         return false;
     }
 }
 //TODO: check that this actually happens as the specification is a little ambigous
 protected override bool ValidResponse(Packet packet)
 {
     if (packet.Header == PacketHeaderType.CommandStationOperationResponse &&
         packet.Payload[0] == Convert.ToByte(PacketIdentifier.CommandStationOperationResponse.ServiceModeEntryBroadcast))
     {
         ResponseData = new GeneralResponse();
         return true;
     }
     else
     {
         return false;
     }
 }
 protected override bool ValidResponse(Packet packet)
 {
     if (packet.Header == PacketHeaderType.CommandStationOperationResponse &&
         packet.Payload[0] == Convert.ToByte(PacketIdentifier.CommandStationOperationResponse.CmdStnSoftwareVersion))
     {
         ResponseData = new CmdStnSoftwareVersionResp();
         return true;
     }
     else
     {
         return false;
     }
 }
 protected override bool ValidResponse(Packet packet)
 {
     if (packet.Header == PacketHeaderType.LocomotiveFunction &&
         (packet.Payload[0] > Convert.ToByte(PacketIdentifier.LocomotiveFunctionResponse.MultiUnitOrDoubleHeaderError) &&
         packet.Payload[0] < (Convert.ToByte(PacketIdentifier.LocomotiveFunctionResponse.MultiUnitOrDoubleHeaderError) + 9))) //TODO: unit test to check this works
     {
         ResponseData = new SetMultiUnitOrDoubleHeaderErrorResp();
         return true;
     }
     else
     {
         return false;
     }
 }
        protected override bool ValidResponse(Packet packet)
        {
            if (packet.Header == PacketHeaderType.CommandStationOperationResponse &&
                packet.Payload[0] == Convert.ToByte(PacketIdentifier.CommandStationOperationResponse.ServiceModeForRegisterAndPagedMode))

            {
                ResponseData = new ServiceModeProgrammingResultsResp();
                return true;
            }
            else if (packet.Header == PacketHeaderType.CommandStationOperationResponse &&
                     packet.Payload[0] == Convert.ToByte(PacketIdentifier.CommandStationOperationResponse.ServiceModeForDirectCvMode))
            {
                ResponseData = new ServiceModeProgrammingResultsResp();
                return true;
            }
            else if (packet.Header == PacketHeaderType.CommandStationOperationResponse &&
                 packet.Payload[0] == Convert.ToByte(PacketIdentifier.CommandStationOperationResponse.ProgrammingInfoDataByteNotFound))
            {
                ResponseData = new GeneralResponse();
                return true;
            }
            else if (packet.Header == PacketHeaderType.CommandStationOperationResponse &&
                     packet.Payload[0] == Convert.ToByte(PacketIdentifier.CommandStationOperationResponse.ProgrammingInfoShortCircuit))
            {
                ResponseData = new GeneralResponse();
                return true;
            }
            else if (packet.Header == PacketHeaderType.CommandStationOperationResponse &&
                     packet.Payload[0] == Convert.ToByte(PacketIdentifier.CommandStationOperationResponse.ProgrammingInfoCommandStationBusy))
            {
                ResponseData = new GeneralResponse();
                return true;
            }
            else if (packet.Header == PacketHeaderType.CommandStationOperationResponse &&
                     packet.Payload[0] == Convert.ToByte(PacketIdentifier.CommandStationOperationResponse.ProgrammingInfoCommandStationReady))
            {
                ResponseData = new GeneralResponse();
                return true;
            }
            else if (packet.Header == PacketHeaderType.CommandStationOperationResponse &&
                     packet.Payload[0] == Convert.ToByte(PacketIdentifier.CommandStationOperationResponse.InstructionUnsupported))
            {
                ResponseData = new GeneralResponse();
                return true;
            }
            else
            {
                return false;
            }
        }
        internal async static void PacketReceived(Packet packet, Stream stream)
        {
            
            //Handle Direct return messages : it is possible this should be placed in the packet class!
            if (packet.Header == PacketHeaderType.CommandStationOperationResponse && packet.Payload[0] == Convert.ToByte(PacketIdentifier.CommandStationOperationResponse.TransferErrors))
            {
                var ackResp = new AckRespMessage();
                //if (XpressNetConstants.UseAsyncWrite)
                //{
                //    //ackResp.WriteAsync(stream);
                //}
                //else
                //{
                    await ackResp.WriteAsync(stream);
                //}
            }
            
            //Handle Broadcast Messages

            if (packet.Header == PacketHeaderType.EmergencyStopAll) 
            {
                var bmr = new BroadcastMessageReceivedEventArgs
                {
                    ResponseType = BroadcastType.EmergencyStop,
                    ReceivedTime = DateTime.Now
                };
                OnBroadcastMessageReceived(bmr);

                
            } 
            else if (packet.Header == PacketHeaderType.CommandStationOperationResponse && packet.Payload[0] == Convert.ToByte(PacketIdentifier.CommandStationOperationResponse.NormalOperationsResumedBroadcast))
            {
                var bmr = new BroadcastMessageReceivedEventArgs
                {
                    ResponseType = BroadcastType.NormalOperationResumed,
                    ReceivedTime = DateTime.Now
                };
                OnBroadcastMessageReceived(bmr);
            }
            else if (packet.Header == PacketHeaderType.CommandStationOperationResponse && packet.Payload[0] == Convert.ToByte(PacketIdentifier.CommandStationOperationResponse.TrackPowerOffBroadcast))
            {
                var bmr = new BroadcastMessageReceivedEventArgs
                {
                    ResponseType = BroadcastType.TrackPowerOff,
                    ReceivedTime = DateTime.Now
                };
                OnBroadcastMessageReceived(bmr);
            }
            else if (packet.Header == PacketHeaderType.CommandStationOperationResponse && packet.Payload[0] == Convert.ToByte(PacketIdentifier.CommandStationOperationResponse.ServiceModeEntryBroadcast))
            {
                var bmr = new BroadcastMessageReceivedEventArgs
                {
                    ResponseType = BroadcastType.ServiceModeEntry,
                    ReceivedTime = DateTime.Now
                };
                OnBroadcastMessageReceived(bmr);
            }
            else if (packet.Header == PacketHeaderType.AccessoryDecoderInformation)
            {
                var bmr = new BroadcastMessageReceivedEventArgs
                {
                    ResponseType = BroadcastType.AccessoryFeedback,
                    ReceivedTime = DateTime.Now
                };
                //bmr.Response = 
                OnBroadcastMessageReceived(bmr);
            }
            //else if (packet.Header == PacketHeaderType.LocomotiveFunction && packet.Payload[0] == Convert.ToByte(PacketIdentifier.LocomotiveFunctionResponses.LocomotiveOperatedByAnotherDevice))
            //{
            //BroadcastMessageReceivedEventArgs bmr = new BroadcastMessageReceivedEventArgs();
            //bmr.ResponseType = BroadcastType.LocomotiveOperatedByAnotherDevice;
            //bmr.Response = 
            //OnBroadcastMessageReceived(bmr);
            //}
            //else if (packet.Header == PacketHeaderType.LocomotiveFunction && packet.Payload[0] == Convert.ToByte(PacketIdentifier.LocomotiveFunctionResponses.LocomotiveDoubleHeaderOccupied))
            //{
            //BroadcastMessageReceivedEventArgs bmr = new BroadcastMessageReceivedEventArgs();
            //bmr.ResponseType = BroadcastType.DoubleHeaderOccupied;
            //bmr.Response = 
            //OnBroadcastMessageReceived(bmr);
            //}

            //else //we may wish to send the broadcasts on anyway so this else may have to be removed!!
            //{
                var pump = new PacketRouter();
                pump.DisseminatePacket(packet);
            //}
        }