Skip to content

Commit 299582c

Browse files
committed
add DFU upload methods
1 parent 780a163 commit 299582c

File tree

4 files changed

+131
-22
lines changed

4 files changed

+131
-22
lines changed

DeviceProgramming.csproj

+17-7
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,21 @@
55
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
66
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
77
<Authors>Benedek Kupper</Authors>
8-
<Version>1.0.3</Version>
98
<Description>Standalone C# library for device firmware programming</Description>
10-
<Copyright>Copyright © Benedek Kupper 2021</Copyright>
11-
<PackageLicenseExpression></PackageLicenseExpression>
9+
<Copyright>Copyright © Benedek Kupper 2024</Copyright>
10+
<PackageLicenseExpression>MIT</PackageLicenseExpression>
1211
<PackageProjectUrl>https://github.com/IntergatedCircuits/DeviceProgramming</PackageProjectUrl>
1312
<RepositoryUrl>https://github.com/IntergatedCircuits/DeviceProgramming</RepositoryUrl>
1413
<PackageTags>Device Firmware Programming S19 IntelHEX DFU DFUSE</PackageTags>
15-
<AssemblyVersion>1.0.3</AssemblyVersion>
16-
<FileVersion>1.0.3</FileVersion>
17-
<PackageReleaseNotes>Change project to multitarget</PackageReleaseNotes>
14+
<PackageReleaseNotes>Add DFU Upload methods</PackageReleaseNotes>
1815
<Company>IntergatedCircuits</Company>
19-
<PackageLicenseFile>LICENSE</PackageLicenseFile>
16+
<PackageReadmeFile>README.md</PackageReadmeFile>
17+
<Version>1.1.0</Version>
18+
<FileVersion>1.1.0</FileVersion>
19+
<AssemblyVersion>1.1.0</AssemblyVersion>
20+
<EnablePackageValidation>true</EnablePackageValidation>
21+
<!-- <PackageValidationBaselineVersion>1.0.3</PackageValidationBaselineVersion> -->
22+
<EnableNETAnalyzers>True</EnableNETAnalyzers>
2023
</PropertyGroup>
2124

2225
<ItemGroup>
@@ -26,4 +29,11 @@
2629
</None>
2730
</ItemGroup>
2831

32+
<ItemGroup>
33+
<None Include="README.md">
34+
<Pack>True</Pack>
35+
<PackagePath>\</PackagePath>
36+
</None>
37+
</ItemGroup>
38+
2939
</Project>

Dfu/Device.cs

+108-10
Original file line numberDiff line numberDiff line change
@@ -180,12 +180,6 @@ public byte[] Upload(ushort blockNumber, uint length)
180180
ControlTransfer(Request.Upload, blockNumber, ref block);
181181
return block;
182182
}
183-
public void Upload(ushort blockNumber, ref byte[] data, int startIndex, int length)
184-
{
185-
byte[] block = new byte[length];
186-
ControlTransfer(Request.Upload, blockNumber, ref block);
187-
Array.Copy(block, 0, data, startIndex, length);
188-
}
189183

190184
public State GetState()
191185
{
@@ -450,6 +444,52 @@ private void VerifyState(Status status, State expectedState)
450444
}
451445
}
452446

447+
/// <summary>
448+
/// Upload a block of firmware from the reconfigured DFU device.
449+
/// </summary>
450+
/// <param name="length">The (maximum) size of memory to upload from the device.</param>
451+
/// <param name="blockNr">The starting block number of memory reading.</param>
452+
/// <returns>The memory dump from the device</returns>
453+
public byte[] UploadBlock(uint length, ushort blockNr = 0)
454+
{
455+
if (!DfuDescriptor.CanUpload)
456+
{
457+
throw new InvalidOperationException("The device doesn't support the upload operation.");
458+
}
459+
ResetToIdle();
460+
byte[] block = new byte[length];
461+
uint transferred = 0;
462+
while (transferred < length)
463+
{
464+
uint transferLen;
465+
if ((transferred + DfuDescriptor.TransferSize) > length)
466+
{
467+
transferLen = length - transferred;
468+
}
469+
else
470+
{
471+
transferLen = (uint)DfuDescriptor.TransferSize;
472+
}
473+
474+
var b = Upload(blockNr, transferLen);
475+
Array.Copy(b, 0, block, transferred, transferLen);
476+
transferred += (uint)b.Length;
477+
blockNr++;
478+
479+
if (b.Length < transferLen)
480+
{
481+
Array.Resize(ref block, (int)transferred);
482+
break;
483+
}
484+
}
485+
// if the last transfer was also TransferSize, add a 0 length transfer to terminate the upload
486+
if (GetState() == State.UploadIdle)
487+
{
488+
Upload(blockNr, 0);
489+
}
490+
return block;
491+
}
492+
453493
/// <summary>
454494
/// Download a contiguous memory segment to the idling DFU device. (DFU spec 1.1)
455495
/// </summary>
@@ -571,6 +611,16 @@ private Status SeErase(uint address)
571611
/(\d+)\*(\d+)([\x20KM]{1})([a-g]{1})(?:,(\d+)\*(\d+)([\x20KM]{1})([a-g]{1}))*$",
572612
RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace);
573613

