串列埠傳輸檔案(YModem協議)
阿新 • • 發佈:2019-01-07
需求:通過串列埠線實現應用程式韌體燒錄到微控制器的flash中
開發語言:C#
串列埠設定:串列埠號,波特率:115200;
開發語言: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