Add Storage Operation Commands (#374)

This commit is contained in:
Laurent Ellerbach 2024-03-21 08:44:45 -04:00 коммит произвёл GitHub
Родитель 3299eeed2b
Коммит e9212f79d8
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
4 изменённых файлов: 460 добавлений и 21 удалений

Просмотреть файл

@ -27,30 +27,33 @@
<Button Content="Disconnect" HorizontalAlignment="Left" Margin="250,102,0,0" VerticalAlignment="Top" Width="98" Click="DisconnectDeviceButton_Click"/>
<Button Content="Ping" HorizontalAlignment="Left" Margin="250,129,0,0" VerticalAlignment="Top" Width="98" Click="PingButton_Click" />
<Button Content="Get Execution" HorizontalAlignment="Left" Margin="250,195,0,0" VerticalAlignment="Top" Width="98" Click="GetExecutionModeButton_Click"/>
<Button Content="Deploy Test" HorizontalAlignment="Left" Margin="162,235,0,0" VerticalAlignment="Top" Width="75" Click="DeployTestButton_Click" />
<Button Content="Get Deployment Map" HorizontalAlignment="Left" Margin="162,275,0,0" VerticalAlignment="Top" Width="75" Click="GetDeploymentMapButton_Click" />
<Button Content="Get Execution" HorizontalAlignment="Left" Margin="250,187,0,0" VerticalAlignment="Top" Width="98" Click="GetExecutionModeButton_Click"/>
<Button Content="Deploy Test" HorizontalAlignment="Left" Margin="162,216,0,0" VerticalAlignment="Top" Width="75" Click="DeployTestButton_Click" />
<Button Content="Get Deployment Map" HorizontalAlignment="Left" Margin="162,245,0,0" VerticalAlignment="Top" Width="75" Click="GetDeploymentMapButton_Click" />
<Button Content="Device Capabilites" HorizontalAlignment="Left" Margin="39,195,0,0" VerticalAlignment="Top" Width="110" Click="DeviceCapabilitesButton_Click" />
<Button Content="Flash Map" HorizontalAlignment="Left" Margin="39,275,0,0" VerticalAlignment="Top" Width="110" Click="FlashMapButton_Click" />
<Button Content="Resolve Assemblies" HorizontalAlignment="Left" Margin="39,235,0,0" VerticalAlignment="Top" Width="110" Click="ResolveAssembliesButton_Click" />
<Button Content="Device Capabilites" HorizontalAlignment="Left" Margin="39,187,0,0" VerticalAlignment="Top" Width="110" Click="DeviceCapabilitesButton_Click" />
<Button Content="Flash Map" HorizontalAlignment="Left" Margin="39,245,0,0" VerticalAlignment="Top" Width="110" Click="FlashMapButton_Click" />
<Button Content="Resolve Assemblies" HorizontalAlignment="Left" Margin="39,216,0,0" VerticalAlignment="Top" Width="110" Click="ResolveAssembliesButton_Click" />
<Button Content="Pause Execution" HorizontalAlignment="Left" Margin="250,235,0,0" VerticalAlignment="Top" Width="98" Click="PauseExecutionButton_Click" />
<Button Content="Resume Execution" HorizontalAlignment="Left" Margin="250,275,0,0" VerticalAlignment="Top" Width="98" Click="ResumeExecutionButton_Click" />
<Button Content="Pause Execution" HorizontalAlignment="Left" Margin="250,216,0,0" VerticalAlignment="Top" Width="98" Click="PauseExecutionButton_Click" />
<Button Content="Resume Execution" HorizontalAlignment="Left" Margin="250,245,0,0" VerticalAlignment="Top" Width="98" Click="ResumeExecutionButton_Click" />
<Button Content="Reboot CLR" HorizontalAlignment="Left" Margin="378,77,0,0" VerticalAlignment="Top" Width="121" Click="RebootDeviceButton_Click"/>
<Button Content="Soft Reboot" HorizontalAlignment="Left" Margin="378,102,0,0" VerticalAlignment="Top" Width="121" Click="SoftRebootDeviceButton_Click"/>
<Button Content="Reboot to bootloader" HorizontalAlignment="Left" Margin="378,129,0,0" VerticalAlignment="Top" Width="121" Click="RebootToBootloaderButton_Click"/>
<Button Content="Stop Processing" HorizontalAlignment="Left" Margin="378,195,0,0" VerticalAlignment="Top" Width="121" Click="StopProcessingButton_Click"/>
<Button Content="Erase Deployment" HorizontalAlignment="Left" Margin="378,235,0,0" VerticalAlignment="Top" Width="121" Click="EraseDeploymentButton_Click" />
<Button Content="Is Init State" HorizontalAlignment="Left" Margin="162,195,0,0" VerticalAlignment="Top" Width="75" Click="IsInitStateButton_Click" />
<Button Content="Get Device Config" HorizontalAlignment="Left" Margin="378,275,0,0" VerticalAlignment="Top" Width="121" Click="GetDeviceConfigButton_Click" />
<Button Content="Set Device Config" HorizontalAlignment="Left" Margin="378,313,0,0" VerticalAlignment="Top" Width="121" Click="SetDeviceConfigButton_Click" />
<Button Content="Reboot CLR" HorizontalAlignment="Left" Margin="364,77,0,0" VerticalAlignment="Top" Width="121" Click="RebootDeviceButton_Click"/>
<Button Content="Soft Reboot" HorizontalAlignment="Left" Margin="364,102,0,0" VerticalAlignment="Top" Width="121" Click="SoftRebootDeviceButton_Click"/>
<Button Content="Reboot to bootloader" HorizontalAlignment="Left" Margin="364,129,0,0" VerticalAlignment="Top" Width="121" Click="RebootToBootloaderButton_Click"/>
<Button Content="Stop Processing" HorizontalAlignment="Left" Margin="364,187,0,0" VerticalAlignment="Top" Width="121" Click="StopProcessingButton_Click"/>
<Button Content="Erase Deployment" HorizontalAlignment="Left" Margin="364,216,0,0" VerticalAlignment="Top" Width="121" Click="EraseDeploymentButton_Click" />
<Button Content="Is Init State" HorizontalAlignment="Left" Margin="162,187,0,0" VerticalAlignment="Top" Width="75" Click="IsInitStateButton_Click" />
<Button Content="Get Device Config" HorizontalAlignment="Left" Margin="364,245,0,0" VerticalAlignment="Top" Width="121" Click="GetDeviceConfigButton_Click" />
<Button Content="Set Device Config" HorizontalAlignment="Left" Margin="364,275,0,0" VerticalAlignment="Top" Width="121" Click="SetDeviceConfigButton_Click" />
<Button Content="ReScan devices" HorizontalAlignment="Left" Margin="250,157,0,0" VerticalAlignment="Top" Width="98" Click="ReScanDevices_Click" />
<Button Content="Read Test" HorizontalAlignment="Left" Margin="250,313,0,0" VerticalAlignment="Top" Width="98" Click="ReadTestButton_Click" />
<Button Content="Target Info" HorizontalAlignment="Left" Margin="39,313,0,0" VerticalAlignment="Top" Width="110" Click="TargetInfoButton_Click" />
<Button Content="Reboot to nanoBooter" HorizontalAlignment="Left" Margin="378,157,0,0" VerticalAlignment="Top" Width="121" Click="RebootToNanoBooterButton_Click"/>
<Button Content="Deploy File" HorizontalAlignment="Left" Margin="162,313,0,0" VerticalAlignment="Top" Width="75" Click="DeployFileTestButton_Click" />
<Button Content="Read Test" HorizontalAlignment="Left" Margin="250,275,0,0" VerticalAlignment="Top" Width="98" Click="ReadTestButton_Click" />
<Button Content="Target Info" HorizontalAlignment="Left" Margin="39,275,0,0" VerticalAlignment="Top" Width="110" Click="TargetInfoButton_Click" />
<Button Content="Reboot to nanoBooter" HorizontalAlignment="Left" Margin="364,157,0,0" VerticalAlignment="Top" Width="121" Click="RebootToNanoBooterButton_Click"/>
<Button Content="Deploy File" HorizontalAlignment="Left" Margin="162,275,0,0" VerticalAlignment="Top" Width="75" Click="DeployFileTestButton_Click" />
<Button Content="Reboot CLR" HorizontalAlignment="Left" Margin="364,77,0,0" VerticalAlignment="Top" Width="121" Click="RebootDeviceButton_Click"/>
<Button Content="Upload File I:\" HorizontalAlignment="Left" Margin="39,306,0,0" VerticalAlignment="Top" Width="110" Click="UploadFileInternalStorage_Click"/>
<Button Content="Rm file I:\" HorizontalAlignment="Left" Margin="162,306,0,0" VerticalAlignment="Top" Width="75" Click="RemoveFileInternalStorage_Click"/>
</Grid>

Просмотреть файл

@ -1092,5 +1092,46 @@ rUCGwbCUDI0mxadJ3Bz4WxR6fyNpBK2yAinWEsikxqEt
// enable button
(sender as Button).IsEnabled = true;
}
private void UploadFileInternalStorage_Click(object sender, RoutedEventArgs e)
{
string fileContent = "1. This is a test file to upload in internal storage. A long message to test more than just a line.\r\n" +
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. " +
"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. " +
"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. " +
"2. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\r\n" +
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. " +
"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. " +
"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. " +
"3. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\r\n" +
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. " +
"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. " +
"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. " +
"4. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\r\n";
//string fileContent = "simple test file";
string fileName = "I:\\upload.txt";
// disable button
(sender as Button).IsEnabled = false;
var reply1 = (DataContext as MainViewModel).AvailableDevices[DeviceGrid.SelectedIndex].DebugEngine.AddStorageFile(fileName, Encoding.UTF8.GetBytes(fileContent));
Debug.WriteLine($"File upload internal success: {reply1}");
// enable button
(sender as Button).IsEnabled = true;
}
private void RemoveFileInternalStorage_Click(object sender, RoutedEventArgs e)
{
string fileName = "I:\\upload.txt";
// disable button
(sender as Button).IsEnabled = false;
var reply1 = (DataContext as MainViewModel).AvailableDevices[DeviceGrid.SelectedIndex].DebugEngine.DeleteStorageFile(fileName);
Debug.WriteLine($"File upload internal success: {reply1}");
// enable button
(sender as Button).IsEnabled = true;
}
}
}

