实例介绍
【实例简介】
【实例截图】
【核心代码】
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小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明


网友评论
我要评论