using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Linq; using System.Windows.Forms; using DevExpress.XtraEditors; using System.IO; using System.Runtime.InteropServices; using System.Threading; using LFP_Manager.Function; using LFP_Manager.Utils; namespace LFP_Manager { public delegate void AutoTxSetEnvent(bool autoTx); public delegate void SendDataUartEvent(ushort dev_addr, byte[] data, bool ReplyFlag, int type); public partial class fmxFwUpdate : XtraForm { #region DEFINES const int FW_UPDATE_START_ADDR = 0x08080000; const int FW_UPDATE_END_ADDR = 0x080E0000 - 1; const int FW_UPDATE_SECTOR_SIZE = 0x20000; const int FW_UPDATE_PACKET_SIZE = 0x800; const int APP_TO_BOOT = 0; const int BOOT_TO_APP = 1; #endregion #region VARIABLES private UInt32 SystemId = 0; private byte[] fwdata; private int fwsize; private int FwStartAddr = 0; private int FwCurrPosition = 0; private int FwSentLength = 0; private bool StopUpdate = true; private DateTime UpdateStartTime; private TimeSpan UpdateTime; public event AutoTxSetEnvent OnAutoTxSet = null; public event SendDataUartEvent OnSendUartData = null; #endregion #region CONSTRUCTORS public fmxFwUpdate(int sID) { InitializeComponent(); SystemId = (UInt32)sID; edTargetID.Text = sID.ToString(); fwdata = null; fwsize = 0; btnFwUpdate.Enabled = false; lcItemFlashErase.Visibility = DevExpress.XtraLayout.Utils.LayoutVisibility.Never; lcItemFlashWrite.Visibility = DevExpress.XtraLayout.Utils.LayoutVisibility.Never; lcItemGotoBoot.Visibility = DevExpress.XtraLayout.Utils.LayoutVisibility.Never; lcItemGotoApp.Visibility = DevExpress.XtraLayout.Utils.LayoutVisibility.Never; } #endregion #region BUTTON EVENTS private void btnClose_Click(object sender, EventArgs e) { Close(); } private void btnFwUpdate_Click(object sender, EventArgs e) { if (edTargetID.Text == "") { MessageBox.Show("Please check target id !!"); return; } SystemId = Convert.ToUInt32(edTargetID.Text); if (StopUpdate == true) { // Working mode change (Application --> Boot) - It need to be wait more than 1.5sec OnAutoTxSet?.Invoke(false); DisplayLabelUpdate("Goto Bootloader Mode"); RequestModeChange(APP_TO_BOOT); UpdateStartTime = DateTime.Now; btnFwUpdate.Text = "Cancel Update"; btnFwUpdate.Enabled = false; for (int i = 0; i < 2000; i += 100) { Thread.Sleep(100); Application.DoEvents(); } btnFwUpdate.Enabled = true; // Flash Erase RequestFlashErase(); } else { StopFwUpdate(); } } private void StopFwUpdate() { StopUpdate = true; btnFwUpdate.Text = "Firmware Update"; pgUpdate.Position = 0; //pgUpdate.Properties.Maximum = 0; //lbUpdateProgress.Text = "-/-"; lbUpdateStatus.Text = "Stop Update"; } public static byte[] ToByteArray(String HexString) { int NumberChars = HexString.Length; byte[] bytes = new byte[NumberChars / 2]; for (int i = 0; i < NumberChars; i += 2) { bytes[i / 2] = Convert.ToByte(HexString.Substring(i, 2), 16); } return bytes; } private void btnFind_Click(object sender, EventArgs e) { OpenFileDialog oDialog; oDialog = new OpenFileDialog(); oDialog.DefaultExt = "*.*"; oDialog.Filter = "hex files (*.hex)|*.hex|All files (*.*)|*.*"; if (oDialog.ShowDialog() == DialogResult.OK) { edFilename.Text = oDialog.FileName; int addr1 = 0; int addr2 = 0; string[] aline = File.ReadLines(edFilename.Text).ToArray(); for (int i = 0; i < aline.Length; i++) { byte[] a = ToByteArray(aline[i].Substring(1, aline[i].Length - 1)); switch (a[3]) { case 0: // data record addr2 = (int)((a[1] << 8) | a[2]) + a[0]; if (FwStartAddr == 0) FwStartAddr = (int)((a[1] << 8) | a[2]); break; case 1: // End of file record. Usually, it is 00000001FF break; case 2: // Extended Segment address record. This indicates segment base address when 16 bits is not enough for addressing memory; break; case 3: // Start segment address record. Indicates initial segment base address. break; case 4: // Extended Linear Address Record – allows 32 bit addressing. addr1 = (int)((a[4] << 8) | a[5]); break; case 5: // Start Linear Address Record. break; } } int FwImageSize = (int)((addr1 << 16) + addr2 - FwStartAddr); if ((FwImageSize % 128) > 0) { FwImageSize = ((FwImageSize / 128) + 1) * 128; } else { FwImageSize = ((FwImageSize / 128) + 0) * 128; } addr1 = 0; addr2 = 0; fwsize = FwImageSize; fwdata = new byte[fwsize]; for (int i = 0; i < fwdata.Length; i++) { fwdata[i] = 0xFF; } for (int i = 0; i < aline.Length; i++) { byte[] a = ToByteArray(aline[i].Substring(1, aline[i].Length - 1)); switch (a[3]) { case 0: // data record addr2 = (int)((a[1] << 8) | a[2]); int len = a[0]; for (int j = 0; j < len; j++) { fwdata[((addr1 << 16) + addr2) - FwStartAddr + j] = a[4 + j]; } break; case 1: // End of file record. Usually, it is 00000001FF break; case 2: // Extended Segment address record. This indicates segment base address when 16 bits is not enough for addressing memory; break; case 3: // Start segment address record. Indicates initial segment base address. break; case 4: // Extended Linear Address Record – allows 32 bit addressing. addr1 = (int)((a[4] << 8) | a[5]); break; case 5: // Start Linear Address Record. break; } } string strName = Path.GetFileName(edFilename.Text); lbFileInfo.Text = string.Format("File Information"); lbFileInfo.Text += string.Format("\r\n - Filename: {0}", strName); lbFileInfo.Text += string.Format("\r\n - File Version: {0}", strName.Substring(0, 12)); lbFileInfo.Text += string.Format("\r\n - File Size: {0:#,##0} bytes", fwsize); lbFileInfo.Text += string.Format("\r\n - Packet Size: {0:#,##0} packets", fwsize / 128); lbFileInfo.Text += string.Format("\r\n - Last packet: {0:#,##0}", fwsize % 128); lbFileInfo.Text += string.Format("\r\n - Start Addr : 0x{0:X8}", FwStartAddr); lbUpdateProgress.Text = string.Format("{0:#,##0}/{1:#,##0} bytes", 0, fwsize); pgUpdate.Properties.Maximum = (int)fwsize; btnFwUpdate.Enabled = true; } } #endregion #region FORM EVENT private void fmxFwUpdate_Activated(object sender, EventArgs e) { //OnAutoTxSet?.Invoke(false); } private void fmxFwUpdate_FormClosed(object sender, FormClosedEventArgs e) { OnAutoTxSet?.Invoke(true); } #endregion #region PUBLIC FUNCTION void DisplayLabelUpdate(string msg) { if (this.InvokeRequired) { this.Invoke(new MethodInvoker(delegate () { lbUpdateStatus.Text = string.Format("Update Status : {0}", msg); })); } else { lbUpdateStatus.Text = string.Format("Update Status : {0}", msg); } } void DisplayUpdateProgress() { if (this.InvokeRequired) { _ = this.Invoke(new MethodInvoker(delegate () { lbUpdateProgress.Text = string.Format("{0:#,##0}/{1:#,##0} bytes", FwCurrPosition, fwsize); pgUpdate.Position = FwCurrPosition; UpdateTime = DateTime.Now - UpdateStartTime; lbUpdateTime.Text = string.Format("{0:mm}:{0:ss}", UpdateTime); })); } else { lbUpdateProgress.Text = string.Format("{0:#,##0}/{1:#,##0} bytes", FwCurrPosition, fwsize); pgUpdate.Position = FwCurrPosition; UpdateTime = DateTime.Now - UpdateStartTime; lbUpdateTime.Text = string.Format("{0:mm}:{0:ss}", UpdateTime); } } public void RecvData(byte[] rdata) { //lbUpdateStatus.Text = String.Format("Recv Data: 0x{0:X8} {1:X2} {2:X2} {3:X2} {4:X2} {5:X2} {6:X2} {7:X2} {8:X2}" // , rhdr, rdata[0], rdata[1], rdata[2], rdata[3], rdata[4], rdata[5], rdata[6], rdata[7]); if (StopUpdate == false) { if (rdata[0] == 0x7F) { switch (rdata[1]) { case 0x43: // Erase Flash if (rdata[2] == 0x79) { // Erase Success DisplayLabelUpdate("Flash Erase Success"); byte[] sdata = new byte[128]; FwCurrPosition = 0; for (int i = 0; i < sdata.Length; i++) { sdata[i] = fwdata[FwCurrPosition + i]; } RequestFlashWrite(FwStartAddr + FwCurrPosition, sdata); } else if (rdata[2] == 0x1F) { // Erase Fail DisplayLabelUpdate("Flash Erase Fail"); StopUpdate = true; } break; case 0x31: // Write Flash if (rdata[2] == 0x79) { // Write Success string str = string.Format("Flash Write Success - {0}/{1}", FwCurrPosition, FwSentLength); DisplayLabelUpdate(str); DisplayUpdateProgress(); FwCurrPosition += FwSentLength; int Remain = fwdata.Length - FwCurrPosition; if (Remain > 0) { int len = (Remain > 128) ? 128 : Remain; byte[] sdata = new byte[len]; for (int i = 0; i < sdata.Length; i++) { sdata[i] = fwdata[FwCurrPosition + i]; } RequestFlashWrite(FwStartAddr + FwCurrPosition, sdata); } else { RequestModeChange(BOOT_TO_APP); // Write Success str = string.Format("Complete Update - {0}/{1}", FwCurrPosition, FwSentLength); DisplayLabelUpdate(str); DisplayUpdateProgress(); //MessageBox.Show("Complete Firmware Update", "Result", MessageBoxButtons.OK, MessageBoxIcon.Information); } } else if (rdata[2] == 0x1F) { // Write Fail DisplayLabelUpdate("Flash Write Fail"); StopUpdate = true; } break; } } } } #endregion #region UART PACKET FUNCTION private void RequestModeChange(int mode) { byte[] sdata = null; byte[] crc; if (mode == 0) { // Normal mode --> Bootloader mode sdata = new byte[8]; sdata[0] = (byte)SystemId; // Dev Address sdata[1] = 0x50; // Function Code sdata[2] = 0x80; // Address H sdata[3] = 0x00; // Address L sdata[4] = 0x00; // Number of Register H sdata[5] = 0x00; // Number of Register L crc = csSerialCommFunction.GetCRC(sdata, 6); sdata[6] = crc[1]; // CRCH sdata[7] = crc[0]; // CRCL StopUpdate = false; } else if (mode == 1) { // Bootloader mode --> Normal mode sdata = new byte[5]; sdata[0] = 0x7F; // Dev Address sdata[1] = 0x21; // Function Code,,+ sdata[2] = 0xDE; // Sub Code crc = csSerialCommFunction.GetCRC(sdata, 3); sdata[3] = crc[1]; // CRCH sdata[4] = crc[0]; // CRCL StopFwUpdate(); } OnSendUartData?.Invoke((ushort)SystemId, sdata, false, 0); } private void RequestFlashErase() { byte[] sdata = null; byte[] crc; // Flash Erase sdata = new byte[5]; sdata[0] = 0x7F; // Dev Address sdata[1] = 0x43; // Function Code sdata[2] = 0xBC; // Sub Code crc = csSerialCommFunction.GetCRC(sdata, 3); sdata[3] = crc[1]; // CRCH sdata[4] = crc[0]; // CRCL OnSendUartData?.Invoke((ushort)SystemId, sdata, true, 0); } private void RequestFlashWrite(int addr, byte[] data) { byte[] sdata = null; byte[] crc; // Flash Write sdata = new byte[6 + 128 + 2]; for (int i = 0; i < sdata.Length; i++) { sdata[i] = 0xFF; } sdata[0] = 0x7F; // Dev Address sdata[1] = 0x31; // Function Code sdata[2] = 0xCE; // Sub Code sdata[3] = (byte)(addr >> 16); // Addr H sdata[4] = (byte)(addr >> 8); // Addr L MSB sdata[5] = (byte)(addr & 0xff); // Addr L LSB for (int i = 0; i < data.Length; i++) { sdata[6 + i] = data[i]; } crc = csSerialCommFunction.GetCRC(sdata, sdata.Length - 2); sdata[sdata.Length - 2] = crc[1]; // CRCH sdata[sdata.Length - 1] = crc[0]; // CRCL FwSentLength = data.Length; OnSendUartData?.Invoke((ushort)SystemId, sdata, false, 0); } #endregion #region BUTTON EVENT private void btnGotoBoot_Click(object sender, EventArgs e) { OnAutoTxSet?.Invoke(false); RequestModeChange(APP_TO_BOOT); UpdateStartTime = DateTime.Now; } private void btnGotoApp_Click(object sender, EventArgs e) { RequestModeChange(BOOT_TO_APP); } private void btnFlashErase_Click(object sender, EventArgs e) { RequestFlashErase(); } private void btnFlashWrite_Click(object sender, EventArgs e) { byte[] sdata = new byte[128]; FwCurrPosition = 0; for (int i = 0; i < sdata.Length; i++) { sdata[i] = fwdata[FwCurrPosition + i]; } RequestFlashWrite(FwStartAddr + FwCurrPosition, sdata); } #endregion } }