diff --git a/NuGet.Config b/NuGet.Config
index ef0bacfd..b02a9811 100644
--- a/NuGet.Config
+++ b/NuGet.Config
@@ -2,6 +2,5 @@
-
diff --git a/README.md b/README.md
index 68c990b3..4f1c518f 100644
--- a/README.md
+++ b/README.md
@@ -158,6 +158,8 @@ To show the details of the ESP32 device connected to COM31.
nanoff --platform esp32 --serialport COM31 --devicedetails
```
+Optionally an extra parameter `--checkpsram` can be passed, which forces the detection of PSRAM availability.
+
### Deploy a managed application to an ESP32 target
To deploy a managed application to an ESP32_PSRAM_REV0 target connected to COM31.
@@ -447,6 +449,50 @@ nanoff --listtargets --platform stm32
If you use the `--listtargets` switch in conjunction with `--preview`, you'll get the list of available firmware packages that are available with experimental or major feature changes.
+## Deploy file to device storage
+
+Some devices like ESP32, Orgpal and few others have storage available. Files can be deployed in this storage. You have to use the `filedeployment` parameter pointing on a JSON file to deploy files while flashing the device:
+
+```console
+nanoff --target XIAO_ESP32C3 --update --masserase --serialport COM21 --filedeployment C:\path\deploy.json
+```
+
+The JSON an optional `SerialPort` in case the port to upload the files must be different than the one to flash the device or not specified in the main command line and a **mandatory** list of `Files` entries. Each entry must contains `DestinationFilePath`, the destination full path file name and `SourceFilePath` to deploy content, otherwise to delete the file, the full path with file name of the source file to be deployed:
+
+```json
+{
+ "serialport":"COM42",
+ "files": [
+ {
+ "DestinationFilePath": "I:\\TestFile.txt",
+ "SourceFilePath": "C:\\tmp\\NFApp3\\NFApp3\\TestFile.txt"
+ },
+ {
+ "DestinationFilePath": "I:\\NoneFile.txt"
+ },
+ {
+ "DestinationFilePath": "I:\\wilnotexist.txt",
+ "SourceFilePath": "C:\\WRONGPATH\\TestFile.txt"
+ }
+ ]
+}
+```
+
+In the case you just want to deploy the files without any other operation, you can just specify:
+
+```console
+nanoff --filedeployment C:\path\deploy.json
+```
+
+In that case, the `SerialPort` must be present in the JSON file.
+
+> [!Note]
+> If a file already exists in the storage, it will be replaced by the new one.
+>
+> If a file does not exist and is requested to be deleted, nothing will happen, a warning will be displayed.
+>
+> If a file can't be uploaded because of a problem, the deployment of the other files will continue and an error will be displayed.
+
## Clear cache location
If needed one can clear the local cache from the firmware packages that are stored there.
@@ -462,6 +508,12 @@ nanoff --clearcache
The exit codes can be checked in [this source file](https://github.com/nanoframework/nanoFirmwareFlasher/blob/main/nanoFirmwareFlasher.Library/ExitCodes.cs).
+## Telemetry
+
+This tool is using anonymous telemetry to help us improve the usage. You can opt out by setting up an environment variable `NANOFRAMEWORK_TELEMETRY_OPTOUT` to 1.
+
+The telemetry information is mainly related to the command line arguments, the firmware versions installed and any issue that can occurs during the code execution.
+
## Feedback and documentation
To provide feedback, report issues and finding out how to contribute please refer to the [Home repo](https://github.com/nanoframework/Home).
diff --git a/README.zh-cn.md b/README.zh-cn.md
index cbc5cb6c..a63ecd5e 100644
--- a/README.zh-cn.md
+++ b/README.zh-cn.md
@@ -138,6 +138,8 @@ nanoff --update --target KALUGA_1 --serialport COM31 --clrfile "C:\nf-interprete
nanoff --platform esp32 --serialport COM31 --devicedetails
```
+可选地,可以传递额外的参数 `--checkpsram`,它会强制检测PSRAM的可用性。
+
### 将托管应用程序部署到ESP32设备
将托管应用程序部署到连接到COM31的ESP32_PSRAM_REV0设备上。
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index fb887f42..046138d2 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -178,11 +178,17 @@ jobs:
vmImage: 'windows-latest'
variables:
- DOTNET_NOLOGO: true
- buildPlatform: 'x64'
- buildConfiguration: 'Release'
- solution: 'nanoFirmwareFlasher.sln'
- run_update_dependents: $[dependencies.Check_Build_Options.outputs['BuildOptions.RUN_UPDATE_DEPENDENTS']]
+ - group: sign-client-credentials
+ - name: DOTNET_NOLOGO
+ value: true
+ - name: buildPlatform
+ value: 'x64'
+ - name: buildConfiguration
+ value: 'Release'
+ - name: solution
+ value: 'nanoFirmwareFlasher.sln'
+ - name: run_update_dependents
+ value: $[dependencies.Check_Build_Options.outputs['BuildOptions.RUN_UPDATE_DEPENDENTS']]
steps:
@@ -203,6 +209,11 @@ jobs:
- task: Cache@2
displayName: Cache NuGet packages
+ condition: >-
+ and(
+ succeeded(),
+ eq(variables['UPDATE_DEPENDENTS'], 'false')
+ )
inputs:
key: 'nuget | "$(Agent.OS)" | **/packages.lock.json, !bin/**'
restoreKeys: |
@@ -321,6 +332,21 @@ jobs:
eq(variables['UPDATE_DEPENDENTS'], 'false')
)
+ # Replace the intrument key
+ - powershell: |
+ . ./common.ps1
+ $fileToReplace = "$(System.DefaultWorkingDirectory)/nanoFirmwareFlasher.Tool\appsettings.json"
+ $sourceString = "INSTRUMENT_KEY"
+ $instrumentKey = "$(InstrumentKey)"
+
+ Find-ReplaceInFile -filePath $fileToReplace -sourceString $sourceString -targetString $instrumentKey
+ displayName: Replace intrument key
+ condition: >-
+ and(
+ succeeded(),
+ eq(variables['UPDATE_DEPENDENTS'], 'false')
+ )
+
- task: CopyFiles@1
condition: >-
and(
@@ -336,7 +362,7 @@ jobs:
flattenFolders: true
- task: DotNetCoreCLI@2
- displayName: Install SignTool tool
+ displayName: Install Sign Client CLI
condition: >-
and(
succeeded(),
@@ -346,19 +372,21 @@ jobs:
inputs:
command: custom
custom: tool
- arguments: install --tool-path . SignClient
+ arguments: install --tool-path . sign --version 0.9.1-beta.23530.1
- pwsh: |
- .\SignClient "Sign" `
- --baseDirectory "$(Build.ArtifactStagingDirectory)" `
- --input "**/*.nupkg" `
- --config "$(Build.Repository.LocalPath)\config\SignClient.json" `
- --filelist "$(Build.Repository.LocalPath)\config\filelist.txt" `
- --user "$(SignClientUser)" `
- --secret '$(SignClientSecret)' `
- --name ".NET nanoFramework firmware flasher" `
+ .\sign code azure-key-vault `
+ "**/*.nupkg" `
+ --base-directory "$(Build.ArtifactStagingDirectory)" `
+ --file-list "$(Build.Repository.LocalPath)\config\filelist.txt" `
--description ".NET nanoFramework firmware flasher" `
- --descriptionUrl "https://github.com/$env:Build_Repository_Name"
+ --description-url "https://github.com/$env:Build_Repository_Name" `
+ --azure-key-vault-tenant-id "$(SignTenantId)" `
+ --azure-key-vault-client-id "$(SignClientId)" `
+ --azure-key-vault-client-secret "$(SignClientSecret)" `
+ --azure-key-vault-certificate "$(SignKeyVaultCertificate)" `
+ --azure-key-vault-url "$(SignKeyVaultUrl)" `
+ --timestamp-url http://timestamp.digicert.com
displayName: Sign packages
continueOnError: true
condition: >-
@@ -388,7 +416,7 @@ jobs:
eq(variables['System.PullRequest.PullRequestId'], ''),
eq(variables['UPDATE_DEPENDENTS'], 'false')
)
- displayName: Push nanoff NuGet package to NuGet
+ displayName: Push nanoff dotnet tool to NuGet
continueOnError: true
inputs:
command: push
@@ -406,7 +434,7 @@ jobs:
eq(variables['System.PullRequest.PullRequestId'], ''),
eq(variables['UPDATE_DEPENDENTS'], 'false')
)
- displayName: Push library NuGet package to NuGet
+ displayName: Push NuGet package with library to NuGet
continueOnError: true
inputs:
command: push
@@ -435,6 +463,7 @@ jobs:
action: create
isDraft: false
addChangeLog: true
+ changeLogType: issueBased
changeLogLabels: |
[
{ "label" : "Type: bug", "displayName" : "Bugs fixed", "state" : "closed" },
@@ -448,6 +477,7 @@ jobs:
- task: PowerShell@2
condition: >-
or(
+ eq(variables['System.PullRequest.PullRequestId'], ''),
eq(variables['UPDATE_DEPENDENTS'], 'true'),
eq(variables['run_update_dependents'], 'true')
)
diff --git a/azure-pipelines/update-dependents.ps1 b/azure-pipelines/update-dependents.ps1
index 399824d8..399db064 100644
--- a/azure-pipelines/update-dependents.ps1
+++ b/azure-pipelines/update-dependents.ps1
@@ -2,7 +2,7 @@
# compute authorization header in format "AUTHORIZATION: basic 'encoded token'"
# 'encoded token' is the Base64 of the string "nfbot:personal-token"
-$auth = "basic $([System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("nfbot:$env:GH_TOKEN"))))"
+$auth = "basic $([System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("nfbot:$env:GH_TOKEN")))"
# init/reset these
$commitMessage = ""
@@ -55,21 +55,21 @@ $commitMessage += "`n[version update]`n`n"
# better add this warning line
$commitMessage += "### :warning: This is an automated update. Merge only after all tests pass. :warning:`n"
-Write-Debug "Git branch"
-
-# create branch to perform updates
-git branch $newBranchName
-
-Write-Debug "Checkout branch"
-
-# checkout branch
-git checkout $newBranchName
-
# check if anything was changed
$repoStatus = "$(git status --short --porcelain)"
if ($repoStatus -ne "")
{
+ Write-Debug "Git branch"
+
+ # create branch to perform updates
+ git branch $newBranchName
+
+ Write-Debug "Checkout branch"
+
+ # checkout branch
+ git checkout $newBranchName
+
Write-Debug "Add changes"
# commit changes
@@ -114,5 +114,5 @@ if ($repoStatus -ne "")
}
else
{
- Write-Host "Nothing udpate at nanoFramework.Tools.FirmwareFlasher."
+ Write-Host "Nothing udpate at $repoName."
}
diff --git a/common.ps1 b/common.ps1
new file mode 100644
index 00000000..d1726636
--- /dev/null
+++ b/common.ps1
@@ -0,0 +1,62 @@
+
+# Common functions used by the other scripts
+
+function Check-DirectoryExists {
+ param (
+ [string]$rootDirectory
+ )
+
+ return Test-Path -Path $rootDirectory -PathType Container
+}
+
+function Find-ReplaceInFiles {
+ param (
+ [string]$rootDirectory,
+ [string]$sourceString,
+ [string]$targetString
+ )
+
+ Get-ChildItem -Recurse -File $rootDirectory | ForEach-Object {
+ $filePath = $_.FullName
+
+ Find-ReplaceInFile -filePath $filePath -sourceString $sourceString -targetString $targetString
+ }
+
+ Write-Host "String replacement completed."
+}
+
+function Find-ReplaceInFile {
+ param (
+ [string]$filePath,
+ [string]$sourceString,
+ [string]$targetString
+ )
+
+ # Get the original encoding of the file
+ $sr = New-Object System.IO.StreamReader($filePath, $true)
+ [char[]] $buffer = new-object char[] 3
+ $sr.Read($buffer, 0, 3)
+ $originalEncoding = $sr.CurrentEncoding
+ $sr.Close()
+
+ # Making it simple as we only want to preserve UTF8 encoding
+ if ( $originalEncoding.BodyName -eq "utf-8" ) {
+ $fileEncoding = "UTF8"
+ }
+ else {
+ $fileEncoding = "ASCII"
+ }
+
+ # Read the content of the file using the original encoding
+ $content = Get-Content -Path $filePath -Raw -Encoding $fileEncoding
+
+ # Perform the replacement
+ $newContent = $content -replace [regex]::Escape($sourceString), $targetString
+
+ if ($content -ne $newContent) {
+ Write-Host "Replacing in $filePath"
+
+ # Save the modified content back to the file using the original encoding
+ Set-Content -Path $filePath -Value $newContent -Encoding $fileEncoding
+ }
+}
\ No newline at end of file
diff --git a/lib/esp32bootloader/bootloader.bin b/lib/esp32bootloader/bootloader.bin
index 613a0f57..b1328019 100644
Binary files a/lib/esp32bootloader/bootloader.bin and b/lib/esp32bootloader/bootloader.bin differ
diff --git a/lib/esp32bootloader/partitions_16mb.bin b/lib/esp32bootloader/partitions_16mb.bin
deleted file mode 100644
index 5f23fc00..00000000
Binary files a/lib/esp32bootloader/partitions_16mb.bin and /dev/null differ
diff --git a/lib/esp32bootloader/partitions_2mb.bin b/lib/esp32bootloader/partitions_2mb.bin
index 7382396f..c8ef86f1 100644
Binary files a/lib/esp32bootloader/partitions_2mb.bin and b/lib/esp32bootloader/partitions_2mb.bin differ
diff --git a/lib/esp32bootloader/partitions_8mb.bin b/lib/esp32bootloader/partitions_8mb.bin
deleted file mode 100644
index 9d403e78..00000000
Binary files a/lib/esp32bootloader/partitions_8mb.bin and /dev/null differ
diff --git a/lib/esp32bootloader/test_startup.bin b/lib/esp32bootloader/test_startup.bin
index 2445e84e..03c9a8bf 100644
Binary files a/lib/esp32bootloader/test_startup.bin and b/lib/esp32bootloader/test_startup.bin differ
diff --git a/lib/esp32s2bootloader/bootloader.bin b/lib/esp32s2bootloader/bootloader.bin
index 26a22275..ff2e735a 100644
Binary files a/lib/esp32s2bootloader/bootloader.bin and b/lib/esp32s2bootloader/bootloader.bin differ
diff --git a/lib/esp32s2bootloader/partitions_16mb.bin b/lib/esp32s2bootloader/partitions_16mb.bin
deleted file mode 100644
index 5f23fc00..00000000
Binary files a/lib/esp32s2bootloader/partitions_16mb.bin and /dev/null differ
diff --git a/lib/esp32s2bootloader/partitions_8mb.bin b/lib/esp32s2bootloader/partitions_8mb.bin
deleted file mode 100644
index 9d403e78..00000000
Binary files a/lib/esp32s2bootloader/partitions_8mb.bin and /dev/null differ
diff --git a/lib/esp32s2bootloader/test_startup.bin b/lib/esp32s2bootloader/test_startup.bin
index 3bda5a03..8015bfa6 100644
Binary files a/lib/esp32s2bootloader/test_startup.bin and b/lib/esp32s2bootloader/test_startup.bin differ
diff --git a/lib/esp32s3bootloader/bootloader.bin b/lib/esp32s3bootloader/bootloader.bin
new file mode 100644
index 00000000..6ea9312d
Binary files /dev/null and b/lib/esp32s3bootloader/bootloader.bin differ
diff --git a/lib/esp32bootloader/partitions_4mb.bin b/lib/esp32s3bootloader/partitions_4mb.bin
similarity index 100%
rename from lib/esp32bootloader/partitions_4mb.bin
rename to lib/esp32s3bootloader/partitions_4mb.bin
diff --git a/lib/esp32s3bootloader/test_startup.bin b/lib/esp32s3bootloader/test_startup.bin
new file mode 100644
index 00000000..d58ec348
Binary files /dev/null and b/lib/esp32s3bootloader/test_startup.bin differ
diff --git a/lib/esptool/esptoolLinux/esptool b/lib/esptool/esptoolLinux/esptool
index d5351adf..3934775f 100644
Binary files a/lib/esptool/esptoolLinux/esptool and b/lib/esptool/esptoolLinux/esptool differ
diff --git a/lib/esptool/esptoolMac/esptool b/lib/esptool/esptoolMac/esptool
index f6493685..288c8a6d 100755
Binary files a/lib/esptool/esptoolMac/esptool and b/lib/esptool/esptoolMac/esptool differ
diff --git a/lib/esptool/esptoolWin/esptool.exe b/lib/esptool/esptoolWin/esptool.exe
index 3844beed..73bd4b55 100644
Binary files a/lib/esptool/esptoolWin/esptool.exe and b/lib/esptool/esptoolWin/esptool.exe differ
diff --git a/lib/jlink/JLink.exe b/lib/jlink/JLink.exe
index fce8f66a..52c8bc62 100644
Binary files a/lib/jlink/JLink.exe and b/lib/jlink/JLink.exe differ
diff --git a/lib/jlink/JLink_x64.dll b/lib/jlink/JLink_x64.dll
index 50f3565c..86dd9267 100644
Binary files a/lib/jlink/JLink_x64.dll and b/lib/jlink/JLink_x64.dll differ
diff --git a/lib/jlinkLinux/JLinkExe b/lib/jlinkLinux/JLinkExe
index 34ec205c..3193251e 100644
Binary files a/lib/jlinkLinux/JLinkExe and b/lib/jlinkLinux/JLinkExe differ
diff --git a/lib/jlinkMac/JLinkExe b/lib/jlinkMac/JLinkExe
index 9861ae0c..73d05920 100644
Binary files a/lib/jlinkMac/JLinkExe and b/lib/jlinkMac/JLinkExe differ
diff --git a/nanoFirmwareFlasher.Library/CC13x26x2Firmware.cs b/nanoFirmwareFlasher.Library/CC13x26x2Firmware.cs
index 6d2dd3a5..6ebb4039 100644
--- a/nanoFirmwareFlasher.Library/CC13x26x2Firmware.cs
+++ b/nanoFirmwareFlasher.Library/CC13x26x2Firmware.cs
@@ -3,9 +3,6 @@
// See LICENSE file in the project root for full license information.
//
-using System.IO;
-using System.Linq;
-
namespace nanoFramework.Tools.FirmwareFlasher
{
///
diff --git a/nanoFirmwareFlasher.Library/CC13x26x2Operations.cs b/nanoFirmwareFlasher.Library/CC13x26x2Operations.cs
index af200876..25166d09 100644
--- a/nanoFirmwareFlasher.Library/CC13x26x2Operations.cs
+++ b/nanoFirmwareFlasher.Library/CC13x26x2Operations.cs
@@ -7,7 +7,6 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
-using System.Linq;
namespace nanoFramework.Tools.FirmwareFlasher
{
@@ -119,7 +118,7 @@ public static async System.Threading.Tasks.Task UpdateFirmwareAsync(
ExitCodes programResult = ExitCodes.OK;
// write HEX files to flash
- if (filesToFlash.Any(f => f.EndsWith(".hex")))
+ if (filesToFlash.Exists(f => f.EndsWith(".hex")))
{
programResult = ccDevice.FlashHexFiles(filesToFlash);
}
@@ -127,7 +126,7 @@ public static async System.Threading.Tasks.Task UpdateFirmwareAsync(
if (programResult == ExitCodes.OK && isApplicationBinFile)
{
// now program the application file
- programResult = ccDevice.FlashBinFiles(new[] { applicationPath }, new[] { deploymentAddress });
+ programResult = ccDevice.FlashBinFiles([applicationPath], [deploymentAddress]);
}
if (updateFw)
diff --git a/nanoFirmwareFlasher.Library/Esp32DeviceInfo.cs b/nanoFirmwareFlasher.Library/Esp32DeviceInfo.cs
index e7470ae2..9dc578d2 100644
--- a/nanoFirmwareFlasher.Library/Esp32DeviceInfo.cs
+++ b/nanoFirmwareFlasher.Library/Esp32DeviceInfo.cs
@@ -65,15 +65,22 @@ public class Esp32DeviceInfo
public PSRamAvailability PSRamAvailable { get; }
///
- /// Constructor
+ /// The size of the PSRAM (in MBytes).
///
- /// Version of the esptool.py
- /// ESP32 chip name
- /// ESP32 chip features
- /// MAC address of the ESP32 chip
- /// Flash manufacturer ID
- /// Flash device type ID
- /// The size of the flash in bytes
+ public int PsRamSize { get; }
+
+ ///
+ /// Constructor.
+ ///
+ /// The type of chip.
+ /// ESP32 chip name.
+ /// ESP32 chip features.
+ /// ESP32 crystal.
+ /// MAC address of the ESP32 chip.
+ /// Flash manufacturer ID.
+ /// Flash device type ID.
+ /// The size of the flash in bytes.
+ /// Availability of PSRAM.
public Esp32DeviceInfo(
string chipType,
string chipName,
@@ -83,7 +90,8 @@ public Esp32DeviceInfo(
byte flashManufacturerId,
short flashDeviceModelId,
int flashSize,
- PSRamAvailability psramAvailability)
+ PSRamAvailability psramAvailability,
+ int psRamSize)
{
ChipType = chipType;
ChipName = chipName;
@@ -94,6 +102,7 @@ public Esp32DeviceInfo(
FlashDeviceId = flashDeviceModelId;
FlashSize = flashSize;
PSRamAvailable = psramAvailability;
+ PsRamSize = psRamSize;
}
internal string GetFlashSizeAsString()
@@ -101,6 +110,11 @@ internal string GetFlashSizeAsString()
return GetFlashSizeAsString(FlashSize);
}
+ ///
+ /// Gets the flash size as a string.
+ ///
+ /// The flash size.
+ /// The flash size.
public static string GetFlashSizeAsString(int flashSize)
{
return flashSize >= 0x10000 ? $"{flashSize / 0x100000}MB" : $"{flashSize / 0x400}kB";
@@ -133,7 +147,7 @@ public override string ToString()
break;
case PSRamAvailability.Yes:
- deviceInfo.AppendLine($"PSRAM: available");
+ deviceInfo.AppendLine($"PSRAM: {PsRamSize}MB");
break;
case PSRamAvailability.No:
diff --git a/nanoFirmwareFlasher.Library/Esp32Firmware.cs b/nanoFirmwareFlasher.Library/Esp32Firmware.cs
index 93a2f80c..f64aa933 100644
--- a/nanoFirmwareFlasher.Library/Esp32Firmware.cs
+++ b/nanoFirmwareFlasher.Library/Esp32Firmware.cs
@@ -24,7 +24,7 @@ internal class Esp32Firmware : FirmwarePackage
///
/// ESP32 nanoCLR is available for 2MB, 4MB, 8MB and 16MB flash sizes
///
- private List SupportedFlashSizes => new() { 0x200000, 0x400000, 0x800000, 0x1000000 };
+ private List SupportedFlashSizes => [0x200000, 0x400000, 0x800000, 0x1000000];
internal string BootloaderPath;
@@ -82,8 +82,12 @@ internal async System.Threading.Tasks.Task DownloadAndExtractAsync(Es
// get ESP32 partitions
FlashPartitions = new Dictionary
{
- // bootloader goes to 0x1000, except for ESP32_C3 and ESP32_S3, which goes to 0x0
- { deviceInfo.ChipType == "ESP32-C3" || deviceInfo.ChipType == "ESP32-S3" ? 0x0 : 0x1000, Path.Combine(LocationPath, BootloaderPath) },
+ // bootloader goes to 0x1000, except for ESP32_C3/C6/H2/S3, which goes to 0x0
+ {
+ deviceInfo.ChipType == "ESP32-C3"
+ || deviceInfo.ChipType == "ESP32-C6"
+ || deviceInfo.ChipType == "ESP32-H2"
+ || deviceInfo.ChipType == "ESP32-S3" ? 0x0 : 0x1000, Path.Combine(LocationPath, BootloaderPath) },
// nanoCLR goes to 0x10000
{ CLRAddress, Path.Combine(LocationPath, "nanoCLR.bin") },
diff --git a/nanoFirmwareFlasher.Library/Esp32Operations.cs b/nanoFirmwareFlasher.Library/Esp32Operations.cs
index e2b6f77a..2aeb693e 100644
--- a/nanoFirmwareFlasher.Library/Esp32Operations.cs
+++ b/nanoFirmwareFlasher.Library/Esp32Operations.cs
@@ -6,6 +6,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Text.RegularExpressions;
namespace nanoFramework.Tools.FirmwareFlasher
{
@@ -93,8 +94,8 @@ public static ExitCodes BackupFlash(
///
/// Perform firmware update on a ESP32 device.
///
- /// to use when performing update.
- /// of device to update.
+ /// to use when performing update.
+ /// of device to update.
/// Name of the target to update.
/// Set to to force download of firmware package.
/// Firmware version to update to.
@@ -103,6 +104,7 @@ public static ExitCodes BackupFlash(
/// Flash address to use when deploying an aplication.
/// Path to CLR file to use for firmware update.
/// to perform validation of update package against connected target.
+ /// If perform mass erase on device before updating.
/// Set verbosity level of progress and error messages.
/// Size of partition table.
/// The with the operation result.
@@ -117,6 +119,7 @@ public static async System.Threading.Tasks.Task UpdateFirmwareAsync(
string deploymentAddress,
string clrFile,
bool fitCheck,
+ bool massErase,
VerbosityLevel verbosity,
PartitionTableSize? partitionTableSize)
{
@@ -126,8 +129,10 @@ public static async System.Threading.Tasks.Task UpdateFirmwareAsync(
// perform sanity checks for the specified target against the connected device details
if (esp32Device.ChipType != "ESP32" &&
- esp32Device.ChipType != "ESP32-S2" &&
esp32Device.ChipType != "ESP32-C3" &&
+ esp32Device.ChipType != "ESP32-C6" &&
+ esp32Device.ChipType != "ESP32-H2" &&
+ esp32Device.ChipType != "ESP32-S2" &&
esp32Device.ChipType != "ESP32-S3")
{
// connected to a device not supported
@@ -218,26 +223,6 @@ public static async System.Threading.Tasks.Task UpdateFirmwareAsync(
}
}
}
- else if (esp32Device.ChipType == "ESP32-S2")
- {
- // version schema for ESP32-S2
- //Previously Used Schemes | Previous Identification | vM.X
- // n/a | 0 | v0.0
- // ECO1 | 1 | v1.0
-
- // can't guess with certainty for this series, better request a target name to the user
-
- Console.ForegroundColor = ConsoleColor.Red;
-
- Console.WriteLine("");
- Console.WriteLine($"For ESP32-S2 series nanoff isn't able to make an educated guess on the best target to use.");
- Console.WriteLine($"Please provide a valid target name using this option '--target MY_ESP32_S2_TARGET' instead of '--platform esp32'.");
- Console.WriteLine("");
-
- Console.ForegroundColor = ConsoleColor.White;
-
- return ExitCodes.E9000;
- }
else if (esp32Device.ChipType == "ESP32-C3")
{
// version schema for ESP32-C3
@@ -274,6 +259,80 @@ public static async System.Threading.Tasks.Task UpdateFirmwareAsync(
// compose target name
targetName = $"ESP32_C3{revisionSuffix}";
}
+ else if (esp32Device.ChipType == "ESP32-C6")
+ {
+ // version schema for ESP32-C6
+
+ string revisionSuffix;
+
+ // so far we are only offering a single ESP32_C6 build
+ if (esp32Device.ChipName.Contains("revision v0.0") || esp32Device.ChipName.Contains("revision v0.1"))
+ {
+ revisionSuffix = "";
+ }
+ else
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+
+ Console.WriteLine("");
+ Console.WriteLine($"Unsupported ESP32_C6 revision.");
+ Console.WriteLine("");
+
+ Console.ForegroundColor = ConsoleColor.White;
+
+ return ExitCodes.E9000;
+ }
+
+ // compose target name
+ targetName = $"ESP32_C6{revisionSuffix}";
+ }
+ else if (esp32Device.ChipType == "ESP32-H2")
+ {
+ // version schema for ESP32-H2
+
+ string revisionSuffix;
+
+ // so far we are only offering a single ESP32_H2 build
+ if (esp32Device.ChipName.Contains("revision v0.1") || esp32Device.ChipName.Contains("revision v0.2"))
+ {
+ revisionSuffix = "";
+ }
+ else
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+
+ Console.WriteLine("");
+ Console.WriteLine($"Unsupported ESP32_H2 revision.");
+ Console.WriteLine("");
+
+ Console.ForegroundColor = ConsoleColor.White;
+
+ return ExitCodes.E9000;
+ }
+
+ // compose target name
+ targetName = $"ESP32_H2{revisionSuffix}";
+ }
+ else if (esp32Device.ChipType == "ESP32-S2")
+ {
+ // version schema for ESP32-S2
+ //Previously Used Schemes | Previous Identification | vM.X
+ // n/a | 0 | v0.0
+ // ECO1 | 1 | v1.0
+
+ // can't guess with certainty for this series, better request a target name to the user
+
+ Console.ForegroundColor = ConsoleColor.Red;
+
+ Console.WriteLine("");
+ Console.WriteLine($"For ESP32-S2 series nanoff isn't able to make an educated guess on the best target to use.");
+ Console.WriteLine($"Please provide a valid target name using this option '--target MY_ESP32_S2_TARGET' instead of '--platform esp32'.");
+ Console.WriteLine("");
+
+ Console.ForegroundColor = ConsoleColor.White;
+
+ return ExitCodes.E9000;
+ }
else if (esp32Device.ChipType == "ESP32-S3")
{
// version schema for ESP32-S3
@@ -388,14 +447,18 @@ public static async System.Threading.Tasks.Task UpdateFirmwareAsync(
string applicationBinary = new FileInfo(applicationPath).FullName;
- // add DEPLOYMENT partition with the address provided in the command OR the address from the partition table
- firmware.FlashPartitions = new Dictionary()
+ // check for empty flash partitions
+ if (firmware.FlashPartitions is null)
{
- {
+ firmware.FlashPartitions = [];
+ }
+
+ // add DEPLOYMENT partition with the address provided in the command OR the address from the partition table
+ firmware.FlashPartitions.Add(
address != 0 ? (int)address : firmware.DeploymentPartitionAddress,
applicationBinary
- }
- };
+ );
+
}
else
{
@@ -403,8 +466,10 @@ public static async System.Threading.Tasks.Task UpdateFirmwareAsync(
}
}
- if (updateFw)
+ if (updateFw
+ && massErase)
{
+ // erase flash, if masse erase was requested
// updating fw calls for a flash erase
if (verbosity >= VerbosityLevel.Normal)
{
@@ -412,7 +477,6 @@ public static async System.Threading.Tasks.Task UpdateFirmwareAsync(
Console.Write($"Erasing flash...");
}
- // erase flash
operationResult = espTool.EraseFlash();
if (operationResult == ExitCodes.OK)
@@ -438,6 +502,47 @@ public static async System.Threading.Tasks.Task UpdateFirmwareAsync(
Console.Write($"Flashing firmware...");
}
+ int configPartitionAddress = 0;
+ int configPartitionSize = 0;
+ string configPartitionBackup = Path.GetRandomFileName();
+
+ // if mass erase wasn't requested, backup config partitition
+ if (!massErase)
+ {
+ // check if the update file includes a partition table
+ if (File.Exists(Path.Combine(firmware.LocationPath, $"partitions_nanoclr_{Esp32DeviceInfo.GetFlashSizeAsString(esp32Device.FlashSize).ToLowerInvariant()}.csv")))
+ {
+ // can't do this without a partition table
+
+
+ // compose path to partition file
+ string partitionCsvFile = Path.Combine(firmware.LocationPath, $"partitions_nanoclr_{Esp32DeviceInfo.GetFlashSizeAsString(esp32Device.FlashSize).ToLowerInvariant()}.csv");
+
+ var partitionDetails = File.ReadAllText(partitionCsvFile);
+
+ // grab details for the config partition
+ string pattern = @"config,.*?(0x[0-9A-Fa-f]+),.*?(0x[0-9A-Fa-f]+),";
+ Regex regex = new Regex(pattern);
+ Match match = regex.Match(partitionDetails);
+
+ if (match.Success)
+ {
+ // just try to parse, ignore failures
+ int.TryParse(match.Groups[1].Value.Substring(2), System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture, out configPartitionAddress);
+ int.TryParse(match.Groups[2].Value.Substring(2), System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture, out configPartitionSize);
+ }
+
+ // backup config partition
+ // ignore failures
+ _ = espTool.BackupConfigPartition(
+ configPartitionBackup,
+ configPartitionAddress,
+ configPartitionSize);
+
+ firmware.FlashPartitions.Add(configPartitionAddress, configPartitionBackup);
+ }
+ }
+
// write to flash
operationResult = espTool.WriteFlash(firmware.FlashPartitions);
@@ -445,8 +550,6 @@ public static async System.Threading.Tasks.Task UpdateFirmwareAsync(
{
if (verbosity >= VerbosityLevel.Normal)
{
- Console.Write($"Flashing firmware...");
-
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("OK".PadRight(110));
@@ -471,10 +574,152 @@ public static async System.Threading.Tasks.Task UpdateFirmwareAsync(
}
}
+ // delete config partition backup
+ try
+ {
+ if (File.Exists(configPartitionBackup))
+ {
+ File.Delete(configPartitionBackup);
+ }
+ }
+ catch
+ {
+ // don't care
+ }
+
Console.ForegroundColor = ConsoleColor.White;
}
return operationResult;
}
+
+ ///
+ /// Deplay application on a ESP32 device.
+ ///
+ /// to use when performing update.
+ /// of device to update.
+ /// Name of the target to update.
+ /// Path to application to update along with the firmware update.
+ /// Flash address to use when deploying an aplication.
+ /// Set verbosity level of progress and error messages.
+ /// Size of partition table.
+ /// The with the operation result.
+ public static async System.Threading.Tasks.Task DeployApplicationAsync(
+ EspTool espTool,
+ Esp32DeviceInfo esp32Device,
+ string targetName,
+ string applicationPath,
+ string deploymentAddress,
+ VerbosityLevel verbosity,
+ PartitionTableSize? partitionTableSize)
+ {
+ uint address = 0;
+
+ // perform sanity checks for the specified target against the connected device details
+ if (esp32Device.ChipType != "ESP32" &&
+ esp32Device.ChipType != "ESP32-C3" &&
+ esp32Device.ChipType != "ESP32-C6" &&
+ esp32Device.ChipType != "ESP32-H2" &&
+ esp32Device.ChipType != "ESP32-S2" &&
+ esp32Device.ChipType != "ESP32-S3")
+ {
+ // connected to a device not supported
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ Console.WriteLine("");
+ Console.WriteLine("******************************* WARNING *******************************");
+ Console.WriteLine("Seems that the connected device is not supported by .NET nanoFramework");
+ Console.WriteLine("Most likely it won't boot");
+ Console.WriteLine("************************************************************************");
+ Console.WriteLine("");
+ }
+
+ Esp32Firmware firmware = new Esp32Firmware(
+ targetName,
+ null,
+ false,
+ partitionTableSize)
+ {
+ Verbosity = verbosity
+ };
+
+ // include application file?
+ if (!string.IsNullOrEmpty(applicationPath))
+ {
+ // check application file
+ if (File.Exists(applicationPath))
+ {
+ // this operation includes a deployment image
+ // try parsing the deployment address from parameter, if provided
+ if (!string.IsNullOrEmpty(deploymentAddress))
+ {
+ // need to remove the leading 0x and to specify that hexadecimal values are allowed
+ if (!uint.TryParse(deploymentAddress.Substring(2), System.Globalization.NumberStyles.AllowHexSpecifier, System.Globalization.CultureInfo.InvariantCulture, out address))
+ {
+ return ExitCodes.E9009;
+ }
+ }
+
+ string applicationBinary = new FileInfo(applicationPath).FullName;
+
+ // check for empty flash partitions
+ if (firmware.FlashPartitions is null)
+ {
+ firmware.FlashPartitions = [];
+ }
+
+ // add DEPLOYMENT partition with the address provided in the command OR the address from the partition table
+ firmware.FlashPartitions.Add(
+ address != 0 ? (int)address : firmware.DeploymentPartitionAddress,
+ applicationBinary
+ );
+ }
+ else
+ {
+ return ExitCodes.E9008;
+ }
+ }
+
+ Console.ForegroundColor = ConsoleColor.White;
+
+ if (verbosity >= VerbosityLevel.Normal)
+ {
+ Console.Write($"Flashing deployment partition...");
+ }
+
+ // write to flash
+ ExitCodes operationResult = espTool.WriteFlash(firmware.FlashPartitions);
+
+ if (operationResult == ExitCodes.OK)
+ {
+ if (verbosity >= VerbosityLevel.Normal)
+ {
+ Console.ForegroundColor = ConsoleColor.Green;
+ Console.WriteLine("OK".PadRight(110));
+
+ // warn user if reboot is not possible
+ if (espTool.CouldntResetTarget)
+ {
+ Console.ForegroundColor = ConsoleColor.Yellow;
+
+ Console.WriteLine("");
+ Console.WriteLine("**********************************************");
+ Console.WriteLine("The connected device is in 'download mode'.");
+ Console.WriteLine("Please reset the chip manually to run nanoCLR.");
+ Console.WriteLine("**********************************************");
+ Console.WriteLine("");
+
+ Console.ForegroundColor = ConsoleColor.White;
+ }
+ }
+ else
+ {
+ Console.WriteLine("");
+ }
+ }
+
+ Console.ForegroundColor = ConsoleColor.White;
+
+ return operationResult;
+ }
}
}
diff --git a/nanoFirmwareFlasher.Library/EspTool.cs b/nanoFirmwareFlasher.Library/EspTool.cs
index 9c372fcf..c9b2f6a4 100644
--- a/nanoFirmwareFlasher.Library/EspTool.cs
+++ b/nanoFirmwareFlasher.Library/EspTool.cs
@@ -29,7 +29,7 @@ public partial class EspTool
private readonly string _serialPort = null;
///
- /// The baud rate for the serial port. The default comming from .
+ /// The baud rate for the serial port. The default comming from CLI Options.BaudRate./>.
///
private int _baudRate = 0;
@@ -43,6 +43,8 @@ public partial class EspTool
///
private int _flashSize = -1;
+
+
private bool connectPatternFound;
private DateTime connectTimeStamp;
@@ -77,6 +79,7 @@ public partial class EspTool
/// The flash mode for the esptool
/// The flash frequency for the esptool
/// Partition table size to use
+ /// The verbosity level of messages
public EspTool(
string serialPort,
int baudRate,
@@ -119,7 +122,7 @@ public EspTool(
}
else
{
- if (!File.Exists(serialPort))
+ if (!System.IO.File.Exists(serialPort))
{
throw new EspToolExecutionException();
}
@@ -142,14 +145,15 @@ public EspTool(
/// The filled info structure with all the information about the connected ESP32 device or null if an error occured
public Esp32DeviceInfo GetDeviceDetails(
string targetName,
- bool requireFlashSize = true)
+ bool requireFlashSize = true,
+ bool forcePsRamCheck = false)
{
string messages;
if (Verbosity >= VerbosityLevel.Normal)
{
Console.ForegroundColor = ConsoleColor.White;
- Console.WriteLine($"Reading details from chip...");
+ Console.Write($"Reading details from chip...");
}
// execute flash_id command and parse the result
@@ -161,7 +165,7 @@ public Esp32DeviceInfo GetDeviceDetails(
null,
out messages))
{
- if(messages.Contains("A fatal error occurred: Failed to connect to Espressif device: No serial data received."))
+ if (messages.Contains("A fatal error occurred: Failed to connect to Espressif device: No serial data received."))
{
Console.ForegroundColor = ConsoleColor.Red;
@@ -193,7 +197,9 @@ public Esp32DeviceInfo GetDeviceDetails(
}
}
- var match = Regex.Match(messages, $"(Detecting chip type... )(?[ESP32\\-ICOCH]+)(.*?[\r\n]*)*(Chip is )(?.*)(.*?[\r\n]*)*(Features: )(?.*)(.*?[\r\n]*)*(Crystal is )(?.*)(.*?[\r\n]*)*(MAC: )(?.*)(.*?[\r\n]*)*(Manufacturer: )(?.*)(.*?[\r\n]*)*(Device: )(?.*)(.*?[\r\n]*)*(Detected flash size: )(?.*)");
+ var match = Regex.Match(messages,
+ $"(Detecting chip type... )(?[ESP32\\-ICOCH6]+)(.*?[\r\n]*)*(Chip is )(?.*)(.*?[\r\n]*)*(Features: )(?.*)(.*?[\r\n]*)*(Crystal is )(?.*)(.*?[\r\n]*)*(MAC: )(?.*)(.*?[\r\n]*)*(Manufacturer: )(?.*)(.*?[\r\n]*)*(Device: )(?.*)(.*?[\r\n]*)*(Detected flash size: )(?.*)");
+
if (!match.Success)
{
throw new EspToolExecutionException(messages);
@@ -231,36 +237,27 @@ public Esp32DeviceInfo GetDeviceDetails(
// lower case, no hifen
_chipType = chipType.ToLower().Replace("-", "");
- // try to find out if PSRAM is present
PSRamAvailability psramIsAvailable = PSRamAvailability.Undetermined;
+ int psRamSize = 0;
- if (name.Contains("PICO"))
+ if (_chipType == "esp32c3"
+ || _chipType == "esp32c6"
+ || _chipType == "esp32h2")
{
- // PICO's don't have PSRAM, so don't even bother
+ // these series doesn't have PSRAM
psramIsAvailable = PSRamAvailability.No;
}
- else if (name.Contains("ESP32-S2")
- && targetName == "FEATHER_S2")
- {
- // FEATHER_S2's have PSRAM, so don't even bother
- psramIsAvailable = PSRamAvailability.Yes;
- }
- else if (name.Contains("ESP32-C3")
- || name.Contains("ESP32-S3"))
+ else if (_chipType == "esp32s3")
{
- // all ESP32-C3/S3 SDK config have support for PSRAM, so don't even bother
+ // For now assuming all S3 have PSRAM.
+ // TODO: following https://github.com/espressif/esptool/issues/970
+ // The download mode register is not cleared so a reset/run command does not work on the S3. We should retest this after depending on what will be the fix for that issue.
psramIsAvailable = PSRamAvailability.Undetermined;
}
else
{
- // if a target name wasn't provided, check for PSRAM
- // except for ESP32_C3 and S3
- if (targetName == null
- && !name.Contains("ESP32-C3")
- && !name.Contains("ESP32-S3"))
- {
- psramIsAvailable = FindPSRamAvailable();
- }
+ //try to find out if PSRAM is present
+ psramIsAvailable = FindPSRamAvailable(out psRamSize, forcePsRamCheck);
}
if (Verbosity >= VerbosityLevel.Normal)
@@ -279,51 +276,95 @@ public Esp32DeviceInfo GetDeviceDetails(
byte.Parse(manufacturer, NumberStyles.AllowHexSpecifier),
short.Parse(device, NumberStyles.HexNumber),
_flashSize,
- psramIsAvailable);
+ psramIsAvailable,
+ psRamSize);
}
///
/// Perform detection of PSRAM availability on connected device.
///
+ /// Force the detection of PSRAM availability.
+ /// Size of the PSRAM device, if detection was succesfull.
/// Information about availability of PSRAM, if that was possible to determine.
- private PSRamAvailability FindPSRamAvailable()
+ private PSRamAvailability FindPSRamAvailable(
+ out int psRamSize,
+ bool force = false)
{
- PSRamAvailability pSRamAvailability = PSRamAvailability.Undetermined;
-
// don't want to output anything from esptool
// backup current verbosity setting
var bkpVerbosity = Verbosity;
Verbosity = VerbosityLevel.Quiet;
- // compose bootloader partition
- var bootloaderPartition = new Dictionary
+ // default to no PSRAM
+ psRamSize = 0;
+
+ try
{
- // bootloader goes to 0x1000, except for ESP32_C3 and ESP32_S3, which goes to 0x0
- { _chipType == "esp32c3" || _chipType == "esp32s3" ? 0x0 : 0x1000, Path.Combine(Utilities.ExecutingPath, $"{_chipType}bootloader", "bootloader.bin") },
+ // if forced, run the test app to determine PSRAM availability
+ if (force)
+ {
+ // adjust flash size according to the series
+ // defautl to 2MB for ESP32 series
+ var flashSize = 2 * 1024 * 1024;
- // nanoCLR goes to 0x10000
- { 0x10000, Path.Combine(Utilities.ExecutingPath, $"{_chipType}bootloader", "test_startup.bin") },
+ if (_chipType == "esp32s2"
+ || _chipType == "esp32s3")
+ {
+ flashSize = 4 * 1024 * 1024;
+ }
- // partition table goes to 0x8000; there are partition tables for 2MB, 4MB, 8MB and 16MB flash sizes
- { 0x8000, Path.Combine(Utilities.ExecutingPath, $"{_chipType}bootloader", $"partitions_{Esp32DeviceInfo.GetFlashSizeAsString(_flashSize).ToLowerInvariant()}.bin") }
- };
+ // compose bootloader partition
+ var bootloaderPartition = new Dictionary
+ {
+ // bootloader goes to 0x1000, except for ESP32_S3, which goes to 0x0
+ { _chipType == "esp32s3" ? 0x0 : 0x1000, Path.Combine(Utilities.ExecutingPath, $"{_chipType}bootloader", "bootloader.bin") },
+
+ // nanoCLR goes to 0x10000
+ { 0x10000, Path.Combine(Utilities.ExecutingPath, $"{_chipType}bootloader", "test_startup.bin") },
+
+ // partition table goes to 0x8000; there are partition tables for 2MB, 4MB, 8MB and 16MB flash sizes
+ { 0x8000, Path.Combine(Utilities.ExecutingPath, $"{_chipType}bootloader", $"partitions_{Esp32DeviceInfo.GetFlashSizeAsString(flashSize).ToLowerInvariant()}.bin") }
+ };
+
+ // need to use standard baud rate here because of boards put in download mode
+ if (WriteFlash(bootloaderPartition, true) != ExitCodes.OK)
+ {
+ // something went wrong, can't determine PSRAM availability
+ return PSRamAvailability.Undetermined;
+ }
+ }
+ else
+ {
+ // execute run command to force soft reset
+ // if the device is running a nanoFramework image, it will output information about the PSRAM
+ if (!RunEspTool(
+ $" run ",
+ true,
+ true,
+ true,
+ '\r',
+ out _))
+ {
+ // something went wrong, can't determine PSRAM availability
+ return PSRamAvailability.Undetermined;
+ }
+ }
- // need to use standard baud rate here because of boards put in download mode
- if (WriteFlash(bootloaderPartition, true) == ExitCodes.OK)
- {
// check if the
if (_esptoolMessage.Contains("esptool.py can not exit the download mode over USB"))
{
// this board was put on download mode manually, can't run the test app...
-
return PSRamAvailability.Undetermined;
}
try
{
- // open COM port and grab output
// force baud rate to 115200 (standard baud rate for boootloader)
- SerialPort espDevice = new SerialPort(_serialPort, 115200);
+ SerialPort espDevice = new(
+ _serialPort,
+ 115200);
+
+ // open COM port and grab output
espDevice.Open();
if (espDevice.IsOpen)
@@ -336,14 +377,35 @@ private PSRamAvailability FindPSRamAvailable()
espDevice.Close();
- // find magic string
+ // look for "magic" string
+
if (bootloaderOutput.Contains("PSRAM initialized"))
{
- pSRamAvailability = PSRamAvailability.Yes;
+ // output similiar to this:
+ // I(206) esp_psram: Found 4MB PSRAM device
+ // I(206) esp_psram: Speed: 40MHz
+ // I(209) esp_psram: PSRAM initialized, cache is in low / high(2 - core) mode.
+
+ // extract PSRAM size
+ var match = Regex.Match(bootloaderOutput, @"Found (?\d+)MB PSRAM device");
+ if (match.Success)
+ {
+ psRamSize = int.Parse(match.Groups["size"].Value);
+ }
+
+ return PSRamAvailability.Yes;
+ }
+ else if (bootloaderOutput.Contains("PSRAM ID read error"))
+ {
+ // output similiar to this:
+ // E(206) quad_psram: PSRAM ID read error: 0xffffffff, PSRAM chip not found or not supported
+ // E(210) esp_psram: PSRAM enabled but initialization failed.Bailing out.
+ return PSRamAvailability.No;
}
else
{
- pSRamAvailability = PSRamAvailability.No;
+ // can't determine PSRAM availability
+ return PSRamAvailability.Undetermined;
}
}
}
@@ -352,11 +414,13 @@ private PSRamAvailability FindPSRamAvailable()
// don't care about any exceptions
}
}
+ finally
+ {
+ // restore verbosity setting
+ Verbosity = bkpVerbosity;
+ }
- // restore verbosity setting
- Verbosity = bkpVerbosity;
-
- return pSRamAvailability;
+ return PSRamAvailability.Undetermined;
}
///
@@ -392,6 +456,44 @@ internal void BackupFlash(string backupFilename,
}
}
+ ///
+ /// Backup the entire flash into a bin file
+ ///
+ /// Backup file including full path
+ /// Start address of the config partition.
+ /// Size of the config partition.
+ /// true if successful
+ internal ExitCodes BackupConfigPartition(
+ string backupFilename,
+ int address,
+ int size)
+ {
+ // execute dump_mem command and parse the result; progress message can be found be searching for backspaces (ASCII code 8)
+ if (!RunEspTool(
+ $"read_flash 0x{address:X} 0x{size:X} \"{backupFilename}\"",
+ false,
+ true,
+ false,
+ null,
+ out string messages))
+ {
+ throw new ReadEsp32FlashException(messages);
+ }
+
+ var match = Regex.Match(messages, "(?Read .*)(.*?\n)*");
+ if (!match.Success)
+ {
+ throw new ReadEsp32FlashException(messages);
+ }
+
+ if (Verbosity >= VerbosityLevel.Detailed)
+ {
+ Console.WriteLine(match.Groups["message"].ToString().Trim());
+ }
+
+ return ExitCodes.OK;
+ }
+
///
/// Erase the entire flash of the ESP32 chip.
///
@@ -458,6 +560,7 @@ internal ExitCodes EraseFlashSegment(uint startAddress, uint length)
/// Write to the flash
///
/// dictionary which keys are the start addresses and the values are the complete filenames (the bin files)
+ /// Use the standard baud rate (default is false).
/// true if successful
internal ExitCodes WriteFlash(
Dictionary partsToWrite,
diff --git a/nanoFirmwareFlasher.Library/Exceptions/CantConnectToDfuDeviceException.cs b/nanoFirmwareFlasher.Library/Exceptions/CantConnectToDfuDeviceException.cs
index afcb1fa9..7cefe0ce 100644
--- a/nanoFirmwareFlasher.Library/Exceptions/CantConnectToDfuDeviceException.cs
+++ b/nanoFirmwareFlasher.Library/Exceptions/CantConnectToDfuDeviceException.cs
@@ -14,18 +14,35 @@ namespace nanoFramework.Tools.FirmwareFlasher
[Serializable]
public class CantConnectToDfuDeviceException : Exception
{
+ ///
+ /// DFU device connection exception.
+ ///
public CantConnectToDfuDeviceException()
{
}
+ ///
+ /// DFU device connection exception.
+ ///
+ /// Message to display.
public CantConnectToDfuDeviceException(string message) : base(message)
{
}
+ ///
+ /// DFU device connection exception.
+ ///
+ /// Message to display.
+ /// The exception to display.
public CantConnectToDfuDeviceException(string message, Exception innerException) : base(message, innerException)
{
}
+ ///
+ /// DFU device connection exception.
+ ///
+ /// Serialized information.
+ /// Streamed context.
protected CantConnectToDfuDeviceException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
diff --git a/nanoFirmwareFlasher.Library/Exceptions/CantConnectToJLinkDeviceException.cs b/nanoFirmwareFlasher.Library/Exceptions/CantConnectToJLinkDeviceException.cs
index e85db4ae..2b01104e 100644
--- a/nanoFirmwareFlasher.Library/Exceptions/CantConnectToJLinkDeviceException.cs
+++ b/nanoFirmwareFlasher.Library/Exceptions/CantConnectToJLinkDeviceException.cs
@@ -14,18 +14,35 @@ namespace nanoFramework.Tools.FirmwareFlasher
[Serializable]
public class CantConnectToJLinkDeviceException : Exception
{
+ ///
+ /// Cannot connect to the J-Link device exception.
+ ///
public CantConnectToJLinkDeviceException()
{
}
+ ///
+ /// Cannot connect to the JLINK device exception.
+ ///
+ /// Message to display.
public CantConnectToJLinkDeviceException(string message) : base(message)
{
}
+ ///
+ /// Cannot connect to the JLINK device exception.
+ ///
+ /// Message to display.
+ /// The exception to display.
public CantConnectToJLinkDeviceException(string message, Exception innerException) : base(message, innerException)
{
}
+ ///
+ /// Cannot connect to the JLINK device exception.
+ ///
+ /// Serialized information.
+ /// Streamed context.
protected CantConnectToJLinkDeviceException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
diff --git a/nanoFirmwareFlasher.Library/Exceptions/CantConnectToJtagDeviceException.cs b/nanoFirmwareFlasher.Library/Exceptions/CantConnectToJtagDeviceException.cs
index ebba5e60..267418a7 100644
--- a/nanoFirmwareFlasher.Library/Exceptions/CantConnectToJtagDeviceException.cs
+++ b/nanoFirmwareFlasher.Library/Exceptions/CantConnectToJtagDeviceException.cs
@@ -14,18 +14,35 @@ namespace nanoFramework.Tools.FirmwareFlasher
[Serializable]
public class CantConnectToJtagDeviceException : Exception
{
+ ///
+ /// Cannot connect to JTAG device exception.
+ ///
public CantConnectToJtagDeviceException()
{
}
+ ///
+ /// Cannot connect to JTAG device exception.
+ ///
+ /// Message to display.
public CantConnectToJtagDeviceException(string message) : base(message)
{
}
+ ///
+ /// Cannot connect to JTAG device exception.
+ ///
+ /// Message to display.
+ /// The exception to display.
public CantConnectToJtagDeviceException(string message, Exception innerException) : base(message, innerException)
{
}
+ ///
+ /// Cannot connect to JTAG device exception.
+ ///
+ /// Serialized information.
+ /// Streamed context.
protected CantConnectToJtagDeviceException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
diff --git a/nanoFirmwareFlasher.Library/Exceptions/CantConnectToNanoDeviceException.cs b/nanoFirmwareFlasher.Library/Exceptions/CantConnectToNanoDeviceException.cs
index b13c7fa7..03eaf0d4 100644
--- a/nanoFirmwareFlasher.Library/Exceptions/CantConnectToNanoDeviceException.cs
+++ b/nanoFirmwareFlasher.Library/Exceptions/CantConnectToNanoDeviceException.cs
@@ -14,18 +14,35 @@ namespace nanoFramework.Tools.FirmwareFlasher
[Serializable]
public class CantConnectToNanoDeviceException : Exception
{
+ ///
+ /// Cannot connect to device exception.
+ ///
public CantConnectToNanoDeviceException()
{
}
+ ///
+ /// Cannot connect to device exception.
+ ///
+ /// Message to display.
public CantConnectToNanoDeviceException(string message) : base(message)
{
}
+ ///
+ /// Cannot connect to device exception.
+ ///
+ /// Message to display.
+ /// The exception to display.
public CantConnectToNanoDeviceException(string message, Exception innerException) : base(message, innerException)
{
}
+ ///
+ /// Cannot connect to device exception.
+ ///
+ /// Serialized information.
+ /// Streamed context.
protected CantConnectToNanoDeviceException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
diff --git a/nanoFirmwareFlasher.Library/Exceptions/DfuFileDoesNotExistException.cs b/nanoFirmwareFlasher.Library/Exceptions/DfuFileDoesNotExistException.cs
index 3c0e316e..c22f5a8e 100644
--- a/nanoFirmwareFlasher.Library/Exceptions/DfuFileDoesNotExistException.cs
+++ b/nanoFirmwareFlasher.Library/Exceptions/DfuFileDoesNotExistException.cs
@@ -14,18 +14,35 @@ namespace nanoFramework.Tools.FirmwareFlasher
[Serializable]
public class DfuFileDoesNotExistException : Exception
{
+ ///
+ /// DFU file does not exist exception.
+ ///
public DfuFileDoesNotExistException()
{
}
+ ///
+ /// DFU file does not exist exception.
+ ///
+ /// Message to display.
public DfuFileDoesNotExistException(string message) : base(message)
{
}
+ ///
+ /// DFU file does not exist exception.
+ ///
+ /// Message to display.
+ /// The exception to display.
public DfuFileDoesNotExistException(string message, Exception innerException) : base(message, innerException)
{
}
+ ///
+ /// DFU file does not exist exception.
+ ///
+ /// Serialized information.
+ /// Streamed context.
protected DfuFileDoesNotExistException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
diff --git a/nanoFirmwareFlasher.Library/Exceptions/DfuOperationFailedException.cs b/nanoFirmwareFlasher.Library/Exceptions/DfuOperationFailedException.cs
index f5e0c131..ce7df3dc 100644
--- a/nanoFirmwareFlasher.Library/Exceptions/DfuOperationFailedException.cs
+++ b/nanoFirmwareFlasher.Library/Exceptions/DfuOperationFailedException.cs
@@ -14,18 +14,35 @@ namespace nanoFramework.Tools.FirmwareFlasher
[Serializable]
public class DfuOperationFailedException : Exception
{
+ ///
+ /// DFU operation failed exception.
+ ///
public DfuOperationFailedException()
{
}
+ ///
+ /// DFU operation failed exception.
+ ///
+ /// Message to display.
public DfuOperationFailedException(string message) : base(message)
{
}
+ ///
+ /// DFU operation failed exception.
+ ///
+ /// Message to display.
+ /// The exception to display.
public DfuOperationFailedException(string message, Exception innerException) : base(message, innerException)
{
}
+ ///
+ /// DFU operation failed exception.
+ ///
+ /// Serialized information.
+ /// Streamed context.
protected DfuOperationFailedException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
diff --git a/nanoFirmwareFlasher.Library/Exceptions/EraseEsp32FlashException.cs b/nanoFirmwareFlasher.Library/Exceptions/EraseEsp32FlashException.cs
index f094b0e9..eceb29f0 100644
--- a/nanoFirmwareFlasher.Library/Exceptions/EraseEsp32FlashException.cs
+++ b/nanoFirmwareFlasher.Library/Exceptions/EraseEsp32FlashException.cs
@@ -19,15 +19,29 @@ public class EraseEsp32FlashException : Exception
///
public string ExecutionError;
+ ///
+ /// ESP32 tool erase exception.
+ ///
+ /// Message to display.
public EraseEsp32FlashException(string message) : base(message)
{
ExecutionError = message;
}
+ ///
+ /// ESP32 tool erase exception.
+ ///
+ /// Message to display.
+ /// The exception to display.
public EraseEsp32FlashException(string message, Exception innerException) : base(message, innerException)
{
}
+ ///
+ /// ESP32 tool erase exception.
+ ///
+ /// Serialized information.
+ /// Streamed context
protected EraseEsp32FlashException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
diff --git a/nanoFirmwareFlasher.Library/Exceptions/EspToolExecutionException.cs b/nanoFirmwareFlasher.Library/Exceptions/EspToolExecutionException.cs
index dd8fdca4..c18e239e 100644
--- a/nanoFirmwareFlasher.Library/Exceptions/EspToolExecutionException.cs
+++ b/nanoFirmwareFlasher.Library/Exceptions/EspToolExecutionException.cs
@@ -19,20 +19,37 @@ public class EspToolExecutionException : Exception
///
public string ExecutionError;
+ ///
+ /// ESP32 tool execution exception.
+ ///
public EspToolExecutionException() : base()
{
}
+ ///
+ /// ESP32 tool execution exception.
+ ///
+ /// Message to display.
public EspToolExecutionException(string message) : base(message)
{
ExecutionError = message;
}
+ ///
+ /// ESP32 tool execution exception.
+ ///
+ /// Message to display.
+ /// The exception to display.
public EspToolExecutionException(string message, Exception innerException) : base(message, innerException)
{
}
+ ///
+ /// ESP32 tool execution exception.
+ ///
+ /// Serialized information.
+ /// Streamed context.
protected EspToolExecutionException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
diff --git a/nanoFirmwareFlasher.Library/Exceptions/NanoDeviceOperationFailedException.cs b/nanoFirmwareFlasher.Library/Exceptions/NanoDeviceOperationFailedException.cs
index 6b117b9e..5e561c7a 100644
--- a/nanoFirmwareFlasher.Library/Exceptions/NanoDeviceOperationFailedException.cs
+++ b/nanoFirmwareFlasher.Library/Exceptions/NanoDeviceOperationFailedException.cs
@@ -14,18 +14,35 @@ namespace nanoFramework.Tools.FirmwareFlasher
[Serializable]
public class NanoDeviceOperationFailedException : Exception
{
+ ///
+ /// NanoFramework Device Operation Exception.
+ ///
public NanoDeviceOperationFailedException()
{
}
+ ///
+ /// NanoFramework Device Operation Exception.
+ ///
+ /// Message to display.
public NanoDeviceOperationFailedException(string message) : base(message)
{
}
+ ///
+ /// NanoFramework Device Operation Exception.
+ ///
+ /// Message to display.
+ /// The exception to display.
public NanoDeviceOperationFailedException(string message, Exception innerException) : base(message, innerException)
{
}
+ ///
+ /// NanoFramework Device Operation Exception.
+ ///
+ /// Serialized information.
+ /// Streamed context.
protected NanoDeviceOperationFailedException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
diff --git a/nanoFirmwareFlasher.Library/Exceptions/NoOperationPerformedException.cs b/nanoFirmwareFlasher.Library/Exceptions/NoOperationPerformedException.cs
new file mode 100644
index 00000000..3b273b00
--- /dev/null
+++ b/nanoFirmwareFlasher.Library/Exceptions/NoOperationPerformedException.cs
@@ -0,0 +1,49 @@
+//
+// Copyright (c) .NET Foundation and Contributors
+// See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Runtime.Serialization;
+
+namespace nanoFramework.Tools.FirmwareFlasher
+{
+ ///
+ /// No operations was performed during the process from the manager.
+ ///
+ public class NoOperationPerformedException : Exception
+ {
+ ///
+ /// No operation performed exception.
+ ///
+ public NoOperationPerformedException()
+ {
+ }
+
+ ///
+ /// No operation performed exception.
+ ///
+ /// Message to display.
+ public NoOperationPerformedException(string message) : base(message)
+ {
+ }
+
+ ///
+ /// No operation performed exception.
+ ///
+ /// Message to display.
+ /// The exception to display.
+ public NoOperationPerformedException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+
+ ///
+ /// No operation performed exception.
+ ///
+ /// Serialized information.
+ /// Streamed context.
+ protected NoOperationPerformedException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ }
+ }
+}
diff --git a/nanoFirmwareFlasher.Library/Exceptions/ReadEsp32FlashException.cs b/nanoFirmwareFlasher.Library/Exceptions/ReadEsp32FlashException.cs
index db402f11..2e878042 100644
--- a/nanoFirmwareFlasher.Library/Exceptions/ReadEsp32FlashException.cs
+++ b/nanoFirmwareFlasher.Library/Exceptions/ReadEsp32FlashException.cs
@@ -19,15 +19,29 @@ public class ReadEsp32FlashException : Exception
///
public string ExecutionError;
+ ///
+ /// ESP32 tool flash exception.
+ ///
+ /// Message to display.
public ReadEsp32FlashException(string message) : base(message)
{
ExecutionError = message;
}
+ ///
+ /// ESP32 tool flash exception.
+ ///
+ /// Message to display.
+ /// The exception to display.
public ReadEsp32FlashException(string message, Exception innerException) : base(message, innerException)
{
}
+ ///
+ /// ESP32 tool flash exception.
+ ///
+ /// Serialized information.
+ /// Streamed context.
protected ReadEsp32FlashException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
diff --git a/nanoFirmwareFlasher.Library/Exceptions/SilinkExecutionException.cs b/nanoFirmwareFlasher.Library/Exceptions/SilinkExecutionException.cs
new file mode 100644
index 00000000..b4d7479d
--- /dev/null
+++ b/nanoFirmwareFlasher.Library/Exceptions/SilinkExecutionException.cs
@@ -0,0 +1,56 @@
+//
+// Copyright (c) .NET Foundation and Contributors
+// See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Runtime.Serialization;
+
+namespace nanoFramework.Tools.FirmwareFlasher
+{
+ ///
+ /// Error executing SI Link command.
+ ///
+ [Serializable]
+ public class SilinkExecutionException : Exception
+ {
+ ///
+ /// Error message from SI Link.
+ ///
+ public string ExecutionError;
+
+ ///
+ /// SI Link Exception.
+ ///
+ public SilinkExecutionException()
+ {
+ }
+
+ ///
+ /// SI Link Exception.
+ ///
+ /// Message to display.
+ public SilinkExecutionException(string message) : base(message)
+ {
+ ExecutionError = message;
+ }
+
+ ///
+ /// SI Link Exception.
+ ///
+ /// Message to display.
+ /// The exception to display.
+ public SilinkExecutionException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+
+ ///
+ /// SI Link Exception.
+ ///
+ /// Serialized information.
+ /// Streamed context.
+ protected SilinkExecutionException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ }
+ }
+}
diff --git a/nanoFirmwareFlasher.Library/Exceptions/StLinkCliExecutionException.cs b/nanoFirmwareFlasher.Library/Exceptions/StLinkCliExecutionException.cs
index 80188d0c..0b10d315 100644
--- a/nanoFirmwareFlasher.Library/Exceptions/StLinkCliExecutionException.cs
+++ b/nanoFirmwareFlasher.Library/Exceptions/StLinkCliExecutionException.cs
@@ -19,19 +19,36 @@ public class StLinkCliExecutionException : Exception
///
public string ExecutionError;
+ ///
+ /// STM32 Programmer CLI Exception.
+ ///
public StLinkCliExecutionException()
{
}
+ ///
+ /// STM32 Programmer CLI Exception.
+ ///
+ /// Message to display.
public StLinkCliExecutionException(string message) : base(message)
{
ExecutionError = message;
}
+ ///
+ /// STM32 Programmer CLI Exception.
+ ///
+ /// Message to display.
+ /// The exception to display.
public StLinkCliExecutionException(string message, Exception innerException) : base(message, innerException)
{
}
+ ///
+ /// STM32 Programmer CLI Exception.
+ ///
+ /// Serialized information.
+ /// Streamed context.
protected StLinkCliExecutionException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
diff --git a/nanoFirmwareFlasher.Library/Exceptions/UniflashCliExecutionException.cs b/nanoFirmwareFlasher.Library/Exceptions/UniflashCliExecutionException.cs
index 5fd714c6..e482c594 100644
--- a/nanoFirmwareFlasher.Library/Exceptions/UniflashCliExecutionException.cs
+++ b/nanoFirmwareFlasher.Library/Exceptions/UniflashCliExecutionException.cs
@@ -19,19 +19,36 @@ public class UniflashCliExecutionException : Exception
///
public string ExecutionError;
+ ///
+ /// UniFlash CLI Execution Exception.
+ ///
public UniflashCliExecutionException()
{
}
+ ///
+ /// UniFlash CLI Execution Exception.
+ ///
+ /// Message to display.
public UniflashCliExecutionException(string message) : base(message)
{
ExecutionError = message;
}
+ ///
+ /// UniFlash CLI Execution Exception.
+ ///
+ /// Message to display.
+ /// The exception to display.
public UniflashCliExecutionException(string message, Exception innerException) : base(message, innerException)
{
}
+ ///
+ /// UniFlash CLI Execution Exception.
+ ///
+ /// Serialized information.
+ /// Streamed context.
protected UniflashCliExecutionException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
diff --git a/nanoFirmwareFlasher.Library/Exceptions/WriteEsp32FlashException.cs b/nanoFirmwareFlasher.Library/Exceptions/WriteEsp32FlashException.cs
index c2d1bb2c..48969a9c 100644
--- a/nanoFirmwareFlasher.Library/Exceptions/WriteEsp32FlashException.cs
+++ b/nanoFirmwareFlasher.Library/Exceptions/WriteEsp32FlashException.cs
@@ -19,15 +19,29 @@ public class WriteEsp32FlashException : Exception
///
public string ExecutionError;
+ ///
+ /// Write the ESPP32 flash exception.
+ ///
+ /// Message to display.
public WriteEsp32FlashException(string message) : base(message)
{
ExecutionError = message;
}
+ ///
+ /// Write the ESPP32 flash exception.
+ ///
+ /// Message to display.
+ /// The exception to display.
public WriteEsp32FlashException(string message, Exception innerException) : base(message, innerException)
{
}
+ ///
+ /// Write the ESPP32 flash exception.
+ ///
+ /// Serialized information.
+ /// Streamed context.
protected WriteEsp32FlashException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
diff --git a/nanoFirmwareFlasher.Library/ExitCodes.cs b/nanoFirmwareFlasher.Library/ExitCodes.cs
index 85bafe5f..e829983b 100644
--- a/nanoFirmwareFlasher.Library/ExitCodes.cs
+++ b/nanoFirmwareFlasher.Library/ExitCodes.cs
@@ -8,6 +8,9 @@
namespace nanoFramework.Tools.FirmwareFlasher
{
+ ///
+ /// Exit Codes.
+ ///
public enum ExitCodes
{
///
@@ -33,7 +36,7 @@ public enum ExitCodes
E1002 = 1002,
///
- /// Error flashing DFU dvice
+ /// Error flashing DFU device
///
[Display(Name = "Error flashing DFU device.")]
E1003 = 1003,
@@ -53,7 +56,7 @@ public enum ExitCodes
///
/// Failed to start execution on the connected device.
///
- [Display(Name = "Failed to start execition on the connected device.")]
+ [Display(Name = "Failed to start execution on the connected device.")]
E1006 = 1006,
///////////////////////
@@ -78,6 +81,12 @@ public enum ExitCodes
[Display(Name = "Error executing operation with nano device.")]
E2002 = 2002,
+ ///
+ /// Error executing operation with nano device.
+ ///
+ [Display(Name = "Error executing file deployment on nano device.")]
+ E2003 = 2003,
+
////////////////////////
// ESP32 tools Errors //
////////////////////////
@@ -315,7 +324,7 @@ public enum ExitCodes
///
/// CLR image file has wrong format. It has to be a binary file.
///
- [Display(Name = "CLR image file has wrong format.It has to be a binary file.")]
+ [Display(Name = "CLR image file has wrong format. It has to be a binary file.")]
E9012 = 9012,
///
diff --git a/nanoFirmwareFlasher.Library/FileDeployment/DeploymentFile.cs b/nanoFirmwareFlasher.Library/FileDeployment/DeploymentFile.cs
new file mode 100644
index 00000000..e29b23ce
--- /dev/null
+++ b/nanoFirmwareFlasher.Library/FileDeployment/DeploymentFile.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace nanoFramework.Tools.FirmwareFlasher.FileDeployment
+{
+ internal class DeploymentFile
+ {
+ ///
+ /// Gets or sets the destination fully qualified file path including file name.
+ ///
+ public string DestinationFilePath { get; set; }
+
+ ///
+ /// Gets or sets the source fully qualified file path including file name.
+ ///
+ public string SourceFilePath { get; set; }
+ }
+}
diff --git a/nanoFirmwareFlasher.Library/FileDeployment/FileDeploymentConfiguration.cs b/nanoFirmwareFlasher.Library/FileDeployment/FileDeploymentConfiguration.cs
new file mode 100644
index 00000000..b2065634
--- /dev/null
+++ b/nanoFirmwareFlasher.Library/FileDeployment/FileDeploymentConfiguration.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace nanoFramework.Tools.FirmwareFlasher.FileDeployment
+{
+ internal class FileDeploymentConfiguration
+ {
+ ///
+ /// Gets or sets the serial port to be used for the deployment.
+ ///
+ public string SerialPort { get; set; }
+
+ ///
+ /// A list of files to deploy and/or delete.
+ ///
+ public List Files { get; set; }
+ }
+}
diff --git a/nanoFirmwareFlasher.Library/FileDeployment/FileDeploymentManager.cs b/nanoFirmwareFlasher.Library/FileDeployment/FileDeploymentManager.cs
new file mode 100644
index 00000000..2936db3e
--- /dev/null
+++ b/nanoFirmwareFlasher.Library/FileDeployment/FileDeploymentManager.cs
@@ -0,0 +1,255 @@
+//
+// Copyright (c) .NET Foundation and Contributors
+// See LICENSE file in the project root for full license information.
+//
+
+using nanoFramework.Tools.Debugger;
+using nanoFramework.Tools.Debugger.Extensions;
+using Newtonsoft.Json;
+using System;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace nanoFramework.Tools.FirmwareFlasher.FileDeployment
+{
+ ///
+ /// File Deployment Manager class.
+ ///
+ public class FileDeploymentManager
+ {
+ private readonly FileDeploymentConfiguration _configuration;
+ private readonly VerbosityLevel _verbosity;
+ private readonly string _serialPort;
+
+ ///
+ /// Creates an instance of FileDeploymentManager.
+ ///
+ public FileDeploymentManager(string configFilePath, string originalPort, VerbosityLevel verbosity)
+ {
+ _configuration = JsonConvert.DeserializeObject(File.ReadAllText(configFilePath));
+ _serialPort = string.IsNullOrEmpty(_configuration.SerialPort) ? originalPort : _configuration.SerialPort;
+ _verbosity = verbosity;
+ }
+
+ ///
+ /// Deploys async the files.
+ ///
+ /// An ExitCode error.
+ public async Task DeployAsync()
+ {
+ // number of retries when performing a deploy operation
+ const int _numberOfRetries = 5;
+ // timeout when performing a deploy operation
+ const int _timeoutMiliseconds = 1000;
+
+ NanoDeviceBase device = null;
+ PortBase serialDebugClient;
+ int retryCount = 0;
+
+ serialDebugClient = PortBase.CreateInstanceForSerial(false);
+
+ try
+ {
+ serialDebugClient.AddDevice(_serialPort);
+
+ device = serialDebugClient.NanoFrameworkDevices[0];
+ }
+ catch (Exception ex)
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine($"Error connecting to nanoDevice on {_serialPort} to deploy files");
+ Console.ForegroundColor = ConsoleColor.White;
+ return ExitCodes.E2000;
+ }
+
+ // check if debugger engine exists
+ if (device.DebugEngine == null)
+ {
+ device.CreateDebugEngine();
+ if (_verbosity >= VerbosityLevel.Normal)
+ {
+ Console.WriteLine($"Debug engine created.");
+ }
+ }
+
+ bool deviceIsInInitializeState = false;
+
+ retryDebug:
+ bool connectResult = device.DebugEngine.Connect(5000, true, true);
+ if (retryCount == 0 && _verbosity >= VerbosityLevel.Normal)
+ {
+ Console.WriteLine($"Device connected and ready for file deployment.");
+ }
+ else if (_verbosity >= VerbosityLevel.Normal)
+ {
+ Console.WriteLine($"Device connect result is {connectResult}. Attempt {retryCount}/{_numberOfRetries}");
+ }
+
+ if (!connectResult)
+ {
+ if (retryCount < _numberOfRetries)
+ {
+ // Give it a bit of time
+ await Task.Delay(100);
+ retryCount++;
+
+ goto retryDebug;
+ }
+ else
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine($"Error connecting to debug engine on nanoDevice on {_serialPort} to deploy files");
+ Console.ForegroundColor = ConsoleColor.White;
+ return ExitCodes.E2000;
+ }
+ }
+
+ retryCount = 0;
+
+ // initial check
+ if (device.DebugEngine.IsDeviceInInitializeState())
+ {
+ if (_verbosity >= VerbosityLevel.Normal)
+ {
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ Console.WriteLine($"Device status verified as being in initialized state. Requesting to resume execution. Attempt {retryCount}/{_numberOfRetries}.");
+ Console.ForegroundColor = ConsoleColor.White;
+ }
+
+ // set flag
+ deviceIsInInitializeState = true;
+
+ // device is still in initialization state, try resume execution
+ device.DebugEngine.ResumeExecution();
+ }
+
+ // handle the workflow required to try resuming the execution on the device
+ // only required if device is not already there
+ // retry 5 times with a 500ms interval between retries
+ while (retryCount++ < _numberOfRetries && deviceIsInInitializeState)
+ {
+ if (!device.DebugEngine.IsDeviceInInitializeState())
+ {
+ if (_verbosity >= VerbosityLevel.Diagnostic)
+ {
+ Console.WriteLine($"Device has completed initialization.");
+ }
+
+ // done here
+ deviceIsInInitializeState = false;
+ break;
+ }
+
+ if (_verbosity >= VerbosityLevel.Diagnostic)
+ {
+ Console.WriteLine($"Waiting for device to report initialization completed ({retryCount}/{_numberOfRetries}).");
+ }
+
+ // provide feedback to user on the 1st pass
+ if (retryCount == 0)
+ {
+ if (_verbosity >= VerbosityLevel.Diagnostic)
+ {
+ Console.WriteLine($"Waiting for device to initialize.");
+ }
+ }
+
+ if (device.DebugEngine.IsConnectedTonanoBooter)
+ {
+ if (_verbosity >= VerbosityLevel.Diagnostic)
+ {
+ Console.WriteLine($"Device reported running nanoBooter. Requesting to load nanoCLR.");
+ }
+
+ // request nanoBooter to load CLR
+ device.DebugEngine.ExecuteMemory(0);
+ }
+ else if (device.DebugEngine.IsConnectedTonanoCLR)
+ {
+ if (_verbosity >= VerbosityLevel.Normal)
+ {
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ Console.WriteLine($"Device reported running nanoCLR. Requesting to reboot nanoCLR.");
+ Console.ForegroundColor = ConsoleColor.White;
+ }
+
+ await Task.Run(delegate
+ {
+ // already running nanoCLR try rebooting the CLR
+ device.DebugEngine.RebootDevice(RebootOptions.ClrOnly);
+ });
+ }
+
+ // wait before next pass
+ // use a back-off strategy of increasing the wait time to accommodate slower or less responsive targets (such as networked ones)
+ await Task.Delay(TimeSpan.FromMilliseconds(_timeoutMiliseconds * (retryCount + 1)));
+
+ await Task.Yield();
+ }
+
+ // check if device is still in initialized state
+ if (!deviceIsInInitializeState)
+ {
+ // Deploy each file
+ foreach (var file in _configuration.Files)
+ {
+ try
+ {
+ if (string.IsNullOrEmpty(file.SourceFilePath))
+ {
+ // deleting
+ Console.Write($"Deleting file {file.DestinationFilePath}...");
+ if (device.DebugEngine.DeleteStorageFile(file.DestinationFilePath) != Debugger.WireProtocol.StorageOperationErrorCode.NoError)
+ {
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ Console.WriteLine();
+ Console.WriteLine($"Error deleting file {file.DestinationFilePath}, it may not exist on the storage.");
+ Console.ForegroundColor = ConsoleColor.White;
+ }
+ else
+ {
+ Console.ForegroundColor = ConsoleColor.Green;
+ Console.WriteLine($"OK");
+ Console.ForegroundColor = ConsoleColor.White;
+ }
+ }
+ else
+ {
+ Console.Write($"Deploying file {file.SourceFilePath} to {file.DestinationFilePath}...");
+ var ret = device.DebugEngine.AddStorageFile(file.DestinationFilePath, File.ReadAllBytes(file.SourceFilePath));
+ if (ret != Debugger.WireProtocol.StorageOperationErrorCode.NoError)
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine();
+ Console.WriteLine($"Error deploying content file {file.SourceFilePath} to {file.DestinationFilePath}");
+ Console.ForegroundColor = ConsoleColor.White;
+ }
+ else
+ {
+ Console.ForegroundColor = ConsoleColor.Green;
+ Console.WriteLine($"OK");
+ Console.ForegroundColor = ConsoleColor.White;
+ }
+ }
+ }
+ catch
+ {
+ if (_verbosity >= VerbosityLevel.Normal)
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine();
+ Console.WriteLine($"Exception deploying content file {file.SourceFilePath} to {file.DestinationFilePath}");
+ Console.ForegroundColor = ConsoleColor.White;
+ }
+ }
+ }
+ }
+ else
+ {
+ return ExitCodes.E2002;
+ }
+
+ return ExitCodes.OK;
+ }
+ }
+}
diff --git a/nanoFirmwareFlasher.Library/FirmwarePackage.cs b/nanoFirmwareFlasher.Library/FirmwarePackage.cs
index 24119bd4..8f1bf341 100644
--- a/nanoFirmwareFlasher.Library/FirmwarePackage.cs
+++ b/nanoFirmwareFlasher.Library/FirmwarePackage.cs
@@ -3,8 +3,10 @@
// See LICENSE file in the project root for full license information.
//
+using Microsoft.ApplicationInsights;
+using Microsoft.ApplicationInsights.DataContracts;
+using Microsoft.Extensions.Configuration;
using nanoFramework.Tools.Debugger;
-using nanoFramework.Tools.FirmwareFlasher;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
@@ -12,6 +14,7 @@
using System.IO.Compression;
using System.Linq;
using System.Net.Http;
+using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
@@ -31,7 +34,6 @@ public abstract class FirmwarePackage : IDisposable
private readonly string _targetName;
private readonly bool _preview;
-
private const string _readmeContent = "This folder contains nanoFramework firmware files. Can safely be removed.";
///
@@ -58,6 +60,9 @@ public static string LocationPathBase
///
public string Version { get; internal set; }
+ ///
+ /// The verbosity level.
+ ///
public VerbosityLevel Verbosity { get; internal set; }
///
@@ -94,10 +99,14 @@ public static string LocationPathBase
///
public object BooterStartAddress { get; internal set; }
+
+
static FirmwarePackage()
{
- _cloudsmithClient = new HttpClient();
- _cloudsmithClient.BaseAddress = new Uri("https://api.cloudsmith.io/v1/packages/net-nanoframework/");
+ _cloudsmithClient = new HttpClient
+ {
+ BaseAddress = new Uri("https://api.cloudsmith.io/v1/packages/net-nanoframework/")
+ };
_cloudsmithClient.DefaultRequestHeaders.Add("Accept", "*/*");
}
@@ -116,6 +125,8 @@ protected FirmwarePackage(NanoDeviceBase nanoDevice)
/// Constructor
///
/// Target name as designated in the repositories.
+ /// The firmware version.
+ /// Whether to use preview versions.
protected FirmwarePackage(
string targetName,
string fwVersion,
@@ -147,7 +158,7 @@ public static List GetTargetList(
// Because new stable releases are published on a regular basis and preview very rarely, we query for stable versions published in past month and preview versions published during the past 6 months.
string requestUri = $"{repoName}/?page_size=500&q=uploaded:'>{(preview ? "6" : "1")} month ago' {(platform.HasValue ? "AND tag:" + platform.Value : "")}";
- List targetPackages = new();
+ List targetPackages = [];
if (verbosity > VerbosityLevel.Normal)
{
@@ -235,7 +246,7 @@ internal async Task DownloadAndExtractAsync()
return ExitCodes.E9006;
}
- List fwFiles = new();
+ List fwFiles = [];
if (_preview)
{
@@ -282,6 +293,7 @@ internal async Task DownloadAndExtractAsync()
filesToDelete.AddRange(Directory.EnumerateFiles(LocationPath, "*.hex").ToList());
filesToDelete.AddRange(Directory.EnumerateFiles(LocationPath, "*.s19").ToList());
filesToDelete.AddRange(Directory.EnumerateFiles(LocationPath, "*.dfu").ToList());
+ filesToDelete.AddRange(Directory.EnumerateFiles(LocationPath, "*.csv").ToList());
foreach (var file in filesToDelete)
{
@@ -336,6 +348,32 @@ internal async Task DownloadAndExtractAsync()
}
stepSuccessful = true;
+
+ // send telemetry data on successful download
+ if (NanoTelemetryClient.TelemetryClient is not null)
+ {
+ AssemblyInformationalVersionAttribute nanoffVersion = null;
+
+ try
+ {
+ nanoffVersion = Attribute.GetCustomAttribute(
+ Assembly.GetEntryAssembly()!,
+ typeof(AssemblyInformationalVersionAttribute))
+ as AssemblyInformationalVersionAttribute;
+ }
+ catch
+ {
+ // OK to fail here, just telemetry
+ }
+
+ var packageTelemetry = new EventTelemetry("PackageDownloaded");
+ packageTelemetry.Properties.Add("TargetName", _targetName);
+ packageTelemetry.Properties.Add("Version", Version);
+ packageTelemetry.Properties.Add("nanoffVersion", nanoffVersion == null ? "unknown" : nanoffVersion.InformationalVersion);
+
+ NanoTelemetryClient.TelemetryClient.TrackEvent(packageTelemetry);
+ NanoTelemetryClient.TelemetryClient.Flush();
+ }
}
catch
{
@@ -637,6 +675,7 @@ private static async Task GetDownloadUrlAsync(
private bool _disposedValue = false; // To detect redundant calls
+ ///
protected void Dispose(bool disposing)
{
if (!_disposedValue)
diff --git a/nanoFirmwareFlasher.Library/FirmwarePackageFactory.cs b/nanoFirmwareFlasher.Library/FirmwarePackageFactory.cs
index 8eb9cef2..cf4d6b82 100644
--- a/nanoFirmwareFlasher.Library/FirmwarePackageFactory.cs
+++ b/nanoFirmwareFlasher.Library/FirmwarePackageFactory.cs
@@ -8,8 +8,18 @@
namespace nanoFramework.Tools.FirmwareFlasher
{
+ ///
+ /// Firmware Package Factory.
+ ///
public class FirmwarePackageFactory
{
+ ///
+ /// Gets the firmware package for the device.
+ ///
+ /// The device.
+ /// The firmware Version.
+ /// The Firmware package.
+ /// The command is not supported.
public static FirmwarePackage GetFirmwarePackage(
NanoDeviceBase nanoDevice,
string fwVersion)
diff --git a/nanoFirmwareFlasher.Library/IManager.cs b/nanoFirmwareFlasher.Library/IManager.cs
new file mode 100644
index 00000000..2942eec9
--- /dev/null
+++ b/nanoFirmwareFlasher.Library/IManager.cs
@@ -0,0 +1,21 @@
+//
+// Copyright (c) .NET Foundation and Contributors
+// See LICENSE file in the project root for full license information.
+//
+
+using System.Threading.Tasks;
+
+namespace nanoFramework.Tools.FirmwareFlasher
+{
+ ///
+ /// Interface for processing platform-specific operations.
+ ///
+ public interface IManager
+ {
+ ///
+ /// Process operations depending on options provided.
+ ///
+ /// Return an value.
+ Task ProcessAsync();
+ }
+}
diff --git a/nanoFirmwareFlasher.Library/JLinkCli.cs b/nanoFirmwareFlasher.Library/JLinkCli.cs
index 3621424e..c483d13d 100644
--- a/nanoFirmwareFlasher.Library/JLinkCli.cs
+++ b/nanoFirmwareFlasher.Library/JLinkCli.cs
@@ -179,34 +179,9 @@ public ExitCodes ExecuteFlashBinFiles(
}
}
- List shadowFiles = new List();
+ List shadowFiles = [];
- // J-Link can't handle diacritc chars
- // developer note: reported to Segger (Case: 60276735) and can be removed if this is fixed/improved
- foreach (string binFile in files)
- {
- if (!binFile.IsNormalized(NormalizationForm.FormD)
- || binFile.Contains(' '))
- {
- var tempFile = Path.Combine(
- Environment.GetEnvironmentVariable("TEMP", EnvironmentVariableTarget.Machine),
- Path.GetFileName(binFile));
-
- // copy file to shadow file
- File.Copy(
- binFile,
- tempFile,
- true);
-
- shadowFiles.Add(tempFile);
- }
- else
- {
- // copy file to shadow list
- shadowFiles.Add(binFile);
- }
-
- }
+ ProcessFilePaths(files, shadowFiles);
// erase flash
if (DoMassErase)
@@ -222,12 +197,12 @@ public ExitCodes ExecuteFlashBinFiles(
DoMassErase = false;
}
- if (Verbosity < VerbosityLevel.Normal)
+ if (Verbosity == VerbosityLevel.Normal)
{
Console.ForegroundColor = ConsoleColor.White;
Console.Write("Flashing device...");
}
- else
+ else if (Verbosity >= VerbosityLevel.Detailed)
{
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine("Flashing device...");
@@ -235,21 +210,18 @@ public ExitCodes ExecuteFlashBinFiles(
// program BIN file(s)
int index = 0;
+ bool warningPromptShown = false;
+
foreach (string binFile in shadowFiles)
{
- // make sure path is absolute
- var binFilePath = Utilities.MakePathAbsolute(
- Environment.CurrentDirectory,
- binFile);
-
if (Verbosity > VerbosityLevel.Normal)
{
Console.ForegroundColor = ConsoleColor.Cyan;
- Console.WriteLine($"{Path.GetFileName(binFilePath)} @ {addresses.ElementAt(index)}");
+ Console.WriteLine($"{Path.GetFileName(binFile)} @ {addresses.ElementAt(index)}");
}
// compose JLink command file
- var jlinkCmdContent = FlashSingleFileCommandTemplate.Replace(FilePathToken, binFilePath).Replace(FlashAddressToken, addresses.ElementAt(index++));
+ var jlinkCmdContent = FlashSingleFileCommandTemplate.Replace(FilePathToken, binFile).Replace(FlashAddressToken, addresses.ElementAt(index++));
var jlinkCmdFilePath = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.jlink");
// create file
@@ -265,8 +237,15 @@ public ExitCodes ExecuteFlashBinFiles(
if (Verbosity >= VerbosityLevel.Normal
&& cliOutput.Contains("Skipped. Contents already match"))
{
+ warningPromptShown = true;
+
Console.ForegroundColor = ConsoleColor.Yellow;
+ if (Verbosity == VerbosityLevel.Normal)
+ {
+ Console.WriteLine();
+ }
+
Console.WriteLine("");
Console.WriteLine("******************* WARNING *********************");
Console.WriteLine("Skip flashing. Contents already match the update.");
@@ -286,12 +265,15 @@ public ExitCodes ExecuteFlashBinFiles(
ShowCLIOutput(cliOutput);
}
- if (Verbosity < VerbosityLevel.Normal)
+ if (Verbosity == VerbosityLevel.Normal)
{
- Console.ForegroundColor = ConsoleColor.Green;
- Console.WriteLine(" OK");
+ if (!warningPromptShown)
+ {
+ Console.ForegroundColor = ConsoleColor.Green;
+ Console.WriteLine(" OK");
+ }
}
- else
+ else if (Verbosity >= VerbosityLevel.Detailed)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Flashing completed...");
@@ -302,38 +284,27 @@ public ExitCodes ExecuteFlashBinFiles(
return ExitCodes.OK;
}
- ///
- /// Executes an operation that flashes a collection of Intel HEX format files to a connected J-Link device.
- ///
- /// List of files to flash to the device.
- /// ID of the J-Link device to execute the operation into. Leave to use the default address.
- ///
- public ExitCodes ExecuteFlashHexFiles(
- IList files,
- string probeId)
+ private void ProcessFilePaths(IList files, List shadowFiles)
{
- // check file existence
- if (files.Any(f => !File.Exists(f)))
- {
- return ExitCodes.E5004;
- }
-
- List shadowFiles = new List();
-
// J-Link can't handle diacritc chars
// developer note: reported to Segger (Case: 60276735) and can be removed if this is fixed/improved
- foreach (string hexFile in files)
+ foreach (string binFile in files)
{
- if (!hexFile.IsNormalized(NormalizationForm.FormD) ||
- hexFile.Contains(' '))
+ // make sure path is absolute
+ var binFilePath = Utilities.MakePathAbsolute(
+ Environment.CurrentDirectory,
+ binFile);
+
+ if (!binFilePath.IsNormalized(NormalizationForm.FormD)
+ || binFilePath.Contains(' '))
{
var tempFile = Path.Combine(
Environment.GetEnvironmentVariable("TEMP", EnvironmentVariableTarget.Machine),
- Path.GetFileName(hexFile));
+ Path.GetFileName(binFilePath));
// copy file to shadow file
File.Copy(
- hexFile,
+ binFilePath,
tempFile,
true);
@@ -342,10 +313,32 @@ public ExitCodes ExecuteFlashHexFiles(
else
{
// copy file to shadow list
- shadowFiles.Add(hexFile);
+ shadowFiles.Add(binFile);
}
+
+ }
+ }
+
+ ///
+ /// Executes an operation that flashes a collection of Intel HEX format files to a connected J-Link device.
+ ///
+ /// List of files to flash to the device.
+ /// ID of the J-Link device to execute the operation into. Leave to use the default address.
+ ///
+ public ExitCodes ExecuteFlashHexFiles(
+ IList files,
+ string probeId)
+ {
+ // check file existence
+ if (files.Any(f => !File.Exists(f)))
+ {
+ return ExitCodes.E5004;
}
+ List shadowFiles = [];
+
+ ProcessFilePaths(files, shadowFiles);
+
// erase flash
if (DoMassErase)
{
@@ -360,12 +353,12 @@ public ExitCodes ExecuteFlashHexFiles(
DoMassErase = false;
}
- if (Verbosity < VerbosityLevel.Normal)
+ if (Verbosity == VerbosityLevel.Normal)
{
Console.ForegroundColor = ConsoleColor.White;
Console.Write("Flashing device...");
}
- else
+ else if (Verbosity >= VerbosityLevel.Detailed)
{
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine("Flashing device...");
@@ -376,18 +369,13 @@ public ExitCodes ExecuteFlashHexFiles(
foreach (string hexFile in shadowFiles)
{
- // make sure path is absolute
- var hexFilePath = Utilities.MakePathAbsolute(
- Environment.CurrentDirectory,
- hexFile);
-
if (Verbosity > VerbosityLevel.Normal)
{
Console.ForegroundColor = ConsoleColor.Cyan;
- Console.WriteLine($"{Path.GetFileName(hexFilePath)}");
+ Console.WriteLine($"{Path.GetFileName(hexFile)}");
}
- listOfFiles.AppendLine($"LoadFile {hexFilePath}");
+ listOfFiles.AppendLine($"LoadFile {hexFile}");
}
// compose JLink command file
@@ -409,11 +397,20 @@ public ExitCodes ExecuteFlashHexFiles(
// OK to delete the JLink command file
File.Delete(jlinkCmdFilePath);
+ bool warningPromptShown = false;
+
if (Verbosity >= VerbosityLevel.Normal
&& cliOutput.Contains("Skipped. Contents already match"))
{
+ warningPromptShown = true;
+
Console.ForegroundColor = ConsoleColor.Yellow;
+ if (Verbosity == VerbosityLevel.Normal)
+ {
+ Console.WriteLine();
+ }
+
Console.WriteLine("");
Console.WriteLine("******************* WARNING *********************");
Console.WriteLine("Skip flashing. Contents already match the update.");
@@ -432,12 +429,15 @@ public ExitCodes ExecuteFlashHexFiles(
ShowCLIOutput(cliOutput);
- if (Verbosity < VerbosityLevel.Normal)
+ if (Verbosity == VerbosityLevel.Normal)
{
- Console.ForegroundColor = ConsoleColor.Green;
- Console.WriteLine(" OK");
+ if (!warningPromptShown)
+ {
+ Console.ForegroundColor = ConsoleColor.Green;
+ Console.WriteLine(" OK");
+ }
}
- else
+ else if (Verbosity >= VerbosityLevel.Detailed)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Flashing completed...");
diff --git a/nanoFirmwareFlasher.Library/JLinkDevice.cs b/nanoFirmwareFlasher.Library/JLinkDevice.cs
index 5cf4dfee..35d26f25 100644
--- a/nanoFirmwareFlasher.Library/JLinkDevice.cs
+++ b/nanoFirmwareFlasher.Library/JLinkDevice.cs
@@ -151,7 +151,7 @@ public static List ListDevices()
if (jlinkMatches.Count == 0)
{
// no J-Link probe found
- return new List();
+ return [];
}
return jlinkMatches.Cast().Select(i => i.Value).ToList();
diff --git a/nanoFirmwareFlasher.Library/JLinkOperations.cs b/nanoFirmwareFlasher.Library/JLinkOperations.cs
index c71f5da5..eba76718 100644
--- a/nanoFirmwareFlasher.Library/JLinkOperations.cs
+++ b/nanoFirmwareFlasher.Library/JLinkOperations.cs
@@ -69,7 +69,7 @@ public static async System.Threading.Tasks.Task UpdateFirmwareAsync(
}
// setup files to flash
- var filesToFlash = new List();
+ List filesToFlash = [];
if (updateFw)
{
@@ -153,7 +153,7 @@ public static async System.Threading.Tasks.Task UpdateFirmwareAsync(
jlinkDevice.Verbosity = verbosity;
// write HEX files to flash
- if (filesToFlash.Any(f => f.EndsWith(".hex")))
+ if (filesToFlash.Exists(f => f.EndsWith(".hex")))
{
operationResult = jlinkDevice.FlashHexFiles(filesToFlash);
}
@@ -161,18 +161,24 @@ public static async System.Threading.Tasks.Task UpdateFirmwareAsync(
if (operationResult == ExitCodes.OK && isApplicationBinFile)
{
// now program the application file
- operationResult = jlinkDevice.FlashBinFiles(new[] { applicationPath }, new[] { deploymentAddress });
+ operationResult = jlinkDevice.FlashBinFiles([applicationPath], [deploymentAddress]);
}
return operationResult;
}
+ ///
+ /// Mass erase device.
+ ///
+ /// The probe ID.
+ /// The verbosity level.
+ ///
public static ExitCodes MassErase(
string probeId,
VerbosityLevel verbosity)
{
// J-Link device
- JLinkDevice jlinkDevice = new JLinkDevice(probeId);
+ JLinkDevice jlinkDevice = new(probeId);
if (!jlinkDevice.DevicePresent)
{
diff --git a/nanoFirmwareFlasher.Library/NanoDeviceOperations.cs b/nanoFirmwareFlasher.Library/NanoDeviceOperations.cs
index 5b75a754..b94a009f 100644
--- a/nanoFirmwareFlasher.Library/NanoDeviceOperations.cs
+++ b/nanoFirmwareFlasher.Library/NanoDeviceOperations.cs
@@ -1,4 +1,4 @@
-////
+////
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
////
@@ -54,7 +54,7 @@ public ObservableCollection ListDevices(bool getDeviceDetails)
{
_ = device.DebugEngine.Connect(
false,
- true);
+ false);
// check that we are in CLR
if (device.DebugEngine.IsConnectedTonanoCLR)
@@ -82,6 +82,8 @@ public ObservableCollection ListDevices(bool getDeviceDetails)
// no need to report this, just move on
}
}
+
+ device.Disconnect(true);
}
}
@@ -161,13 +163,6 @@ public ExitCodes GetDeviceDetails(
// report issue
throw new CantConnectToNanoDeviceException("Couldn't connect to specified nano device.");
}
-
- if (nanoDevice is null)
- {
- throw new ArgumentNullException(nameof(nanoDevice));
- }
-
- return ExitCodes.E2000;
}
///
@@ -286,7 +281,7 @@ public async Task UpdateDeviceClrAsync(
}
}
- bool attemptToLaunchBooter = false;
+ bool booterLaunched = false;
if (nanoDevice.DebugEngine.IsConnectedTonanoCLR)
{
@@ -304,9 +299,9 @@ public async Task UpdateDeviceClrAsync(
Console.ForegroundColor = ConsoleColor.White;
}
- attemptToLaunchBooter = nanoDevice.ConnectToNanoBooter();
+ booterLaunched = nanoDevice.ConnectToNanoBooter();
- if (!attemptToLaunchBooter)
+ if (!booterLaunched)
{
// check for version where the software reboot to nanoBooter was made available
if (currentClrVersion != null &&
@@ -332,10 +327,10 @@ public async Task UpdateDeviceClrAsync(
}
else
{
- attemptToLaunchBooter = true;
+ booterLaunched = true;
}
- if (attemptToLaunchBooter &&
+ if (booterLaunched &&
nanoDevice.Ping() == Debugger.WireProtocol.ConnectionSource.nanoBooter)
{
// get address for CLR block expected by device
@@ -378,7 +373,7 @@ public async Task UpdateDeviceClrAsync(
}
}
- if (attemptToLaunchBooter)
+ if (booterLaunched)
{
// try to reboot target
if (verbosity >= VerbosityLevel.Normal)
@@ -406,7 +401,7 @@ public async Task UpdateDeviceClrAsync(
}
else
{
- if (attemptToLaunchBooter)
+ if (!booterLaunched)
{
// only report this as an error if the launch was successful
throw new NanoDeviceOperationFailedException("Failed to launch nanoBooter. Quitting update.");
diff --git a/nanoFirmwareFlasher.Library/NanoTelemetryClient.cs b/nanoFirmwareFlasher.Library/NanoTelemetryClient.cs
new file mode 100644
index 00000000..0763af7a
--- /dev/null
+++ b/nanoFirmwareFlasher.Library/NanoTelemetryClient.cs
@@ -0,0 +1,61 @@
+//
+// Copyright (c) .NET Foundation and Contributors
+// See LICENSE file in the project root for full license information.
+//
+
+using Microsoft.ApplicationInsights;
+using System;
+
+namespace nanoFramework.Tools.FirmwareFlasher
+{
+ ///
+ /// Telemetry client for sending telemetry data to Application Insights.
+ ///
+ public class NanoTelemetryClient
+ {
+ private static TelemetryClient _myTelemetryClient;
+
+ // flag to signal that the telemetry client field initialized has been processed
+ private static bool notProcessed = true;
+
+ ///
+ /// Connection string for .
+ ///
+ public static string ConnectionString;
+
+ ///
+ /// Gets the to use for sending telemetry data.
+ ///
+ public static TelemetryClient TelemetryClient => GetTelemetryClient();
+
+ private static TelemetryClient GetTelemetryClient()
+ {
+ if (notProcessed && _myTelemetryClient is null)
+ {
+ string optOutTelemetry = Environment.GetEnvironmentVariable("NANOFRAMEWORK_TELEMETRY_OPTOUT");
+
+ if (!string.IsNullOrEmpty(ConnectionString)
+ && (optOutTelemetry is null || optOutTelemetry != "1"))
+ {
+ // parsing the connection string could fail
+ try
+ {
+ _myTelemetryClient = new TelemetryClient(new Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration()
+ {
+ ConnectionString = ConnectionString
+ });
+ }
+ catch
+ {
+ // don't care, telemetry is not mandatory
+ };
+ }
+
+ // set flag to false to signal that the telemetry client field has been processed
+ notProcessed = false;
+ }
+
+ return _myTelemetryClient;
+ }
+ }
+}
diff --git a/nanoFirmwareFlasher.Library/PartitionTableSize.cs b/nanoFirmwareFlasher.Library/PartitionTableSize.cs
index 230c11c5..a89b5e11 100644
--- a/nanoFirmwareFlasher.Library/PartitionTableSize.cs
+++ b/nanoFirmwareFlasher.Library/PartitionTableSize.cs
@@ -5,11 +5,26 @@
namespace nanoFramework.Tools.FirmwareFlasher
{
+ ///
+ /// The partition table size.
+ ///
public enum PartitionTableSize
{
+ ///
+ /// Two.
+ ///
_2 = 2,
+ ///
+ /// Four.
+ ///
_4 = 4,
+ ///
+ /// Eight.
+ ///
_8 = 8,
- _16 = 16,
+ ///
+ /// Sixteen.
+ ///
+ _16 = 16
}
}
diff --git a/nanoFirmwareFlasher.Library/SilinkCli.cs b/nanoFirmwareFlasher.Library/SilinkCli.cs
index 1f93f6cc..3a2c8bda 100644
--- a/nanoFirmwareFlasher.Library/SilinkCli.cs
+++ b/nanoFirmwareFlasher.Library/SilinkCli.cs
@@ -15,6 +15,9 @@
namespace nanoFramework.Tools.FirmwareFlasher
{
+ ///
+ /// SI Link CLI.
+ ///
public class SilinkCli
{
private const int SilinkTelnetPort = 49000;
diff --git a/nanoFirmwareFlasher.Library/Stm32Operations.cs b/nanoFirmwareFlasher.Library/Stm32Operations.cs
index 6a27d5c6..32583aee 100644
--- a/nanoFirmwareFlasher.Library/Stm32Operations.cs
+++ b/nanoFirmwareFlasher.Library/Stm32Operations.cs
@@ -12,8 +12,26 @@
namespace nanoFramework.Tools.FirmwareFlasher
{
+ ///
+ /// Runs STM32 specific operations.
+ ///
public class Stm32Operations
{
+ ///
+ /// Updates the device firmware.
+ ///
+ /// The name of the target.
+ /// The firmware version to send.
+ /// Whether preview packages should be used.
+ /// Update firmware to latest version.
+ /// Path to the directory where the files are located.
+ /// The start memory address.
+ /// The DFU device ID.
+ /// The JTAG ID.
+ /// Checks whether the firmware will fit.
+ /// The connection interface.
+ /// The verbosity level to use.
+ /// The outcome.
public static async System.Threading.Tasks.Task UpdateFirmwareAsync(
string targetName,
string fwVersion,
@@ -197,7 +215,7 @@ public static async System.Threading.Tasks.Task UpdateFirmwareAsync(
if (operationResult == ExitCodes.OK && isApplicationBinFile)
{
// now program the application file
- operationResult = dfuDevice.FlashBinFiles(new[] { applicationPath }, new[] { deploymentAddress });
+ operationResult = dfuDevice.FlashBinFiles([applicationPath], [deploymentAddress]);
}
if (
@@ -264,7 +282,7 @@ public static async System.Threading.Tasks.Task UpdateFirmwareAsync(
if (operationResult == ExitCodes.OK && isApplicationBinFile)
{
// now program the application file
- operationResult = jtagDevice.FlashBinFiles(new[] { applicationPath }, new[] { deploymentAddress });
+ operationResult = jtagDevice.FlashBinFiles([applicationPath], [deploymentAddress]);
}
if (
@@ -323,6 +341,12 @@ private static void PerformTargetCheck(string target, StmJtagDevice jtagDevice)
}
}
+ ///
+ /// Resets the device.
+ ///
+ /// the JTAG ID.
+ /// The verbosity level.
+ /// The outcome.
public static ExitCodes ResetMcu(
string jtagId,
VerbosityLevel verbosity)
@@ -350,6 +374,12 @@ public static ExitCodes ResetMcu(
return jtagDevice.ResetMcu();
}
+ ///
+ /// Erases the device flash memory.
+ ///
+ /// The ID of the JTAG interface.
+ /// The verbosity level.
+ /// The outcome.
public static ExitCodes MassErase(
string jtagId,
VerbosityLevel verbosity)
@@ -377,6 +407,12 @@ public static ExitCodes MassErase(
return jtagDevice.MassErase();
}
+ ///
+ /// Installs DFU driver.
+ ///
+ /// The verbosity level to display.
+ /// The installation result.
+ /// The installation failed. Use verbose output to see why.
public static ExitCodes InstallDfuDrivers(VerbosityLevel verbosityLevel)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
@@ -490,6 +526,12 @@ public static ExitCodes InstallDfuDrivers(VerbosityLevel verbosityLevel)
}
}
+ ///
+ /// Installs the JTAG drivers.
+ ///
+ /// Message verbosity level.
+ /// Installation result.
+ /// The installation failed. Use verbose output to see why.
public static ExitCodes InstallJtagDrivers(VerbosityLevel verbosityLevel)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
@@ -567,12 +609,22 @@ public static ExitCodes InstallJtagDrivers(VerbosityLevel verbosityLevel)
}
+ ///
+ /// The device connection interface.
+ ///
public enum Interface
{
+ ///
+ /// None.
+ ///
None = 0,
-
+ ///
+ /// JTAG.
+ ///
Jtag,
-
+ ///
+ /// DFU.
+ ///
Dfu
}
}
diff --git a/nanoFirmwareFlasher.Library/StmDeviceBase.cs b/nanoFirmwareFlasher.Library/StmDeviceBase.cs
index 0b825ff4..47d3e331 100644
--- a/nanoFirmwareFlasher.Library/StmDeviceBase.cs
+++ b/nanoFirmwareFlasher.Library/StmDeviceBase.cs
@@ -35,6 +35,12 @@ public abstract class StmDeviceBase
///
public VerbosityLevel Verbosity { get; set; } = VerbosityLevel.Normal;
+ ///
+ /// Runs the STM32 programmer CLI.
+ ///
+ /// arguments to send.
+ /// The returned message.
+ ///
public static string RunSTM32ProgrammerCLI(string arguments)
{
try
@@ -115,6 +121,11 @@ public static string RunSTM32ProgrammerCLI(string arguments)
}
}
+ ///
+ /// Gets the Error Message From STM32CLI.
+ ///
+ /// The retrived input.
+ /// The outcome.
public static string GetErrorMessageFromSTM32CLI(string cliOutput)
{
var regEx = new Regex(@"Error: (?.+).", RegexOptions.IgnoreCase);
@@ -137,6 +148,10 @@ public static string GetErrorMessageFromSTM32CLI(string cliOutput)
return "";
}
+ ///
+ /// Output to CLI.
+ ///
+ /// Message to display.
public void ShowCLIOutput(string cliOutput)
{
// show CLI output, if verbosity is diagnostic
@@ -159,11 +174,20 @@ public void ShowCLIOutput(string cliOutput)
}
}
+ ///
+ /// Lists all found devices.
+ ///
+ ///
public static string ExecuteListDevices()
{
return RunSTM32ProgrammerCLI("--list");
}
+ ///
+ /// Wipes the whole flash memory of the device.
+ ///
+ /// The device connection details.
+ /// The outcome.
public ExitCodes ExecuteMassErase(string connectDetails)
{
if (Verbosity >= VerbosityLevel.Normal)
@@ -198,6 +222,12 @@ public ExitCodes ExecuteMassErase(string connectDetails)
return ExitCodes.OK;
}
+ ///
+ /// Flash HEX files to device.
+ ///
+ /// The HEX files to flash.
+ /// The device connection details.
+ /// The outcome.
public ExitCodes ExecuteFlashHexFiles(
IList files,
string connectDetails)
@@ -273,6 +303,13 @@ public ExitCodes ExecuteFlashHexFiles(
return ExitCodes.OK;
}
+ ///
+ /// Flash BIN files to device.
+ ///
+ /// The files to flash.
+ /// The memory locations.
+ /// The device connection details.
+ /// The outcome.
public ExitCodes ExecuteFlashBinFiles(
IList files,
IList addresses,
@@ -355,7 +392,7 @@ public ExitCodes ExecuteFlashBinFiles(
var cliOutput = RunSTM32ProgrammerCLI($"-c {connectDetails} mode=UR -w \"{binFilePath}\" {addresses.ElementAt(index++)}");
- if (!cliOutput.Contains("Programming Complete."))
+ if (!cliOutput.Contains("File download complete"))
{
ShowCLIOutput(cliOutput);
diff --git a/nanoFirmwareFlasher.Library/StmDfuDevice.cs b/nanoFirmwareFlasher.Library/StmDfuDevice.cs
index 3155dfde..c1a803cb 100644
--- a/nanoFirmwareFlasher.Library/StmDfuDevice.cs
+++ b/nanoFirmwareFlasher.Library/StmDfuDevice.cs
@@ -11,6 +11,9 @@
namespace nanoFramework.Tools.FirmwareFlasher
{
+ ///
+ /// STM32 DFU Device.
+ ///
public class StmDfuDevice : StmDeviceBase
{
// Device ID of the connected DFU device.
@@ -219,7 +222,7 @@ public ExitCodes StartExecution(string startAddress)
if (dfuMatches.Count == 0)
{
// no DFU device found
- return new List<(string serial, string device)>();
+ return [];
}
return dfuMatches.Cast().Select(i => (serial: i.Groups["serial"].Value, device: i.Groups["device"].Value)).ToList();
diff --git a/nanoFirmwareFlasher.Library/StmJtagDevice.cs b/nanoFirmwareFlasher.Library/StmJtagDevice.cs
index f8831811..e43bba35 100644
--- a/nanoFirmwareFlasher.Library/StmJtagDevice.cs
+++ b/nanoFirmwareFlasher.Library/StmJtagDevice.cs
@@ -11,6 +11,9 @@
namespace nanoFramework.Tools.FirmwareFlasher
{
+ ///
+ /// STM32 JTAG Device.
+ ///
public class StmJtagDevice : StmDeviceBase
{
///
@@ -205,7 +208,7 @@ public static List ListDevices()
if (jtagMatches.Count == 0)
{
// no JTAG found
- return new List();
+ return [];
}
return jtagMatches.Cast().Select(i => i.Value).ToList();
diff --git a/nanoFirmwareFlasher.Library/SupportedPlatform.cs b/nanoFirmwareFlasher.Library/SupportedPlatform.cs
index a57bb309..17d25537 100644
--- a/nanoFirmwareFlasher.Library/SupportedPlatform.cs
+++ b/nanoFirmwareFlasher.Library/SupportedPlatform.cs
@@ -5,11 +5,26 @@
namespace nanoFramework.Tools.FirmwareFlasher
{
+ ///
+ /// Supported Platform.
+ ///
public enum SupportedPlatform
{
+ ///
+ /// ESP32.
+ ///
esp32 = 0,
+ ///
+ /// STM32.
+ ///
stm32 = 1,
+ ///
+ /// TI Simplelink.
+ ///
ti_simplelink = 2,
+ ///
+ /// Silabs GG11.
+ ///
gg11
}
}
diff --git a/nanoFirmwareFlasher.Library/VerbosityLevel.cs b/nanoFirmwareFlasher.Library/VerbosityLevel.cs
index bb5839bb..d8260e06 100644
--- a/nanoFirmwareFlasher.Library/VerbosityLevel.cs
+++ b/nanoFirmwareFlasher.Library/VerbosityLevel.cs
@@ -5,12 +5,30 @@
namespace nanoFramework.Tools.FirmwareFlasher
{
+ ///
+ /// Verbosity Level.
+ ///
public enum VerbosityLevel
{
+ ///
+ /// Quiet.
+ ///
Quiet = 0,
+ ///
+ /// Minimal.
+ ///
Minimal = 1,
+ ///
+ /// Normal.
+ ///
Normal = 2,
+ ///
+ /// Detailed.
+ ///
Detailed = 3,
+ ///
+ /// Diagnostic.
+ ///
Diagnostic = 4
}
}
diff --git a/nanoFirmwareFlasher.Library/nanoFirmwareFlasher.Library.csproj b/nanoFirmwareFlasher.Library/nanoFirmwareFlasher.Library.csproj
index 57b303bc..0b474a2f 100644
--- a/nanoFirmwareFlasher.Library/nanoFirmwareFlasher.Library.csproj
+++ b/nanoFirmwareFlasher.Library/nanoFirmwareFlasher.Library.csproj
@@ -2,7 +2,7 @@
library
- net6.0;net472
+ net8.0;net472
AnyCPU
latest
nanoFramework.Tools.FirmwareFlasher
@@ -29,6 +29,7 @@
True
true
+ true
@@ -58,7 +59,10 @@
-
+
+
+
+
@@ -93,6 +97,8 @@
+
+
@@ -124,5 +130,34 @@
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
diff --git a/nanoFirmwareFlasher.Library/packages.lock.json b/nanoFirmwareFlasher.Library/packages.lock.json
index 3c7d8e10..9390fa32 100644
--- a/nanoFirmwareFlasher.Library/packages.lock.json
+++ b/nanoFirmwareFlasher.Library/packages.lock.json
@@ -2,11 +2,43 @@
"version": 1,
"dependencies": {
".NETFramework,Version=v4.7.2": {
+ "Microsoft.ApplicationInsights": {
+ "type": "Direct",
+ "requested": "[2.22.0, )",
+ "resolved": "2.22.0",
+ "contentHash": "3AOM9bZtku7RQwHyMEY3tQMrHIgjcfRDa6YQpd/QG2LDGvMydSlL9Di+8LLMt7J2RDdfJ7/2jdYv6yHcMJAnNw==",
+ "dependencies": {
+ "System.Diagnostics.DiagnosticSource": "5.0.0"
+ }
+ },
+ "Microsoft.Extensions.Configuration": {
+ "type": "Direct",
+ "requested": "[8.0.0, )",
+ "resolved": "8.0.0",
+ "contentHash": "0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.Configuration.Json": {
+ "type": "Direct",
+ "requested": "[8.0.0, )",
+ "resolved": "8.0.0",
+ "contentHash": "C2wqUoh9OmRL1akaCcKSTmRU8z0kckfImG7zLNI8uyi47Lp+zd5LWAD17waPQEqCz3ioWOCrFUo+JJuoeZLOBw==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "8.0.0",
+ "Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Configuration.FileExtensions": "8.0.0",
+ "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0",
+ "System.Text.Json": "8.0.0"
+ }
+ },
"nanoFramework.Tools.Debugger.Net": {
"type": "Direct",
- "requested": "[2.4.34, )",
- "resolved": "2.4.34",
- "contentHash": "+QLH66C/dceiSlyWyfOEM5lOYZb13w5TjxvuB+ludaKTtD1IsZ4XAeXHen6P98eppgp3OLEus1GfMq7aGDj5Fw==",
+ "requested": "[2.4.42, )",
+ "resolved": "2.4.42",
+ "contentHash": "3RWlCdTOkf0RDHRc+qFs0Di4QP9JLwaa3msLK1WT+XUeIaG45MJo9WLJ+tBS4rXcn0dHQSAKIP17q374WmaMag==",
"dependencies": {
"Polly": "7.2.3",
"PropertyChanged.Fody": "2.6.1",
@@ -51,6 +83,67 @@
"resolved": "4.2.1",
"contentHash": "46t+e1eESclH4TkfqUEYAgZ1+ZbXSFS7GqSKvtcw6u2yT05heDKdzj1r3YA/6FCZM4uB4z7qRW9V+gBsCilonQ=="
},
+ "Microsoft.Bcl.AsyncInterfaces": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "3WA9q9yVqJp222P3x1wYIGDAkpjAku0TMUaaQV22g6L67AI0LdOIrVS7Ht2vJfLHGSPVuqN94vIr15qn+HEkHw==",
+ "dependencies": {
+ "System.Threading.Tasks.Extensions": "4.5.4"
+ }
+ },
+ "Microsoft.Extensions.Configuration.Abstractions": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Primitives": "8.0.0",
+ "System.ValueTuple": "4.5.0"
+ }
+ },
+ "Microsoft.Extensions.Configuration.FileExtensions": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "McP+Lz/EKwvtCv48z0YImw+L1gi1gy5rHhNaNIY2CrjloV+XY8gydT8DjMR6zWeL13AFK+DioVpppwAuO1Gi1w==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "8.0.0",
+ "Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
+ "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0",
+ "Microsoft.Extensions.FileProviders.Physical": "8.0.0",
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.FileProviders.Abstractions": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "ZbaMlhJlpisjuWbvXr4LdAst/1XxH3vZ6A0BsgTphZ2L4PGuxRLz7Jr/S7mkAAnOn78Vu0fKhEgNF5JO3zfjqQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.FileProviders.Physical": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "UboiXxpPUpwulHvIAVE36Knq0VSHaAmfrFkegLyBZeaADuKezJ/AIXYAW8F5GBlGk/VaibN2k/Zn1ca8YAfVdA==",
+ "dependencies": {
+ "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0",
+ "Microsoft.Extensions.FileSystemGlobbing": "8.0.0",
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.FileSystemGlobbing": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ=="
+ },
+ "Microsoft.Extensions.Primitives": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==",
+ "dependencies": {
+ "System.Memory": "4.5.5",
+ "System.Runtime.CompilerServices.Unsafe": "6.0.0"
+ }
+ },
"Polly": {
"type": "Transitive",
"resolved": "7.2.3",
@@ -64,16 +157,50 @@
"Fody": "4.2.1"
}
},
+ "System.Buffers": {
+ "type": "Transitive",
+ "resolved": "4.5.1",
+ "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg=="
+ },
+ "System.Diagnostics.DiagnosticSource": {
+ "type": "Transitive",
+ "resolved": "5.0.0",
+ "contentHash": "tCQTzPsGZh/A9LhhA6zrqCRV4hOHsK90/G7q3Khxmn6tnB1PuNU0cRaKANP2AWcF9bn0zsuOoZOSrHuJk6oNBA==",
+ "dependencies": {
+ "System.Memory": "4.5.4",
+ "System.Runtime.CompilerServices.Unsafe": "5.0.0"
+ }
+ },
"System.IO": {
"type": "Transitive",
"resolved": "4.3.0",
"contentHash": "3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg=="
},
+ "System.Memory": {
+ "type": "Transitive",
+ "resolved": "4.5.5",
+ "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==",
+ "dependencies": {
+ "System.Buffers": "4.5.1",
+ "System.Numerics.Vectors": "4.5.0",
+ "System.Runtime.CompilerServices.Unsafe": "4.5.3"
+ }
+ },
+ "System.Numerics.Vectors": {
+ "type": "Transitive",
+ "resolved": "4.5.0",
+ "contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ=="
+ },
"System.Runtime": {
"type": "Transitive",
"resolved": "4.3.0",
"contentHash": "JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw=="
},
+ "System.Runtime.CompilerServices.Unsafe": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
+ },
"System.Security.Cryptography.Algorithms": {
"type": "Transitive",
"resolved": "4.3.0",
@@ -103,14 +230,83 @@
"System.Security.Cryptography.Algorithms": "4.3.0",
"System.Security.Cryptography.Encoding": "4.3.0"
}
+ },
+ "System.Text.Encodings.Web": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==",
+ "dependencies": {
+ "System.Buffers": "4.5.1",
+ "System.Memory": "4.5.5",
+ "System.Runtime.CompilerServices.Unsafe": "6.0.0"
+ }
+ },
+ "System.Text.Json": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "OdrZO2WjkiEG6ajEFRABTRCi/wuXQPxeV6g8xvUJqdxMvvuCCEk86zPla8UiIQJz3durtUEbNyY/3lIhS0yZvQ==",
+ "dependencies": {
+ "Microsoft.Bcl.AsyncInterfaces": "8.0.0",
+ "System.Buffers": "4.5.1",
+ "System.Memory": "4.5.5",
+ "System.Runtime.CompilerServices.Unsafe": "6.0.0",
+ "System.Text.Encodings.Web": "8.0.0",
+ "System.Threading.Tasks.Extensions": "4.5.4",
+ "System.ValueTuple": "4.5.0"
+ }
+ },
+ "System.Threading.Tasks.Extensions": {
+ "type": "Transitive",
+ "resolved": "4.5.4",
+ "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==",
+ "dependencies": {
+ "System.Runtime.CompilerServices.Unsafe": "4.5.3"
+ }
+ },
+ "System.ValueTuple": {
+ "type": "Transitive",
+ "resolved": "4.5.0",
+ "contentHash": "okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ=="
}
},
- "net6.0": {
+ "net8.0": {
+ "Microsoft.ApplicationInsights": {
+ "type": "Direct",
+ "requested": "[2.22.0, )",
+ "resolved": "2.22.0",
+ "contentHash": "3AOM9bZtku7RQwHyMEY3tQMrHIgjcfRDa6YQpd/QG2LDGvMydSlL9Di+8LLMt7J2RDdfJ7/2jdYv6yHcMJAnNw==",
+ "dependencies": {
+ "System.Diagnostics.DiagnosticSource": "5.0.0"
+ }
+ },
+ "Microsoft.Extensions.Configuration": {
+ "type": "Direct",
+ "requested": "[8.0.0, )",
+ "resolved": "8.0.0",
+ "contentHash": "0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.Configuration.Json": {
+ "type": "Direct",
+ "requested": "[8.0.0, )",
+ "resolved": "8.0.0",
+ "contentHash": "C2wqUoh9OmRL1akaCcKSTmRU8z0kckfImG7zLNI8uyi47Lp+zd5LWAD17waPQEqCz3ioWOCrFUo+JJuoeZLOBw==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "8.0.0",
+ "Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Configuration.FileExtensions": "8.0.0",
+ "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0",
+ "System.Text.Json": "8.0.0"
+ }
+ },
"nanoFramework.Tools.Debugger.Net": {
"type": "Direct",
- "requested": "[2.4.34, )",
- "resolved": "2.4.34",
- "contentHash": "+QLH66C/dceiSlyWyfOEM5lOYZb13w5TjxvuB+ludaKTtD1IsZ4XAeXHen6P98eppgp3OLEus1GfMq7aGDj5Fw==",
+ "requested": "[2.4.42, )",
+ "resolved": "2.4.42",
+ "contentHash": "3RWlCdTOkf0RDHRc+qFs0Di4QP9JLwaa3msLK1WT+XUeIaG45MJo9WLJ+tBS4rXcn0dHQSAKIP17q374WmaMag==",
"dependencies": {
"Polly": "7.2.3",
"PropertyChanged.Fody": "2.6.1",
@@ -183,6 +379,54 @@
"resolved": "4.2.1",
"contentHash": "46t+e1eESclH4TkfqUEYAgZ1+ZbXSFS7GqSKvtcw6u2yT05heDKdzj1r3YA/6FCZM4uB4z7qRW9V+gBsCilonQ=="
},
+ "Microsoft.Extensions.Configuration.Abstractions": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.Configuration.FileExtensions": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "McP+Lz/EKwvtCv48z0YImw+L1gi1gy5rHhNaNIY2CrjloV+XY8gydT8DjMR6zWeL13AFK+DioVpppwAuO1Gi1w==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "8.0.0",
+ "Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
+ "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0",
+ "Microsoft.Extensions.FileProviders.Physical": "8.0.0",
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.FileProviders.Abstractions": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "ZbaMlhJlpisjuWbvXr4LdAst/1XxH3vZ6A0BsgTphZ2L4PGuxRLz7Jr/S7mkAAnOn78Vu0fKhEgNF5JO3zfjqQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.FileProviders.Physical": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "UboiXxpPUpwulHvIAVE36Knq0VSHaAmfrFkegLyBZeaADuKezJ/AIXYAW8F5GBlGk/VaibN2k/Zn1ca8YAfVdA==",
+ "dependencies": {
+ "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0",
+ "Microsoft.Extensions.FileSystemGlobbing": "8.0.0",
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.FileSystemGlobbing": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ=="
+ },
+ "Microsoft.Extensions.Primitives": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g=="
+ },
"Microsoft.NETCore.Platforms": {
"type": "Transitive",
"resolved": "1.1.1",
@@ -483,15 +727,8 @@
},
"System.Diagnostics.DiagnosticSource": {
"type": "Transitive",
- "resolved": "4.3.0",
- "contentHash": "tD6kosZnTAGdrEa0tZSuFyunMbt/5KYDnHdndJYGqZoNy00XVXyACd5d6KnE1YgYv3ne2CjtAfNXo/fwEhnKUA==",
- "dependencies": {
- "System.Collections": "4.3.0",
- "System.Diagnostics.Tracing": "4.3.0",
- "System.Reflection": "4.3.0",
- "System.Runtime": "4.3.0",
- "System.Threading": "4.3.0"
- }
+ "resolved": "5.0.0",
+ "contentHash": "tCQTzPsGZh/A9LhhA6zrqCRV4hOHsK90/G7q3Khxmn6tnB1PuNU0cRaKANP2AWcF9bn0zsuOoZOSrHuJk6oNBA=="
},
"System.Diagnostics.Tools": {
"type": "Transitive",
@@ -1011,6 +1248,19 @@
"System.Text.Encoding": "4.3.0"
}
},
+ "System.Text.Encodings.Web": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ=="
+ },
+ "System.Text.Json": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "OdrZO2WjkiEG6ajEFRABTRCi/wuXQPxeV6g8xvUJqdxMvvuCCEk86zPla8UiIQJz3durtUEbNyY/3lIhS0yZvQ==",
+ "dependencies": {
+ "System.Text.Encodings.Web": "8.0.0"
+ }
+ },
"System.Text.RegularExpressions": {
"type": "Transitive",
"resolved": "4.3.0",
diff --git a/nanoFirmwareFlasher.Tests/packages.lock.json b/nanoFirmwareFlasher.Tests/packages.lock.json
deleted file mode 100644
index 2ce9903c..00000000
--- a/nanoFirmwareFlasher.Tests/packages.lock.json
+++ /dev/null
@@ -1,73 +0,0 @@
-{
- "version": 1,
- "dependencies": {
- "net6.0": {
- "coverlet.collector": {
- "type": "Direct",
- "requested": "[6.0.0, )",
- "resolved": "6.0.0",
- "contentHash": "tW3lsNS+dAEII6YGUX/VMoJjBS1QvsxqJeqLaJXub08y1FSjasFPtQ4UBUsudE9PNrzLjooClMsPtY2cZLdXpQ=="
- },
- "Microsoft.NET.Test.Sdk": {
- "type": "Direct",
- "requested": "[17.6.0, )",
- "resolved": "17.6.0",
- "contentHash": "tHyg4C6c89QvLv6Utz3xKlba4EeoyJyIz59Q1NrjRENV7gfGnSE6I+sYPIbVOzQttoo2zpHDgOK/p6Hw2OlD7A==",
- "dependencies": {
- "Microsoft.CodeCoverage": "17.6.0",
- "Microsoft.TestPlatform.TestHost": "17.6.0"
- }
- },
- "MSTest.TestAdapter": {
- "type": "Direct",
- "requested": "[3.0.3, )",
- "resolved": "3.0.3",
- "contentHash": "k2LRhIKbgc0HQQvTYZVsBby3I1V9q4h+xbXP3A0yQuB1jEeMze/JnJb3UCyUUElSx1CAfmyMazuTfbYaZwqZGw=="
- },
- "MSTest.TestFramework": {
- "type": "Direct",
- "requested": "[3.0.3, )",
- "resolved": "3.0.3",
- "contentHash": "7EN6HmpSuNBnk3UP/FHvg3VeL13Gwc/D5vtZ+SFIkzDO99avVm8oYqbe19JCht4wy9cY13dpNA4gssCE8hp08Q=="
- },
- "Microsoft.CodeCoverage": {
- "type": "Transitive",
- "resolved": "17.6.0",
- "contentHash": "5v2GwzpR7JEuQUzupjx3zLwn2FutADW/weLzLt726DR3WXxsM+ICPoJG6pxuKFsumtZp890UrVuudTUhsE8Qyg=="
- },
- "Microsoft.TestPlatform.ObjectModel": {
- "type": "Transitive",
- "resolved": "17.6.0",
- "contentHash": "AA/rrf5zwC5/OBLEOajkhjbVTM3SvxRXy8kcQ8e4mJKojbyZvqqhpfNg362N9vXU94DLg9NUTFOAnoYVT0pTJw==",
- "dependencies": {
- "NuGet.Frameworks": "5.11.0",
- "System.Reflection.Metadata": "1.6.0"
- }
- },
- "Microsoft.TestPlatform.TestHost": {
- "type": "Transitive",
- "resolved": "17.6.0",
- "contentHash": "7YdgUcIeCPVKLC7n7LNKDiEHWc7z3brkkYPdUbDnFsvf6WvY9UfzS0VSUJ8P2NgN0CDSD223GCJFSjSBLZRqOQ==",
- "dependencies": {
- "Microsoft.TestPlatform.ObjectModel": "17.6.0",
- "Newtonsoft.Json": "13.0.1"
- }
- },
- "Newtonsoft.Json": {
- "type": "Transitive",
- "resolved": "13.0.1",
- "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A=="
- },
- "NuGet.Frameworks": {
- "type": "Transitive",
- "resolved": "5.11.0",
- "contentHash": "eaiXkUjC4NPcquGWzAGMXjuxvLwc6XGKMptSyOGQeT0X70BUZObuybJFZLA0OfTdueLd3US23NBPTBb6iF3V1Q=="
- },
- "System.Reflection.Metadata": {
- "type": "Transitive",
- "resolved": "1.6.0",
- "contentHash": "COC1aiAJjCoA5GBF+QKL2uLqEBew4JsCkQmoHKbN3TlOZKa2fKLz5CpiRQKDz0RsAOEGsVKqOD5bomsXq/4STQ=="
- }
- }
- }
-}
\ No newline at end of file
diff --git a/nanoFirmwareFlasher.Tool/Esp32Manager.cs b/nanoFirmwareFlasher.Tool/Esp32Manager.cs
new file mode 100644
index 00000000..6d3d2f44
--- /dev/null
+++ b/nanoFirmwareFlasher.Tool/Esp32Manager.cs
@@ -0,0 +1,205 @@
+//
+// Copyright (c) .NET Foundation and Contributors
+// See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace nanoFramework.Tools.FirmwareFlasher
+{
+ ///
+ /// Class to manage different operations specific to the ESP32 platform.
+ ///
+ public class Esp32Manager : IManager
+ {
+ private readonly Options _options;
+ private readonly VerbosityLevel _verbosityLevel;
+
+ public Esp32Manager(Options options, VerbosityLevel verbosityLevel)
+ {
+ if (options == null)
+ {
+ throw new ArgumentNullException(nameof(options));
+ }
+
+ if (options.Platform != SupportedPlatform.esp32)
+ {
+ throw new NotSupportedException($"{nameof(options)} - {options.Platform}");
+ }
+
+ _options = options;
+ _verbosityLevel = verbosityLevel;
+ }
+
+ ///
+ public async Task ProcessAsync()
+ {
+ // COM port is mandatory for ESP32
+ if (string.IsNullOrEmpty(_options.SerialPort))
+ {
+ return ExitCodes.E6001;
+ }
+
+ EspTool espTool;
+
+ try
+ {
+ espTool = new EspTool(
+ _options.SerialPort,
+ _options.BaudRate,
+ _options.Esp32FlashMode,
+ _options.Esp32FlashFrequency,
+ _options.Esp32PartitionTableSize,
+ _verbosityLevel);
+ }
+ catch (Exception)
+ {
+ return ExitCodes.E4005;
+ }
+
+ Esp32DeviceInfo esp32Device;
+
+ if (espTool.ComPortAvailable)
+ {
+ esp32Device = espTool.GetDeviceDetails(
+ _options.TargetName,
+ // if partition table size is specified, no need to get flash size
+ _options.Esp32PartitionTableSize == null,
+ _options.CheckPsRam);
+ }
+ else
+ {
+ // couldn't open COM port
+ // done here, this command has no further processing
+ return ExitCodes.E6000;
+ }
+
+ if (_verbosityLevel >= VerbosityLevel.Normal)
+ {
+ Console.ForegroundColor = ConsoleColor.Cyan;
+
+ Console.WriteLine("");
+ Console.WriteLine($"Connected to:");
+ Console.WriteLine($"{esp32Device}");
+
+ Console.ForegroundColor = ConsoleColor.White;
+
+ // if this is a PICO and baud rate is not 115200 or 1M5, operations will most likely fail
+ // warn user about this
+ if (
+ esp32Device.ChipName.Contains("ESP32-PICO")
+ && (_options.BaudRate != 115200
+ && _options.BaudRate != 1500000))
+ {
+ Console.ForegroundColor = ConsoleColor.Yellow;
+
+ Console.WriteLine("");
+ Console.WriteLine("****************************** WARNING ******************************");
+ Console.WriteLine("The connected device it's an ESP32 PICO which can be picky about the ");
+ Console.WriteLine("baud rate used. Recommendation is to use --baud 115200 ");
+ Console.WriteLine("*********************************************************************");
+ Console.WriteLine("");
+
+ Console.ForegroundColor = ConsoleColor.White;
+ }
+ }
+
+ // set verbosity
+ espTool.Verbosity = _verbosityLevel;
+
+ // backup requested
+ // Should backup be an unique operation => exit whatever success or not ?
+ // In this case, should find how manage a NoOperationPerformedException info
+ if (!string.IsNullOrEmpty(_options.BackupPath) ||
+ !string.IsNullOrEmpty(_options.BackupFile))
+ {
+ // backup path specified, backup deployment
+ var exitCode = Esp32Operations.BackupFlash(espTool, esp32Device, _options.BackupPath, _options.BackupFile, _verbosityLevel);
+
+ if (exitCode != ExitCodes.OK)
+ {
+ // done here
+ return exitCode;
+ }
+ }
+
+ // show device details
+ if (_options.DeviceDetails)
+ {
+ // device details already output
+ return ExitCodes.OK;
+ }
+
+ bool updateAndDeploy = false;
+
+ // update operation requested?
+ if (_options.Update)
+ {
+ // write flash
+ var exitCode = await Esp32Operations.UpdateFirmwareAsync(
+ espTool,
+ esp32Device,
+ _options.TargetName,
+ true,
+ _options.FwVersion,
+ _options.Preview,
+ _options.DeploymentImage,
+ null,
+ _options.ClrFile,
+ !_options.FitCheck,
+ _options.MassErase,
+ _verbosityLevel,
+ _options.Esp32PartitionTableSize);
+
+ if (exitCode != ExitCodes.OK)
+ {
+ // done here
+ return exitCode;
+ }
+
+ updateAndDeploy = true;
+ }
+
+ // deploy without update
+ if (_options.Deploy && !_options.Update)
+ {
+ // need to take care of flash address
+ string appFlashAddress = string.Empty;
+
+ if (_options.FlashAddress.Any())
+ {
+ // take the first address, it should be the only one valid
+ appFlashAddress = _options.FlashAddress.ElementAt(0);
+ }
+
+ // this to flash a deployment image without updating the firmware
+ // write flash
+ var exitCode = await Esp32Operations.DeployApplicationAsync(
+ espTool,
+ esp32Device,
+ _options.TargetName,
+ _options.DeploymentImage,
+ appFlashAddress,
+ _verbosityLevel,
+ _options.Esp32PartitionTableSize);
+
+ if (exitCode != ExitCodes.OK)
+ {
+ // done here
+ return exitCode;
+ }
+
+ updateAndDeploy = true;
+ }
+
+ if (!updateAndDeploy)
+ {
+ throw new NoOperationPerformedException();
+ }
+
+ return ExitCodes.OK;
+ }
+ }
+}
diff --git a/nanoFirmwareFlasher.Tool/NanoDeviceManager.cs b/nanoFirmwareFlasher.Tool/NanoDeviceManager.cs
new file mode 100644
index 00000000..ed23b99b
--- /dev/null
+++ b/nanoFirmwareFlasher.Tool/NanoDeviceManager.cs
@@ -0,0 +1,91 @@
+using nanoFramework.Tools.Debugger;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace nanoFramework.Tools.FirmwareFlasher
+{
+ ///
+ /// Class to manage different operations specific to the nano devices.
+ ///
+ public class NanoDeviceManager : IManager
+ {
+ private readonly Options _options;
+ private readonly VerbosityLevel _verbosityLevel;
+
+ public NanoDeviceManager(Options options, VerbosityLevel verbosityLevel)
+ {
+ if (options == null)
+ {
+ throw new ArgumentNullException(nameof(options));
+ }
+
+ _options = options;
+ _verbosityLevel = verbosityLevel;
+ }
+
+ ///
+ public async Task ProcessAsync()
+ {
+ bool failedToDoSomething = true;
+ ExitCodes exitCode = ExitCodes.OK;
+
+ // COM port is mandatory for nano device operations
+ if (string.IsNullOrEmpty(_options.SerialPort))
+ {
+ return ExitCodes.E6001;
+ }
+
+ NanoDeviceOperations _nanoDeviceOperations = new NanoDeviceOperations();
+
+ if (_options.DeviceDetails)
+ {
+ NanoDeviceBase nanoDevice = null;
+ return _nanoDeviceOperations.GetDeviceDetails(
+ _options.SerialPort,
+ ref nanoDevice);
+ }
+ else if (_options.Update)
+ {
+ exitCode = await _nanoDeviceOperations.UpdateDeviceClrAsync(
+ _options.SerialPort,
+ _options.FwVersion,
+ _options.ClrFile,
+ _verbosityLevel);
+
+ if (exitCode != ExitCodes.OK)
+ {
+ return exitCode;
+ }
+
+ // flag operation as done
+ failedToDoSomething = false;
+ }
+
+ if (_options.Deploy)
+ {
+ exitCode = _nanoDeviceOperations.DeployApplication(
+ _options.SerialPort,
+ _options.DeploymentImage,
+ _verbosityLevel);
+
+ if (exitCode != ExitCodes.OK)
+ {
+ return exitCode;
+ }
+
+ // flag operation as done
+ failedToDoSomething = false;
+ }
+
+ if (failedToDoSomething)
+ {
+ throw new NoOperationPerformedException();
+ }
+
+ return exitCode;
+ }
+ }
+}
diff --git a/nanoFirmwareFlasher.Tool/Options.cs b/nanoFirmwareFlasher.Tool/Options.cs
index 7ae44a9f..02bdb0c2 100644
--- a/nanoFirmwareFlasher.Tool/Options.cs
+++ b/nanoFirmwareFlasher.Tool/Options.cs
@@ -133,6 +133,13 @@ public class Options
HelpText = "Partition table size to use. Valid sizes are: 2, 4, 8 and 16.")]
public PartitionTableSize? Esp32PartitionTableSize { get; set; }
+ [Option(
+ "checkpsram",
+ Required = false,
+ Default = false,
+ HelpText = "Perform check for PSRAM in device.")]
+ public bool CheckPsRam { get; set; }
+
#endregion
@@ -282,7 +289,7 @@ public class Options
[Option(
"address",
Required = false,
- HelpText = "Address(es) where to flash the BIN file(s). Hexadecimal format (e.g. 0x08000000). Required when specifying a BIN file with -binfile argument or flashing a deployment image with -deployment argument.")]
+ HelpText = "Address(es) where to flash the BIN file(s). Hexadecimal format (e.g. 0x08000000). Required when specifying a BIN file with --binfile argument or flashing a deployment image with --deploy argument.")]
public IList FlashAddress { get; set; }
[Option(
@@ -334,13 +341,19 @@ public class Options
HelpText = "Reads details from connected device.")]
public bool DeviceDetails { get; set; }
+ [Option(
+ "filedeployment",
+ Required = false,
+ Default = null,
+ HelpText = "JSON file containing file deployment settings.")]
+ public string FileDeployment { get; set; }
+
#endregion
[Usage(ApplicationAlias = "nanoff")]
public static IEnumerable Examples =>
- new List
- {
+ [
new("- Update ESP32 WROVER Kit device with latest available firmware", new Options { TargetName = "ESP_WROVER_KIT", Update = true }),
new("- Update specific STM32 device (ST_STM32F769I_DISCOVERY) with latest available firmware, using JTAG interface", new Options { TargetName = "ST_STM32F769I_DISCOVERY" , Update = true, JtagUpdate = true}),
new("- Update ESP32 device with latest available firmware (stable version), device is connected to COM31", new Options { Platform = SupportedPlatform.esp32, Update = true, SerialPort = "COM31" }),
@@ -350,6 +363,6 @@ public class Options
new("- Install STM32 JTAG drivers", new Options { InstallJtagDrivers = true}),
new("- List all available STM32 targets", new Options { ListTargets = true, Platform = SupportedPlatform.stm32 }),
new("- List all available COM ports", new Options { ListComPorts = true }),
- };
+ ];
}
}
diff --git a/nanoFirmwareFlasher.Tool/Program.cs b/nanoFirmwareFlasher.Tool/Program.cs
index 19503969..ed131e37 100644
--- a/nanoFirmwareFlasher.Tool/Program.cs
+++ b/nanoFirmwareFlasher.Tool/Program.cs
@@ -5,8 +5,9 @@
using CommandLine;
using CommandLine.Text;
-using nanoFramework.Tools.Debugger;
+using Microsoft.Extensions.Configuration;
using nanoFramework.Tools.FirmwareFlasher.Extensions;
+using nanoFramework.Tools.FirmwareFlasher.FileDeployment;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
@@ -17,7 +18,6 @@
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
-using System.Threading;
using System.Threading.Tasks;
namespace nanoFramework.Tools.FirmwareFlasher
@@ -32,8 +32,6 @@ internal class Program
private static CopyrightInfo _copyrightInfo;
private static NanoDeviceOperations _nanoDeviceOperations;
- internal static string ExecutingPath;
-
public static async Task Main(string[] args)
{
// take care of static fields
@@ -49,7 +47,15 @@ public static async Task Main(string[] args)
// need this to be able to use ProcessStart at the location where the .NET Core CLI tool is running from
string codeBase = Assembly.GetExecutingAssembly().Location;
var fullPath = Path.GetFullPath(codeBase);
- ExecutingPath = Path.GetDirectoryName(fullPath);
+ var ExecutingPath = Path.GetDirectoryName(fullPath);
+
+ // grab AppInsights connection string to setup telemetry client
+ IConfigurationRoot appConfigurationRoot = new ConfigurationBuilder()
+ .SetBasePath(ExecutingPath)
+ .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
+ .Build();
+
+ NanoTelemetryClient.ConnectionString = appConfigurationRoot?["iConnectionString"];
// check for empty argument collection
if (!args.Any())
@@ -59,7 +65,7 @@ public static async Task Main(string[] args)
// because of short-comings in CommandLine parsing
// need to customize the output to provide a consistent output
var parser = new Parser(config => config.HelpWriter = null);
- var result = parser.ParseArguments(new[] { "", "" });
+ var result = parser.ParseArguments(new string[] { "", "" });
var helpText = new HelpText(
new HeadingInfo(_headerInfo),
@@ -95,7 +101,7 @@ await parsedArguments
if (_verbosityLevel > VerbosityLevel.Quiet)
{
- OutputError(_exitCode, _verbosityLevel > VerbosityLevel.Normal, _extraMessage);
+ OutputError(_exitCode, _verbosityLevel >= VerbosityLevel.Normal, _extraMessage);
}
// force clean-up
@@ -145,6 +151,10 @@ private static void CheckVersion()
private static Task HandleErrorsAsync(IEnumerable errors)
{
+ if (errors.All(e => e.Tag == ErrorType.HelpRequestedError || e.Tag == ErrorType.VersionRequestedError))
+ {
+ return Task.CompletedTask;
+ }
_exitCode = ExitCodes.E9000;
return Task.CompletedTask;
}
@@ -297,7 +307,7 @@ static async Task RunOptionsAndReturnExitCodeAsync(Options o)
{
var connectedDevices = _nanoDeviceOperations.ListDevices(_verbosityLevel > VerbosityLevel.Normal);
- if (connectedDevices.Count() == 0)
+ if (!connectedDevices.Any())
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("No devices found");
@@ -362,93 +372,41 @@ static async Task RunOptionsAndReturnExitCodeAsync(Options o)
if (o.NanoDevice)
{
- // COM port is mandatory for nano device operations
- if (string.IsNullOrEmpty(o.SerialPort))
+ // check for invalid options passed with nano device operations
+ if (o.Platform.HasValue
+ || !string.IsNullOrEmpty(o.TargetName))
{
- _exitCode = ExitCodes.E6001;
+ _exitCode = ExitCodes.E9000;
+ _extraMessage = "Incompatible options combined with --nanodevice.";
return;
}
- _nanoDeviceOperations = new NanoDeviceOperations();
+ var manager = new NanoDeviceManager(o, _verbosityLevel);
- if (o.DeviceDetails)
+ // COM port is mandatory for nano device operations
+ if (string.IsNullOrEmpty(o.SerialPort))
{
- try
- {
- NanoDeviceBase nanoDevice = null;
- _exitCode = _nanoDeviceOperations.GetDeviceDetails(
- o.SerialPort,
- ref nanoDevice);
-
- // done here
- return;
- }
- catch (CantConnectToNanoDeviceException ex)
- {
- _exitCode = ExitCodes.E2000;
- _extraMessage = ex.Message;
-
- return;
- }
+ _exitCode = ExitCodes.E6001;
}
- else if (o.Update)
+ else
{
try
{
- _exitCode = await _nanoDeviceOperations.UpdateDeviceClrAsync(
- o.SerialPort,
- o.FwVersion,
- o.ClrFile,
- _verbosityLevel);
-
- if (_exitCode != ExitCodes.OK)
- {
- return;
- }
+ _exitCode = await manager.ProcessAsync();
}
catch (CantConnectToNanoDeviceException ex)
{
_exitCode = ExitCodes.E2001;
_extraMessage = ex.Message;
-
- return;
- }
- catch (Exception ex)
- {
- _exitCode = ExitCodes.E2002;
- _extraMessage = ex.Message;
-
- return;
}
- }
-
- if (o.Deploy)
- {
- try
+ catch (NoOperationPerformedException)
{
- _exitCode = _nanoDeviceOperations.DeployApplication(
- o.SerialPort,
- o.DeploymentImage,
- _verbosityLevel);
-
- if (_exitCode != ExitCodes.OK)
- {
- return;
- }
- }
- catch (CantConnectToNanoDeviceException ex)
- {
- _exitCode = ExitCodes.E2001;
- _extraMessage = ex.Message;
-
- return;
+ DisplayNoOperationMessage();
}
catch (Exception ex)
{
_exitCode = ExitCodes.E2002;
_extraMessage = ex.Message;
-
- return;
}
}
@@ -461,8 +419,16 @@ static async Task RunOptionsAndReturnExitCodeAsync(Options o)
// if a target name was specified, try to be smart and set the platform accordingly (in case it wasn't specified)
if (o.Platform == null
- && !string.IsNullOrEmpty(o.TargetName))
+ && !string.IsNullOrEmpty(o.TargetName))
{
+ // check for invalid options passed with platform option
+ if (o.NanoDevice)
+ {
+ _exitCode = ExitCodes.E9000;
+ _extraMessage = "Incompatible options combined with --platform.";
+ return;
+ }
+
// easiest one: ESP32
if (o.TargetName.StartsWith("ESP")
|| o.TargetName.StartsWith("M5")
@@ -545,10 +511,10 @@ static async Task RunOptionsAndReturnExitCodeAsync(Options o)
}
// ESP32 related
else if (
- !string.IsNullOrEmpty(o.SerialPort) ||
- (o.BaudRate != 921600) ||
+ !string.IsNullOrEmpty(o.SerialPort) &&
+ ((o.BaudRate != 921600) ||
(o.Esp32FlashMode != "dio") ||
- (o.Esp32FlashFrequency != 40))
+ (o.Esp32FlashFrequency != 40)))
{
o.Platform = SupportedPlatform.esp32;
}
@@ -560,232 +526,39 @@ static async Task RunOptionsAndReturnExitCodeAsync(Options o)
if (o.Platform == SupportedPlatform.esp32)
{
- // COM port is mandatory for ESP32
- if (string.IsNullOrEmpty(o.SerialPort))
- {
- _exitCode = ExitCodes.E6001;
- return;
- }
-
- EspTool espTool;
+ var manager = new Esp32Manager(o, _verbosityLevel);
try
{
- espTool = new EspTool(
- o.SerialPort,
- o.BaudRate,
- o.Esp32FlashMode,
- o.Esp32FlashFrequency,
- o.Esp32PartitionTableSize,
- _verbosityLevel);
- }
- catch (Exception)
- {
- _exitCode = ExitCodes.E4005;
- return;
+ _exitCode = await manager.ProcessAsync();
}
-
- Esp32DeviceInfo esp32Device;
-
- if (espTool.ComPortAvailable)
+ catch (EspToolExecutionException ex)
{
- try
- {
- esp32Device = espTool.GetDeviceDetails(o.TargetName, o.Esp32PartitionTableSize == null);
- }
- catch (EspToolExecutionException ex)
- {
- _exitCode = ExitCodes.E4000;
- _extraMessage = ex.Message;
-
- return;
- }
- }
- else
- {
- // couldn't open COM port
- // done here, this command has no further processing
- _exitCode = ExitCodes.E6000;
-
- return;
+ _exitCode = ExitCodes.E4000;
+ _extraMessage = ex.Message;
}
-
- if (_verbosityLevel >= VerbosityLevel.Normal)
+ catch (ReadEsp32FlashException ex)
{
- Console.ForegroundColor = ConsoleColor.Cyan;
-
- Console.WriteLine("");
- Console.WriteLine($"Connected to:");
- Console.WriteLine($"{esp32Device}");
-
- Console.ForegroundColor = ConsoleColor.White;
-
- // if this is a PICO and baud rate is not 115200 or 1M5, operations will most likely fail
- // warn user about this
- if (
- esp32Device.ChipName.Contains("ESP32-PICO")
- && (o.BaudRate != 115200
- && o.BaudRate != 1500000))
- {
- Console.ForegroundColor = ConsoleColor.Yellow;
-
- Console.WriteLine("");
- Console.WriteLine("****************************** WARNING ******************************");
- Console.WriteLine("The connected device it's an ESP32 PICO which can be picky about the ");
- Console.WriteLine("baud rate used. Recommendation is to use --baud 115200 ");
- Console.WriteLine("*********************************************************************");
- Console.WriteLine("");
-
- Console.ForegroundColor = ConsoleColor.White;
- }
+ _exitCode = ExitCodes.E4004;
+ _extraMessage = ex.Message;
}
-
- // set verbosity
- espTool.Verbosity = _verbosityLevel;
-
- // backup requested
- if (!string.IsNullOrEmpty(o.BackupPath) ||
- !string.IsNullOrEmpty(o.BackupFile))
+ catch (WriteEsp32FlashException ex)
{
- try
- {
- // backup path specified, backup deployment
- _exitCode = Esp32Operations.BackupFlash(espTool, esp32Device, o.BackupPath, o.BackupFile, _verbosityLevel);
-
- if (_exitCode != ExitCodes.OK)
- {
- // done here
- return;
- }
-
- operationPerformed = true;
- }
- catch (ReadEsp32FlashException ex)
- {
- _exitCode = ExitCodes.E4004;
- _extraMessage = ex.Message;
-
- // done here
- return;
- }
+ _exitCode = ExitCodes.E4003;
+ _extraMessage = ex.Message;
}
-
- // show device details
- if (o.DeviceDetails)
+ catch (NoOperationPerformedException)
{
- // device details already output
- _exitCode = ExitCodes.OK;
-
- // done here
- return;
+ DisplayNoOperationMessage();
}
-
- // update operation requested?
- if (o.Update)
- {
- try
- {
- // write flash
- _exitCode = await Esp32Operations.UpdateFirmwareAsync(
- espTool,
- esp32Device,
- o.TargetName,
- true,
- o.FwVersion,
- o.Preview,
- o.DeploymentImage,
- null,
- o.ClrFile,
- !o.FitCheck,
- _verbosityLevel,
- o.Esp32PartitionTableSize);
-
- if (_exitCode != ExitCodes.OK)
- {
- // done here
- return;
- }
-
- // done here
- _exitCode = ExitCodes.OK;
- return;
- }
- catch (ReadEsp32FlashException ex)
- {
- _exitCode = ExitCodes.E4004;
- _extraMessage = ex.Message;
- }
- catch (WriteEsp32FlashException ex)
- {
- _exitCode = ExitCodes.E4003;
- _extraMessage = ex.Message;
- }
- catch (EspToolExecutionException ex)
- {
- _exitCode = ExitCodes.E4000;
- _extraMessage = ex.Message;
- }
- }
-
- // it's OK to deploy after update
- if (o.Deploy)
+ catch (Exception ex)
{
- // need to take care of flash address
- string appFlashAddress = string.Empty;
-
- if (o.FlashAddress.Any())
- {
- // take the first address, it should be the only one valid
- appFlashAddress = o.FlashAddress.ElementAt(0);
- }
-
- // this to flash a deployment image without updating the firmware
- try
- {
- // write flash
- _exitCode = await Esp32Operations.UpdateFirmwareAsync(
- espTool,
- esp32Device,
- o.TargetName,
- false,
- null,
- false,
- o.DeploymentImage,
- appFlashAddress,
- null,
- !o.FitCheck,
- _verbosityLevel,
- o.Esp32PartitionTableSize);
-
- if (_exitCode != ExitCodes.OK)
- {
- // done here
- return;
- }
-
- // done here
- _exitCode = ExitCodes.OK;
- return;
- }
- catch (ReadEsp32FlashException ex)
- {
- _exitCode = ExitCodes.E4004;
- _extraMessage = ex.Message;
- }
- catch (WriteEsp32FlashException ex)
- {
- _exitCode = ExitCodes.E4003;
- _extraMessage = ex.Message;
- }
- catch (EspToolExecutionException ex)
- {
- _exitCode = ExitCodes.E4000;
- _extraMessage = ex.Message;
- }
+ // exception with
+ _exitCode = ExitCodes.E4000;
+ _extraMessage = ex.Message;
}
- // done here
- return;
+ operationPerformed = true;
}
#endregion
@@ -794,353 +567,34 @@ static async Task RunOptionsAndReturnExitCodeAsync(Options o)
if (o.Platform == SupportedPlatform.stm32)
{
- if (o.InstallDfuDrivers)
- {
- _exitCode = Stm32Operations.InstallDfuDrivers(_verbosityLevel);
+ var manager = new Stm32Manager(o, _verbosityLevel);
- // done here
- return;
- }
-
- if (o.InstallJtagDrivers)
+ try
{
- _exitCode = Stm32Operations.InstallJtagDrivers(_verbosityLevel);
-
- // done here
- return;
+ _exitCode = await manager.ProcessAsync();
}
-
- if (o.ListDevicesInDfuMode)
+ catch (CantConnectToDfuDeviceException)
{
- var connecteDevices = StmDfuDevice.ListDevices();
-
- Console.ForegroundColor = ConsoleColor.Cyan;
-
- if (connecteDevices.Count() == 0)
- {
- Console.ForegroundColor = ConsoleColor.Yellow;
- Console.WriteLine("No DFU devices found");
- }
- else
- {
- Console.WriteLine("-- Connected DFU devices --");
-
- foreach ((string serial, string device) device in connecteDevices)
- {
- Console.WriteLine($"{device.serial} @ {device.device}");
- }
-
- Console.WriteLine("---------------------------");
- }
-
- Console.ForegroundColor = ConsoleColor.White;
-
// done here, this command has no further processing
- _exitCode = ExitCodes.OK;
-
- return;
+ _exitCode = ExitCodes.E1005;
}
-
- if (o.ListJtagDevices)
+ catch (CantConnectToJtagDeviceException)
{
- try
- {
- var connecteDevices = StmJtagDevice.ListDevices();
-
- Console.ForegroundColor = ConsoleColor.Cyan;
-
- if (connecteDevices.Count == 0)
- {
- Console.WriteLine("No JTAG devices found");
- }
- else
- {
- Console.WriteLine("-- Connected JTAG devices --");
-
- foreach (string deviceId in connecteDevices)
- {
- Console.WriteLine(deviceId);
- }
-
- Console.WriteLine("---------------------------");
- }
-
- // done here, this command has no further processing
- _exitCode = ExitCodes.OK;
- }
- catch (Exception ex)
- {
- // exception with
- _exitCode = ExitCodes.E5000;
- _extraMessage = ex.Message;
- }
-
- Console.ForegroundColor = ConsoleColor.White;
-
- return;
- }
-
- var connectedStDfuDevices = StmDfuDevice.ListDevices();
- var connectedStJtagDevices = StmJtagDevice.ListDevices();
-
- if (o.BinFile.Any() &&
- o.HexFile.Any() &&
- connectedStDfuDevices.Count != 0)
- {
-
- #region STM32 DFU options
-
- try
- {
- var dfuDevice = new StmDfuDevice(o.DfuDeviceId);
-
- if (!dfuDevice.DevicePresent)
- {
- // no JTAG device found
-
- // done here, this command has no further processing
- _exitCode = ExitCodes.E5001;
-
- return;
- }
-
- if (_verbosityLevel >= VerbosityLevel.Normal)
- {
- Console.WriteLine($"Connected to JTAG device with ID {dfuDevice.DfuId}");
- }
-
- // set verbosity
- dfuDevice.Verbosity = _verbosityLevel;
-
- // get mass erase option
- dfuDevice.DoMassErase = o.MassErase;
-
- if (o.HexFile.Any())
- {
- _exitCode = dfuDevice.FlashHexFiles(o.HexFile);
-
- // done here
- return;
- }
-
- if (o.BinFile.Any())
- {
- _exitCode = dfuDevice.FlashBinFiles(o.BinFile, o.FlashAddress);
-
- // done here
- return;
- }
- }
- catch (CantConnectToDfuDeviceException)
- {
- // done here, this command has no further processing
- _exitCode = ExitCodes.E1005;
- }
-
- #endregion
-
- }
- else if (
- o.BinFile.Any() &&
- o.HexFile.Any() &&
- connectedStJtagDevices.Count != 0
- )
- {
- // this has to be a JTAG connected device
-
- #region STM32 JTAG options
-
- try
- {
- var jtagDevice = new StmJtagDevice(o.JtagDeviceId);
-
- if (!jtagDevice.DevicePresent)
- {
- // no JTAG device found
-
- // done here, this command has no further processing
- _exitCode = ExitCodes.E5001;
-
- return;
- }
-
- if (_verbosityLevel >= VerbosityLevel.Normal)
- {
- Console.WriteLine($"Connected to JTAG device with ID {jtagDevice.JtagId}");
- }
-
- // set verbosity
- jtagDevice.Verbosity = _verbosityLevel;
-
- // get mass erase option
- jtagDevice.DoMassErase = o.MassErase;
-
- if (o.HexFile.Any())
- {
- _exitCode = jtagDevice.FlashHexFiles(o.HexFile);
-
- // done here
- return;
- }
-
- if (o.BinFile.Any())
- {
- _exitCode = jtagDevice.FlashBinFiles(o.BinFile, o.FlashAddress);
-
- // done here
- return;
- }
- }
- catch (CantConnectToJtagDeviceException)
- {
- // done here, this command has no further processing
- _exitCode = ExitCodes.E5002;
- }
-
- #endregion
+ // done here, this command has no further processing
+ _exitCode = ExitCodes.E5002;
}
- else if (!string.IsNullOrEmpty(o.TargetName))
+ catch (NoOperationPerformedException)
{
- // update operation requested?
- if (o.Update)
- {
- // this to update the device with fw from CloudSmith
-
- // need to take care of flash address
- string appFlashAddress = null;
-
- if (o.FlashAddress.Any())
- {
- // take the first address, it should be the only one valid
- appFlashAddress = o.FlashAddress.ElementAt(0);
- }
-
- Interface updateInterface = Interface.None;
-
- if (o.DfuUpdate && o.JtagUpdate)
- {
- // can't select both JTAG and DFU simultaneously
- _exitCode = ExitCodes.E9000;
- return;
- }
- else if (o.DfuUpdate)
- {
- updateInterface = Interface.Dfu;
- }
- else if (o.JtagUpdate)
- {
- updateInterface = Interface.Jtag;
- }
-
- _exitCode = await Stm32Operations.UpdateFirmwareAsync(
- o.TargetName,
- o.FwVersion,
- o.Preview,
- true,
- o.DeploymentImage,
- appFlashAddress,
- o.DfuDeviceId,
- o.JtagDeviceId,
- !o.FitCheck,
- updateInterface,
- _verbosityLevel);
-
- operationPerformed = true;
-
- if (_exitCode != ExitCodes.OK)
- {
- // done here
- return;
- }
- }
-
- // it's OK to deploy after update
- if (o.Deploy)
- {
- // this to flash a deployment image without updating the firmware
-
- // need to take care of flash address
- string appFlashAddress;
-
- if (o.FlashAddress.Any())
- {
- // take the first address, it should be the only one valid
- appFlashAddress = o.FlashAddress.ElementAt(0);
- }
- else
- {
- _exitCode = ExitCodes.E9009;
- return;
- }
-
- Interface updateInterface = Interface.None;
-
- if (o.DfuUpdate && o.JtagUpdate)
- {
- // can't select both JTAG and DFU simultaneously
- _exitCode = ExitCodes.E9000;
- return;
- }
- else if (o.DfuUpdate)
- {
- updateInterface = Interface.Dfu;
- }
- else if (o.JtagUpdate)
- {
- updateInterface = Interface.Jtag;
- }
-
- _exitCode = await Stm32Operations.UpdateFirmwareAsync(
- o.TargetName,
- null,
- false,
- false,
- o.DeploymentImage,
- appFlashAddress,
- o.DfuDeviceId,
- o.JtagDeviceId,
- !o.FitCheck,
- updateInterface,
- _verbosityLevel);
-
- operationPerformed = true;
-
- if (_exitCode != ExitCodes.OK)
- {
- // done here
- return;
- }
- }
-
- // reset MCU requested?
- if (o.ResetMcu)
- {
- _exitCode = Stm32Operations.ResetMcu(
- o.JtagDeviceId,
- _verbosityLevel);
-
- // done here
- return;
- }
+ DisplayNoOperationMessage();
}
- else if (o.MassErase)
+ catch (Exception ex)
{
- _exitCode = Stm32Operations.MassErase(
- o.JtagDeviceId,
- _verbosityLevel);
-
- // done here
- return;
+ // exception with
+ _exitCode = ExitCodes.E5000;
+ _extraMessage = ex.Message;
}
- else if (o.ResetMcu)
- {
- _exitCode = Stm32Operations.ResetMcu(
- o.JtagDeviceId,
- _verbosityLevel);
- // done here
- return;
- }
+ operationPerformed = true;
}
#endregion
@@ -1149,96 +603,24 @@ static async Task RunOptionsAndReturnExitCodeAsync(Options o)
if (o.Platform == SupportedPlatform.ti_simplelink)
{
- if (o.TIInstallXdsDrivers)
- {
- _exitCode = CC13x26x2Operations.InstallXds110Drivers(_verbosityLevel);
+ var manager = new TIManager(o, _verbosityLevel);
- // done here
- return;
+ try
+ {
+ _exitCode = await manager.ProcessAsync();
}
-
- if (!string.IsNullOrEmpty(o.TargetName))
+ catch (NoOperationPerformedException)
{
- // update operation requested?
- if (o.Update)
- {
- // this to update the device with fw from Cloudsmith
-
- // need to take care of flash address
- string appFlashAddress = null;
-
- if (o.FlashAddress.Any())
- {
- // take the first address, it should be the only one valid
- appFlashAddress = o.FlashAddress.ElementAt(0);
- }
-
- _exitCode = await CC13x26x2Operations.UpdateFirmwareAsync(
- o.TargetName,
- o.FwVersion,
- o.Preview,
- true,
- o.DeploymentImage,
- appFlashAddress,
- _verbosityLevel);
-
- operationPerformed = true;
-
- if (_exitCode != ExitCodes.OK)
- {
- // done here
- return;
- }
- }
-
- // it's OK to deploy after update
- if (o.Deploy)
- {
- // this to flash a deployment image without updating the firmware
-
- // need to take care of flash address
- string appFlashAddress = null;
-
- if (o.FlashAddress.Any())
- {
- // take the first address, it should be the only one valid
- appFlashAddress = o.FlashAddress.ElementAt(0);
- }
- else
- {
- _exitCode = ExitCodes.E9009;
- return;
- }
-
- _exitCode = await CC13x26x2Operations.UpdateFirmwareAsync(
- o.TargetName,
- null,
- false,
- false,
- o.DeploymentImage,
- appFlashAddress,
- _verbosityLevel);
-
- operationPerformed = true;
-
- if (_exitCode != ExitCodes.OK)
- {
- // done here
- return;
- }
- }
-
- // reset MCU requested?
- if (o.ResetMcu)
- {
- // can't reset CC13x2 device without configuration file
- // would require to specify the exact target name and then had to try parsing that
- _exitCode = ExitCodes.E9000;
-
- // done here
- return;
- }
+ DisplayNoOperationMessage();
+ }
+ catch (Exception ex)
+ {
+ // exception with
+ _exitCode = ExitCodes.E5000;
+ _extraMessage = ex.Message;
}
+
+ operationPerformed = true;
}
#endregion
@@ -1247,237 +629,80 @@ static async Task RunOptionsAndReturnExitCodeAsync(Options o)
if (o.Platform == SupportedPlatform.gg11)
{
- if (o.ListJLinkDevices)
- {
- try
- {
- var connecteDevices = JLinkDevice.ListDevices();
+ var manager = new SilabsManager(o, _verbosityLevel);
- Console.ForegroundColor = ConsoleColor.Cyan;
-
- if (connecteDevices.Count == 0)
- {
- Console.WriteLine("No J-Link devices found");
- }
- else
- {
- Console.WriteLine("-- Connected USB J-Link devices --");
-
- foreach (string deviceId in connecteDevices)
- {
- Console.WriteLine(deviceId);
- }
-
- Console.WriteLine("----------------------------------");
- }
-
- // done here, this command has no further processing
- _exitCode = ExitCodes.OK;
- }
- catch (Exception ex)
- {
- // exception with
- _exitCode = ExitCodes.E8000;
- _extraMessage = ex.Message;
- }
-
- Console.ForegroundColor = ConsoleColor.White;
-
- return;
+ try
+ {
+ _exitCode = await manager.ProcessAsync();
}
-
- var connectedJLinkDevices = JLinkDevice.ListDevices();
-
-
- if (o.BinFile.Any()
- && connectedJLinkDevices.Count != 0)
+ catch (CantConnectToJLinkDeviceException)
{
- try
- {
- var jlinkDevice = new JLinkDevice(o.JLinkDeviceId);
-
- if (!jlinkDevice.DevicePresent)
- {
- // no J-Link device found
-
- // done here, this command has no further processing
- _exitCode = ExitCodes.E8001;
-
- return;
- }
-
- if (_verbosityLevel >= VerbosityLevel.Normal)
- {
- Console.WriteLine($"Connected to J-Link device with ID {jlinkDevice.ProbeId}");
- }
-
- if (_verbosityLevel == VerbosityLevel.Diagnostic)
- {
- Console.WriteLine($"Firmware: {jlinkDevice.Firmare}");
- Console.WriteLine($"Hardware: {jlinkDevice.Hardware}");
- }
-
- // set VCP baud rate (if requested)
- if (o.SetVcpBaudRate.HasValue)
- {
- _ = SilinkCli.SetVcpBaudRate(
- o.JLinkDeviceId is null ? connectedJLinkDevices.First() : "",
- o.SetVcpBaudRate.Value,
- _verbosityLevel);
- }
-
- // set verbosity
- jlinkDevice.Verbosity = _verbosityLevel;
-
- // get mass erase option
- jlinkDevice.DoMassErase = o.MassErase;
-
- if (o.BinFile.Any())
- {
- _exitCode = jlinkDevice.FlashBinFiles(o.BinFile, o.FlashAddress);
-
- // done here
- return;
- }
- }
- catch (CantConnectToJLinkDeviceException)
- {
- // done here, this command has no further processing
- _exitCode = ExitCodes.E8002;
- }
+ // done here, this command has no further processing
+ _exitCode = ExitCodes.E8001;
}
- else if (!string.IsNullOrEmpty(o.TargetName))
+ catch (SilinkExecutionException)
{
- // update operation requested?
- if (o.Update)
- {
- // this to update the device with fw from CloudSmith
-
- // need to take care of flash address
- string appFlashAddress = null;
-
- if (o.FlashAddress.Any())
- {
- // take the first address, it should be the only one valid
- appFlashAddress = o.FlashAddress.ElementAt(0);
- }
-
- _exitCode = await JLinkOperations.UpdateFirmwareAsync(
- o.TargetName,
- o.FwVersion,
- o.Preview,
- true,
- o.DeploymentImage,
- appFlashAddress,
- o.JLinkDeviceId,
- !o.FitCheck,
- _verbosityLevel);
-
- operationPerformed = true;
-
- if (o.SetVcpBaudRate.HasValue)
- {
- // set VCP baud rate (if needed)
- _ = SilinkCli.SetVcpBaudRate(
- o.JLinkDeviceId is null ? connectedJLinkDevices.First() : "",
- o.SetVcpBaudRate.Value,
- _verbosityLevel);
- }
-
- if (_exitCode != ExitCodes.OK)
- {
- // done here
- return;
- }
- }
-
- // it's OK to deploy after update
- if (o.Deploy)
- {
- // this to flash a deployment image without updating the firmware
-
- // need to take care of flash address
- string appFlashAddress;
-
- if (o.FlashAddress.Any())
- {
- // take the first address, it should be the only one valid
- appFlashAddress = o.FlashAddress.ElementAt(0);
- }
- else
- {
- _exitCode = ExitCodes.E9009;
- return;
- }
+ // done here, this command has no further processing
+ _exitCode = ExitCodes.E8002;
+ }
+ catch (NoOperationPerformedException)
+ {
+ DisplayNoOperationMessage();
+ }
+ catch (Exception ex)
+ {
+ // exception with
+ _exitCode = ExitCodes.E8000;
+ _extraMessage = ex.Message;
+ }
- _exitCode = await JLinkOperations.UpdateFirmwareAsync(
- o.TargetName,
- null,
- false,
- false,
- o.DeploymentImage,
- appFlashAddress,
- o.JLinkDeviceId,
- !o.FitCheck,
- _verbosityLevel);
+ operationPerformed = true;
+ }
- operationPerformed = true;
+ #endregion
- if (_exitCode != ExitCodes.OK)
- {
- // done here
- return;
- }
- }
- }
- else if (o.MassErase)
+ // done nothing... or maybe not...
+ if (!operationPerformed && string.IsNullOrEmpty(o.FileDeployment))
+ {
+ DisplayNoOperationMessage();
+ }
+ else
+ {
+ if ((_exitCode == ExitCodes.OK) && !string.IsNullOrEmpty(o.FileDeployment))
{
+ FileDeploymentManager deploy = new FileDeploymentManager(o.FileDeployment, o.SerialPort, _verbosityLevel);
try
{
- _exitCode = JLinkOperations.MassErase(
- o.JLinkDeviceId,
- _verbosityLevel);
- }
- catch (CantConnectToJLinkDeviceException)
- {
- // exception with
- _exitCode = ExitCodes.E8001;
-
+ _exitCode = await deploy.DeployAsync();
}
catch (Exception ex)
{
// exception with
- _exitCode = ExitCodes.E8000;
+ _exitCode = ExitCodes.E2003;
_extraMessage = ex.Message;
}
-
- // done here
- return;
}
}
+ }
- #endregion
-
- // done nothing... or maybe not...
- if (!operationPerformed)
- {
- // because of short-comings in CommandLine parsing
- // need to customize the output to provide a consistent output
- var parser = new Parser(config => config.HelpWriter = null);
- var result = parser.ParseArguments(new[] { "", "" });
-
- var helpText = new HelpText(
- new HeadingInfo(_headerInfo),
- _copyrightInfo)
- .AddPreOptionsLine("")
- .AddPreOptionsLine("No operation was performed with the options supplied.")
- .AddPreOptionsLine("")
- .AddPreOptionsLine(HelpText.RenderUsageText(result))
- .AddPreOptionsLine("")
- .AddOptions(result);
-
- Console.WriteLine(helpText.ToString());
- }
+ private static void DisplayNoOperationMessage()
+ {
+ // because of short-comings in CommandLine parsing
+ // need to customize the output to provide a consistent output
+ var parser = new Parser(config => config.HelpWriter = null);
+ var result = parser.ParseArguments(new string[] { "", "" });
+
+ var helpText = new HelpText(
+ new HeadingInfo(_headerInfo),
+ _copyrightInfo)
+ .AddPreOptionsLine("")
+ .AddPreOptionsLine("No operation was performed with the options supplied.")
+ .AddPreOptionsLine("")
+ .AddPreOptionsLine(HelpText.RenderUsageText(result))
+ .AddPreOptionsLine("")
+ .AddOptions(result);
+
+ Console.WriteLine(helpText.ToString());
}
private static void DisplayBoardDetails(List boards)
diff --git a/nanoFirmwareFlasher.Tool/SilabsManager.cs b/nanoFirmwareFlasher.Tool/SilabsManager.cs
new file mode 100644
index 00000000..260fd2d3
--- /dev/null
+++ b/nanoFirmwareFlasher.Tool/SilabsManager.cs
@@ -0,0 +1,245 @@
+//
+// Copyright (c) .NET Foundation and Contributors
+// See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace nanoFramework.Tools.FirmwareFlasher
+{
+ ///
+ /// Class to manage different operations specific to the Silabs GG11 platform.
+ ///
+ public class SilabsManager : IManager
+ {
+ private readonly Options _options;
+ private readonly VerbosityLevel _verbosityLevel;
+
+ public SilabsManager(Options options, VerbosityLevel verbosityLevel)
+ {
+ if (options == null)
+ {
+ throw new ArgumentNullException(nameof(options));
+ }
+
+ if (options.Platform != SupportedPlatform.gg11)
+ {
+ throw new NotSupportedException($"{nameof(options)} - {options.Platform}");
+ }
+
+ _options = options;
+ _verbosityLevel = verbosityLevel;
+ }
+
+ ///
+ public async Task ProcessAsync()
+ {
+ if (_options.ListJLinkDevices)
+ {
+ var connecteDevices = JLinkDevice.ListDevices();
+
+ Console.ForegroundColor = ConsoleColor.Cyan;
+
+ if (connecteDevices.Count == 0)
+ {
+ Console.WriteLine("No J-Link devices found");
+ }
+ else
+ {
+ Console.WriteLine("-- Connected USB J-Link devices --");
+
+ foreach (string deviceId in connecteDevices)
+ {
+ Console.WriteLine(deviceId);
+ }
+
+ Console.WriteLine("----------------------------------");
+ }
+
+ Console.ForegroundColor = ConsoleColor.White;
+
+ // done here, this command has no further processing
+ return ExitCodes.OK;
+ }
+
+ var connectedJLinkDevices = JLinkDevice.ListDevices();
+ bool updateAndDeploy = false;
+
+ if ((_options.BinFile.Any() ||
+ !string.IsNullOrEmpty(_options.DeploymentImage))
+ && connectedJLinkDevices.Count != 0)
+ {
+ try
+ {
+ var jlinkDevice = new JLinkDevice(_options.JLinkDeviceId);
+
+ if (!jlinkDevice.DevicePresent)
+ {
+ // no J-Link device found
+
+ // done here, this command has no further processing
+ return ExitCodes.E8001;
+ }
+
+ if (_verbosityLevel >= VerbosityLevel.Normal)
+ {
+ Console.WriteLine($"Connected to J-Link device with ID {jlinkDevice.ProbeId}");
+ }
+
+ if (_verbosityLevel == VerbosityLevel.Diagnostic)
+ {
+ Console.WriteLine($"Firmware: {jlinkDevice.Firmare}");
+ Console.WriteLine($"Hardware: {jlinkDevice.Hardware}");
+ }
+
+ // set VCP baud rate (if requested)
+ if (_options.SetVcpBaudRate.HasValue)
+ {
+ _ = SilinkCli.SetVcpBaudRate(
+ _options.JLinkDeviceId is null ? connectedJLinkDevices.First() : "",
+ _options.SetVcpBaudRate.Value,
+ _verbosityLevel);
+ }
+
+ // set verbosity
+ jlinkDevice.Verbosity = _verbosityLevel;
+
+ // get mass erase option
+ jlinkDevice.DoMassErase = _options.MassErase;
+
+ // is there a bin file to flash?
+ if (_options.BinFile.Any())
+ {
+ var exitCode = jlinkDevice.FlashBinFiles(_options.BinFile, _options.FlashAddress);
+
+ if (exitCode != ExitCodes.OK)
+ {
+ // done here
+ return exitCode;
+ }
+
+ updateAndDeploy = true;
+ }
+ else if (!string.IsNullOrEmpty(_options.DeploymentImage) && _options.Deploy)
+ {
+ var exitCode = jlinkDevice.FlashBinFiles(
+ [_options.DeploymentImage],
+ _options.FlashAddress);
+
+ if (exitCode != ExitCodes.OK)
+ {
+ // done here
+ return exitCode;
+ }
+
+ updateAndDeploy = true;
+ }
+ }
+ catch (CantConnectToJLinkDeviceException)
+ {
+ // exception too vague for the full list of commands above
+ throw new SilinkExecutionException();
+ }
+ }
+ else if (!string.IsNullOrEmpty(_options.TargetName))
+ {
+ // update operation requested?
+ if (_options.Update)
+ {
+ // this to update the device with fw from CloudSmith
+
+ // need to take care of flash address
+ string appFlashAddress = null;
+
+ if (_options.FlashAddress.Any())
+ {
+ // take the first address, it should be the only one valid
+ appFlashAddress = _options.FlashAddress.ElementAt(0);
+ }
+
+ var exitCode = await JLinkOperations.UpdateFirmwareAsync(
+ _options.TargetName,
+ _options.FwVersion,
+ _options.Preview,
+ true,
+ _options.DeploymentImage,
+ appFlashAddress,
+ _options.JLinkDeviceId,
+ !_options.FitCheck,
+ _verbosityLevel);
+
+ if (_options.SetVcpBaudRate.HasValue)
+ {
+ // set VCP baud rate (if needed)
+ _ = SilinkCli.SetVcpBaudRate(
+ _options.JLinkDeviceId is null ? connectedJLinkDevices.First() : "",
+ _options.SetVcpBaudRate.Value,
+ _verbosityLevel);
+ }
+
+ if (exitCode != ExitCodes.OK)
+ {
+ // done here
+ return exitCode;
+ }
+
+ updateAndDeploy = true;
+ }
+
+ // it's OK to deploy after a successful update
+ if (_options.Deploy)
+ {
+ // this to flash a deployment image without updating the firmware
+
+ // need to take care of flash address
+ string appFlashAddress;
+
+ if (_options.FlashAddress.Any())
+ {
+ // take the first address, it should be the only one valid
+ appFlashAddress = _options.FlashAddress.ElementAt(0);
+ }
+ else
+ {
+ return ExitCodes.E9009;
+ }
+
+ var exitCode = await JLinkOperations.UpdateFirmwareAsync(
+ _options.TargetName,
+ null,
+ false,
+ false,
+ _options.DeploymentImage,
+ appFlashAddress,
+ _options.JLinkDeviceId,
+ !_options.FitCheck,
+ _verbosityLevel);
+
+ if (exitCode != ExitCodes.OK)
+ {
+ // done here
+ return exitCode;
+ }
+
+ updateAndDeploy = true;
+ }
+ }
+ else if (_options.MassErase)
+ {
+ return JLinkOperations.MassErase(
+ _options.JLinkDeviceId,
+ _verbosityLevel);
+ }
+
+ if (!updateAndDeploy)
+ {
+ throw new NoOperationPerformedException();
+ }
+
+ return ExitCodes.OK;
+ }
+ }
+}
diff --git a/nanoFirmwareFlasher.Tool/Stm32Manager.cs b/nanoFirmwareFlasher.Tool/Stm32Manager.cs
new file mode 100644
index 00000000..120222cf
--- /dev/null
+++ b/nanoFirmwareFlasher.Tool/Stm32Manager.cs
@@ -0,0 +1,331 @@
+//
+// Copyright (c) .NET Foundation and Contributors
+// See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace nanoFramework.Tools.FirmwareFlasher
+{
+ ///
+ /// Class to manage different operations specific to the STM32 platform.
+ ///
+ public class Stm32Manager : IManager
+ {
+ private readonly Options _options;
+ private readonly VerbosityLevel _verbosityLevel;
+
+ public Stm32Manager(Options options, VerbosityLevel verbosityLevel)
+ {
+ if (options == null)
+ {
+ throw new ArgumentNullException(nameof(options));
+ }
+
+ if (options.Platform != SupportedPlatform.stm32)
+ {
+ throw new NotSupportedException($"{nameof(options)} - {options.Platform}");
+ }
+
+ _options = options;
+ _verbosityLevel = verbosityLevel;
+ }
+
+ ///
+ public async Task ProcessAsync()
+ {
+ if (_options.InstallDfuDrivers)
+ {
+ return Stm32Operations.InstallDfuDrivers(_verbosityLevel);
+ }
+
+ if (_options.InstallJtagDrivers)
+ {
+ return Stm32Operations.InstallJtagDrivers(_verbosityLevel);
+ }
+
+ if (_options.ListDevicesInDfuMode)
+ {
+ var connecteDevices = StmDfuDevice.ListDevices();
+
+ Console.ForegroundColor = ConsoleColor.Cyan;
+
+ if (connecteDevices.Count() == 0)
+ {
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ Console.WriteLine("No DFU devices found");
+ }
+ else
+ {
+ Console.WriteLine("-- Connected DFU devices --");
+
+ foreach ((string serial, string device) device in connecteDevices)
+ {
+ Console.WriteLine($"{device.serial} @ {device.device}");
+ }
+
+ Console.WriteLine("---------------------------");
+ }
+
+ Console.ForegroundColor = ConsoleColor.White;
+
+ // done here, this command has no further processing
+ return ExitCodes.OK;
+ }
+
+ if (_options.ListJtagDevices)
+ {
+ var connecteDevices = StmJtagDevice.ListDevices();
+
+ Console.ForegroundColor = ConsoleColor.Cyan;
+
+ if (connecteDevices.Count == 0)
+ {
+ Console.WriteLine("No JTAG devices found");
+ }
+ else
+ {
+ Console.WriteLine("-- Connected JTAG devices --");
+
+ foreach (string deviceId in connecteDevices)
+ {
+ Console.WriteLine(deviceId);
+ }
+
+ Console.WriteLine("---------------------------");
+ }
+
+ Console.ForegroundColor = ConsoleColor.White;
+
+ // done here, this command has no further processing
+ return ExitCodes.OK;
+ }
+
+ var connectedStDfuDevices = StmDfuDevice.ListDevices();
+ var connectedStJtagDevices = StmJtagDevice.ListDevices();
+ bool updateAndDeploy = false;
+
+ if (connectedStDfuDevices.Count != 0 &&
+ (_options.BinFile.Any() ||
+ _options.HexFile.Any()))
+ {
+
+ #region STM32 DFU options
+
+ var dfuDevice = new StmDfuDevice(_options.DfuDeviceId);
+
+ if (!dfuDevice.DevicePresent)
+ {
+ // no JTAG device found
+
+ // done here, this command has no further processing
+ return ExitCodes.E5001;
+ }
+
+ if (_verbosityLevel >= VerbosityLevel.Normal)
+ {
+ Console.WriteLine($"Connected to JTAG device with ID {dfuDevice.DfuId}");
+ }
+
+ // set verbosity
+ dfuDevice.Verbosity = _verbosityLevel;
+
+ // get mass erase option
+ dfuDevice.DoMassErase = _options.MassErase;
+
+ if (_options.HexFile.Any())
+ {
+ return dfuDevice.FlashHexFiles(_options.HexFile);
+ }
+
+ if (_options.BinFile.Any())
+ {
+ return dfuDevice.FlashBinFiles(_options.BinFile, _options.FlashAddress);
+ }
+
+ #endregion
+
+ }
+ else if (connectedStJtagDevices.Count != 0 &&
+ (_options.BinFile.Any() ||
+ _options.HexFile.Any()))
+ {
+ // this has to be a JTAG connected device
+
+ #region STM32 JTAG options
+
+ var jtagDevice = new StmJtagDevice(_options.JtagDeviceId);
+
+ if (!jtagDevice.DevicePresent)
+ {
+ // no JTAG device found
+
+ // done here, this command has no further processing
+ return ExitCodes.E5001;
+ }
+
+ if (_verbosityLevel >= VerbosityLevel.Normal)
+ {
+ Console.WriteLine($"Connected to JTAG device with ID {jtagDevice.JtagId}");
+ }
+
+ // set verbosity
+ jtagDevice.Verbosity = _verbosityLevel;
+
+ // get mass erase option
+ jtagDevice.DoMassErase = _options.MassErase;
+
+ if (_options.HexFile.Any())
+ {
+ return jtagDevice.FlashHexFiles(_options.HexFile);
+ }
+
+ if (_options.BinFile.Any())
+ {
+ return jtagDevice.FlashBinFiles(_options.BinFile, _options.FlashAddress);
+ }
+
+ #endregion
+ }
+ else if (!string.IsNullOrEmpty(_options.TargetName))
+ {
+ // update operation requested?
+ if (_options.Update)
+ {
+ // this to update the device with fw from CloudSmith
+
+ // need to take care of flash address
+ string appFlashAddress = null;
+
+ if (_options.FlashAddress.Any())
+ {
+ // take the first address, it should be the only one valid
+ appFlashAddress = _options.FlashAddress.ElementAt(0);
+ }
+
+ Interface updateInterface = Interface.None;
+
+ if (_options.DfuUpdate && _options.JtagUpdate)
+ {
+ // can't select both JTAG and DFU simultaneously
+ return ExitCodes.E9000;
+ }
+ else if (_options.DfuUpdate)
+ {
+ updateInterface = Interface.Dfu;
+ }
+ else if (_options.JtagUpdate)
+ {
+ updateInterface = Interface.Jtag;
+ }
+
+ var exitCode = await Stm32Operations.UpdateFirmwareAsync(
+ _options.TargetName,
+ _options.FwVersion,
+ _options.Preview,
+ true,
+ _options.DeploymentImage,
+ appFlashAddress,
+ _options.DfuDeviceId,
+ _options.JtagDeviceId,
+ !_options.FitCheck,
+ updateInterface,
+ _verbosityLevel);
+
+ if (exitCode != ExitCodes.OK)
+ {
+ // done here
+ return exitCode;
+ }
+
+ updateAndDeploy = true;
+ }
+
+ // it's OK to deploy after a successful update
+ if (_options.Deploy)
+ {
+ // this to flash a deployment image without updating the firmware
+
+ // need to take care of flash address
+ string appFlashAddress;
+
+ if (_options.FlashAddress.Any())
+ {
+ // take the first address, it should be the only one valid
+ appFlashAddress = _options.FlashAddress.ElementAt(0);
+ }
+ else
+ {
+ return ExitCodes.E9009;
+ }
+
+ Interface updateInterface = Interface.None;
+
+ if (_options.DfuUpdate && _options.JtagUpdate)
+ {
+ // can't select both JTAG and DFU simultaneously
+ return ExitCodes.E9000;
+ }
+ else if (_options.DfuUpdate)
+ {
+ updateInterface = Interface.Dfu;
+ }
+ else if (_options.JtagUpdate)
+ {
+ updateInterface = Interface.Jtag;
+ }
+
+ var exitCode = await Stm32Operations.UpdateFirmwareAsync(
+ _options.TargetName,
+ null,
+ false,
+ false,
+ _options.DeploymentImage,
+ appFlashAddress,
+ _options.DfuDeviceId,
+ _options.JtagDeviceId,
+ !_options.FitCheck,
+ updateInterface,
+ _verbosityLevel);
+
+ if (exitCode != ExitCodes.OK)
+ {
+ // done here
+ return exitCode;
+ }
+
+ updateAndDeploy = true;
+ }
+
+ // reset MCU requested?
+ if (_options.ResetMcu)
+ {
+ return Stm32Operations.ResetMcu(
+ _options.JtagDeviceId,
+ _verbosityLevel);
+ }
+ }
+ else if (_options.MassErase)
+ {
+ return Stm32Operations.MassErase(
+ _options.JtagDeviceId,
+ _verbosityLevel);
+ }
+ else if (_options.ResetMcu)
+ {
+ return Stm32Operations.ResetMcu(
+ _options.JtagDeviceId,
+ _verbosityLevel);
+ }
+
+ if (!updateAndDeploy)
+ {
+ throw new NoOperationPerformedException();
+ }
+
+ return ExitCodes.OK;
+ }
+ }
+}
diff --git a/nanoFirmwareFlasher.Tool/TIManager.cs b/nanoFirmwareFlasher.Tool/TIManager.cs
new file mode 100644
index 00000000..ed1d150b
--- /dev/null
+++ b/nanoFirmwareFlasher.Tool/TIManager.cs
@@ -0,0 +1,133 @@
+//
+// Copyright (c) .NET Foundation and Contributors
+// See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace nanoFramework.Tools.FirmwareFlasher
+{
+ ///
+ /// Class to manage different operations specific to the TI SimpleLink platform.
+ ///
+ public class TIManager : IManager
+ {
+ private readonly Options _options;
+ private readonly VerbosityLevel _verbosityLevel;
+
+ public TIManager(Options options, VerbosityLevel verbosityLevel)
+ {
+ if (options == null)
+ {
+ throw new ArgumentNullException(nameof(options));
+ }
+
+ if (options.Platform != SupportedPlatform.ti_simplelink)
+ {
+ throw new NotSupportedException($"{nameof(options)} - {options.Platform}");
+ }
+
+ _options = options;
+ _verbosityLevel = verbosityLevel;
+ }
+
+ ///
+ public async Task ProcessAsync()
+ {
+ if (_options.TIInstallXdsDrivers)
+ {
+ return CC13x26x2Operations.InstallXds110Drivers(_verbosityLevel);
+ }
+
+ bool updateAndDeploy = false;
+
+ if (!string.IsNullOrEmpty(_options.TargetName))
+ {
+ // update operation requested?
+ if (_options.Update)
+ {
+ // this to update the device with fw from Cloudsmith
+
+ // need to take care of flash address
+ string appFlashAddress = null;
+
+ if (_options.FlashAddress.Any())
+ {
+ // take the first address, it should be the only one valid
+ appFlashAddress = _options.FlashAddress.ElementAt(0);
+ }
+
+ var exitCode = await CC13x26x2Operations.UpdateFirmwareAsync(
+ _options.TargetName,
+ _options.FwVersion,
+ _options.Preview,
+ true,
+ _options.DeploymentImage,
+ appFlashAddress,
+ _verbosityLevel);
+
+ if (exitCode != ExitCodes.OK)
+ {
+ // done here
+ return exitCode;
+ }
+
+ updateAndDeploy = true;
+ }
+
+ // it's OK to deploy after a successful update
+ if (_options.Deploy)
+ {
+ // this to flash a deployment image without updating the firmware
+
+ // need to take care of flash address
+ string appFlashAddress = null;
+
+ if (_options.FlashAddress.Any())
+ {
+ // take the first address, it should be the only one valid
+ appFlashAddress = _options.FlashAddress.ElementAt(0);
+ }
+ else
+ {
+ return ExitCodes.E9009;
+ }
+
+ var exitCode = await CC13x26x2Operations.UpdateFirmwareAsync(
+ _options.TargetName,
+ null,
+ false,
+ false,
+ _options.DeploymentImage,
+ appFlashAddress,
+ _verbosityLevel);
+
+ if (exitCode != ExitCodes.OK)
+ {
+ // done here
+ return exitCode;
+ }
+
+ updateAndDeploy = true;
+ }
+
+ // reset MCU requested?
+ if (_options.ResetMcu)
+ {
+ // can't reset CC13x2 device without configuration file
+ // would require to specify the exact target name and then had to try parsing that
+ return ExitCodes.E9000;
+ }
+ }
+
+ if (!updateAndDeploy)
+ {
+ throw new NoOperationPerformedException();
+ }
+
+ return ExitCodes.OK;
+ }
+ }
+}
diff --git a/nanoFirmwareFlasher.Tool/appsettings.json b/nanoFirmwareFlasher.Tool/appsettings.json
new file mode 100644
index 00000000..d48501ab
--- /dev/null
+++ b/nanoFirmwareFlasher.Tool/appsettings.json
@@ -0,0 +1,3 @@
+{
+ "iConnectionString": "INSTRUMENT_KEY"
+}
diff --git a/nanoFirmwareFlasher.Tool/nanoFirmwareFlasher.Tool.csproj b/nanoFirmwareFlasher.Tool/nanoFirmwareFlasher.Tool.csproj
index 32ff9837..cd689b21 100644
--- a/nanoFirmwareFlasher.Tool/nanoFirmwareFlasher.Tool.csproj
+++ b/nanoFirmwareFlasher.Tool/nanoFirmwareFlasher.Tool.csproj
@@ -18,17 +18,17 @@
.NET nanoFirmwareFlasher tool to flash firmware images to target devices.
- latest
true
AnyCPU
AnyCPU;x64
any
true
true
+ true
- net6.0
+ net8.0
net472
@@ -46,6 +46,7 @@
+
@@ -68,6 +69,12 @@
+
+
+ Always
+
+
+
@@ -76,8 +83,8 @@
-
- net6.0\
+
+ net8.0\
diff --git a/nanoFirmwareFlasher.Tool/packages.lock.json b/nanoFirmwareFlasher.Tool/packages.lock.json
index b9bd781b..d6c47f8a 100644
--- a/nanoFirmwareFlasher.Tool/packages.lock.json
+++ b/nanoFirmwareFlasher.Tool/packages.lock.json
@@ -1,7 +1,7 @@
{
"version": 1,
"dependencies": {
- "net6.0": {
+ "net8.0": {
"CommandLineParser": {
"type": "Direct",
"requested": "[2.9.1, )",
@@ -14,6 +14,17 @@
"resolved": "4.7.0",
"contentHash": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA=="
},
+ "nanoFramework.Tools.Debugger.Net": {
+ "type": "Direct",
+ "requested": "[2.4.42, )",
+ "resolved": "2.4.42",
+ "contentHash": "3RWlCdTOkf0RDHRc+qFs0Di4QP9JLwaa3msLK1WT+XUeIaG45MJo9WLJ+tBS4rXcn0dHQSAKIP17q374WmaMag==",
+ "dependencies": {
+ "Polly": "7.2.3",
+ "PropertyChanged.Fody": "2.6.1",
+ "System.IO.Ports": "7.0.0"
+ }
+ },
"Nerdbank.GitVersioning": {
"type": "Direct",
"requested": "[3.6.133, )",
@@ -25,6 +36,83 @@
"resolved": "4.2.1",
"contentHash": "46t+e1eESclH4TkfqUEYAgZ1+ZbXSFS7GqSKvtcw6u2yT05heDKdzj1r3YA/6FCZM4uB4z7qRW9V+gBsCilonQ=="
},
+ "Microsoft.ApplicationInsights": {
+ "type": "Transitive",
+ "resolved": "2.22.0",
+ "contentHash": "3AOM9bZtku7RQwHyMEY3tQMrHIgjcfRDa6YQpd/QG2LDGvMydSlL9Di+8LLMt7J2RDdfJ7/2jdYv6yHcMJAnNw==",
+ "dependencies": {
+ "System.Diagnostics.DiagnosticSource": "5.0.0"
+ }
+ },
+ "Microsoft.Extensions.Configuration": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.Configuration.Abstractions": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.Configuration.FileExtensions": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "McP+Lz/EKwvtCv48z0YImw+L1gi1gy5rHhNaNIY2CrjloV+XY8gydT8DjMR6zWeL13AFK+DioVpppwAuO1Gi1w==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "8.0.0",
+ "Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
+ "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0",
+ "Microsoft.Extensions.FileProviders.Physical": "8.0.0",
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.Configuration.Json": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "C2wqUoh9OmRL1akaCcKSTmRU8z0kckfImG7zLNI8uyi47Lp+zd5LWAD17waPQEqCz3ioWOCrFUo+JJuoeZLOBw==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "8.0.0",
+ "Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Configuration.FileExtensions": "8.0.0",
+ "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0",
+ "System.Text.Json": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.FileProviders.Abstractions": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "ZbaMlhJlpisjuWbvXr4LdAst/1XxH3vZ6A0BsgTphZ2L4PGuxRLz7Jr/S7mkAAnOn78Vu0fKhEgNF5JO3zfjqQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.FileProviders.Physical": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "UboiXxpPUpwulHvIAVE36Knq0VSHaAmfrFkegLyBZeaADuKezJ/AIXYAW8F5GBlGk/VaibN2k/Zn1ca8YAfVdA==",
+ "dependencies": {
+ "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0",
+ "Microsoft.Extensions.FileSystemGlobbing": "8.0.0",
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.FileSystemGlobbing": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ=="
+ },
+ "Microsoft.Extensions.Primitives": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g=="
+ },
"Microsoft.NETCore.Platforms": {
"type": "Transitive",
"resolved": "1.1.1",
@@ -45,16 +133,6 @@
"System.Runtime": "4.3.0"
}
},
- "nanoFramework.Tools.Debugger.Net": {
- "type": "Transitive",
- "resolved": "2.4.34",
- "contentHash": "+QLH66C/dceiSlyWyfOEM5lOYZb13w5TjxvuB+ludaKTtD1IsZ4XAeXHen6P98eppgp3OLEus1GfMq7aGDj5Fw==",
- "dependencies": {
- "Polly": "7.2.3",
- "PropertyChanged.Fody": "2.6.1",
- "System.IO.Ports": "7.0.0"
- }
- },
"NETStandard.Library": {
"type": "Transitive",
"resolved": "1.6.1",
@@ -345,15 +423,8 @@
},
"System.Diagnostics.DiagnosticSource": {
"type": "Transitive",
- "resolved": "4.3.0",
- "contentHash": "tD6kosZnTAGdrEa0tZSuFyunMbt/5KYDnHdndJYGqZoNy00XVXyACd5d6KnE1YgYv3ne2CjtAfNXo/fwEhnKUA==",
- "dependencies": {
- "System.Collections": "4.3.0",
- "System.Diagnostics.Tracing": "4.3.0",
- "System.Reflection": "4.3.0",
- "System.Runtime": "4.3.0",
- "System.Threading": "4.3.0"
- }
+ "resolved": "5.0.0",
+ "contentHash": "tCQTzPsGZh/A9LhhA6zrqCRV4hOHsK90/G7q3Khxmn6tnB1PuNU0cRaKANP2AWcF9bn0zsuOoZOSrHuJk6oNBA=="
},
"System.Diagnostics.Tools": {
"type": "Transitive",
@@ -914,6 +985,19 @@
"System.Text.Encoding": "4.3.0"
}
},
+ "System.Text.Encodings.Web": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ=="
+ },
+ "System.Text.Json": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "OdrZO2WjkiEG6ajEFRABTRCi/wuXQPxeV6g8xvUJqdxMvvuCCEk86zPla8UiIQJz3durtUEbNyY/3lIhS0yZvQ==",
+ "dependencies": {
+ "System.Text.Encodings.Web": "8.0.0"
+ }
+ },
"System.Text.RegularExpressions": {
"type": "Transitive",
"resolved": "4.3.0",
@@ -1005,15 +1089,18 @@
"nanoFramework.Tools.FirmwareFlasher": {
"type": "Project",
"dependencies": {
+ "Microsoft.ApplicationInsights": "[2.22.0, )",
+ "Microsoft.Extensions.Configuration": "[8.0.0, )",
+ "Microsoft.Extensions.Configuration.Json": "[8.0.0, )",
"Newtonsoft.Json": "[13.0.3, )",
"System.ComponentModel.Annotations": "[5.0.0, )",
"System.IO.Ports": "[7.0.0, )",
"System.Net.Http": "[4.3.4, )",
- "nanoFramework.Tools.Debugger.Net": "[2.4.34, )"
+ "nanoFramework.Tools.Debugger.Net": "[2.4.42, )"
}
}
},
- "net6.0/any": {
+ "net8.0/any": {
"runtime.any.System.Collections": {
"type": "Transitive",
"resolved": "4.3.0",
@@ -1590,6 +1677,11 @@
"runtime.any.System.Text.Encoding.Extensions": "4.3.0"
}
},
+ "System.Text.Encodings.Web": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ=="
+ },
"System.Threading.Tasks": {
"type": "Transitive",
"resolved": "4.3.0",
diff --git a/update-esptool.ps1 b/update-esptool.ps1
index 4a437bd7..1168c431 100644
--- a/update-esptool.ps1
+++ b/update-esptool.ps1
@@ -64,9 +64,9 @@ Remove-Item -Path (Join-Path -Path $PSScriptRoot -ChildPath "lib\esptool\esptool
# copy files to the correct locations
"Copying files to tools folders..." | Write-Host -ForegroundColor White -NoNewline
-Move-Item -Path (Join-Path -Path $env:TEMP -ChildPath "esptool-$version-win64\**" -Resolve) -Destination (Join-Path -Path $PSScriptRoot -ChildPath "lib\esptool\esptoolWin" -Resolve) -Force
-Move-Item -Path (Join-Path -Path $env:TEMP -ChildPath "esptool-$version-macos\**" -Resolve) -Destination (Join-Path -Path $PSScriptRoot -ChildPath "lib\esptool\esptoolMac" -Resolve) -Force
-Move-Item -Path (Join-Path -Path $env:TEMP -ChildPath "esptool-$version-linux-amd64\**" -Resolve) -Destination (Join-Path -Path $PSScriptRoot -ChildPath "lib\esptool\esptoolLinux" -Resolve) -Force
+Move-Item -Path (Join-Path -Path $env:TEMP -ChildPath "esptool-win64\**" -Resolve) -Destination (Join-Path -Path $PSScriptRoot -ChildPath "lib\esptool\esptoolWin" -Resolve) -Force
+Move-Item -Path (Join-Path -Path $env:TEMP -ChildPath "esptool-macos\**" -Resolve) -Destination (Join-Path -Path $PSScriptRoot -ChildPath "lib\esptool\esptoolMac" -Resolve) -Force
+Move-Item -Path (Join-Path -Path $env:TEMP -ChildPath "esptool-linux-amd64\**" -Resolve) -Destination (Join-Path -Path $PSScriptRoot -ChildPath "lib\esptool\esptoolLinux" -Resolve) -Force
"OK" | Write-Host -ForegroundColor Green
# cleanup files
diff --git a/update-jlink.ps1 b/update-jlink.ps1
index fe3a5a97..9967a79d 100644
--- a/update-jlink.ps1
+++ b/update-jlink.ps1
@@ -4,7 +4,7 @@
# this PS1 downloads the latest version of SEGGER J-Link from their website and unpacks it
# version
-$version = "766f"
+$version = "792k"
# make sure security doesn't block our request
[Net.ServicePointManager]::SecurityProtocol = "tls12, tls11"