diff --git a/README.md b/README.md index 7890d636..c238d7b7 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,11 @@ Is part of **nanoFramework** toolbox, along with other various tools that are re It makes use of several 3rd party tools: -- Espressif esptool. +- Espressif esptool You can find the esptool and licensing information on the repository [here](http://github.com/espressif/esptool). -- ST DfuSe USB. - You can find the source, licensing information and documentation [here](https://www.st.com/en/development-tools/stsw-stm32080.html). -- ST-LINK Utility. +- QMKDfuSe + Tool based on STM DfusSe tool. You can find the source, licensing information and documentation [here](https://github.com/qmk/qmk_dfuse). +- ST-LINK Utility You can find the source, licensing information and documentation [here](https://www.st.com/content/st_com/en/products/development-tools/software-development-tools/stm32-software-development-tools/stm32-programmers/stsw-link004.html). - Texas Instruments Uniflash You can find the Uniflash tool and licensing information [here](http://www.ti.com/tool/download/UNIFLASH). diff --git a/lib/stdfu/qmk-dfuse.exe b/lib/stdfu/qmk-dfuse.exe new file mode 100644 index 00000000..1b674b36 Binary files /dev/null and b/lib/stdfu/qmk-dfuse.exe differ diff --git a/lib/stdfu/x64/STDFU.dll b/lib/stdfu/x64/STDFU.dll deleted file mode 100644 index 6ef75b58..00000000 Binary files a/lib/stdfu/x64/STDFU.dll and /dev/null differ diff --git a/lib/stdfu/x64/STTubeDevice30.dll b/lib/stdfu/x64/STTubeDevice30.dll deleted file mode 100644 index 3a7945f8..00000000 Binary files a/lib/stdfu/x64/STTubeDevice30.dll and /dev/null differ diff --git a/lib/stdfu/x86/STDFU.dll b/lib/stdfu/x86/STDFU.dll deleted file mode 100644 index 90e78051..00000000 Binary files a/lib/stdfu/x86/STDFU.dll and /dev/null differ diff --git a/lib/stdfu/x86/STTubeDevice30.dll b/lib/stdfu/x86/STTubeDevice30.dll deleted file mode 100644 index deada9cf..00000000 Binary files a/lib/stdfu/x86/STTubeDevice30.dll and /dev/null differ diff --git a/nanoFirmwareFlasher/Exceptions/BadDfuProtocolVersionException.cs b/nanoFirmwareFlasher/Exceptions/BadDfuProtocolVersionException.cs deleted file mode 100644 index 8ac82275..00000000 --- a/nanoFirmwareFlasher/Exceptions/BadDfuProtocolVersionException.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Runtime.Serialization; - -namespace nanoFramework.Tools.FirmwareFlasher -{ - /// - /// The connected DFU device is running a non supported version of the DFU protocol. - /// - [Serializable] - internal class BadDfuProtocolVersionException : Exception - { - public ushort DfuVersion { get; } - - public BadDfuProtocolVersionException() - { - } - - public BadDfuProtocolVersionException(ushort bcdDFUVersion) - { - DfuVersion = bcdDFUVersion; - } - - public BadDfuProtocolVersionException(string message) : base(message) - { - } - - public BadDfuProtocolVersionException(string message, Exception innerException) : base(message, innerException) - { - } - - protected BadDfuProtocolVersionException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - } -} diff --git a/nanoFirmwareFlasher/Exceptions/CantReadDfuDescriptorException.cs b/nanoFirmwareFlasher/Exceptions/CantReadDfuDescriptorException.cs deleted file mode 100644 index d44032c3..00000000 --- a/nanoFirmwareFlasher/Exceptions/CantReadDfuDescriptorException.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Runtime.Serialization; - -namespace nanoFramework.Tools.FirmwareFlasher -{ - /// - /// Couldn't read the DFU descriptor of the connected DFU device. - /// - [Serializable] - internal class CantReadDfuDescriptorException : Exception - { - public uint ErrorCode { get; } - - public CantReadDfuDescriptorException(uint errorCode) - { - ErrorCode = errorCode; - } - - public CantReadDfuDescriptorException(uint errorCode, string message) : base(message) - { - } - - public CantReadDfuDescriptorException(uint errorCode, string message, Exception innerException) : base(message, innerException) - { - } - - protected CantReadDfuDescriptorException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - } -} diff --git a/nanoFirmwareFlasher/Exceptions/CantReadUsbDescriptorException.cs b/nanoFirmwareFlasher/Exceptions/CantReadUsbDescriptorException.cs deleted file mode 100644 index 611a8768..00000000 --- a/nanoFirmwareFlasher/Exceptions/CantReadUsbDescriptorException.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Runtime.Serialization; - -namespace nanoFramework.Tools.FirmwareFlasher -{ - /// - /// Couldn't read the USB descriptor of the DFU device. - /// - [Serializable] - internal class CantReadUsbDescriptorException : Exception - { - public uint ErrorCode { get; } - - public CantReadUsbDescriptorException(uint errorCode) - { - ErrorCode = errorCode; - } - - public CantReadUsbDescriptorException(uint errorCode, string message) : base(message) - { - } - - public CantReadUsbDescriptorException(uint errorCode, string message, Exception innerException) : base(message, innerException) - { - } - - protected CantReadUsbDescriptorException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - } -} diff --git a/nanoFirmwareFlasher/Exceptions/DfuFileDoesNotExistException.cs b/nanoFirmwareFlasher/Exceptions/DfuFileDoesNotExistException.cs index 1a55cd42..5303e701 100644 --- a/nanoFirmwareFlasher/Exceptions/DfuFileDoesNotExistException.cs +++ b/nanoFirmwareFlasher/Exceptions/DfuFileDoesNotExistException.cs @@ -1,4 +1,9 @@ -using System; +// +// Copyright (c) 2020 The nanoFramework project contributors +// See LICENSE file in the project root for full license information. +// + +using System; using System.Runtime.Serialization; namespace nanoFramework.Tools.FirmwareFlasher diff --git a/nanoFirmwareFlasher/Exceptions/DfuOperationFailedException.cs b/nanoFirmwareFlasher/Exceptions/DfuOperationFailedException.cs new file mode 100644 index 00000000..63be5676 --- /dev/null +++ b/nanoFirmwareFlasher/Exceptions/DfuOperationFailedException.cs @@ -0,0 +1,33 @@ +// +// Copyright (c) 2020 The nanoFramework project contributors +// See LICENSE file in the project root for full license information. +// + +using System; +using System.Runtime.Serialization; + +namespace nanoFramework.Tools.FirmwareFlasher +{ + /// + /// Verification of DFU write failed. + /// + [Serializable] + internal class DfuOperationFailedException : Exception + { + public DfuOperationFailedException() + { + } + + public DfuOperationFailedException(string message) : base(message) + { + } + + public DfuOperationFailedException(string message, Exception innerException) : base(message, innerException) + { + } + + protected DfuOperationFailedException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } +} diff --git a/nanoFirmwareFlasher/Exceptions/DfuVerificationFailedException.cs b/nanoFirmwareFlasher/Exceptions/DfuVerificationFailedException.cs deleted file mode 100644 index cd64efd0..00000000 --- a/nanoFirmwareFlasher/Exceptions/DfuVerificationFailedException.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Runtime.Serialization; - -namespace nanoFramework.Tools.FirmwareFlasher -{ - /// - /// Verification of DFU write failed. - /// - [Serializable] - internal class DfuVerificationFailedException : Exception - { - public DfuVerificationFailedException() - { - } - - public DfuVerificationFailedException(string message) : base(message) - { - } - - public DfuVerificationFailedException(string message, Exception innerException) : base(message, innerException) - { - } - - protected DfuVerificationFailedException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - } -} diff --git a/nanoFirmwareFlasher/ExitCodes.cs b/nanoFirmwareFlasher/ExitCodes.cs index a3032300..54e997c3 100644 --- a/nanoFirmwareFlasher/ExitCodes.cs +++ b/nanoFirmwareFlasher/ExitCodes.cs @@ -25,12 +25,6 @@ public enum ExitCodes : int [Display(Name = "No DFU device found. Make sure it's connected and has booted in DFU mode")] E1000 = 1000, - /// - /// Error with DFU file - /// - [Display(Name = "Error with DFU file")] - E1001 = 1001, - /// /// DFU file doesn't exist /// diff --git a/nanoFirmwareFlasher/Program.cs b/nanoFirmwareFlasher/Program.cs index 880ee003..c22bf78d 100644 --- a/nanoFirmwareFlasher/Program.cs +++ b/nanoFirmwareFlasher/Program.cs @@ -515,8 +515,8 @@ static async Task RunOptionsAndReturnExitCodeAsync(Options o) } catch (Exception ex) { - // exception with DFU file - _exitCode = ExitCodes.E1001; + // exception with DFU operation + _exitCode = ExitCodes.E1003; _extraMessage = ex.Message; } } diff --git a/nanoFirmwareFlasher/StDfu.cs b/nanoFirmwareFlasher/StDfu.cs deleted file mode 100644 index 87fec3dd..00000000 --- a/nanoFirmwareFlasher/StDfu.cs +++ /dev/null @@ -1,1178 +0,0 @@ -// -// Copyright (c) 2019 The nanoFramework project contributors -// See LICENSE file in the project root for full license information. -// - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Runtime.Serialization; -using System.Text; - -namespace nanoFramework.Tools.FirmwareFlasher -{ - internal class StDfu - { - #region DFU file structures - - // generic method to marshal a section of a byte array into a struct - static void StructFromBytes(ref T pstruct, byte[] abyBuff, int nOffset) - { - int nLen = Marshal.SizeOf(pstruct); - IntPtr pbyMarsh = Marshal.AllocHGlobal(nLen); - Marshal.Copy(abyBuff, nOffset, pbyMarsh, nLen); - pstruct = (T)Marshal.PtrToStructure(pbyMarsh, pstruct.GetType()); - Marshal.FreeHGlobal(pbyMarsh); - } - - // DFU file header - [StructLayout(LayoutKind.Sequential, Pack = 1)] - unsafe struct DfuHeader - { - // "DfuSe" - public fixed byte Signature[5]; - public byte Version; - // size of the sections from the header to the tail - public uint DfuImageSize; - // how many targets in the file - public byte TargetsCount; - } - - // DFU target header - [StructLayout(LayoutKind.Sequential, Pack = 1)] - unsafe struct DfuImageTarget - { - // "Target" - public fixed byte Signature[6]; - public byte AlternateSetting; - // flag that the target has a name - public uint IsNamed; - // target name, which is optional - public fixed byte TargetName[255]; - // size of the elements that follow the header - public uint TargetSize; - // how many elements in this target - public uint NumElements; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - unsafe struct DfuImageElement - { - // start address - public uint Address; - // size of the data block - public uint Size; - // data follow the Size field - } - - //this is always at the end of the file, so you can seek there and work backwards - [StructLayout(LayoutKind.Sequential, Pack = 1)] - unsafe struct DfuTail - { - public ushort Version; - public ushort Pid; - public ushort Vid; - // DFU version, seems to be fixed with 0x011A - public ushort DfuVersion; - // signature with DFU ASCII backwards: 'U'(55) 'F'(46) 'D'(44) - public fixed byte Signature[3]; - // tail length (16) - public byte Length; - // file CRC excluding the CRC - public uint Crc; - } - - #endregion - - #region DFU descriptors - - public class DfuFile - { - public ushort Vid = 0; - public ushort Pid = 0; - public ushort Version = 0; - public DfuTarget[] DfuTargets = null; - } - - public class DfuTarget - { - public string Name = null; - public DfuElement[] DfuElements = null; - } - - public class DfuElement - { - public uint Address = 0xffffffff; - public byte[] Data = null; - } - - #endregion - - public const uint STDFU_ERROR_OFFSET = 0x12340000; - - public const uint STDFU_NOERROR = STDFU_ERROR_OFFSET + 0x0; - public const uint STDFU_MEMORY = STDFU_ERROR_OFFSET + 0x1; - public const uint STDFU_BADPARAMETER = STDFU_ERROR_OFFSET + 0x2; - - public const uint STDFU_NOTIMPLEMENTED = STDFU_ERROR_OFFSET + 0x3; - public const uint STDFU_ENUMFINISHED = STDFU_ERROR_OFFSET + 0x4; - public const uint STDFU_OPENDRIVERERROR = STDFU_ERROR_OFFSET + 0x5; - - public const uint STDFU_ERRORDESCRIPTORBUILDING = STDFU_ERROR_OFFSET + 0x6; - public const uint STDFU_PIPECREATIONERROR = STDFU_ERROR_OFFSET + 0x7; - public const uint STDFU_PIPERESETERROR = STDFU_ERROR_OFFSET + 0x8; - public const uint STDFU_PIPEABORTERROR = STDFU_ERROR_OFFSET + 0x9; - public const uint STDFU_STRINGDESCRIPTORERROR = STDFU_ERROR_OFFSET + 0xA; - - public const uint STDFU_DRIVERISCLOSED = STDFU_ERROR_OFFSET + 0xB; - public const uint STDFU_VENDOR_RQ_PB = STDFU_ERROR_OFFSET + 0xC; - public const uint STDFU_ERRORWHILEREADING = STDFU_ERROR_OFFSET + 0xD; - public const uint STDFU_ERRORBEFOREREADING = STDFU_ERROR_OFFSET + 0xE; - public const uint STDFU_ERRORWHILEWRITING = STDFU_ERROR_OFFSET + 0xF; - public const uint STDFU_ERRORBEFOREWRITING = STDFU_ERROR_OFFSET + 0x10; - public const uint STDFU_DEVICERESETERROR = STDFU_ERROR_OFFSET + 0x11; - public const uint STDFU_CANTUSEUNPLUGEVENT = STDFU_ERROR_OFFSET + 0x12; - public const uint STDFU_INCORRECTBUFFERSIZE = STDFU_ERROR_OFFSET + 0x13; - public const uint STDFU_DESCRIPTORNOTFOUND = STDFU_ERROR_OFFSET + 0x14; - public const uint STDFU_PIPESARECLOSED = STDFU_ERROR_OFFSET + 0x15; - public const uint STDFU_PIPESAREOPEN = STDFU_ERROR_OFFSET + 0x16; - - public const uint STDFU_TIMEOUTWAITINGFORRESET = STDFU_ERROR_OFFSET + 0x17; - - public const uint STDFU_RQ_GET_DEVICE_DESCRIPTOR = 0x02000000; - public const uint STDFU_RQ_GET_DFU_DESCRIPTOR = 0x03000000; - public const uint STDFU_RQ_GET_STRING_DESCRIPTOR = 0x04000000; - public const uint STDFU_RQ_GET_NB_OF_CONFIGURATIONS = 0x05000000; - public const uint STDFU_RQ_GET_CONFIGURATION_DESCRIPTOR = 0x06000000; - public const uint STDFU_RQ_GET_NB_OF_INTERFACES = 0x07000000; - public const uint STDFU_RQ_GET_NB_OF_ALTERNATES = 0x08000000; - public const uint STDFU_RQ_GET_INTERFACE_DESCRIPTOR = 0x09000000; - public const uint STDFU_RQ_OPEN = 0x0A000000; - public const uint STDFU_RQ_CLOSE = 0x0B000000; - public const uint STDFU_RQ_DETACH = 0x0C000000; - public const uint STDFU_RQ_DOWNLOAD = 0x0D000000; - public const uint STDFU_RQ_UPLOAD = 0x0E000000; - public const uint STDFU_RQ_GET_STATUS = 0x0F000000; - public const uint STDFU_RQ_CLR_STATUS = 0x10000000; - public const uint STDFU_RQ_GET_STATE = 0x11000000; - public const uint STDFU_RQ_ABORT = 0x12000000; - public const uint STDFU_RQ_SELECT_ALTERNATE = 0x13000000; - public const uint STDFU_RQ_AWAITINGPNPUNPLUGEVENT = 0x14000000; - public const uint STDFU_RQ_AWAITINGPNPPLUGEVENT = 0x15000000; - public const uint STDFU_RQ_IDENTIFYINGDEVICE = 0x16000000; - - private const char SEPARATOR_ADDRESS = '/'; - private const char SEPARATOR_ADDRESS_ALIASED = '-'; - private const char SEPARATOR_BLOCKS = ','; - private const char SEPARATOR_NBSECTORS_SECTORSIZE = '*'; - - // DFU States - public const uint STATE_IDLE = 0x00; - public const uint STATE_DETACH = 0x01; - public const uint STATE_DFU_IDLE = 0x02; - public const uint STATE_DFU_DOWNLOAD_SYNC = 0x03; - public const uint STATE_DFU_DOWNLOAD_BUSY = 0x04; - public const uint STATE_DFU_DOWNLOAD_IDLE = 0x05; - public const uint STATE_DFU_MANIFEST_SYNC = 0x06; - public const uint STATE_DFU_MANIFEST = 0x07; - public const uint STATE_DFU_MANIFEST_WAIT_RESET = 0x08; - public const uint STATE_DFU_UPLOAD_IDLE = 0x09; - public const uint STATE_DFU_ERROR = 0x0A; - - public const uint STATE_DFU_UPLOAD_SYNC = 0x91; - public const uint STATE_DFU_UPLOAD_BUSY = 0x92; - - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] - public struct UsbInterfaceDescriptor - { - 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; - }; - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] - public struct DfuFunctionalDescriptor - { - public byte bLength; - public byte bDescriptorType; - public byte bmAttributes; - public ushort wDetachTimeOut; - public ushort wTransfertSize; - public ushort bcdDFUVersion; - }; - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] - public struct DfuStatus - { - 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 UsbDeviceDescriptor - { - 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; - }; - - // from MAPPINGSECTOR - public class MappingSector - { - public enum SectorType - { - InternalFLASH, - OptionBytes, - OTP, - DeviceFeature, - Other - }; - - public uint StartAddress; - public uint SectorIndex; - public uint SectorSize; - public SectorType Type; - public string Name; - - public MappingSector(string name, SectorType sectorType, uint startAddress, uint size, uint sectorIndex) - { - Name = name; - Type = sectorType; - StartAddress = startAddress; - SectorSize = size; - SectorIndex = sectorIndex; - } - } - - #region imports from STDFU.dll - - // export from dumpbin - // 1 0 000014A0 STDFU_Abort - // 2 1 00001030 STDFU_Close - // 3 2 000013F0 STDFU_Clrstatus - // 4 3 00001210 STDFU_Detach - // 5 4 00001290 STDFU_Dnload - // 6 5 000010B0 STDFU_GetConfigurationDescriptor - // 7 6 00001130 STDFU_GetDFUDescriptor - // 8 7 00001050 STDFU_GetDeviceDescriptor - // 9 8 00001110 STDFU_GetInterfaceDescriptor - //10 9 000010F0 STDFU_GetNbOfAlternates - //11 A 00001090 STDFU_GetNbOfConfigurations - //12 B 000010D0 STDFU_GetNbOfInterfaces - //13 C 00001070 STDFU_GetStringDescriptor - //14 D 00001440 STDFU_Getstate - //15 E 00001360 STDFU_Getstatus - //16 F 00001010 STDFU_Open - //17 10 000011F0 STDFU_SelectCurrentConfiguration - //18 11 000012F0 STDFU_Upload - - - [DllImport(@"stdfu\STDFU.dll", EntryPoint = "STDFU_GetInterfaceDescriptor", CharSet = CharSet.Ansi)] - internal static extern uint STDFU_GetInterfaceDescriptor( - ref IntPtr handle, - uint nConfigIdx, - uint nInterfaceIdx, - uint nAltSetIdx, - ref UsbInterfaceDescriptor pDesc); - - - [DllImport(@"stdfu\STDFU.dll", EntryPoint = "STDFU_SelectCurrentConfiguration", CharSet = CharSet.Ansi)] - private static extern uint STDFU_SelectCurrentConfiguration( - ref IntPtr hDevice, - uint ConfigIndex, - uint InterfaceIndex, - uint AlternateSetIndex); - - - [DllImport(@"stdfu\STDFU.dll", EntryPoint = "STDFU_GetDFUDescriptor", CharSet = CharSet.Ansi)] - internal static extern uint STDFU_GetDFUDescriptor( - ref IntPtr handle, - ref uint DFUInterfaceNum, - ref uint NBOfAlternates, - ref DfuFunctionalDescriptor dfuDescriptor); - - [DllImport(@"stdfu\STDFU.dll", EntryPoint = "STDFU_GetDeviceDescriptor", CharSet = CharSet.Ansi)] - internal static extern uint STDFU_GetDeviceDescriptor( - ref IntPtr handle, - ref UsbDeviceDescriptor descriptor); - - [DllImport(@"stdfu\STDFU.dll", EntryPoint = "STDFU_GetStringDescriptor", CharSet = CharSet.Ansi)] - internal static extern uint STDFU_GetStringDescriptor( - ref IntPtr handle, - uint index, - IntPtr stringBuffer, - uint stringLength); - - [DllImport(@"stdfu\STDFU.dll", EntryPoint = "STDFU_Dnload", CharSet = CharSet.Ansi)] - internal static extern uint STDFU_Dnload( - ref IntPtr hDevice, - [MarshalAs(UnmanagedType.LPArray)]byte[] pBuffer, - uint nBytes, - ushort nBlocks); - - [DllImport(@"stdfu\STDFU.dll", EntryPoint = "STDFU_Getstatus", CharSet = CharSet.Ansi)] - internal static extern uint STDFU_GetStatus( - ref IntPtr hDevice, - ref DfuStatus dfuStatus); - - [DllImport(@"stdfu\STDFU.dll", EntryPoint = "STDFU_Clrstatus", CharSet = CharSet.Ansi)] - internal static extern uint STDFU_ClrStatus(ref IntPtr hDevice); - - [DllImport(@"stdfu\STDFU.dll", EntryPoint = "STDFU_Open", CharSet = CharSet.Ansi)] - internal static extern uint STDFU_Open( - [MarshalAs(UnmanagedType.LPStr)]string szDevicePath, - out IntPtr hDevice); - - [DllImport(@"stdfu\STDFU.dll", EntryPoint = "STDFU_Upload", CharSet = CharSet.Ansi)] - internal static extern uint STDFU_Upload( - ref IntPtr hDevice, - [MarshalAs(UnmanagedType.LPArray)]byte[] pBuffer, - uint nBytes, - ushort nBlocks); - - - - #endregion - - internal static List CreateMappingFromDevice( - IntPtr hDevice, - uint alternates, - DfuFunctionalDescriptor dfuDescriptor) - { - List sectorMap = new List((int)alternates); - - uint returnValue; - uint interfaceIndex = 0; - IntPtr stringBuffer = Marshal.AllocHGlobal(512); - - UsbInterfaceDescriptor usbInterfaceDescriptor = new UsbInterfaceDescriptor(); - - // Loop through Internal FLASH, Option bytes, OTP and Device Feature - for (uint i = 0; i < alternates; i++) - { - uint sectorIndex = 0; - - returnValue = STDFU_GetInterfaceDescriptor(ref hDevice, 0, interfaceIndex, i, ref usbInterfaceDescriptor); - - if (returnValue != STDFU_NOERROR) - { - throw new ErrorGettingInterfaceDescriptorException(); - } - - // sanity check - if (usbInterfaceDescriptor.iInterface == 0) - { - throw new ErrorGettingInterfaceDescriptorException(); - } - - returnValue = STDFU_GetStringDescriptor(ref hDevice, usbInterfaceDescriptor.iInterface, stringBuffer, 512); - if (returnValue != STDFU_NOERROR) - { - throw new ErrorGettingStringDescriptorException(); - } - - if (returnValue == STDFU_NOERROR) - { - ushort numberOfSectors = 0; - MappingSector.SectorType type; - - var rawSectorDescription = Marshal.PtrToStringAnsi(stringBuffer); - - // sanity check - if (rawSectorDescription[0] != '@') - { - throw new WrongOrInvalidStringDescriptorException(); - } - - var sectorName = rawSectorDescription.Substring(1, rawSectorDescription.IndexOf('/') - 1); - sectorName = sectorName.TrimEnd(' '); - - if (sectorName.Equals("Internal Flash")) - { - type = MappingSector.SectorType.InternalFLASH; - } - else if (sectorName.Equals("Option Bytes")) - { - type = MappingSector.SectorType.OptionBytes; - } - else if (sectorName.Equals("OTP Memory")) - { - type = MappingSector.SectorType.OTP; - } - else if (sectorName.Equals("Device Feature")) - { - type = MappingSector.SectorType.DeviceFeature; - } - else - { - type = MappingSector.SectorType.Other; - } - - var startAddress = uint.Parse(rawSectorDescription.Substring(rawSectorDescription.IndexOf(SEPARATOR_ADDRESS) + 3, 8), System.Globalization.NumberStyles.HexNumber); - - var sectorDescription = rawSectorDescription; - - while (sectorDescription.IndexOf(SEPARATOR_NBSECTORS_SECTORSIZE) >= 0) - { - var sectorN = sectorDescription.Substring(sectorDescription.IndexOf(SEPARATOR_NBSECTORS_SECTORSIZE) - 3, 3); - if (char.IsDigit(sectorN[0])) - { - numberOfSectors = ushort.Parse(sectorN); - } - else - { - numberOfSectors = ushort.Parse(sectorN.Substring(1)); - } - - var sectorSize = ushort.Parse(sectorDescription.Substring(sectorDescription.IndexOf(SEPARATOR_NBSECTORS_SECTORSIZE) + 1, 3)); - if (sectorDescription[sectorDescription.IndexOf(SEPARATOR_NBSECTORS_SECTORSIZE) + 4] == 'K') - { - sectorSize *= 1024; - } - else if (sectorDescription[sectorDescription.IndexOf(SEPARATOR_NBSECTORS_SECTORSIZE) + 4] == 'M') - { - sectorSize *= 1024; - } - - for (sectorIndex = 0; sectorIndex < numberOfSectors; sectorIndex++) - { - sectorMap.Add(new MappingSector(sectorName, type, startAddress, sectorSize, sectorIndex)); - startAddress += sectorSize; - } - - sectorDescription = sectorDescription.Substring(sectorDescription.IndexOf(SEPARATOR_NBSECTORS_SECTORSIZE) + 1); - } - } - else - { - break; - } - } - - return sectorMap; - } - - public bool ParseDfuFile( - string filepath, - out ushort vid, - out ushort pid, - out ushort version, - bool outputMessages = false) - { - byte[] fileData; - bool retval = true; - - try - { - // read content from DFU file - fileData = System.IO.File.ReadAllBytes(filepath); - - // check prefix - if (Encoding.UTF8.GetString(fileData, 0, 5) != "DfuSe") - { - throw new DfuFileException("File signature error"); - } - - // check version - if (fileData[5] != 1) - { - throw new DfuFileException("DFU file version must be 1"); - } - - // check 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 DfuFileException("File suffix error"); - } - - // check the CRC - var crc = BitConverter.ToUInt32(fileData, fileData.Length - 4); - if (crc != CalculateCRC(fileData)) - { - throw new DfuFileException("File CRC error"); - } - - // get VID, PID and version number from file - 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; - } - - internal static unsafe DfuFile LoadDfuFile( - string filePath, - VerbosityLevel verbosity) - { - byte[] fileData; - DfuFile dfuFile = new DfuFile(); - - if (verbosity >= VerbosityLevel.Normal) - { - Console.Write("Loading DFU file..."); - } - - try - { - ///////////////// - // read the file - fileData = System.IO.File.ReadAllBytes(filePath); - - // parse DFU header - DfuHeader dfuHeader = new DfuHeader(); - StructFromBytes(ref dfuHeader, fileData, 0); - - if (verbosity >= VerbosityLevel.Normal) - { - Console.WriteLine(" OK"); - } - - //////////////////// - // validate DFU file - - if (verbosity >= VerbosityLevel.Normal) - { - Console.Write("Validating DFU file..."); - } - - // sanity check on the prefix - if (dfuHeader.Signature[0] == (byte)'D' && - dfuHeader.Signature[1] == (byte)'f' && - dfuHeader.Signature[2] == (byte)'u' && - dfuHeader.Signature[3] == (byte)'S' && - dfuHeader.Signature[4] == (byte)'e' - ) - { - // we are good - } - else - { - throw new DfuFileException("Bad file header"); - } - - // check DFU file format version - if (dfuHeader.Version != 1) - { - throw new DfuFileException("DFU file version must be 1"); - } - - // check if there are any targets in the file - if (dfuHeader.TargetsCount > 0) - { - // we are good - } - else - { - throw new DfuFileException("File has no targets"); - } - - // DFU tail at the end of the file - DfuTail dfuTail = new DfuTail(); - StructFromBytes(ref dfuTail, fileData, fileData.Length - Marshal.SizeOf(dfuTail)); - - // check signature - if (dfuTail.Signature[0] == (byte)'U' && - dfuTail.Signature[1] == (byte)'F' && - dfuTail.Signature[2] == (byte)'D') - { - // we are good - } - else - { - throw new DfuFileException("Wrong file signature"); - } - - // check declared length and DFU version - if (16 != dfuTail.Length || - 0x011a != dfuTail.DfuVersion) - { - throw new DfuFileException("Wrong tail size or version"); - } - - // check CRC - if (dfuTail.Crc != CalculateCRC(fileData)) - { - throw new DfuFileException("Bad CRC"); - } - - // get VID, PID and version number - dfuFile.Vid = dfuTail.Vid; - dfuFile.Pid = dfuTail.Pid; - dfuFile.Version = dfuTail.Version; - - if (verbosity >= VerbosityLevel.Normal) - { - Console.WriteLine(" OK"); - } - - ///////////////////////// - // now parse the DFU file - - if (verbosity >= VerbosityLevel.Normal) - { - Console.Write("Parsing DFU file..."); - } - - // build targets array - dfuFile.DfuTargets = new DfuTarget[dfuHeader.TargetsCount]; - - // loop through each target, then loop through each image element - int targetCursor = Marshal.SizeOf(typeof(DfuHeader)); - - for (int targetIndex = 0; targetIndex < dfuFile.DfuTargets.Length; ++targetIndex) - { - dfuFile.DfuTargets[targetIndex] = new DfuTarget(); - DfuTarget dfuTarget = dfuFile.DfuTargets[targetIndex]; - - DfuImageTarget dfuImageTarget = new DfuImageTarget(); - - StructFromBytes(ref dfuImageTarget, fileData, targetCursor); - - // check signature - if (dfuImageTarget.Signature[0] == (byte)'T' && - dfuImageTarget.Signature[1] == (byte)'a' && - dfuImageTarget.Signature[2] == (byte)'r' && - dfuImageTarget.Signature[3] == (byte)'g' && - dfuImageTarget.Signature[4] == (byte)'e' && - dfuImageTarget.Signature[5] == (byte)'t') - { - // we are good - } - else - { - throw new DfuFileException($"Bad signature for target { targetIndex } @ position { targetCursor }"); - } - - // get target name, if set - if (dfuImageTarget.IsNamed > 0) - { - // this requires a bit of processing to read the string with the name - int nameLenght = 0; - byte* pRawBuffer = dfuImageTarget.TargetName; - - // move through buffer until a \0 (terminator) is found - // target name is 255 chars (max) - for (int i = 0; i < 255; i++) - { - if (*pRawBuffer++ == 0) - { - nameLenght = i; - break; - } - } - - // load byte array from pointer - byte[] nameBuffer = new byte[nameLenght]; - pRawBuffer = dfuImageTarget.TargetName; - for (int i = 0; i < nameLenght; i++) - { - nameBuffer[i] = *pRawBuffer++; - } - - dfuTarget.Name = Encoding.ASCII.GetString(nameBuffer, 0, nameLenght); - } - else - { - dfuTarget.Name = ""; - } - - if (dfuImageTarget.NumElements == 0) - { - throw new DfuFileException($"Target { targetIndex } has no elements"); - } - else - { - dfuTarget.DfuElements = new DfuElement[dfuImageTarget.NumElements]; - - int elementCursor = targetCursor + Marshal.SizeOf(typeof(DfuImageTarget)); - - for (int elementIndex = 0; elementIndex < dfuTarget.DfuElements.Length; ++elementIndex) - { - dfuTarget.DfuElements[elementIndex] = new DfuElement(); - DfuElement dfuElem = dfuTarget.DfuElements[elementIndex]; - - DfuImageElement dfuImageElement = new DfuImageElement(); - StructFromBytes(ref dfuImageElement, fileData, elementCursor); - - dfuElem.Address = dfuImageElement.Address; - dfuElem.Data = fileData.Skip(elementCursor + Marshal.SizeOf(typeof(DfuImageElement))).Take((int)dfuImageElement.Size).ToArray(); - elementCursor += Marshal.SizeOf(typeof(DfuImageElement)) + (int)dfuImageElement.Size; - } - } - - targetCursor += Marshal.SizeOf(typeof(DfuImageTarget)) + (int)dfuImageTarget.TargetSize; - } - - if (verbosity >= VerbosityLevel.Normal) - { - Console.WriteLine(" OK"); - } - - return dfuFile; - } - catch (Exception ex) - { - throw new DfuFileException("DFU file read failed. " + ex.Message); - } - } - - private static uint CalculateCRC(byte[] data) - { - uint crcValue = 0xFFFFFFFF; - int i; - - for (i = 0; i < data.Length - 4; i++) - { - crcValue = _crcTable[((crcValue) ^ (data[i])) & 0xff] ^ ((crcValue) >> 8); - } - - return crcValue; - } - - #region CrcTable - - private static readonly uint[] _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 - - internal static void PartialErase( - IntPtr hDevice, - uint startAddress, - uint size, - List mapSector, - bool outputMessages = false) - { - foreach (MappingSector s in mapSector) - { - if ((startAddress < s.StartAddress + s.SectorSize) && (startAddress + size > s.StartAddress)) - { - EraseSector(hDevice, s.StartAddress); - } - } - } - - private static void EraseSector( - IntPtr hDevice, - uint Address) - { - DfuStatus dfuStatus = new DfuStatus(); - - uint returnValue; - 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); - - returnValue = STDFU_SelectCurrentConfiguration(ref hDevice, 0, 0, 0); - if (returnValue == STDFU_NOERROR) - { - STDFU_GetStatus(ref hDevice, ref dfuStatus); - - while (dfuStatus.bState != STATE_DFU_IDLE) - { - STDFU_ClrStatus(ref hDevice); - STDFU_GetStatus(ref hDevice, ref dfuStatus); - } - - returnValue = STDFU_Dnload(ref hDevice, Command, 5, 0); - if (returnValue == STDFU_NOERROR) - { - STDFU_GetStatus(ref hDevice, ref dfuStatus); - - while (dfuStatus.bState != STATE_DFU_IDLE) - { - STDFU_ClrStatus(ref hDevice); - returnValue = STDFU_GetStatus(ref hDevice, ref dfuStatus); - } - - if (returnValue != STDFU_NOERROR) - { - throw new DownloadException("STDFU_Dnload returned " + returnValue.ToString("X8")); - } - } - else - { - throw new DownloadException("STDFU_Dnload returned " + returnValue.ToString("X8")); - } - } - else - { - throw new SelectConfigurationException("STDFU_SelectCurrentConfiguration returned " + returnValue.ToString("X8")); - } - } - - internal static void MassErase( - IntPtr hDevice, - bool outputMessages = false) - { - DfuStatus dfuStatus = new DfuStatus(); - - byte[] EraseCommand = { 0x41, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - - uint returnValue = STDFU_SelectCurrentConfiguration(ref hDevice, 0, 0, 1); - if (returnValue == STDFU_NOERROR) - { - STDFU_GetStatus(ref hDevice, ref dfuStatus); - - while (dfuStatus.bState != STATE_DFU_IDLE) - { - STDFU_ClrStatus(ref hDevice); - STDFU_GetStatus(ref hDevice, ref dfuStatus); - } - - returnValue = STDFU_Dnload(ref hDevice, EraseCommand, 1, 0); - if (returnValue == STDFU_NOERROR) - { - 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 DownloadException($"{returnValue.ToString("X8")}"); - } - } - else - { - throw new SelectConfigurationException($"{returnValue.ToString("X8")}"); - } - } - - internal static void WriteBlock( - IntPtr hDevice, - uint address, - byte[] data, - uint blockNumber) - { - uint returnValue; - DfuStatus dfuStatus = new DfuStatus(); - - if (0 == blockNumber) - { - SetAddressPointer(hDevice, address); - } - - returnValue = STDFU_GetStatus(ref hDevice, ref dfuStatus); - while (dfuStatus.bState != STATE_DFU_IDLE) - { - STDFU_ClrStatus(ref hDevice); - STDFU_GetStatus(ref hDevice, ref dfuStatus); - } - - returnValue = STDFU_Dnload(ref hDevice, data, (uint)data.Length, (ushort)(blockNumber + 2)); - - STDFU_GetStatus(ref hDevice, ref dfuStatus); - if (dfuStatus.bState != STATE_DFU_DOWNLOAD_BUSY) - { - throw new DownloadException("STDFU_Dnload returned " + returnValue.ToString("X8")); - } - - while (dfuStatus.bState != STATE_DFU_IDLE) - { - STDFU_ClrStatus(ref hDevice); - STDFU_GetStatus(ref hDevice, ref dfuStatus); - } - } - - internal static void ReadBlock( - IntPtr hDevice, - uint address, - byte[] data, - uint blockNumber) - { - DfuStatus dfuStatus = new DfuStatus(); - - 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_Upload(ref hDevice, data, (uint)data.Length, (ushort)(blockNumber + 2)); - - STDFU_GetStatus(ref hDevice, ref dfuStatus); - while (dfuStatus.bState != STATE_DFU_UPLOAD_IDLE) - { - STDFU_ClrStatus(ref hDevice); - STDFU_GetStatus(ref hDevice, ref dfuStatus); - } - } - - private static void SetAddressPointer( - IntPtr hDevice, - uint address) - { - byte[] command = new byte[5]; - DfuStatus dfuStatus = new DfuStatus(); - - 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); - } - } - - internal static void Detach(IntPtr hDevice, uint address) - { - DfuStatus dfuStatus = new DfuStatus(); - - STDFU_GetStatus(ref hDevice, ref dfuStatus); - while (dfuStatus.bState != STATE_DFU_IDLE) - { - STDFU_ClrStatus(ref hDevice); - STDFU_GetStatus(ref hDevice, ref dfuStatus); - } - - byte[] command = new byte[5]; - 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 command pointer to the launch 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); - } - - // send 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); - } - } - - #region Exceptions - - [Serializable] - internal class SelectConfigurationException : Exception - { - public SelectConfigurationException() - { - } - - public SelectConfigurationException(string message) : base(message) - { - } - - public SelectConfigurationException(string message, Exception innerException) : base(message, innerException) - { - } - - protected SelectConfigurationException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - } - - [Serializable] - internal class DownloadException : Exception - { - public DownloadException() - { - } - - public DownloadException(string message) : base(message) - { - } - - public DownloadException(string message, Exception innerException) : base(message, innerException) - { - } - - protected DownloadException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - } - - [Serializable] - internal class DfuFileException : Exception - { - public DfuFileException() - { - } - - public DfuFileException(string message) : base(message) - { - } - - public DfuFileException(string message, Exception innerException) : base(message, innerException) - { - } - - protected DfuFileException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - } - - [Serializable] - internal class WrongOrInvalidStringDescriptorException : Exception - { - public WrongOrInvalidStringDescriptorException() - { - } - - public WrongOrInvalidStringDescriptorException(string message) : base(message) - { - } - - public WrongOrInvalidStringDescriptorException(string message, Exception innerException) : base(message, innerException) - { - } - - protected WrongOrInvalidStringDescriptorException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - } - - [Serializable] - internal class ErrorGettingStringDescriptorException : Exception - { - public ErrorGettingStringDescriptorException() - { - } - - public ErrorGettingStringDescriptorException(string message) : base(message) - { - } - - public ErrorGettingStringDescriptorException(string message, Exception innerException) : base(message, innerException) - { - } - - protected ErrorGettingStringDescriptorException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - } - - [Serializable] - internal class ErrorGettingInterfaceDescriptorException : Exception - { - public ErrorGettingInterfaceDescriptorException() - { - } - - public ErrorGettingInterfaceDescriptorException(string message) : base(message) - { - } - - public ErrorGettingInterfaceDescriptorException(string message, Exception innerException) : base(message, innerException) - { - } - - protected ErrorGettingInterfaceDescriptorException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - } - - #endregion -} diff --git a/nanoFirmwareFlasher/StmDfuDevice.cs b/nanoFirmwareFlasher/StmDfuDevice.cs index 988f1b3a..2499a9e6 100644 --- a/nanoFirmwareFlasher/StmDfuDevice.cs +++ b/nanoFirmwareFlasher/StmDfuDevice.cs @@ -5,13 +5,14 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Management; +using System.Text; namespace nanoFramework.Tools.FirmwareFlasher { - // STSW-ST7009 // DFU Development Kit package (Device Firmware Upgrade). @@ -24,20 +25,6 @@ internal class StmDfuDevice private static Guid s_dfuGuid = new Guid("3FE809AB-FB91-4CB5-A643-69670D52366E"); private readonly string _deviceId; - private readonly IntPtr _hDevice = IntPtr.Zero; - private readonly StDfu.DfuFunctionalDescriptor _dfuDescriptor; - - private readonly uint _numberOfBlocks; - //private readonly uint _startAddress; - - private readonly List _sectorMap; - - private int targetIndex = 0; - - /// - /// Maximum size of a block of data for writing, this is set depending on the bootloader version - /// - private UInt16 _maxWriteBlockSize = 1024; /// /// Property with option for performing mass erase on the connected device. @@ -57,8 +44,6 @@ internal class StmDfuDevice // that follows the pattern: USB\\VID_0483&PID_DF11\\3380386D3134 public string DeviceId => _deviceId?.Split('\\', ' ')[2]; - public StDfu.UsbDeviceDescriptor _usbDescriptor { get; } - /// /// Option to output progress messages. /// Default is . @@ -71,8 +56,6 @@ internal class StmDfuDevice /// ID of the device to connect to. public StmDfuDevice(string deviceId = null) { - uint returnValue; - ManagementObjectCollection usbDevicesCollection; // build a managed object searcher to find USB devices with the ST DFU VID & PID along with the device description @@ -98,81 +81,12 @@ public StmDfuDevice(string deviceId = null) return; } - // store USB device ID - _deviceId = deviceId; - - // ST DFU is expecting a device path in the WQL pattern: + // ST DFU is expecting a device path with the WQL pattern: // "\\?\USB#VID_0483&PID_DF11#3380386D3134#{3FE809AB-FB91-4CB5-A643-69670D52366E}" // The GUID there is for the USB interface declared by DFU devices - string devicePath = @"\\?\" + deviceId.Replace(@"\", "#") + @"#{" + s_dfuGuid.ToString() + "}"; - - // open device - returnValue = StDfu.STDFU_Open(devicePath, out _hDevice); //this causes an error using x64 on .netCore 2.1 due to trying to access the Registry - if (returnValue != StDfu.STDFU_NOERROR) - { - throw new CantOpenDfuDeviceException(returnValue); - } - - // read USB descriptor - StDfu.UsbDeviceDescriptor usbDescriptor = new StDfu.UsbDeviceDescriptor(); - returnValue = StDfu.STDFU_GetDeviceDescriptor(ref _hDevice, ref usbDescriptor); - - if (returnValue == StDfu.STDFU_NOERROR) - { - _usbDescriptor = usbDescriptor; - - // check protocol version - // update max write block size - switch (_usbDescriptor.bcdDevice) - { - case 0x011A: - case 0x0200: - _maxWriteBlockSize = 1024; - break; - - case 0x02100: - case 0x2200: - _maxWriteBlockSize = 2048; - break; - - default: - throw new BadDfuProtocolVersionException(usbDescriptor.bcdDevice.ToString("X4")); - } - } - else - { - throw new CantReadUsbDescriptorException(returnValue); - } - - // read DFU descriptor - var dfuDescriptor = new StDfu.DfuFunctionalDescriptor(); - uint interfaceIndex = 0, alternates = 0; - returnValue = StDfu.STDFU_GetDFUDescriptor(ref _hDevice, ref interfaceIndex, ref alternates, ref dfuDescriptor); - - if (returnValue == StDfu.STDFU_NOERROR) - { - _dfuDescriptor = dfuDescriptor; - - // Enable and disable programming choice, bitManifestationTolerant - if (_dfuDescriptor.wTransfertSize == 8) - { - // Low Speed Devices - _numberOfBlocks = 8; - } - if (_dfuDescriptor.wTransfertSize == 128) - { - // Full Speed Devices - _numberOfBlocks = 128; - } - } - else - { - throw new CantReadDfuDescriptorException(returnValue); - } - - // create sector mapping for device - _sectorMap = StDfu.CreateMappingFromDevice(_hDevice, alternates, dfuDescriptor); + // store USB device ID + _deviceId = @"\\?\" + deviceId.Replace(@"\", "#") + @"#{" + s_dfuGuid.ToString() + "}"; } /// @@ -187,20 +101,28 @@ public void FlashDfuFile(string filePath) throw new DfuFileDoesNotExistException(); } - // load DFU file - - StDfu.DfuFile dfuFile = StDfu.LoadDfuFile(filePath, Verbosity); - // erase flash if (DoMassErase) { - if (Verbosity >= VerbosityLevel.Normal) - { - Console.Write("Mass erase device..."); - } + Console.WriteLine("WARNING: mass erase is not currently supported for DFU devices."); + } - StDfu.MassErase(_hDevice, Verbosity >= VerbosityLevel.Normal); + if (Verbosity >= VerbosityLevel.Normal) + { + Console.Write("Flashing device..."); + } + + // write flash, verify, reboot + // DFU is picky about the device path: requires it to be lower caps + if (!RunDfuCommandTool($" -d \"{filePath}\" -D {_deviceId.ToLowerInvariant()} -v -r ", out string messages)) + { + // something went wrong + throw new DfuOperationFailedException(); + } + // check for successfull message + if (messages.Contains("Successfully left DFU mode !")) + { if (Verbosity >= VerbosityLevel.Normal) { Console.WriteLine(" OK"); @@ -208,122 +130,106 @@ public void FlashDfuFile(string filePath) } else { - //erase only the sections we will program - if (Verbosity >= VerbosityLevel.Normal) - { - Console.Write("Erasing sectors to program..."); - } - - StDfu.DfuTarget dfuTarErase = dfuFile.DfuTargets[0]; + // something went wrong + throw new DfuOperationFailedException(); + } + } - for (int nIdxElem = 0; nIdxElem < dfuTarErase.DfuElements.Length; ++nIdxElem) - { - StDfu.DfuElement dfuElem = dfuTarErase.DfuElements[nIdxElem]; + /// + /// Search connected DFU devices. + /// + /// A collection of connected DFU devices. + public static List ListDfuDevices() + { + ManagementObjectCollection usbDevicesCollection; - StDfu.PartialErase(_hDevice, dfuElem.Address, (uint)dfuElem.Data.Length, _sectorMap, Verbosity >= VerbosityLevel.Detailed); - } + // build a managed object searcher to find USB devices with the ST DFU VID & PID along with the device description + using (var searcher = new ManagementObjectSearcher(@"SELECT * FROM Win32_PnPEntity WHERE DeviceID Like ""USB\\VID_0483&PID_DF11%"" AND Description Like ""STM Device in DFU Mode"" ")) + usbDevicesCollection = searcher.Get(); - if (Verbosity >= VerbosityLevel.Normal) - { - Console.WriteLine(" OK"); - } - } + // the split bellow is to get only the ID part of the USB ID + // that follows the pattern: USB\\VID_0483&PID_DF11\\3380386D3134 + return usbDevicesCollection.OfType().Select(mo => (mo.Properties["DeviceID"].Value as string).Split('\\', ' ')[2]).ToList(); + } - // flash the device - StDfu.DfuTarget dfuTarget = dfuFile.DfuTargets[targetIndex]; + /// + /// Run the esptool one time + /// + /// the esptool command (e.g. write_flash) incl. all arguments (if needed) + /// StandardOutput and StandardError messages that the esptool prints out + /// true if the esptool exit code was 0; false otherwise + private bool RunDfuCommandTool( + string commandWithArguments, + out string messages) + { + // create the process start info - if (Verbosity >= VerbosityLevel.Normal) + // prepare the process start of the esptool + Process dfuCommandTool = new Process(); + dfuCommandTool.StartInfo = new ProcessStartInfo(Path.Combine(Program.ExecutingPath, "stdfu", "qmk-dfuse.exe"), commandWithArguments) { - Console.Write("Flashing device..."); - } + WorkingDirectory = Path.Combine(Program.ExecutingPath, "stdfu"), + UseShellExecute = false, + RedirectStandardError = true, + RedirectStandardOutput = true + }; - // write flash - for (int elementIndex = 0; elementIndex < dfuTarget.DfuElements.Length; ++elementIndex) + // start esptool and wait for exit + if (dfuCommandTool.Start()) { - StDfu.DfuElement dfuElement = dfuTarget.DfuElements[elementIndex]; - - // Write the data in MaxWriteBlockSize blocks - for (uint blockNumber = 0; blockNumber <= (uint)dfuElement.Data.Length / _maxWriteBlockSize; blockNumber++) + // if no progress output needed wait unlimited time until comment exits + if (Verbosity < VerbosityLevel.Detailed) { - // grab data for write and store it into a 2048 byte buffer - byte[] buffer = dfuElement.Data.Skip((int)(_maxWriteBlockSize * blockNumber)).Take(_maxWriteBlockSize).ToArray(); - - StDfu.WriteBlock(_hDevice, dfuElement.Address, buffer, blockNumber); + dfuCommandTool.WaitForExit(); } } - - if (Verbosity >= VerbosityLevel.Normal) + else { - Console.WriteLine(" OK"); + throw new EspToolExecutionException("Error starting DfuSeCommand!"); } - if (Verbosity >= VerbosityLevel.Normal) - { - Console.Write("Verifying flash..."); - } + StringBuilder messageBuilder = new StringBuilder(); - // read back for confirmation - for (int elementIndex = 0; elementIndex < dfuTarget.DfuElements.Length; ++elementIndex) + // showing progress is a little bit tricky + if (Verbosity >= VerbosityLevel.Detailed) { - StDfu.DfuElement dfuElement = dfuTarget.DfuElements[elementIndex]; - - // read the data in MaxWriteBlockSize blocks - for (uint blockNumber = 0; blockNumber <= (uint)dfuElement.Data.Length / _maxWriteBlockSize; blockNumber++) + // loop until esptool exit + while (!dfuCommandTool.HasExited) { - byte[] readBuffer = new byte[_maxWriteBlockSize]; - StDfu.ReadBlock(_hDevice, dfuElement.Address, readBuffer, blockNumber); - - // get data for the current block - byte[] buffer = dfuElement.Data.Skip((int)(_maxWriteBlockSize * blockNumber)).Take(_maxWriteBlockSize).ToArray(); - - // exit condition has to be tied with the buffer length because the data for the last block - // can be shorter than the block max size - for(int index = 0; index < buffer.Length; index++) + // loop until there is no next char to read from standard output + while (true) { - if(readBuffer[index] != buffer[index]) + int next = dfuCommandTool.StandardOutput.Read(); + if (next != -1) + { + // append the char to the message buffer + char nextChar = (char)next; + messageBuilder.Append((char)next); + // print progress and set the cursor to the beginning of the line (\r) + Console.Write(nextChar); + } + else { - Console.WriteLine(""); - Console.WriteLine($"Error verifying flash write. Check failed for block address 0x{dfuElement.Address + blockNumber * _maxWriteBlockSize:X8}."); - throw new DfuVerificationFailedException(); + break; } } } - } - if (Verbosity >= VerbosityLevel.Normal) - { - Console.WriteLine(" OK"); + // collect any last messages + messageBuilder.AppendLine(dfuCommandTool.StandardOutput.ReadToEnd()); + messageBuilder.Append(dfuCommandTool.StandardError.ReadToEnd()); } - - if (Verbosity >= VerbosityLevel.Normal) + else { - Console.Write("Launching nanoBooter..."); + // collect all messages + messageBuilder.AppendLine(dfuCommandTool.StandardOutput.ReadToEnd()); + messageBuilder.Append(dfuCommandTool.StandardError.ReadToEnd()); } - // always reboot with nanoBooter - StDfu.Detach(_hDevice, 0x08000000); - - if (Verbosity >= VerbosityLevel.Normal) - { - Console.WriteLine(" OK"); - } - } + messages = messageBuilder.ToString(); - /// - /// Search connected DFU devices. - /// - /// A collection of connected DFU devices. - public static List ListDfuDevices() - { - ManagementObjectCollection usbDevicesCollection; - - // build a managed object searcher to find USB devices with the ST DFU VID & PID along with the device description - using (var searcher = new ManagementObjectSearcher(@"SELECT * FROM Win32_PnPEntity WHERE DeviceID Like ""USB\\VID_0483&PID_DF11%"" AND Description Like ""STM Device in DFU Mode"" ")) - usbDevicesCollection = searcher.Get(); - - // the split bellow is to get only the ID part of the USB ID - // that follows the pattern: USB\\VID_0483&PID_DF11\\3380386D3134 - return usbDevicesCollection.OfType().Select(mo => (mo.Properties["DeviceID"].Value as string).Split('\\', ' ')[2]).ToList(); + // true if exit code was 0 (success) + return dfuCommandTool.ExitCode == 0; } } } diff --git a/nanoFirmwareFlasher/nanoFirmwareFlasher.csproj b/nanoFirmwareFlasher/nanoFirmwareFlasher.csproj index 47a882ef..0ff36aff 100644 --- a/nanoFirmwareFlasher/nanoFirmwareFlasher.csproj +++ b/nanoFirmwareFlasher/nanoFirmwareFlasher.csproj @@ -53,7 +53,7 @@ - + true content\stdfu;contentFiles\stdfu