using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace XMX.FileTransmit { public enum YModemCheckMode { CheckSum, CRC16 } public enum YModemType { YModem, YModem_1K } /// /// YModem接收到的消息类型 /// enum YmodemMessageType : int { KEY_C, ACK, NAK, EOT, PACKET, PACKET_ERROR, CAN } /// /// YModem接收到的消息内容 /// internal class YmodemMessage { private YmodemMessageType _MessageType; private object _Value; public YmodemMessage(YmodemMessageType type) : this(type, null) { } public YmodemMessage(YmodemMessageType type, object value) { _MessageType = type; _Value = value; } public YmodemMessageType MessageType { get { return _MessageType; } } public object Value { get { return _Value; } } } /// /// Xmodem发送步骤 /// internal enum YmodemSendStage : int { WaitReceiveRequestFileInfo, //等待接收端请求文件头 WaitReceiveRequestFirstPacket, PacketSending, WaitReceiveAnswerEndTransmit, // 等待接收方应答EOT WaitReceiveNextFileReq, // 等等接收方请求下一个文件 } /// /// Xmodem接收步骤 /// internal enum YmodemReceiveStage : int { WaitForFileInfo, WaitForFirstPacket, PacketReceiving, } public class YModemInfo { private YModemType _YModemType; private TransmitMode _TransType; public YModemInfo() : this(YModemType.YModem, TransmitMode.Send) { } public YModemInfo(YModemType type, TransmitMode transType) { _YModemType = type; _TransType = transType; } public YModemType Type { get { return _YModemType; } set { _YModemType = value; } } public TransmitMode TransMode { get { return _TransType; } set { _TransType = value; } } //public YModemCheckMode CheckMode //{ // get { return _CheckMode; } // set { _CheckMode = value; } //} } public class YModem : IFileTramsmit, ITransmitUart { private readonly byte SOH = 0x01; private readonly byte STX = 0x02; private readonly byte EOT = 0x04; private readonly byte ACK = 0x06; private readonly byte NAK = 0x15; private readonly byte CAN = 0x18; private readonly byte KEY_C = 0x43; //'C'; private int RetryMax = 6; YModemInfo ymodemInfo = new YModemInfo(); private Thread TransThread; private bool IsStart = false; private int reTryCount; private ManualResetEvent waitReceiveEvent = new ManualResetEvent(false); private YmodemReceiveStage ReceiveStage; private YmodemSendStage SendStage; private Queue msgQueue = new Queue(); public YModem(TransmitMode transType, YModemType ymodemType, int reTryCount) { RetryMax = reTryCount; ymodemInfo.Type = ymodemType; ymodemInfo.TransMode = transType; } public void Start() { IsStart = true; reTryCount = 0; ReceiveStage = YmodemReceiveStage.WaitForFileInfo; SendStage = YmodemSendStage.WaitReceiveRequestFileInfo; TransThread = new Thread(new ThreadStart(TransThreadHandler)); TransThread.IsBackground = true; TransThread.Name = "YmodemTransThread"; TransThread.Start(); if (ymodemInfo.TransMode == TransmitMode.Receive) { if (StartReceive != null) { StartReceive(ymodemInfo, null); } } } public void Stop() { if (ymodemInfo.TransMode == TransmitMode.Receive) { Abort(); } else { SendEOT(); } } public void Abort() { IsStart = false; SendCAN(); if (EndOfTransmit != null) { EndOfTransmit(ymodemInfo, null); } } /// /// 解析数据 /// /// private void ParseReceivedMessage(byte[] data) { YmodemMessage ReceivedMessage = null; if (data == null) { ReceivedMessage = null; } else { if (data[0] == STX || data[0] == SOH) { ReceivedMessage = new YmodemMessage(YmodemMessageType.PACKET_ERROR); int packetLen = 0; if (data[0] == STX) { packetLen = 1024; } else if (data[0] == SOH) { packetLen = 128; } int checkDataLen = 2; if (packetLen + 3 + checkDataLen == data.Length) { int packetNo = 0; if (data[1] == Convert.ToByte((~data[2]) & 0xFF)) { packetNo = data[1]; } int frameCheckCode = 0; int calCheckCode = -1; byte[] packet = new byte[packetLen]; Array.Copy(data, 3, packet, 0, packetLen); frameCheckCode = (data[3 + packetLen] << 8) + data[3 + packetLen + 1]; calCheckCode = Convert.ToUInt16(DataCheck.GetCRC(CRCType.CRC16_XMODEM, packet) & 0xFFFF); if (frameCheckCode == calCheckCode) { ReceivedMessage = new YmodemMessage(YmodemMessageType.PACKET, new PacketEventArgs(packetNo, packet)); } } } else { foreach (byte b in data) { ReceivedMessage = null; if (b == EOT) { ReceivedMessage = new YmodemMessage(YmodemMessageType.EOT); } else if (b == CAN) { ReceivedMessage = new YmodemMessage(YmodemMessageType.CAN); } else if (b == NAK) { ReceivedMessage = new YmodemMessage(YmodemMessageType.NAK); } else if (b == ACK) { ReceivedMessage = new YmodemMessage(YmodemMessageType.ACK); } else if (b == KEY_C) { ReceivedMessage = new YmodemMessage(YmodemMessageType.KEY_C); } else { } if (ReceivedMessage!=null) { msgQueue.Enqueue(ReceivedMessage); } } } } waitReceiveEvent.Set(); } private void SendFrameToUart(byte data) { byte[] bytes = new byte[1]; bytes[0] = data; SendFrameToUart(bytes); } private void SendFrameToUart(byte[] data) { if (SendToUartEvent != null) { SendToUartEvent(ymodemInfo, new SendToUartEventArgs(data)); } } private void SendACK() { SendFrameToUart(ACK); } private void SendNAK() { SendFrameToUart(NAK); } private void SendKEYC() { SendFrameToUart(KEY_C); } private void SendCAN() { byte[] bytes = new byte[5]; for (int i = 0; i < 5; i++) { bytes[i] = CAN; } SendFrameToUart(bytes); } private void SendEOT() { SendFrameToUart(EOT); SendStage = YmodemSendStage.WaitReceiveAnswerEndTransmit; } private void SendNoFilesToSend() { //int packetLen = ymodemInfo.Type == YModemType.YModem ? 128 : 1024; byte[] endPacket = new byte[3 + 128 + 2]; endPacket[0] = 0x01; endPacket[1] = 0x00; endPacket[2] = 0xFF; SendFrameToUart(endPacket); if (EndOfTransmit != null) { EndOfTransmit(ymodemInfo, null); } IsStart = false; } void TransThreadHandler() { while (IsStart) { if (ymodemInfo.TransMode == TransmitMode.Send) { SendHandler(); } else if (ymodemInfo.TransMode == TransmitMode.Receive) { ReceiveHandler(); } } } void SendHandler() { YmodemMessage msg; if (msgQueue.Count > 0) { msg = msgQueue.Dequeue(); if (msg != null) { reTryCount = 0; switch (msg.MessageType) { case YmodemMessageType.NAK: if (SendStage == YmodemSendStage.WaitReceiveAnswerEndTransmit) { SendEOT(); } else { // 通知重发 if (ReSendPacket != null) { ReSendPacket(ymodemInfo, null); } } break; case YmodemMessageType.KEY_C: if (SendStage == YmodemSendStage.WaitReceiveRequestFileInfo) { // 通知发头一包CRC if (StartSend != null) { StartSend(ymodemInfo, null); } } else if (SendStage == YmodemSendStage.WaitReceiveRequestFirstPacket) //等待第一包 { SendStage = YmodemSendStage.PacketSending; // 通知发下一包 if (SendNextPacket != null) { SendNextPacket(ymodemInfo, null); } } else if (SendStage == YmodemSendStage.WaitReceiveNextFileReq) //接收方请求下一个文件 { SendNoFilesToSend(); } break; case YmodemMessageType.ACK: if (SendStage == YmodemSendStage.WaitReceiveRequestFileInfo) { SendStage = YmodemSendStage.WaitReceiveRequestFirstPacket; //等待接收方请求第一包数据 } else if (SendStage == YmodemSendStage.PacketSending) { // 通知发下一包 if (SendNextPacket != null) { SendNextPacket(ymodemInfo, null); } } else if (SendStage == YmodemSendStage.WaitReceiveAnswerEndTransmit) { SendStage = YmodemSendStage.WaitReceiveNextFileReq; //等待接收方请求下一个文件 } break; case YmodemMessageType.CAN: // 通知中止 if (AbortTransmit != null) { AbortTransmit(ymodemInfo, null); } break; default: break; } } } else { if (waitReceiveEvent.WaitOne(3000)) { waitReceiveEvent.Reset(); } else { reTryCount++; if (reTryCount > RetryMax) { IsStart = false; //通知接收超时 if (TransmitTimeOut != null) { TransmitTimeOut(ymodemInfo, null); } } } } } void ReceiveHandler() { if (ReceiveStage == YmodemReceiveStage.WaitForFileInfo || ReceiveStage == YmodemReceiveStage.WaitForFirstPacket) { SendKEYC(); } if (msgQueue.Count > 0) { YmodemMessage msg = msgQueue.Dequeue(); if (msg != null) { reTryCount = 0; switch (msg.MessageType) { case YmodemMessageType.PACKET: PacketEventArgs e = msg.Value as PacketEventArgs; if (ReceiveStage == YmodemReceiveStage.WaitForFileInfo) { if (e.PacketNo == 0) { ReceiveStage = YmodemReceiveStage.WaitForFirstPacket; SendACK(); if (ReceivedPacket != null) { ReceivedPacket(ymodemInfo, new PacketEventArgs(e.PacketNo, e.Packet)); } } //else //{ // SendNAK(); //} } else if (ReceiveStage == YmodemReceiveStage.WaitForFirstPacket || ReceiveStage == YmodemReceiveStage.PacketReceiving) { if (ReceiveStage == YmodemReceiveStage.WaitForFirstPacket) { ReceiveStage = YmodemReceiveStage.PacketReceiving; } SendACK(); if (ReceivedPacket != null) { ReceivedPacket(ymodemInfo, new PacketEventArgs(e.PacketNo, e.Packet)); } // 通知发下一包 if (SendNextPacket != null) { SendNextPacket(ymodemInfo, null); } } break; case YmodemMessageType.PACKET_ERROR: SendNAK(); // 通知重发 if (ReSendPacket != null) { ReSendPacket(ymodemInfo, null); } break; case YmodemMessageType.EOT: SendACK(); // 通知完成 if (EndOfTransmit != null) { EndOfTransmit(ymodemInfo, null); } break; case YmodemMessageType.CAN: SendACK(); // 通知中止 if (AbortTransmit != null) { AbortTransmit(ymodemInfo, null); } break; default: break; } } } else { if (waitReceiveEvent.WaitOne(3000)) { waitReceiveEvent.Reset(); } else { reTryCount++; if (reTryCount > RetryMax) { IsStart = false; //通知接收超时 if (TransmitTimeOut != null) { TransmitTimeOut(ymodemInfo, null); } } } } } #region IFileTramsmit 成员 public event EventHandler StartSend; public event EventHandler StartReceive; public event EventHandler SendNextPacket; public event EventHandler ReSendPacket; public event EventHandler AbortTransmit; public event EventHandler EndOfTransmit; public event EventHandler TransmitTimeOut; public event PacketEventHandler ReceivedPacket; public void SendPacket(PacketEventArgs packet) { int packetLen = 0; int checkLen = 0; byte[] data; checkLen = 2; if (ymodemInfo.Type == YModemType.YModem_1K) { packetLen = 1024; } else { packetLen = 128; } data = new byte[3 + packetLen + checkLen]; data[0] = SOH; if (ymodemInfo.Type == YModemType.YModem_1K) { data[0] = STX; } data[1] = Convert.ToByte(packet.PacketNo & 0xFF); data[2] = Convert.ToByte((~data[1]) & 0xFF); Array.Copy(packet.Packet, 0, data, 3, packetLen); UInt16 crc = Convert.ToUInt16(DataCheck.GetCRC(CRCType.CRC16_XMODEM, packet.Packet) & 0xFFFF); data[3 + packetLen] = Convert.ToByte(crc >> 8); data[3 + packetLen + 1] = Convert.ToByte(crc & 0xFF); SendFrameToUart(data); } #endregion #region ITransmitUart 成员 public event SendToUartEventHandler SendToUartEvent; public void ReceivedFromUart(byte[] data) { ParseReceivedMessage(data); } #endregion } }