From 7af0825e7d716934e76755f82559a6518ec3e678 Mon Sep 17 00:00:00 2001 From: Chris Tacke Date: Thu, 28 Sep 2023 16:18:48 -0500 Subject: [PATCH] fix file read error condition, file CRC/hash --- .../Current/Firmware/FirmwareWriteCommand.cs | 9 +++- .../SerialConnection.ListenerProc.cs | 8 ++- .../Connections/SerialConnection.cs | 51 ++++++++++++++----- .../Serial Requests/InitFileWriteRequest.cs | 11 ++-- 4 files changed, 56 insertions(+), 23 deletions(-) diff --git a/Source/v2/Meadow.Cli/Commands/Current/Firmware/FirmwareWriteCommand.cs b/Source/v2/Meadow.Cli/Commands/Current/Firmware/FirmwareWriteCommand.cs index b6fe8a46..75273f48 100644 --- a/Source/v2/Meadow.Cli/Commands/Current/Firmware/FirmwareWriteCommand.cs +++ b/Source/v2/Meadow.Cli/Commands/Current/Firmware/FirmwareWriteCommand.cs @@ -130,7 +130,14 @@ protected override async ValueTask ExecuteCommand(IMeadowConnection connection, // the connection passes messages back to us (info about actions happening on-device connection.DeviceMessageReceived += (s, e) => { - Logger.LogInformation(e.message); + if (e.message.Contains("% downloaded")) + { + // don't echo this, as we're already reporting % written + } + else + { + Logger.LogInformation(e.message); + } }; var package = await GetSelectedPackage(); diff --git a/Source/v2/Meadow.Hcom/Connections/SerialConnection.ListenerProc.cs b/Source/v2/Meadow.Hcom/Connections/SerialConnection.ListenerProc.cs index c253b398..8da21441 100644 --- a/Source/v2/Meadow.Hcom/Connections/SerialConnection.ListenerProc.cs +++ b/Source/v2/Meadow.Hcom/Connections/SerialConnection.ListenerProc.cs @@ -1,5 +1,4 @@ -using Microsoft.Extensions.Logging; -using System.Diagnostics; +using System.Diagnostics; namespace Meadow.Hcom { @@ -230,8 +229,7 @@ private async Task ListenerProc() _readFileInfo.FileStream = File.Create(_readFileInfo.LocalFileName); var uploadRequest = RequestBuilder.Build(); - EncodeAndSendPacket(uploadRequest.Serialize()); - // (this as IMeadowConnection).EnqueueRequest(uploadRequest); + await EncodeAndSendPacket(uploadRequest.Serialize()); } else if (response is UploadDataPacketResponse udp) { @@ -318,8 +316,8 @@ private async Task ListenerProc() } catch (Exception ex) { + RaiseConnectionError(ex); Debug.WriteLine($"listen error {ex.Message}"); - _logger?.LogTrace(ex, "An error occurred while listening to the serial port."); await Task.Delay(1000); } } diff --git a/Source/v2/Meadow.Hcom/Connections/SerialConnection.cs b/Source/v2/Meadow.Hcom/Connections/SerialConnection.cs index f94a982b..cbdab95a 100644 --- a/Source/v2/Meadow.Hcom/Connections/SerialConnection.cs +++ b/Source/v2/Meadow.Hcom/Connections/SerialConnection.cs @@ -2,6 +2,8 @@ using System.Buffers; using System.Diagnostics; using System.IO.Ports; +using System.Security.Cryptography; +using System.Text; namespace Meadow.Hcom; @@ -931,10 +933,28 @@ private async Task WriteFile( CancellationToken? cancellationToken = null) { var command = RequestBuilder.Build(); + + var fileBytes = File.ReadAllBytes(localFileName); + + var fileHash = Encoding.ASCII.GetBytes("12345678901234567890123456789012"); // must be 32 bytes + if (writeAddress != 0) + { + // calculate the MD5 hash of the file - we have to send it as a UTF8 string, not as bytes. + using var md5 = MD5.Create(); + var hashBytes = md5.ComputeHash(fileBytes); + var hashString = BitConverter.ToString(hashBytes) + .Replace("-", "") + .ToLowerInvariant(); + fileHash = Encoding.UTF8.GetBytes(hashString); + } + var fileCrc = NuttxCrc.Crc32part(fileBytes, (uint)fileBytes.Length, 0); + command.SetParameters( localFileName, meadowFileName ?? Path.GetFileName(localFileName), + fileCrc, writeAddress, + fileHash, initialRequestType); var accepted = false; @@ -967,21 +987,21 @@ void OnFileError(object? sender, Exception exception) } // now send the file data - - using FileStream fs = File.OpenRead(localFileName); - // The maximum data bytes is max packet size - 2 bytes for the sequence number byte[] packet = new byte[Protocol.HCOM_PROTOCOL_PACKET_MAX_SIZE - 2]; int bytesRead; ushort sequenceNumber = 0; var progress = 0; - var expected = fs.Length; + var expected = fileBytes.Length; var fileName = Path.GetFileName(localFileName); base.RaiseFileWriteProgress(fileName, progress, expected); + var oldTimeout = _port.ReadTimeout; + _port.ReadTimeout = 60000; + while (true) { if (cancellationToken.HasValue && cancellationToken.Value.IsCancellationRequested) @@ -991,15 +1011,20 @@ void OnFileError(object? sender, Exception exception) sequenceNumber++; - // sequence number at the start of the packet Array.Copy(BitConverter.GetBytes(sequenceNumber), packet, 2); - // followed by the file data - bytesRead = fs.Read(packet, 2, packet.Length - 2); - if (bytesRead <= 0) break; - await EncodeAndSendPacket(packet, bytesRead + 2, cancellationToken); - progress += bytesRead; + + var toRead = fileBytes.Length - progress; + if (toRead > packet.Length - 2) + { + toRead = packet.Length - 2; + } + Array.Copy(fileBytes, progress, packet, 2, toRead); + await EncodeAndSendPacket(packet, toRead + 2, cancellationToken); + progress += toRead; base.RaiseFileWriteProgress(fileName, progress, expected); + if (progress >= fileBytes.Length) break; } + _port.ReadTimeout = oldTimeout; base.RaiseFileWriteProgress(fileName, expected, expected); @@ -1035,21 +1060,21 @@ void OnFileError(object? sender, Exception exception) { FileReadCompleted += OnFileReadCompleted; FileException += OnFileError; + ConnectionError += OnFileError; EnqueueRequest(command); if (!await WaitForResult( () => { - if (ex != null) throw ex; - return completed; + return completed | ex != null; }, cancellationToken)) { return false; } - return true; + return ex == null; } finally { diff --git a/Source/v2/Meadow.Hcom/Serial Requests/InitFileWriteRequest.cs b/Source/v2/Meadow.Hcom/Serial Requests/InitFileWriteRequest.cs index 2035f349..a284dcef 100644 --- a/Source/v2/Meadow.Hcom/Serial Requests/InitFileWriteRequest.cs +++ b/Source/v2/Meadow.Hcom/Serial Requests/InitFileWriteRequest.cs @@ -83,9 +83,13 @@ internal class InitFileWriteRequest : Request public void SetParameters( string localFile, string meadowFileName, - int espAddress = 0, + uint fileCrc, + int espAddress, + byte[] espHash, RequestType requestType = RequestType.HCOM_MDOW_REQUEST_START_FILE_TRANSFER) { + if (espHash.Length != 32) throw new ArgumentException(); + // file write has additional header payload that's sent with the request, build it here _requestType = requestType; @@ -97,13 +101,12 @@ public void SetParameters( MeadowFileName = meadowFileName; var nameBytes = Encoding.ASCII.GetBytes(meadowFileName); - var espHash = Encoding.ASCII.GetBytes("12345678901234567890123456789012"); // Must be 32 bytes Payload = new byte[4 + 4 + 4 + 32 + nameBytes.Length]; Array.Copy(BitConverter.GetBytes((uint)source.Length), 0, Payload, 0, 4); // file size - Array.Copy(BitConverter.GetBytes((uint)source.Length), 0, Payload, 4, 4); // file crc + Array.Copy(BitConverter.GetBytes(fileCrc), 0, Payload, 4, 4); // file crc Array.Copy(BitConverter.GetBytes(espAddress), 0, Payload, 8, 4); // ESP flash address offset - Array.Copy(espHash, 0, Payload, 12, espHash.Length); // TODO: ESP hash (dev note: this appears to never be used or needed?) + Array.Copy(espHash, 0, Payload, 12, espHash.Length); Array.Copy(nameBytes, 0, Payload, 44, nameBytes.Length); // file name } } \ No newline at end of file