1. 程式人生 > >串列埠傳輸檔案(YModem協議)

串列埠傳輸檔案(YModem協議)

需求:通過串列埠線實現應用程式韌體燒錄到微控制器的flash中
開發語言:C#
串列埠設定:串列埠號,波特率:115200;

檔案傳輸函式如下:

        //燒錄檔案函式
        public bool YmodemUploadFile()
        {
            /* control signals */
            const byte STX = 2;  // Start of TeXt 
            const byte EOT = 4;  // End Of Transmission
            const byte ACK = 6;  // Positive ACknowledgement
            const byte C = 67;   // capital letter C
            /* sizes */
            const int dataSize = 1024;
            const int crcSize = 2;
            /* THE PACKET: 1029 bytes */
            /* header: 3 bytes */
            // STX        
            int invertedPacketNumber = 255;
            /* data: 1024 bytes */
            byte[] data = new byte[dataSize];
            /* footer: 2 bytes */
            byte[] CRC = new byte[crcSize];
            /* get the file */
            //string strfilepath = m_configData.ini_burningfilespath;
            FileStream fileStream = new FileStream(@path, FileMode.Open, FileAccess.Read);//讀取bin檔案的path           
            m_strMsglogString += ("\r\nreading buring files...\r\n");
            ShowExcuteProcessInfo();            
            DateTime dt = DateTime.Now;
            byte[] ack;
            ack = new byte[] { 0x31 };
            try
            {
                serialPort1.Write(ack, 0, 1);
            }
            catch
            {
                MessageBox.Show("Exception");
            }
            Thread.Sleep(300);            
            try
            {
                ///* send the initial packet with filename and filesize */
                m_strMsglogString += ("waiting for the serial response...\r\n");
                ShowExcuteProcessInfo(); 
                int AAA = serialPort1.ReadByte();
                //pictureBoxResult.BackgroundImage = Properties.Resources.faillight;
                if (serialPort1.ReadByte() != C)
                {
                    MessageBox.Show("Can't begin the transfer.");
                    //Console.WriteLine("Can't begin the transfer.");
                    //pictureBoxResult.BackgroundImage = Properties.Resources.faillight;
                    ShowTestFailResult();
                    return false;
                }
                m_strMsglogString += ("send the initial packet with filename and filesize ...\r\n");
                ShowExcuteProcessInfo(); 
                sendYmodemInitialPacket
(STX, packetNumber, invertedPacketNumber, data, dataSize, path, fileStream, CRC, crcSize); if (serialPort1.ReadByte() != ACK) { MessageBox.Show("Can't send the initial packet."); ShowTestFailResult(); return false; } if (serialPort1.ReadByte() != C) { MessageBox.Show("22Can't send the initial packet."); ShowTestFailResult(); return false; } btn_download.Invoke ( //委託,託管無引數的任何方法 new MethodInvoker ( delegate { btn_download.Text = "正在燒錄"; } ) ); /* send packets with a cycle until we send the last byte */ m_strMsglogString += ("\r\nsending packets...\r\n"); ShowExcuteProcessInfo(); int fileReadCount; do { /* if this is the last packet fill the remaining bytes with 0 */ fileReadCount = fileStream.Read(data, 0, dataSize); if (fileReadCount == 0) break; if (fileReadCount != dataSize) for (int i = fileReadCount; i < dataSize; i++) data[i] = 0; /*calculate packetNumber */ packetNumber++; //if (packetNumber > 255) // packetNumber -= 256; ThreadFunction(); Console.WriteLine(packetNumber); //Thread.Sleep(300); /* calculate invertedPacketNumber */ invertedPacketNumber = 255 - packetNumber % 256; /* calculate CRC */ Crc16Ccitt crc16Ccitt = new Crc16Ccitt(InitialCrcValue.Zeros); CRC = crc16Ccitt.ComputeChecksumBytes(data); /* send the packet */ sendYmodemPacket
(STX, packetNumber, invertedPacketNumber, data, dataSize, CRC, crcSize); int iii = serialPort1.ReadByte(); /* wait for ACK */ if (iii != (int)ACK) { MessageBox.Show("Couldn't send a packet."); //Console.WriteLine("Couldn't send a packet."); ShowTestFailResult(); return false; } } while (dataSize == fileReadCount); /* send EOT (tell the downloader we are finished) */ serialPort1.Write(new byte[] { EOT }, 0, 1); /* send closing packet */ packetNumber = 0; invertedPacketNumber = 255; data = new byte[dataSize]; CRC = new byte[crcSize]; m_strMsglogString += ("\r\nsend closing packet...\r\n"); ShowExcuteProcessInfo(); sendYmodemClosingPacket
(STX, packetNumber, invertedPacketNumber, data, dataSize, CRC, crcSize); /* get ACK (downloader acknowledge the EOT) */ if (serialPort1.ReadByte() != ACK) { Console.WriteLine("Can't complete the transfer."); ShowTestFailResult(); return false; } } catch (TimeoutException) { throw new Exception("Eductor does not answering"); } finally { fileStream.Close(); } packetNumber = fsLen; ThreadFunction(); Console.WriteLine("File transfer is succesful"); TimeSpan span = DateTime.Now - dt; btn_download.Invoke ( //委託,託管無引數的任何方法 new MethodInvoker ( delegate { btn_download.Text = "開始燒錄"; } ) ); m_strMsglogString += ("\r\n燒錄完成,耗時:" + span.ToString() + "\r\n"); ShowExcuteProcessInfo(); txb_section.Invoke ( //委託,託管無引數的任何方法 new MethodInvoker ( delegate { txb_section.Text = "0"; } ) ); Thread.Sleep(2000); return true; }

檔案傳輸函式包含了YModem協議檔案傳輸的過程,根據YModem協議,傳送資料之前和之後都需建立握手通訊,

        //YModem協議 初始化包
        private void sendYmodemInitialPacket(byte STX, int packetNumber, int invertedPacketNumber, byte[] data, int dataSize, string path, FileStream fileStream, byte[] CRC, int crcSize)
        {
            string fileName = System.IO.Path.GetFileName(path);
            string fileSize = fileStream.Length.ToString();

            /* add filename to data */
            int i;
            for (i = 0; i < fileName.Length && (fileName.ToCharArray()[i] != 0); i++)
            {
                data[i] = (byte)fileName.ToCharArray()[i];
            }
            data[i] = 0;

            /* add filesize to data */
            int j;
            for (j = 0; j < fileSize.Length && (fileSize.ToCharArray()[j] != 0); j++)
            {
                data[(i + 1) + j] = (byte)fileSize.ToCharArray()[j];
            }
            data[(i + 1) + j] = 0;

            /* fill the remaining data bytes with 0 */
            for (int k = ((i + 1) + j) + 1; k < dataSize; k++)
            {
                data[k] = 0;
            }

            /* calculate CRC */
            Crc16Ccitt crc16Ccitt = new Crc16Ccitt(InitialCrcValue.Zeros);
            CRC = crc16Ccitt.ComputeChecksumBytes(data);

            /* send the packet */
            sendYmodemPacket(STX, packetNumber, invertedPacketNumber, data, dataSize, CRC, crcSize);
        }
       
        //YModem協議 尾包
        private void sendYmodemClosingPacket(byte STX, int packetNumber, int invertedPacketNumber, byte[] data, int dataSize, byte[] CRC, int crcSize)
        {
            /* calculate CRC */
            Crc16Ccitt crc16Ccitt = new Crc16Ccitt(InitialCrcValue.Zeros);
            CRC = crc16Ccitt.ComputeChecksumBytes(data);

            /* send the packet */
            sendYmodemPacket(STX, packetNumber, invertedPacketNumber, data, dataSize, CRC, crcSize);
        }
        

以上是YModem協議進行檔案傳輸的大致過程。由於YModem協議每次傳輸1024位元組的資料,整個燒錄檔案是預載入的,可以根據具體情況加上進度條資訊。

實現原始碼可參考:https://download.csdn.net/download/shufac/10308977