cancel
Showing results for 
Search instead for 
Did you mean: 

Accessing ST Dfuse DLL with C#

jonas239955
Associate II
Posted on April 12, 2012 at 10:26

To integrate firmware update functionality into a custom c♯ application I start to use ST Dfuse dll from c♯. I managed to enumerate and identify the device (UM0392 - 3.1 and 3.2) but now get stucked  while trying to erase the device. Out of the manual:

DWORD OperationCode;

PDWORD pNbAlternates;

PMAPPING pMapping;

PHANDLE pHandle;

// Programming the operation contex

lstrcpy(Context.szDevLink, DFUName);

Context.DfuGUID=GUID_DFU;

Context.AppGUID=GUID_APP;

Context.Operation=OPERATION_ERASE;

Context.bDontSendFFTransfersForUpgrade= TRUE;

STDFUPRT_CreateMappingFromDevice((LPSTR)(LPCSTR)DFUName,&pMapping, &NbAlternates);

STDFUFILES_CreateImageFromMapping(pHandle, pMapping);

STDFUFILES_FilterImageForOperation(hImage, m_pMapping+TargetSel,

OPERATION_ERASE, FALSE);

Context.hImage=hImage;

if( STDFUPRT_LaunchOperation(&Context, &OperationCode) != STDFUPRT_NOERROR)

{

Printf(�Erase error�);

}

The call of STDFUPRT_LaunchOperation() does always return a STDFUPRT_BADPARAMETER error.

Is there a way to get some more information about this error? Which parameter is bad?

The first parameter in LaunchOperation() is a pointer to the struct DFUThreadContext. I rebuilt this struct in c♯ using the information given in UM0384.pdf chapter 4.3.4. My UM0384 is revision 1 - June 2007 - wonder if that user manual is still up-to-date?!?

I did not find UM0384 on the webpage (my copy is out of the package UM0412.zip). Does anyone have a newer one?

Thanks in advance for any help

#st-dfu #st-dfuse #dfuse
52 REPLIES 52
hansen
Associate II
Posted on April 14, 2012 at 10:15

Hi,

This happens because C++ and C# dont store variables the same way.Hence what you are trying to pass to the dll is not what its expecting.

What you can do is modify the source and make a standalone exe which you can call from your app and pass commands to it

marcoandarcia9
Associate II
Posted on May 23, 2012 at 17:49

Hi, 

I am trying as well to create my own c# application to load hexfiles and modify option bytes of my ST32. I am havin troubles getting started on this task. I am using the DLLs shown in (UM0384)(STDFU.dll,STDFUFiles.dll,STDFUPRT.dll)

 however I am having difficulties converting the typedef from c++ to c#. for example PUSB_INTERFACE_DESCRIPTOR, LPSTR

Thanks. 

Marco.

jonas239955
Associate II
Posted on June 01, 2012 at 16:54

Hi Marco,

For LPSTR I use the following type in .Net C#:

[MarshalAsAttribute(UnmanagedType.LPStr)] String szDevicePath

I haven't used PUSB_INTERFACE_DESCRIPTOR so far but in UM0384 on page 11 (3.3.2) the type is specified in detail.

Unfortunately I still do not know how to create type DFUThreadContext in .Net C#. My last try looks like this:

[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]

 

internal struct DFUThreadContext

 

{

 

  // Data that are driven by user

 

    [FieldOffset(0)]

 

    internal System.Guid DfuGUID;

 

    [FieldOffset(16)]

 

    internal System.Guid AppGUID;

 

    [FieldOffset(32)]

 

    internal Int16 Operation;

 

    [FieldOffset(34)]

 

    internal Int16 bDontSendFFTransfersForUpgrade;

 

    [FieldOffset(36)]

 

    internal Int32 hImage;

 

 

  // Data that are driven by user initially. But can be changed by STDFUPRT.dll

 

    [FieldOffset(40)]

 

    internal byte szDevLink;

 

 

  // Data that are driven by the Dll that can be read by user, but never written

 

    [FieldOffset(300)]

 

    internal Int32 dwTag;

 

    [FieldOffset(304)]

 

    internal byte Percent;

 

    [FieldOffset(305)]

 

    internal Int16 wTransferSize;

 

    [FieldOffset(307)]

 

    internal DFUSTATUS LastDFUStatus;

 

    [FieldOffset(313)]

 

    internal Int16 CurrentRequest;

 

    [FieldOffset(315)]

 

    internal Int16 CurrentNBlock;

 

    [FieldOffset(317)]

 

    internal Int16 CurrentLength;

 

    [FieldOffset(319)]

 

    internal Int32 CurrentAddress;

 

    [FieldOffset(323)]

 

    internal Int16 CurrentImageElement;

 

    [FieldOffset(325)]

 

    internal Int32 ErrorCode;

 

    [FieldOffset(329)]

 

    internal Int32 hDevice;

 

}

Still got the same badparameter-error. Any ideas??

Cheers

marcoandarcia9
Associate II
Posted on June 05, 2012 at 20:58