Просмотреть файл

@ -41,6 +41,45 @@ namespace nanoFramework.Tools.Debugger.WireProtocol
Unknown = 0xFFFF,
}
/// <summary>
/// Storage operation error codes.
/// </summary>
public enum StorageOperationErrorCode : uint
{
///////////////////////////////////////////////////////////////////////////////////////////
// NEED TO KEEP THESE IN SYNC WITH native 'StorageOperationErrorCode' enum in Debugger.h //
///////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// No error.
/// </summary>
NoError = 0x0001,
/// <summary>
/// Write error.
/// </summary>
WriteError = 0x0010,
/// <summary>
/// Delete error.
/// </summary>
DeleteError = 0x0020,
/// <summary>
/// Platform dependent error.
/// </summary>
PlatformError = 0x0030,
/////////////////////////////////////////////////////////
// The following element is not present in native code //
/////////////////////////////////////////////////////////
/// <summary>
/// Target does not support storage operations.
/// </summary>
NotSupported = 0xFFFF,
}
public class Commands
{
public const uint c_Monitor_Ping = 0x00000000; // The payload is empty, this command is used to let the other side know we are here...
@ -58,6 +97,7 @@ namespace nanoFramework.Tools.Debugger.WireProtocol
public const uint c_Monitor_OemInfo = 0x0000000E;
public const uint c_Monitor_QueryConfiguration = 0x0000000F;
public const uint c_Monitor_UpdateConfiguration = 0x00000010;
public const uint c_Monitor_StorageOperation = 0x00000011;
public const uint c_Monitor_TargetInfo = 0x00000020;
public class Monitor_Message : IConverter
@ -529,6 +569,136 @@ namespace nanoFramework.Tools.Debugger.WireProtocol
}
}
/// <summary>
/// Perform storage operation on the target device.
/// </summary>
public class Monitor_StorageOperation : OverheadBase
{
/// <summary>
/// Storage operation to be performed.
/// </summary>
public uint Operation = (byte)StorageOperation.None;
/// <summary>
/// File name for the the storage operation.
/// </summary>
[IgnoreDataMember]
public string FileName = string.Empty;
/// <summary>
/// Length of the name of the file to be used in the operation.
/// </summary>
public uint NameLength = 0;
/// <summary>
/// Length of the data to be used in the operation.
/// </summary>
public uint DataLength = 0;
/// <summary>
/// Offset in the file data of the chunck in this operation.
/// </summary>
/// <remarks>
/// This is to be used by the target device to know where to start writing the chunk data.
/// </remarks>
public uint Offset = 0;
/// <summary>
/// Data buffer to be sent to the device.
/// </summary>
public byte[] Data;
public class Reply
{
public uint ErrorCode;
};
/// <summary>
/// Prepare for sending a storage operation to the target device.
/// </summary>
/// <param name="operation"><see cref="StorageOperation"/> to be performed.</param>
/// <param name="name">Name of the file to be used in the operation.</param>
public void SetupOperation(
StorageOperation operation,
string name)
{
Operation = (uint)operation;
FileName = name;
}
/// <summary>
/// Prepare for sending a storage operation to the target device.
/// </summary>
/// <param name="buffer">Data buffer to be sent to the device.</param>
/// <param name="offset">Offset in the <paramref name="buffer"/> to start copying data from.</param>
/// <param name="length">Length of the data to be copied from the <paramref name="buffer"/>.</param>
public override bool PrepareForSend(
byte[] buffer,
int length,
int offset = 0)
{
// setup the data payload
DataLength = (uint)length;
Data = new byte[length + FileName.Length];
// add the file name to the data property buffer
var tempName = Encoding.UTF8.GetBytes(FileName);
NameLength = (uint)tempName.Length;
Array.Copy(tempName, 0, Data, 0, NameLength);
// copy the buffer data to the data property buffer
Array.Copy(buffer, offset, Data, NameLength, length);
return true;
}
internal void PrepareForSend()
{
// add the file name to the data property buffer
Data = Encoding.UTF8.GetBytes(FileName);
NameLength = (uint)FileName.Length;
}
//////////////////////////////////////////////////////////////////////////////////////
// !!! KEEP IN SYNC WITH typedef enum Monitor_StorageOperation (in native code) !!! //
//////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// Storage operation to be performed.
/// </summary>
public enum StorageOperation : byte
{
/// <summary>
/// Not specified.
/// </summary>
None = 0,
/// <summary>
/// Write to storage.
/// </summary>
/// <remarks>
/// If the file already exists, it will be overwritten.
/// </remarks>
Write = 1,
/// <summary>
/// Delete from storage.
/// </summary>
/// <remarks>
/// If the file doesn't exist, no action is taken.
/// </remarks>
Delete = 2,
/// <summary>
/// Append to a file.
/// </summary>
/// <remarks>
/// If the file doesn't exist, no action is taken.
/// </remarks>
Append = 3
}
}
public const uint c_Debugging_Execution_BasePtr = 0x00020000; // Returns the pointer for the ExecutionEngine object.
public const uint c_Debugging_Execution_ChangeConditions = 0x00020001; // Sets/resets the state of the debugger.
public const uint c_Debugging_Execution_SecurityKey = 0x00020002; // Sets security key.
@ -1857,7 +2027,7 @@ namespace nanoFramework.Tools.Debugger.WireProtocol
while (len < num && buf[len] != 0) len++;
if (fUTF8) return Encoding.UTF8.GetString(buf, 0, len);
else return Encoding.UTF8.GetString(buf, 0, len);
else return Encoding.ASCII.GetString(buf, 0, len);
}
public static object ResolveCommandToPayload(uint cmd, bool fReply, CLRCapabilities capabilities)
@ -1878,6 +2048,7 @@ namespace nanoFramework.Tools.Debugger.WireProtocol
case c_Monitor_FlashSectorMap: return new Monitor_FlashSectorMap.Reply();
case c_Monitor_QueryConfiguration: return new Monitor_QueryConfiguration.Reply();
case c_Monitor_UpdateConfiguration: return new Monitor_UpdateConfiguration.Reply();
case c_Monitor_StorageOperation: return new Monitor_StorageOperation.Reply();
case c_Debugging_Execution_BasePtr: return new Debugging_Execution_BasePtr.Reply();
case c_Debugging_Execution_ChangeConditions: return new DebuggingExecutionChangeConditions.Reply();
@ -1951,6 +2122,7 @@ namespace nanoFramework.Tools.Debugger.WireProtocol
case c_Monitor_DeploymentMap: return new Monitor_DeploymentMap();
case c_Monitor_FlashSectorMap: return new Monitor_FlashSectorMap();
case c_Monitor_QueryConfiguration: return new Monitor_QueryConfiguration();
case c_Monitor_StorageOperation: return new Monitor_StorageOperation();
case c_Debugging_Execution_BasePtr: return new Debugging_Execution_BasePtr();
case c_Debugging_Execution_ChangeConditions: return new DebuggingExecutionChangeConditions();