614+
/// <summary>
615+
/// Parses the string description of a DFU alternate setting into a memory layout.
616+
/// </summary>
617+
/// <param name="altSel">DFU alternate setting index</param>
618+
/// <returns>The parsed memory layout</returns>
619+
private NamedLayout ParseLayout(byte altSel)
620+
{
621+
return ParseLayout(GetString(iAlternateSetting(altSel)));
622+
}
623+
574624
/// <summary>
575625
/// Parses the string description of a DFU alternate setting into a memory layout.
576626
/// </summary>
@@ -640,8 +690,7 @@ private void Download(Dictionary<byte, NamedMemory> sortedMemory)
640690
byte altSel = memoryWithAltSel.Key;
641691
var memory = memoryWithAltSel.Value;
642692

643-
string ml = GetString(iAlternateSetting(altSel));
644-
var layout = ParseLayout(ml);
693+
var layout = ParseLayout(altSel);
645694
int segNo = 0;
646695
int lastSeg = memory.Segments.Count - 1;
647696

@@ -776,8 +825,7 @@ private Dictionary<byte, NamedMemory> SortMemoryByAltSetting(RawMemory memory)
776825
// go through the available memories (each of which is an alternate setting)
777826
for (altSel = 0; altSel < NumberOfAlternateSettings; altSel++)
778827
{
779-
string ml = GetString(iAlternateSetting(altSel));
780-
var layout = ParseLayout(ml);
828+
var layout = ParseLayout(altSel);
781829
int segCount = 0;
782830
var newMem = new NamedMemory(layout.Name);
783831

@@ -814,6 +862,56 @@ private Dictionary<byte, NamedMemory> SortMemoryByAltSetting(RawMemory memory)
814862

815863
return sortedMemory;
816864
}
865+
866+
/// <summary>
867+
/// Upload part of the firmware image from the reconfigured DFU device.
868+
/// </summary>
869+
/// <param name="mblock">Memory block to read from</param>
870+
/// <returns>The memory segment provided by the device</returns>
871+
public Segment UploadBlock(Block mblock)
872+
{
873+
// perform a bunch of tests first
874+
if (DfuDescriptor.DfuVersion != Protocol.SeVersion)
875+
{
876+
throw new InvalidOperationException("The device doesn't support the DFUSE protocol.");
877+
}
878+
879+
byte altSel = 0;
880+
for (; altSel < NumberOfAlternateSettings; altSel++)
881+
{
882+
var layout = ParseLayout(altSel);
883+
if ((mblock.StartAddress >= layout.StartAddress) && (mblock.EndAddress <= layout.EndAddress))
884+
{
885+
foreach (var block in layout.Blocks)
886+
{
887+
if (block.Overlaps(mblock) && !block.Permissions.IsReadable())
888+
{
889+
throw new ArgumentOutOfRangeException("mblock", mblock, "The provided memory block is not readable on the target device.");
890+
}
891+
}
892+
break;
893+
}
894+
}
895+
if (altSel == NumberOfAlternateSettings)
896+
{
897+
throw new ArgumentOutOfRangeException("mblock", mblock, "The provided memory block is not available on the target device.");
898+
}
899+
900+
// select this memory layout for upload
901+
AlternateSetting = altSel;
902+
903+
// select start address
904+
ResetToIdle();
905+
906+
Status status = SeSetAddress((uint)mblock.StartAddress);
907+
VerifyState(status, State.DnloadIdle);
908+
909+
// perform memory dump
910+
// TODO: ensure block number doesn't overflow
911+
byte[] memory = UploadBlock((uint)mblock.Size, 2);
912+
913+
return new Segment(mblock.StartAddress, memory);
914+
}
817915
#endregion
818916
}
819917
}

Memory/Block.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ namespace DeviceProgramming.Memory
55
/// <summary>
66
/// This class represents a memory unit that can be read/written/erased (depending on permissions) as a whole.
77
/// </summary>
8-
public struct Block : IEquatable<Block>, IComparable<Block>
8+
public readonly struct Block : IEquatable<Block>, IComparable<Block>
99
{
1010
public readonly UInt64 StartAddress;
1111
public readonly UInt64 Size;
1212
public readonly Memory.Permissions Permissions;
13+
public UInt64 EndAddress { get { return StartAddress + Size - 1; } }
1314

14-
public Block(ulong startAddress, ulong size, Memory.Permissions permissions)
15+
public Block(ulong startAddress, ulong size, Memory.Permissions permissions = Permissions.Inaccessible)
1516
{
1617
StartAddress = startAddress;
1718
Size = size;

Memory/Layout.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ namespace DeviceProgramming.Memory
88
/// </summary>
99
public class Layout
1010
{
11-
public UInt64 StartAddress
12-
{
13-
get
11+
public UInt64 StartAddress
12+
{
13+
get
1414
{
1515
if (Blocks.Count == 0)
1616
{

0 commit comments

Comments
 (0)