Hi, Jonas 

I already caught up with you, now I need to import the DFUThreadContext class in C#, to perform the download, upload, etc etc ... I have been doing some research and I think we must write a wrapper for that, we can't import  the c++ class into c#. However I was checking out the in UM0392 3.5 DFU basic requests and seems like it doesn't require that class. I wanted to know if you tried that already.

  Thanks. 

Marco.

marcoandarcia9
Associate II
Posted on June 05, 2012 at 21:04

for the CharSet why do you use Ansi? for all my structures I have been using CharSet.Auto, and they have been working fine so far, let me try using your structure, with CharSet.Auto.

marcoandarcia9
Associate II
Posted on June 06, 2012 at 16:24

Hi, Jonas 

I got it to work!!! 

Here is the structure I used and how I implemented it. 

 [StructLayout(LayoutKind.Sequential,CharSet=CharSet.Auto)] 

        public struct DFUThreadContext

        {

            public Guid DFUGUID;

            public Guid APPGUID;

            public int Operation;

            public Boolean bDontSendFFTransfersForUpgrade;

            public IntPtr hImage;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]

            public string szDevLink;

            public UInt32 dwTag;

            public byte percent;

            public UInt16 wTransferSize;

            DFUSTATUS LastDfuStatus;

            int current_status;

            uint CurrentNBlock;

            uint CurrentLenght;

            UInt32 CurrentAddress;

            uint CurrentImageElement;

            UInt32 ErrorCode;

            IntPtr hDevice;

        }

 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]

        public struct DFUSTATUS

        {

            byte bStatus;

            byte bwPollTimeout;

            byte bState;

            byte iString;

        }

  public void Erase()

        {

            try

            {

                UInt32 OperationCode;

                UInt32 pNbAlternates = 0;

                IntPtr phandle;

                Context.szDevLink = DetailData.DevicePath;

                Context.DFUGUID = GUID_DFU;

                Context.APPGUID = GUID_APP;

                Context.Operation = STDFUPRT.OPERATION_ERASE;

                Context.bDontSendFFTransfersForUpgrade = true;

                UInt32 error_code = STDFUPRT_CreateMappingFromDevice(Context.szDevLink, ref Mapping, ref pNbAlternates);

                Debug.WriteLine(error_code.ToString(''X''));

            }

            catch (Exception ex)

            {

                Debug.WriteLine(ex.ToString());

            }

        }

        

so far is working great, I went on the source code of the DfuSe and translated the structure, for me it was hard to build the structute for the threadcontext, out of the UM. if you go to  STDFUPrint.h in the source code you'll find the structure. 

jonas239955
Associate II
Posted on June 07, 2012 at 15:00

Hey marco,

did you get something usefull in ''Mapping'' (2. parameter)? I don't and therefore the next step STDFUFILES_CreateImageFromMapping() fails.

The manual says it should be a pointer to a pointer to a MAPPING struct. I used a pointer to a MAPPING struct, which is wrong. So the question is how to get a pointer to a pointer to a struct in .net c#?

I tried with unsafe code but received this compile error:

Cannot take the address of, get the size of, or declare a pointer to a managed type.

MAPPING needs to be an unmanaged type and that's really bad because my MAPPING looks like this:

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]

        public struct MAPPING

        {

            public byte nAlternate;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]

            public string Name;

            public UInt32 NbSectors;

            public MAPPINGSECTOR pSectors;

        }

As far as I know MAPPING is a managed type because there is a reference to MAPPINGSECTOR in it.

Is there any other way?

marcoandarcia9
Associate II
Posted on June 07, 2012 at 15:34

Hi, Jonas

that's a problem that I am encountering, for the name in MAPPING its returning a weird symbol however for STDFUFILES_CreateImageFromMap() does not fails. 

here are my signatures for the functions. 

