/// <summary> /// Attempts to deploy an SREC (.hex) file to the connected .Net Micro Framework device. The /// signatureFile is used to validate the image once it has been deployed to the device. If /// the signature does not match the image is erased. /// </summary> /// <param name="srecFile">Storage file with the SREC (.hex) file</param> /// <param name="signatureFile">Storage file with the signature file (.sig) for the corresponding SREC file in the srecFile parameter</param> /// <param name="entrypoint">Out parameter that is set to the entry point address for the given SREC file</param> /// <returns>Returns false if the deployment fails, true otherwise /// Possible exceptions: MFFileNotFoundException, MFDeviceNoResponseException, MFUserExitException /// </returns> public async Task <Tuple <uint, bool> > DeployAsync(StorageFile srecFile, StorageFile signatureFile, CancellationToken cancellationToken, IProgress <ProgressReport> progress = null) { uint entryPoint = 0; if (!srecFile.IsAvailable) { throw new FileNotFoundException(srecFile.Path); } if (DebugEngine == null) { throw new MFDeviceNoResponseException(); } // make sure we know who we are talking to if (await CheckForMicroBooterAsync(cancellationToken)) { var reply = await DeploySRECAsync(srecFile, cancellationToken); // check if request was successful if (reply.Item2) { entryPoint = reply.Item1; return(new Tuple <uint, bool>(entryPoint, true)); } else { return(new Tuple <uint, bool>(0, false)); } } await DebugEngine.ConnectAsync(1, 1000, false, ConnectionSource.Unknown); List <SRecordFile.Block> blocks = new List <SRecordFile.Block>(); entryPoint = await SRecordFile.ParseAsync(srecFile, blocks, signatureFile != null?signatureFile : null); if (blocks.Count > 0) { long total = 0; long value = 0; for (int i = 0; i < blocks.Count; i++) { total += (blocks[i] as SRecordFile.Block).data.Length; } await PrepareForDeployAsync(blocks, cancellationToken, progress); foreach (SRecordFile.Block block in blocks) { long len = block.data.Length; uint addr = block.address; // check if cancellation was requested if (cancellationToken.IsCancellationRequested) { throw new MFUserExitException(); } block.data.Seek(0, SeekOrigin.Begin); progress?.Report(new ProgressReport(0, total, string.Format("Erasing sector 0x{0:x08}", block.address))); // the clr requires erase before writing if (!await DebugEngine.EraseMemoryAsync(block.address, (uint)len)) { return(new Tuple <uint, bool>(0, false)); } while (len > 0) { // check if cancellation was requested if (cancellationToken.IsCancellationRequested) { throw new MFUserExitException(); } int buflen = len > 1024 ? 1024 : (int)len; byte[] data = new byte[buflen]; if (block.data.Read(data, 0, buflen) <= 0) { return(new Tuple <uint, bool>(0, false)); } if (!await DebugEngine.WriteMemoryAsync(addr, data)) { return(new Tuple <uint, bool>(0, false)); } value += buflen; addr += (uint)buflen; len -= buflen; progress?.Report(new ProgressReport(value, total, string.Format("Deploying {0}...", srecFile.Name))); } if (DebugEngine.ConnectionSource != ConnectionSource.TinyCLR) { byte[] emptySig = new byte[128]; progress?.Report(new ProgressReport(value, total, "Checking Signature...")); if (!await DebugEngine.CheckSignatureAsync(((block.signature == null || block.signature.Length == 0) ? emptySig : block.signature), 0)) { throw new MFSignatureFailureException(signatureFile); } } } } return(new Tuple <uint, bool>(entryPoint, true)); }
/// <summary> /// Erases the deployment sectors of the connected .Net Micro Framework device /// </summary> /// <param name="options">Identifies which areas are to be erased</param> /// <param name="cancellationToken">Cancellation token to allow caller to cancel task</param> /// <param name="progress">Progress report of execution</param> /// <returns>Returns false if the erase fails, true otherwise /// Possible exceptions: MFUserExitException, MFDeviceNoResponseException /// </returns> public async Task <bool> EraseAsync(EraseOptions options, CancellationToken cancellationToken, IProgress <ProgressReport> progress = null) { bool ret = false; bool fReset = false; if (DebugEngine == null) { throw new MFDeviceNoResponseException(); } if (!await DebugEngine.ConnectAsync(2, 500, true)) { throw new MFDeviceNoResponseException(); } if (!IsClrDebuggerEnabled || 0 != (options & EraseOptions.Firmware)) { fReset = (await PingAsync() == PingConnectionType.TinyCLR); if (!await ConnectToTinyBooterAsync(cancellationToken)) { throw new MFTinyBooterConnectionFailureException(); } } var reply = await DebugEngine.GetFlashSectorMapAsync(); if (reply == null) { throw new MFDeviceNoResponseException(); } Commands.Monitor_Ping.Reply ping = await DebugEngine.GetConnectionSourceAsync(); ret = true; long total = 0; long value = 0; bool isConnectedToCLR = ((ping != null) && (ping.m_source == Commands.Monitor_Ping.c_Ping_Source_TinyCLR)); if (isConnectedToCLR) { await DebugEngine.PauseExecutionAsync(); } List <Commands.Monitor_FlashSectorMap.FlashSectorData> eraseSectors = new List <Commands.Monitor_FlashSectorMap.FlashSectorData>(); foreach (Commands.Monitor_FlashSectorMap.FlashSectorData flashSectorData in reply) { if (cancellationToken.IsCancellationRequested) { throw new MFUserExitException(); } switch (flashSectorData.m_flags & Commands.Monitor_FlashSectorMap.c_MEMORY_USAGE_MASK) { case Commands.Monitor_FlashSectorMap.c_MEMORY_USAGE_DEPLOYMENT: if (EraseOptions.Deployment == (options & EraseOptions.Deployment)) { eraseSectors.Add(flashSectorData); total++; } break; case Commands.Monitor_FlashSectorMap.c_MEMORY_USAGE_UPDATE: if (EraseOptions.UpdateStorage == (options & EraseOptions.UpdateStorage)) { eraseSectors.Add(flashSectorData); total++; } break; case Commands.Monitor_FlashSectorMap.c_MEMORY_USAGE_SIMPLE_A: case Commands.Monitor_FlashSectorMap.c_MEMORY_USAGE_SIMPLE_B: if (EraseOptions.SimpleStorage == (options & EraseOptions.SimpleStorage)) { eraseSectors.Add(flashSectorData); total++; } break; case Commands.Monitor_FlashSectorMap.c_MEMORY_USAGE_STORAGE_A: case Commands.Monitor_FlashSectorMap.c_MEMORY_USAGE_STORAGE_B: if (EraseOptions.UserStorage == (options & EraseOptions.UserStorage)) { eraseSectors.Add(flashSectorData); total++; } break; case Commands.Monitor_FlashSectorMap.c_MEMORY_USAGE_FS: if (EraseOptions.FileSystem == (options & EraseOptions.FileSystem)) { eraseSectors.Add(flashSectorData); total++; } break; case Commands.Monitor_FlashSectorMap.c_MEMORY_USAGE_CONFIG: case Commands.Monitor_FlashSectorMap.c_MEMORY_USAGE_CODE: if (EraseOptions.Firmware == (options & EraseOptions.Firmware)) { eraseSectors.Add(flashSectorData); total++; } break; } } foreach (Commands.Monitor_FlashSectorMap.FlashSectorData flashSectorData in eraseSectors) { progress?.Report(new ProgressReport(value, total, string.Format("Erasing sector 0x{0:x08}", flashSectorData.m_address))); ret &= await DebugEngine.EraseMemoryAsync(flashSectorData.m_address, flashSectorData.m_size); value++; } // reset if we specifically entered tinybooter for the erase if (fReset) { await DebugEngine.ExecuteMemoryAsync(0); } // reboot if we are talking to the clr if (isConnectedToCLR) { progress?.Report(new ProgressReport(0, 0, "Rebooting...")); await DebugEngine.RebootDeviceAsync(RebootOption.RebootClrOnly); } return(ret); }