实例介绍
【实例简介】
【实例截图】
【核心代码】
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; //using Avacta.VetAX.Device.Interface; using System.ComponentModel; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; namespace DFU_Example { class FirmwareUpdate : Win32Usb, IFirmwareUpdate { const UInt16 HID_VID = 0x1234; const UInt16 HID_PID = 0x5678; const byte HID_DETACH_REPORT_ID = 0x80; const byte USAGE_DETACH = 0x55; const uint STDFU_ERROR_OFFSET = 0x12340000; const uint STDFU_NOERROR = STDFU_ERROR_OFFSET 0; const byte STATE_IDLE = 0x00; const byte STATE_DETACH = 0x01; const byte STATE_DFU_IDLE = 0x02; const byte STATE_DFU_DOWNLOAD_SYNC = 0x03; const byte STATE_DFU_DOWNLOAD_BUS = 0x04; const byte STATE_DFU_DOWNLOAD_IDLE = 0x05; const byte STATE_DFU_MANIFEST_SYNC = 0x06; const byte STATE_DFU_MANIFEST = 0x07; const byte STATE_DFU_MANIFEST_WAIT_RESET = 0x08; const byte STATE_DFU_UPLOAD_IDLE = 0x09; const byte STATE_DFU_ERROR = 0x0A; const byte STATE_DFU_UPLOAD_SYNC = 0x91; const byte STATE_DFU_UPLOAD_BUSY = 0x92; IntPtr INVALID_HANDLE_VALUE = (System.IntPtr)(-1); Guid GUID_DFU = new Guid( 0x3fe809ab, 0xfb91, 0x4cb5, 0xa6, 0x43, 0x69, 0x67, 0x0d, 0x52, 0x36, 0x6e ); Guid GUID_APP = new Guid( 0xcb979912, 0x5029, 0x420a, 0xae, 0xb1, 0x34, 0xfc, 0x0a, 0x7d, 0x57, 0x26 ); /// <summary>Thread to run the firmware update process</summary> private Thread thread; /// <summary>Event handler for firmware update progress event</summary> public event FirmwareUpdateProgressEventHandler OnFirmwareUpdateProgress; private String DFU_FilePath = ""; private UInt16 VID = 0; private UInt16 PID = 0; private UInt16 Version = 0; private String ImageName = ""; private String DFU_DevicePath = ""; /// <summary>Handle to open HID device, if any</summary> SafeFileHandle _ParentHandle = null; /// <summary>List of classes describing each programmable sector of the micro-controller</summary> private List<MappingSector> Sectors; /// <summary>Maximum size of a block of data for writing, this is set depending on the bootloader version</summary> private UInt16 MaxWriteBlockSize = 1024; /// <summary>Set true to request that the firmware update process start with a mass erase of the micro-controller /// This is not suitable unless the DFU module is in ROM because it would erase the bootloader itself.</summary> private bool DoMassErase; /// <summary> /// Update the device firmware with the referenced DFU file data /// </summary> /// <param name="DFU_FilePath">Full path of DFU file for new firmware</param> /// <param name="DoMassErase">True to mass erase the device, false to erase by sectors. /// Unless the DFU module is in ROM, the device should be erased by sectors or else the DFU module will be erased public void UpdateFirmware(String DFU_FilePath, bool DoMassErase) { this.DFU_FilePath = DFU_FilePath; this.DoMassErase = DoMassErase; thread = new Thread( DoFirmwareUpdate ); thread.Name = "Firmware update thread"; thread.Start(); } /// <summary> /// Mass erase a device. /// Useful for a device which has been read protected, otherwise it can't be programmed with a ULink. /// Obviously erases the DFU module unless it is in ROM /// Assumes the device is already in DFU mode. /// </summary> public void MassErase() { IntPtr hDevice = IntPtr.Zero; try { if (OnFirmwareUpdateProgress != null) OnFirmwareUpdateProgress(this, new FirmwareUpdateProgressEventArgs(0, "Detecting device", false)); FindAndDetachHID(); if (OnFirmwareUpdateProgress != null) OnFirmwareUpdateProgress(this, new FirmwareUpdateProgressEventArgs(10, "Opening the device", false)); hDevice = OpenDFU_Device(out Sectors, out MaxWriteBlockSize); if( OnFirmwareUpdateProgress != null ) OnFirmwareUpdateProgress(this, new FirmwareUpdateProgressEventArgs(20, "Performing mass erase", false)); MassErase(hDevice); if( OnFirmwareUpdateProgress != null ) OnFirmwareUpdateProgress(this, new FirmwareUpdateProgressEventArgs(100, "Mass erase complete", false)); } catch (Exception ex) { if( OnFirmwareUpdateProgress != null ) OnFirmwareUpdateProgress(this, new FirmwareUpdateProgressEventArgs(100, ex.Message, true)); } } /// <summary> /// Function to sequence the firmware update /// </summary> private void DoFirmwareUpdate() { int i; byte[] FileData = new byte[0]; UInt32 ElementAddress = 0; UInt32 ElementSize = 0; byte[] ElementData; IntPtr hDevice = IntPtr.Zero; UInt32 BlockNumber; byte[] Block; try { if( OnFirmwareUpdateProgress != null ) OnFirmwareUpdateProgress(this, new FirmwareUpdateProgressEventArgs(0, "Detecting device", false)); FindAndDetachHID(); if( OnFirmwareUpdateProgress != null ) OnFirmwareUpdateProgress(this, new FirmwareUpdateProgressEventArgs(2, "Loading the DFU file", false)); LoadDFU_File( FileData, out ElementData, out ElementAddress, out ElementSize); if( OnFirmwareUpdateProgress != null ) OnFirmwareUpdateProgress(this, new FirmwareUpdateProgressEventArgs(3, "Opening the device", false)); hDevice = OpenDFU_Device(out Sectors, out MaxWriteBlockSize); if (DoMassErase) { if( OnFirmwareUpdateProgress != null ) OnFirmwareUpdateProgress(this, new FirmwareUpdateProgressEventArgs(4, "Performing mass erase", false)); MassErase(hDevice); if( OnFirmwareUpdateProgress != null ) OnFirmwareUpdateProgress(this, new FirmwareUpdateProgressEventArgs(5, "Mass erase complete", false)); } else { if( OnFirmwareUpdateProgress != null ) OnFirmwareUpdateProgress(this, new FirmwareUpdateProgressEventArgs(4, "Performing partial erase", false)); PartialErase(hDevice, ElementAddress, ElementSize, Sectors ); if( OnFirmwareUpdateProgress != null ) OnFirmwareUpdateProgress(this, new FirmwareUpdateProgressEventArgs(5, "Partial erase complete", false)); } System.Threading.Thread.Sleep(500); // Write the data in 2048byte blocks for (BlockNumber = 0; BlockNumber <= ElementSize / MaxWriteBlockSize; BlockNumber ) { if( OnFirmwareUpdateProgress != null ) OnFirmwareUpdateProgress(this, new FirmwareUpdateProgressEventArgs(10 (80 * BlockNumber * MaxWriteBlockSize / ElementSize ), "Writing block " BlockNumber.ToString(), false)); // Get the data for write and massage it into a 2048 byte block Block = ElementData.Skip((int)(MaxWriteBlockSize * BlockNumber)).Take((int)MaxWriteBlockSize).ToArray(); if (Block.Length < MaxWriteBlockSize) { i = Block.Length; Array.Resize(ref Block, (int)MaxWriteBlockSize); // Pad with 0xFF so our CRC matches the ST Bootloader and the ULink's CRC for (; i < MaxWriteBlockSize; i ) { Block[i] = 0xFF; } } WriteBlock(hDevice, ElementAddress, Block, BlockNumber); } if( OnFirmwareUpdateProgress != null ) OnFirmwareUpdateProgress(this, new FirmwareUpdateProgressEventArgs(95, "Restarting", false)); Detach(hDevice, ElementAddress); if( OnFirmwareUpdateProgress != null ) OnFirmwareUpdateProgress(this, new FirmwareUpdateProgressEventArgs(100, "Programming complete", false)); } catch (Exception ex) { if( OnFirmwareUpdateProgress != null ) OnFirmwareUpdateProgress(this, new FirmwareUpdateProgressEventArgs(100, ex.Message, true)); } } /// <summary> /// Look for a HID device with the expected VID and PID, if found, send the detach message /// </summary> private void FindAndDetachHID() { int i; // If we are connected to a device with the expected VID and PID, send the detach message if (FindDevice(HID_VID, HID_PID)) { //byte[] Feature = new byte[65]; // Assign a buffer in unmananged memory IntPtr Feature = Marshal.AllocHGlobal(65); Marshal.WriteByte(Feature, 0, HID_DETACH_REPORT_ID); Marshal.WriteByte(Feature, 1, USAGE_DETACH); for (i = 2; i < 65; i ) { Marshal.WriteByte(Feature, i, 0); } if (HidD_SetFeature(_ParentHandle, Feature, 65)) { if (OnFirmwareUpdateProgress != null) OnFirmwareUpdateProgress(this, new FirmwareUpdateProgressEventArgs(1, "HID detach success", false)); } else { // SensiPOD usually replies to this with 31, ERROR_GEN_FAILURE, but it still works... if (OnFirmwareUpdateProgress != null) OnFirmwareUpdateProgress(this, new FirmwareUpdateProgressEventArgs(1, "HID detach error = " (Marshal.GetLastWin32Error()).ToString(), false)); //throw (new Exception("HID detach failed")); } Marshal.FreeHGlobal(Feature); System.Threading.Thread.Sleep(5000); } } /// <summary> /// Function to find a device with a given VID and PID /// </summary> /// <param name="nVid">VID to search for</param> /// <param name="nPid">PID to search for</param> /// <returns>True if matching device is found</returns> public bool FindDevice(UInt16 nVid, UInt16 nPid) { String strDevicePath; string strPath = string.Empty; string strSearch = string.Format("vid_{0:x4}&pid_{1:x4}", nVid, nPid); // first, build the path search string Guid gHid; HidD_GetHidGuid(out gHid); // next, get the GUID from Windows that it uses to represent the HID USB interface IntPtr hInfoSet = SetupDiGetClassDevs(ref gHid, null, IntPtr.Zero, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); // this gets a list of all HID devices currently connected to the computer (InfoSet) try { DeviceInterfaceData oInterface = new DeviceInterfaceData(); // build up a device interface data block oInterface.Size = Marshal.SizeOf(oInterface); // 28 in 32bit or 32 in 64bit mode, // Now iterate through the InfoSet memory block assigned within Windows in the call to SetupDiGetClassDevs // to get device details for each device connected int nIndex = 0; while (SetupDiEnumDeviceInterfaces(hInfoSet, 0, ref gHid, (uint)nIndex, ref oInterface)) // this gets the device interface information for a device at index 'nIndex' in the memory block { strDevicePath = GetDevicePath(hInfoSet, ref oInterface); // get the device path (see helper method 'GetDevicePath') if (strDevicePath.IndexOf(strSearch) >= 0) // do a string search, if we find the VID/PID string then we found our device! { return true; } nIndex ; // if we get here, we didn't find our device. So move on to the next one. } if (0 != Marshal.GetLastWin32Error()) { if (ERROR_NO_MORE_ITEMS == Marshal.GetLastWin32Error()) { // Do nothing, this just means the ARM_Board wasn't found } else if (ERROR_INVALID_USER_BUFFER == Marshal.GetLastWin32Error()) { throw new Exception("Size member of hInfoSet is not set correctly (5 for 32bit or 8 for 64bit)"); } else { throw new Exception("SetupDiEnumDeviceInterfaces returned error " Marshal.GetLastWin32Error().ToString()); } } } finally { // Before we go, we have to free up the InfoSet memory reserved by SetupDiGetClassDevs SetupDiDestroyDeviceInfoList(hInfoSet); } return false; // oops, didn't find our device } /// <summary> /// Helper method to return the device path given a DeviceInterfaceData structure and an InfoSet handle. /// Used in 'FindDevice' so check that method out to see how to get an InfoSet handle and a DeviceInterfaceData. /// </summary> /// <param name="hInfoSet">Handle to the InfoSet</param> /// <param name="oInterface">DeviceInterfaceData structure</param> /// <returns>The device path or null if there was some problem</returns> private string GetDevicePath(IntPtr hInfoSet, ref DeviceInterfaceData oInterface) { uint nRequiredSize = 0; // Get the device interface details if (!SetupDiGetDeviceInterfaceDetail(hInfoSet, ref oInterface, IntPtr.Zero, 0, ref nRequiredSize, IntPtr.Zero)) { DeviceInterfaceDetailData oDetail = new DeviceInterfaceDetailData(); if (IntPtr.Size == 8) // If we are compiled as 64bit { oDetail.Size = 8; } else if (IntPtr.Size == 4) // If we are compiled as 32 bit { oDetail.Size = 5; } else { throw new Exception("Operating system is neither 32 nor 64 bits!"); } if (SetupDiGetDeviceInterfaceDetail(hInfoSet, ref oInterface, ref oDetail, nRequiredSize, ref nRequiredSize, IntPtr.Zero)) { return oDetail.DevicePath; } } return null; } /// <summary> /// Scan a DFU file to get the VID, PID and file version /// It is recommended that the VID and PID are checked before proceeding with the firmware update /// </summary> /// <param name="Filepath">DFU filepath</param> /// <param name="VID">Vendor Identifier</param> /// <param name="PID">Product Identifier</param> /// <param name="Version">DFU file firmware version</param> /// <returns>true if success, else false</returns> public bool ParseDFU_File(String Filepath, out UInt16 VID, out UInt16 PID, out UInt16 Version) { byte[] FileData; UInt32 CRC = 0; bool Retval = true; try { // Read the file into memory FileData = System.IO.File.ReadAllBytes(Filepath); // Check the prefix if (Encoding.UTF8.GetString(FileData, 0, 5) != "DfuSe") { throw new Exception("File signature error"); } if (FileData[5] != 1) { throw new Exception("DFU file version must be 1"); } // Check the suffix if ((Encoding.UTF8.GetString(FileData, FileData.Length - 8, 3) != "UFD") || (FileData[FileData.Length - 5] != 16) || (FileData[FileData.Length - 10] != 0x1A) || (FileData[FileData.Length - 9] != 0x01)) { throw new Exception("File suffix error"); } // Check the CRC CRC = BitConverter.ToUInt32(FileData, FileData.Length - 4); if (CRC != CalculateCRC(FileData)) { throw new Exception("File CRC error"); } // Get VID, PID and version number VID = BitConverter.ToUInt16(FileData, FileData.Length - 12); PID = BitConverter.ToUInt16(FileData, FileData.Length - 14); Version = BitConverter.ToUInt16(FileData, FileData.Length - 16); } catch { VID = 0; PID = 0; Version = 0; Retval = false; } return (Retval); } /// <summary> /// Load a DFU file and pull out the actual firmware image /// </summary> /// <param name="FileData">Complete file as a byte array</param> /// <param name="ElementData">Image data only</param> /// <param name="ElementAddress">Starting address in the micro-controller for the image</param> /// <param name="ElementSize">Size of the image</param> private void LoadDFU_File(byte[] FileData, out byte[] ElementData, out UInt32 ElementAddress, out UInt32 ElementSize) { UInt32 TargetSize = 0; UInt32 CRC = 0; UInt32 Elements = 0; try { // Read the file into memory FileData = System.IO.File.ReadAllBytes(DFU_FilePath); // Check the prefix if( Encoding.UTF8.GetString(FileData,0,5) != "DfuSe" ) { throw new Exception("File signature error"); } if (FileData[5] != 1) { throw new Exception("DFU file version must be 1"); } if (FileData[10] != 1) { throw new Exception("There should be exactly one target in the DFU file"); } // Check the suffix if ((Encoding.UTF8.GetString(FileData, FileData.Length - 8, 3) != "UFD") || (FileData[FileData.Length - 5] != 16) || (FileData[FileData.Length - 10] != 0x1A) || (FileData[FileData.Length - 9] != 0x01)) { throw new Exception("File suffix error"); } // Check the CRC CRC = BitConverter.ToUInt32(FileData, FileData.Length - 4); if( CRC != CalculateCRC(FileData)) { throw new Exception("File CRC error"); } // Get VID, PID and version number VID = BitConverter.ToUInt16(FileData, FileData.Length - 12); PID = BitConverter.ToUInt16(FileData, FileData.Length - 14); Version = BitConverter.ToUInt16(FileData, FileData.Length - 16); // Now check the target prefix, we assume there is only one target in the file if( Encoding.UTF8.GetString(FileData,11,6) != "Target" ) { throw new Exception("Target signature error"); } TargetSize = BitConverter.ToUInt32(FileData, 277); if (0 != FileData[18]) { int len = Array.FindIndex(FileData, 22, (x) => x == 0); ImageName = Encoding.UTF8.GetString(FileData, 22, len - 22); } else { ImageName = "DFU Image"; } Elements = BitConverter.ToUInt32(FileData, 281); if (Elements != 1) { throw new Exception("We only expect one element in the target"); } ElementAddress = BitConverter.ToUInt32(FileData, 285); ElementSize = BitConverter.ToUInt32(FileData, 289); ElementData = FileData.Skip(293).Take((int)ElementSize).ToArray(); if( OnFirmwareUpdateProgress != null ) OnFirmwareUpdateProgress(this, new FirmwareUpdateProgressEventArgs(5, "DFU file parsed" ElementSize.ToString() ElementAddress.ToString(), false)); } catch (Exception ex) { throw new Exception("DFU file read failed. " ex.Message); } } /// <summary> /// Helper function to calculate the CRC /// </summary> /// <param name="FileData">Data to calculate the CRC for</param> /// <returns>CRC</returns> private UInt32 CalculateCRC(byte[] FileData) { UInt32 Retval = 0xFFFFFFFF; int i; for (i = 0; i < FileData.Length - 4; i ) { Retval = CrcTable[((Retval) ^ (FileData[i])) & 0xff] ^ ((Retval) >> 8); } return (Retval); } /// <summary> /// Open the connection to the single DFU device which is attached to this computer. Also parse the sector descriptions to build a list of sectors. /// </summary> /// <returns>Handle to the device</returns> private IntPtr OpenDFU_Device(out List<MappingSector> Sectors, out UInt16 MaxWriteBlockSize) { int i = 10; uint Index = 0; Guid GUID = GUID_DFU; DeviceInterfaceData ifData = new DeviceInterfaceData(); ifData.Size = Marshal.SizeOf(ifData); DeviceInterfaceDetailData ifDetail = new DeviceInterfaceDetailData(); UInt32 Size = 0; IntPtr hInfoSet = SetupDiGetClassDevs(ref GUID, null, IntPtr.Zero, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); // this gets a list of all DFU devices currently connected to the computer (InfoSet) IntPtr hDevice = IntPtr.Zero; Sectors = null; MaxWriteBlockSize = 1024; try { if (hInfoSet == INVALID_HANDLE_VALUE) { throw new Exception("SetupDiGetClassDevs returned error=" Marshal.GetLastWin32Error().ToString()); } // Loop ten times hoping to find exactly one DFU device while (i-- > 0) { Index = 0; while (SetupDiEnumDeviceInterfaces(hInfoSet, 0, ref GUID, Index, ref ifData)) { Index ; } if (0 == Index) { System.Threading.Thread.Sleep(500); } else { break; } } if (1 == Index) { SetupDiEnumDeviceInterfaces(hInfoSet, 0, ref GUID, 0, ref ifData); SetupDiGetDeviceInterfaceDetail(hInfoSet, ref ifData, IntPtr.Zero, 0, ref Size, IntPtr.Zero); // ifDetail.Size = (int)Size; if (IntPtr.Size == 8) // If we are compiled as 64bit { ifDetail.Size = 8; } else if (IntPtr.Size == 4) // If we are compiled as 32 bit { ifDetail.Size = 5; } else { throw new Exception("Operating system is neither 32 nor 64 bits!"); } if( Marshal.SizeOf(ifDetail) < Size ) { throw new Exception("ifDetail too small"); } if (true == SetupDiGetDeviceInterfaceDetail(hInfoSet, ref ifData, ref ifDetail, Size, ref Size, IntPtr.Zero)) { DFU_DevicePath = ifDetail.DevicePath.ToUpper(); if (STDFU_NOERROR == STDFU_Open(DFU_DevicePath, out hDevice)) { if( OnFirmwareUpdateProgress != null ) OnFirmwareUpdateProgress(this, new FirmwareUpdateProgressEventArgs(10, "DFU device opened OK", false)); USB_DeviceDescriptor Descriptor = new USB_DeviceDescriptor(); if (STDFU_NOERROR == STDFU_GetDeviceDescriptor(ref hDevice, ref Descriptor)) { switch (Descriptor.bcdDevice) { case 0x011A: case 0x0200: MaxWriteBlockSize = 1024; break; case 0x02100: MaxWriteBlockSize = 2048; break; default: throw new Exception("Unsupported bootloader version=" Descriptor.bcdDevice.ToString("X4")); break; } UInt32 Dummy1 = 0; UInt32 Dummy2 = 0; DFU_FunctionalDescriptor CurrentDeviceDescriptor = new DFU_FunctionalDescriptor(); if (STDFU_NOERROR == STDFU_GetDFUDescriptor(ref hDevice, ref Dummy1, ref Dummy2, ref CurrentDeviceDescriptor)) { if( OnFirmwareUpdateProgress != null ) OnFirmwareUpdateProgress(this, new FirmwareUpdateProgressEventArgs(14, "Got DFU Descriptor " CurrentDeviceDescriptor.bcdDFUVersion.ToString(), false)); Sectors = CreateMappingFromDevice(hDevice); } else { throw new Exception("STDFU_GetDFUDescriptor failed, error code=" Marshal.GetLastWin32Error().ToString()); } } else { throw new Exception("STDFU_GetDeviceDescriptor failed, error code=" Marshal.GetLastWin32Error().ToString()); } } else { throw new Exception("STDFU_Open failed, error code=" Marshal.GetLastWin32Error().ToString()); } } } else { throw new Exception("There must be exactly one DFU device attached to the computer"); } } catch( Exception ex ) { throw new Exception(ex.Message); // del(100, ex.Message, true); } finally { // Before we go, we have to free up the InfoSet memory reserved by SetupDiGetClassDevs SetupDiDestroyDeviceInfoList(hInfoSet); } return (hDevice); } /// <summary> /// Mass erase the micro-controller /// </summary> /// <param name="hDevice">Handle to the USB connection to the micro-controller</param> private void MassErase(IntPtr hDevice) { DFU_Status dfuStatus = new DFU_Status(); UInt32 Result = 0; byte[] EraseCommand = { 0x41, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; if (STDFU_NOERROR == (Result = STDFU_SelectCurrentConfiguration( ref hDevice, 0, 0, 1))) { STDFU_GetStatus(ref hDevice, ref dfuStatus); while (dfuStatus.bState != STATE_DFU_IDLE) { STDFU_ClrStatus(ref hDevice); STDFU_GetStatus(ref hDevice, ref dfuStatus); } if (STDFU_NOERROR == (Result = STDFU_Dnload(ref hDevice, EraseCommand, 1, 0))) { STDFU_GetStatus(ref hDevice, ref dfuStatus); while (dfuStatus.bState != STATE_DFU_IDLE) { STDFU_ClrStatus(ref hDevice); STDFU_GetStatus(ref hDevice, ref dfuStatus); } } else { throw new Exception("STDFU_Dnload returned " Result.ToString("X8")); } } else { throw new Exception("STDFU_SelectCurrentConfiguration returned " Result.ToString("X8")); } } private void PartialErase(IntPtr hDevice, UInt32 StartAddress, UInt32 Size, List<MappingSector> SectorList) { foreach (MappingSector s in SectorList) { if ((StartAddress < s.dwStartAddress s.dwSectorSize) && (StartAddress Size > s.dwStartAddress)) { EraseSector(hDevice, s.dwStartAddress); } } } /// <summary> /// Erase a sector /// </summary> /// <param name="hDevice">Device handle</param> /// <param name="Address">Start address of sector for erase</param> private void EraseSector(IntPtr hDevice, UInt32 Address) { DFU_Status dfuStatus = new DFU_Status(); UInt32 Result = 0; byte[] Command = { 0x41, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; Command[1] = (byte)(Address & 0xFF); Command[2] = (byte)((Address >> 8) & 0xFF); Command[3] = (byte)((Address >> 16) & 0xFF); Command[4] = (byte)((Address >> 24) & 0xFF); if (STDFU_NOERROR == (Result = STDFU_SelectCurrentConfiguration(ref hDevice, 0, 0, 0))) { STDFU_GetStatus(ref hDevice, ref dfuStatus); while (dfuStatus.bState != STATE_DFU_IDLE) { STDFU_ClrStatus(ref hDevice); STDFU_GetStatus(ref hDevice, ref dfuStatus); } if (STDFU_NOERROR == (Result = STDFU_Dnload(ref hDevice, Command, 5, 0))) { STDFU_GetStatus(ref hDevice, ref dfuStatus); while (dfuStatus.bState != STATE_DFU_IDLE) { STDFU_ClrStatus(ref hDevice); STDFU_GetStatus(ref hDevice, ref dfuStatus); } } else { throw new Exception("STDFU_Dnload returned " Result.ToString("X8")); } } else { throw new Exception("STDFU_SelectCurrentConfiguration returned " Result.ToString("X8")); } } /// <summary> /// Write a block of data to the micro-controller /// </summary> /// <param name="hDevice">Handle to the USB connection to the micro-controller</param> /// <param name="Address">Address to write the data to</param> /// <param name="Data">Data for write</param> /// <param name="BlockNumber">Data block number</param> private void WriteBlock(IntPtr hDevice, UInt32 Address, byte[] Data, UInt32 BlockNumber) { byte[] Command = new byte[5]; DFU_Status dfuStatus = new DFU_Status(); if (Data.Length > MaxWriteBlockSize) { throw new Exception("Block size too big (" Data.Length.ToString() ")"); } if (0 == BlockNumber) { SetAddressPointer(hDevice, Address); } STDFU_GetStatus(ref hDevice, ref dfuStatus); while (dfuStatus.bState != STATE_DFU_IDLE) { STDFU_ClrStatus(ref hDevice); STDFU_GetStatus(ref hDevice, ref dfuStatus); } STDFU_Dnload(ref hDevice, Data, (UInt32)Data.Length, (UInt16)(BlockNumber 2)); STDFU_GetStatus(ref hDevice, ref dfuStatus); while (dfuStatus.bState != STATE_DFU_IDLE) { STDFU_ClrStatus(ref hDevice); STDFU_GetStatus(ref hDevice, ref dfuStatus); } } /// <summary> /// Set the address pointer used in the DFU module within the micro-controller /// </summary> /// <param name="hDevice">Handle to the USB connection to the micro-controller</param> /// <param name="Address">Value to set address pointer to</param> private void SetAddressPointer(IntPtr hDevice, UInt32 Address) { byte[] Command = new byte[5]; DFU_Status dfuStatus = new DFU_Status(); STDFU_GetStatus(ref hDevice, ref dfuStatus); while (dfuStatus.bState != STATE_DFU_IDLE) { STDFU_ClrStatus(ref hDevice); STDFU_GetStatus(ref hDevice, ref dfuStatus); } Command[0] = 0x21; Command[1] = (byte)(Address & 0xFF); Command[2] = (byte)((Address >> 8) & 0xFF); Command[3] = (byte)((Address >> 16) & 0xFF); Command[4] = (byte)((Address >> 24) & 0xFF); STDFU_Dnload(ref hDevice, Command, 5, 0); STDFU_GetStatus(ref hDevice, ref dfuStatus); while (dfuStatus.bState != STATE_DFU_IDLE) { STDFU_ClrStatus(ref hDevice); STDFU_GetStatus(ref hDevice, ref dfuStatus); } } /// <summary> /// Disconnect the DFU mode USB connection and request the micro-controller to jump to a given address /// Used after firmware update has completed to run the new firmware. /// </summary> /// <param name="hDevice">Handle to the USB connection to the micro-controller</param> /// <param name="Address">Address to jump to</param> private void Detach(IntPtr hDevice, UInt32 Address) { byte[] Command = new byte[5]; DFU_Status dfuStatus = new DFU_Status(); STDFU_GetStatus(ref hDevice, ref dfuStatus); while (dfuStatus.bState != STATE_DFU_IDLE) { STDFU_ClrStatus(ref hDevice); STDFU_GetStatus(ref hDevice, ref dfuStatus); } Command[0] = 0x21; Command[1] = (byte)(Address & 0xFF); Command[2] = (byte)((Address >> 8) & 0xFF); Command[3] = (byte)((Address >> 16) & 0xFF); Command[4] = (byte)((Address >> 24) & 0xFF); // Set the command pointer to the new application base address STDFU_Dnload(ref hDevice, Command, 5, 0); STDFU_GetStatus(ref hDevice, ref dfuStatus); while (dfuStatus.bState != STATE_DFU_IDLE) { STDFU_ClrStatus(ref hDevice); STDFU_GetStatus(ref hDevice, ref dfuStatus); } // Issue the DFU detach command STDFU_Dnload(ref hDevice, Command, 0, 0); STDFU_GetStatus(ref hDevice, ref dfuStatus); STDFU_ClrStatus(ref hDevice); STDFU_GetStatus(ref hDevice, ref dfuStatus); } /// <summary> /// Create a list of the programmable sectors within the micro-controller, based on the string(s) which we read from the device /// </summary> /// <param name="hDevice">Handle to the USB connection to the micro-controller</param> /// <returns>List of sector classes</returns> private List<MappingSector> CreateMappingFromDevice(IntPtr hDevice) { List<MappingSector> Sectors = new List<MappingSector>(); UInt32 Result = 0; UInt32 InterfaceIndex = 0; UInt32 NumberOfAlternates = 0; DFU_FunctionalDescriptor dfuDescriptor = new DFU_FunctionalDescriptor(); USB_InterfaceDescriptor usbDescriptor = new USB_InterfaceDescriptor(); uint i = 0; IntPtr StringBuffer = Marshal.AllocHGlobal(512); String MapDesc; if (STDFU_NOERROR == (Result = STDFU_GetDFUDescriptor(ref hDevice, ref InterfaceIndex, ref NumberOfAlternates, ref dfuDescriptor))) { // Loop thru Internal FLASH, Option bytes, OTP and Device Feature for (i = 0; i < NumberOfAlternates; i ) { if (STDFU_NOERROR == (Result = STDFU_GetInterfaceDescriptor(ref hDevice, 0, InterfaceIndex, i, ref usbDescriptor))) { if (0 == usbDescriptor.iInterface) { throw new Exception("STDFU_GetInterfaceDescriptor bad value in iInterface"); } if (STDFU_NOERROR == (Result = STDFU_GetStringDescriptor(ref hDevice, usbDescriptor.iInterface, StringBuffer, 512))) { // ByteArray = Marshal.ReadByte( UInt32 StartAddress; UInt16 NumberOfSectors = 0; UInt32 SectorSize = 0; UInt16 j = 0; MappingSector.SectorType SType = MappingSector.SectorType.Other; String SectorName; String SectorDescription; String SectorN; MapDesc = Marshal.PtrToStringAnsi(StringBuffer); if ('@' != MapDesc[0]) { throw new Exception("STDFU_GetStringDescriptor bad value in MapDesc, i=" i.ToString()); } SectorName = MapDesc.Substring(1, MapDesc.IndexOf('/') - 1); SectorName = SectorName.TrimEnd(' '); if (SectorName.Equals("Internal Flash")) { SType = MappingSector.SectorType.InternalFLASH; } else if (SectorName.Equals("Option Bytes")) { SType = MappingSector.SectorType.OptionBytes; } else if (SectorName.Equals("OTP Memory")) { SType = MappingSector.SectorType.OTP; } else if (SectorName.Equals("Device Feature")) { SType = MappingSector.SectorType.DeviceFeature; } else { SType = MappingSector.SectorType.Other; } StartAddress = UInt32.Parse(MapDesc.Substring(MapDesc.IndexOf('/') 3, 8), System.Globalization.NumberStyles.HexNumber); SectorDescription = MapDesc; while (SectorDescription.IndexOf('*') >= 0) { SectorN = SectorDescription.Substring(SectorDescription.IndexOf('*') - 3, 3); if (char.IsDigit(SectorN[0])) { NumberOfSectors = UInt16.Parse(SectorN); } else { NumberOfSectors = UInt16.Parse(SectorN.Substring(1)); } if (SectorDescription.Substring(SectorDescription.IndexOf('*') 3, 1) == "K") { SectorSize = UInt16.Parse(SectorDescription.Substring(SectorDescription.IndexOf('*') 1, 2)); } else { SectorSize = UInt16.Parse(SectorDescription.Substring(SectorDescription.IndexOf('*') 1, 3)); } if ('k' == char.ToLower(SectorDescription[SectorDescription.IndexOf('*') 4])) { SectorSize *= 1024; } for (j = 0; j < NumberOfSectors; j ) { Sectors.Add(new MappingSector(SectorName, SType, StartAddress, SectorSize, j)); StartAddress = SectorSize; } SectorDescription = SectorDescription.Substring(SectorDescription.IndexOf('*') 1); } } else { break; } } else { throw new Exception("STDFU_GetInterfaceDescriptor returned " Result.ToString()); } } } else { throw new Exception("STDFU_GetDFUDescriptor returned " Result.ToString()); } return (Sectors); } #region CrcTable private UInt32[] CrcTable = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; #endregion /// <summary> /// Class to encapsulate information about a programmable sector of memory within the micro-controller /// </summary> public class MappingSector { public enum SectorType { InternalFLASH, OptionBytes, OTP, DeviceFeature, Other }; public SectorType Type; public String Name; public UInt32 dwStartAddress; public UInt32 dwSectorIndex; public UInt32 dwSectorSize; public MappingSector(String Name, SectorType SType, UInt32 StartAddress, UInt32 Size, UInt16 SectorIndex) { this.Name = Name; this.Type = SType; this.dwStartAddress = StartAddress; this.dwSectorSize = Size; this.dwSectorIndex = SectorIndex; } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct USB_DeviceDescriptor // Taken from usb100.h { public byte bLength; public byte bDescriptorType; public ushort bcdUSB; public byte bDeviceClass; public byte bDeviceSubClass; public byte bDeviceProtocol; public byte bMaxPacketSize0; public ushort idVendor; public ushort idProduct; public ushort bcdDevice; public byte iManufacturer; public byte iProduct; public byte iSerialNumber; public byte bNumConfigurations; }; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct DFU_FunctionalDescriptor { public byte bLength; public byte bDescriptorType; // Should be 0x21 public byte bmAttributes; public UInt16 wDetachTimeOut; public UInt16 wTransfertSize; public UInt16 bcdDFUVersion; }; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct DFU_Status { public byte bStatus; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] bwPollTimeout; public byte bState; public byte iString; }; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct USB_InterfaceDescriptor { public byte bLength; public byte bDescriptorType; public byte bInterfaceNumber; public byte bAlternateSetting; public byte bNumEndpoints; public byte bInterfaceClass; public byte bInterfaceSubClass; public byte bInterfaceProtocol; public byte iInterface; }; /// <summary> /// Open the DFU driver, get the handle /// </summary> /// <param name="szDevicePath">Device path string</param> /// <param name="hDevice">Device handle, populated by this call</param> /// <returns>STDFU_NOERROR if successful, else error codes</returns> [DllImport("STDFU.dll", EntryPoint = "STDFU_Open", CharSet = CharSet.Ansi)] public static extern UInt32 STDFU_Open([MarshalAs(UnmanagedType.LPStr)]String szDevicePath, out IntPtr hDevice); [DllImport("STDFU.dll", EntryPoint = "STDFU_SelectCurrentConfiguration", CharSet = CharSet.Ansi)] public static extern UInt32 STDFU_SelectCurrentConfiguration(ref IntPtr hDevice, UInt32 ConfigIndex, UInt32 InterfaceIndex, UInt32 AlternateSetIndex ); [DllImport("STDFU.dll", EntryPoint = "STDFU_GetDeviceDescriptor", CharSet = CharSet.Auto)] public static extern UInt32 STDFU_GetDeviceDescriptor(ref IntPtr handle, ref USB_DeviceDescriptor descriptor); [DllImport("STDFU.dll", EntryPoint = "STDFU_GetDFUDescriptor", CharSet = CharSet.Auto)] public static extern UInt32 STDFU_GetDFUDescriptor(ref IntPtr handle, ref uint DFUInterfaceNum, ref uint NBOfAlternates, ref DFU_FunctionalDescriptor dfuDescriptor); [DllImport("STDFU.dll", EntryPoint = "STDFU_GetInterfaceDescriptor", CharSet = CharSet.Auto)] public static extern UInt32 STDFU_GetInterfaceDescriptor(ref IntPtr handle, UInt32 ConfigIndex, UInt32 InterfaceIndex, UInt32 AlternateIndex, ref USB_InterfaceDescriptor usbDescriptor); /// <summary> /// Get a string descriptor from the DFU driver /// </summary> /// <param name="handle">Handle to DFU device</param> /// <param name="Index">Index of desired string, if this is not valid the function will return an error</param> /// <param name="StringBuffer">Buffer for the string to be copied to</param> /// <param name="BufferSize">Size of buffer</param> /// <returns>STDEVICE_NOERROR or error code</returns> [DllImport("STDFU.dll", EntryPoint = "STDFU_GetStringDescriptor", CharSet = CharSet.Auto)] public static extern UInt32 STDFU_GetStringDescriptor(ref IntPtr handle, UInt32 Index, IntPtr StringBuffer, UInt32 BufferSize); [DllImport("STDFU.dll", EntryPoint = "STDFU_Dnload", CharSet = CharSet.Ansi)] public static extern UInt32 STDFU_Dnload(ref IntPtr hDevice, [MarshalAs(UnmanagedType.LPArray)]byte[] pBuffer, UInt32 nBytes, UInt16 nBlocks); [DllImport("STDFU.dll", EntryPoint = "STDFU_Getstatus", CharSet = CharSet.Ansi)] public static extern UInt32 STDFU_GetStatus(ref IntPtr hDevice, ref DFU_Status dfuStatus); [DllImport("STDFU.dll", EntryPoint = "STDFU_Clrstatus", CharSet = CharSet.Ansi)] public static extern UInt32 STDFU_ClrStatus(ref IntPtr hDevice); } }
好例子网口号:伸出你的我的手 — 分享!
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明
网友评论
我要评论