[DllImport(''STDFU.dll'',EntryPoint=''STDFU_Open'',CharSet = CharSet.Ansi)]

        public static extern UInt32 STDFU_Open([MarshalAs(UnmanagedType.LPStr)]string devicePath, out IntPtr handle);

        [DllImport(''STDFU.dll'',EntryPoint=''STDFU_GetDeviceDescriptor'', CharSet=CharSet.Auto)]

        public static extern UInt32 STDFU_GetDeviceDescriptor(ref IntPtr handle, ref USB100.USB_DEVICE_DESCRIPTOR 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 USB100.DFU_FUNCTIONAL_DESCRIPTOR dfuDescriptor);

        [DllImport(''STDFUPRT.dll'', EntryPoint = ''STDFUPRT_CreateMappingFromDevice'', CharSet = CharSet.Auto)]

        //public static extern UInt32 STDFUPRT_CreateMappingFromDevice([MarshalAs(UnmanagedType.LPStr)]string DFUNAME, ref STDFUPRT.MAPPING Mapping, ref UInt32 pNbAlternates);

        public static extern UInt32 STDFUPRT_CreateMappingFromDevice([MarshalAs(UnmanagedType.LPStr)]string DFUNAME, ref STDFUPRT.MAPPING Mapping, ref UInt32 pNbAlternates);

        [DllImport(''STDFUPRT.dll'', EntryPoint = ''STDFUPRT_LaunchOperation'', CharSet = CharSet.Auto)]

        public static extern UInt32 STDFUPRT_LaunchOperation(STDFUPRT.DFUThreadContext Context, UInt32 Operation);

        

        [DllImport(''STDFUFILES.dll'', EntryPoint = ''STDFUFILES_CreateImageFromMapping'', CharSet = CharSet.Auto)]

        public static extern UInt32 STDFUFILES_CreateImageFromMapping(ref IntPtr handle, ref STDFUPRT.MAPPING pMapping);

        [DllImport(''STDFUFILES.dll'', EntryPoint = ''STDFUFILES_FilterImageForOperation'', CharSet = CharSet.Auto)]

        public static extern UInt32 STDFUFILES_FilterImageForOperation(IntPtr handle, ref STDFUPRT.MAPPING Mapping, UInt32 operation, bool bTruncatedLeadFFForUpgrade);

        [DllImport(''kernel32.dll'', CharSet = CharSet.Auto)]

        static extern IntPtr lstrcpy([Out]String lpstring1, string lpstring2);

  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]

        public struct MAPPING

        {

            public byte nAlternate;

            [MarshalAs(UnmanagedType.ByValTStr,SizeConst=260)]

            public string Name;

            public UInt32 NbSectors;

            public MAPPINGSECTOR pSectors;

           

        }

        [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]

        public struct MAPPINGSECTOR

        {

            public UInt32 dwStartAddress;

            public UInt32 dwAliasedAddress;

            public UInt32 dwSectorIndex;

            public UInt32 dwSectorSize;

            public byte bSectorType;

            public bool UseForOperation;

        }

    } 

 public void Erase()

        {

            try

            {

                UInt32 OperationCode = STDFUPRT.OPERATION_ERASE;

                UInt32 pNbAlternates = 0;

                IntPtr phandle = IntPtr.Zero;

                

                Context.szDevLink = DetailData.DevicePath;

                Context.DFUGUID = GUID_DFU;

                Context.APPGUID = GUID_APP;

                Context.Operation = STDFUPRT.OPERATION_ERASE;

                Context.bDontSendFFTransfersForUpgrade = true;

                

                UInt32 error_code = STDFUPRT_CreateMappingFromDevice(Context.szDevLink, ref Mapping, ref pNbAlternates);

                Debug.WriteLine(''Error_Code: 0x''+error_code.ToString(''X''));

                Debug.WriteLine(''Erase() pNbAlternates: '' + pNbAlternates+'' Mapping Name: ''+Mapping.Name+'', NbSectors: ''+Mapping.NbSectors);

                Debug.WriteLine(''Erase() SectorSize: '' + Mapping.pSectors.dwSectorSize+'', SectorType: ''+Mapping.pSectors.bSectorType);

                

                error_code = STDFUFILES_CreateImageFromMapping(ref phandle, ref Mapping);

                Debug.WriteLine(''Erase() error code: 0x''+error_code.ToString(''X''));

                Debug.WriteLine(''Erase() Name: '' + Mapping.Name.ToString()+'' Sectors:''+Mapping.pSectors.dwStartAddress+''  Sector Size: ''+Mapping.pSectors.dwSectorSize);

                error_code = STDFUFILES_FilterImageForOperation(phandle, ref Mapping, (uint)Context.Operation, false);

                

                Debug.WriteLine(''Erase(): error_code =  0x''+error_code.ToString(''X''));

                Debug.WriteLine(''Erase(): Start_Address: 0x''+Mapping.pSectors.dwStartAddress.ToString(''X'')+'', ''+Mapping.Name.ToString());

                Context.hImage = phandle;

                error_code = STDFUPRT_LaunchOperation(Context, OperationCode);

                Debug.WriteLine(''Erase(): LaunchOperation: 0x'' + error_code.ToString(''X''));

            }

            catch (Exception ex)

            {

                Debug.WriteLine(ex.ToString());

            }

I get for the Name parameter of the mapping struct a weird character, different every time I run my code. 

I get the error when I am trying to erase the device, and its about writing in protected memory one of my arrays is too short. 

hope this helps.  if you have any progress on your part please post, lol I'm already tired of trying to get this to work. 

GL.
marcoandarcia9
Associate II
Posted on June 07, 2012 at 20:10

Hi Jonas

I just pass the MAPPING structure by reference, on the function that should pass the pointer right? (I am actually learning while doing this). use the keyword ref  when  pass MAPPING as a pointer.

do you know what the alternates are? for the function STDFUPRT_CreateMappingFromDevice? in the guide there is no info about them, I just know that for my device turns to 4. I think this has something to do why is not working. 

Also, I think you are right there is something wring with my structure for MAPPING, I've been all day trying to make it fit, but it doesn't the Name parameter, is truncated some how I think, even though I marshal it to char[] I could see the 260 spaces. something really weird is going on. this API  is horrible!!!