Просмотреть файл

@ -32,6 +32,11 @@ namespace nanoFramework.Tools.Debugger
/// </summary>
private const int _InterRequestSleep = 2;
/// <summary>
/// This constant is to be used in progress report when performing delete operation.
/// </summary>
public const int StorageDeleteOperationProgressStep = 10;
internal IPort _portDefinition;
internal Controller _controlller { get; set; }
@ -4423,6 +4428,224 @@ namespace nanoFramework.Tools.Debugger
return (int)WireProtocolPacketSize - cmd.Overhead;
}
#region Storage methods
/// <summary>
/// Add a file to the device storage.
/// </summary>
/// <param name="fileName">File name.</param>
/// <param name="fileContent">Content of the file.</param>
/// <param name="operationExecutedLenght">Count of bytes already executed in this operation.</param>
/// <param name="operationTotalLength">Total length of the operation, in bytes.</param>
/// <param name="progress">An <see cref="IProgress&lt;MessageWithProgress&gt;"/> object to track the progress of the deploy operation.</param>
/// <param name="log">An <see cref="IProgress&lt;String&gt;"/> object to log the progress of the deploy operation.</param>
/// <returns>Operation result as a <see cref="StorageOperationErrorCode"/>.</returns>
public StorageOperationErrorCode AddStorageFile(
string fileName,
byte[] fileContent,
int operationExecutedLenght = 0,
int operationTotalLength = 0,
IProgress<MessageWithProgress> progress = null,
IProgress<string> log = null)
{
// counters to manage the chunked update process
int count = fileContent.Length;
int position = 0;
int packetLength = 0;
StorageOperationErrorCode operationOutcome = StorageOperationErrorCode.WriteError;
log?.Report($"Storing '{fileName}'...");
while (count > 0)
{
// Send by chunk, the first chunk is a write, the others will be appened
var storageOperation = new Commands.Monitor_StorageOperation();
storageOperation.SetupOperation(
position == 0 ? Commands.Monitor_StorageOperation.StorageOperation.Write : Commands.Monitor_StorageOperation.StorageOperation.Append,
fileName);
// get packet length, either the maximum allowed size or whatever is still available to TX
packetLength = Math.Min(GetPacketMaxLength(storageOperation), count);
storageOperation.PrepareForSend(fileContent, packetLength, position);
// update offset field
storageOperation.Offset = (uint)position;
progress?.Report(new MessageWithProgress($"Storing '{fileName}' file in target storage...", (uint)(operationExecutedLenght + position + packetLength), (uint)operationTotalLength));
log?.Report($"Sent {position + packetLength}/{fileContent.Length} bytes.");
// send the file chunk to the device
IncomingMessage reply = PerformSyncRequest(Commands.c_Monitor_StorageOperation, 0, storageOperation);
if (reply != null)
{
if (!reply.IsPositiveAcknowledge())
{
// target doesn't support this command
operationOutcome = StorageOperationErrorCode.NotSupported;
}
else
{
if (reply.Payload is Commands.Monitor_StorageOperation.Reply cmdReply)
{
operationOutcome = (StorageOperationErrorCode)cmdReply.ErrorCode;
if (operationOutcome != StorageOperationErrorCode.NoError)
{
// done here
break;
}
}
else
{
// set generic write error
operationOutcome = StorageOperationErrorCode.WriteError;
// done here
break;
}
}
}
else
{
// set generic write error
operationOutcome = StorageOperationErrorCode.WriteError;
// done here
break;
}
// update counters
count -= packetLength;
position += packetLength;
}
// clear progress report message
progress?.Report(new MessageWithProgress(""));
if (operationOutcome != StorageOperationErrorCode.NoError)
{
// there was an error, compose error message...
var errorMessage = new StringBuilder($"Error sending {packetLength} bytes to device. Store operation failed. ");
switch (operationOutcome)
{
case StorageOperationErrorCode.PlatformError:
errorMessage.Append("Error is platform related.");
break;
case StorageOperationErrorCode.NotSupported:
errorMessage = new StringBuilder($"Target doesn't have support to access storage. "); ;
break;
default:
errorMessage.Append("Unknown error.");
break;
}
// ...and report it
log?.Report(errorMessage.ToString());
}
return operationOutcome;
}
/// <summary>
/// Delete a file from the device storage.
/// </summary>
/// <param name="fileName">Name of file to delete.</param>
/// <param name="operationExecutedLenght">Count of bytes already executed in this operation.</param>
/// <param name="operationTotalLength">Total length of the operation, in bytes.</param>
/// <param name="progress">An <see cref="IProgress&lt;MessageWithProgress&gt;"/> object to track the progress of the deploy operation.</param>
/// <param name="log">An <see cref="IProgress&lt;String&gt;"/> object to log the progress of the deploy operation.</param>
/// <returns>Operation result as a <see cref="StorageOperationErrorCode"/>.</returns>
/// <remarks>
/// When computing the operation total length, use the constant <see cref="StorageDeleteOperationProgressStep"/> as the step weight and consider that this will be executed in a single step.
/// </remarks>
public StorageOperationErrorCode DeleteStorageFile(
string fileName,
int operationExecutedLenght = 0,
int operationTotalLength = 0,
IProgress<MessageWithProgress> progress = null,
IProgress<string> log = null)
{
StorageOperationErrorCode operationOutcome = StorageOperationErrorCode.DeleteError;
var storop = new Commands.Monitor_StorageOperation();
storop.SetupOperation(
Commands.Monitor_StorageOperation.StorageOperation.Delete,
fileName);
storop.PrepareForSend();
progress?.Report(new MessageWithProgress($"Deleting '{fileName}' from target storage...", (uint)(operationExecutedLenght + StorageDeleteOperationProgressStep), (uint)operationTotalLength));
log?.Report($"Deleting '{fileName}' from target storage...");
IncomingMessage reply = PerformSyncRequest(
Commands.c_Monitor_StorageOperation,
0,
storop);
if (reply != null)
{
if (!reply.IsPositiveAcknowledge())
{
// target doesn't support this command
operationOutcome = StorageOperationErrorCode.NotSupported;
}
else
{
if (reply.Payload is Commands.Monitor_StorageOperation.Reply cmdReply)
{
operationOutcome = (StorageOperationErrorCode)cmdReply.ErrorCode;
}
else
{
// set generic write error
operationOutcome = StorageOperationErrorCode.DeleteError;
}
}
}
// clear progress report message
progress?.Report(new MessageWithProgress(""));
if (operationOutcome != StorageOperationErrorCode.NoError)
{
// there was an error, compose error message...
var errorMessage = new StringBuilder($"Error deleting file from storage. ");
switch (operationOutcome)
{
case StorageOperationErrorCode.PlatformError:
errorMessage.Append("Error platform related.");
break;
case StorageOperationErrorCode.DeleteError:
errorMessage.Append("Couldn't delete the file.");
break;
case StorageOperationErrorCode.NotSupported:
errorMessage = new StringBuilder($"Target doesn't have support to access storage. "); ;
break;
default:
errorMessage.Append("Unknown error.");
break;
}
// ...and report it
log?.Report(errorMessage.ToString());
}
return operationOutcome;
}
#endregion
/// <summary>
/// Writes a specific configuration block to the device.
/// The configuration block is updated only with the changes for this configuration part.