// This method is called to sent to Visual Studio debugging to Mono public static void ForwardVisualStudioDataToMono(byte[] debuggerData, MeadowSerialDevice meadow, int userData) { // Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}-MDM-Forwarding {debuggerData.Length} bytes to Mono via hcom"); _meadowRequestType = HcomMeadowRequestType.HCOM_MDOW_REQUEST_DEBUGGING_DEBUGGER_DATA; new SendTargetData(meadow).BuildAndSendSimpleData(debuggerData, _meadowRequestType, (uint)userData); }
public static void WriteFileToFlash(MeadowSerialDevice meadow, string fileName, string targetFileName = null, int partition = 0) { meadowRequestType = HcomMeadowRequestType.HCOM_MDOW_REQUEST_START_FILE_TRANSFER; if (string.IsNullOrWhiteSpace(targetFileName)) { targetFileName = Path.GetFileName(fileName); } // For the STM32F7 on meadow, we need source file and destination file names. string[] csvArray = fileName.Split(','); if (csvArray.Length == 1) { // No CSV, just the source file name. So we'll assume the targetFileName is correct TransmitFileInfoToExtFlash(meadow, meadowRequestType, fileName, targetFileName, partition, 0, false, true); } else { // At this point, the fileName field should contain a CSV string containing the source // and destionation file names, always in an even number. if (csvArray.Length % 2 != 0) { Console.WriteLine("Please provide a CSV input with file names \"source, destination, source, destination\""); return; } for (int i = 0; i < csvArray.Length; i += 2) { // Send files one-by-one TransmitFileInfoToExtFlash(meadow, meadowRequestType, csvArray[i].Trim(), csvArray[i + 1].Trim(), partition, 0, false); } } }
//========================================================================== // This is most of the mandatory part of every non-data packet private int BuildMeadowBoundSimpleCommand(HcomMeadowRequestType requestType, UInt32 userData, ref byte[] messageBytes) { // Note: Could use the StructLayout attribute to build int offset = 0; // Two byte seq numb Array.Copy(BitConverter.GetBytes((UInt16)HCOM_PROTOCOL_COMMAND_SEQ_NUMBER), 0, messageBytes, offset, sizeof(UInt16)); offset += sizeof(UInt16); // Protocol version Array.Copy(BitConverter.GetBytes((UInt16)HCOM_PROTOCOL_CURRENT_VERSION_NUMBER), 0, messageBytes, offset, sizeof(UInt16)); offset += sizeof(UInt16); // Command type (2 bytes) Array.Copy(BitConverter.GetBytes((UInt16)requestType), 0, messageBytes, offset, sizeof(UInt16)); offset += sizeof(UInt16); // Extra Data Array.Copy(BitConverter.GetBytes((UInt16)HCOM_PROTOCOL_EXTRA_DATA_DEFAULT_VALUE), 0, messageBytes, offset, sizeof(UInt16)); offset += sizeof(UInt16); // User Data Array.Copy(BitConverter.GetBytes((UInt32)userData), 0, messageBytes, offset, sizeof(UInt32)); offset += sizeof(UInt32); return(offset); }
//========================================================================== // Build and send a "simple" message with only a header internal void BuildAndSendSimpleCommand(HcomMeadowRequestType requestType, UInt32 userData) { var messageBytes = new byte[HCOM_PROTOCOL_COMMAND_REQUIRED_HEADER_LENGTH]; // Populate the header BuildMeadowBoundSimpleCommand(requestType, userData, ref messageBytes); EncodeAndSendPacket(messageBytes, 0, HCOM_PROTOCOL_COMMAND_REQUIRED_HEADER_LENGTH); }
private static void TransmitFileInfoToExtFlash(MeadowSerialDevice meadow, HcomMeadowRequestType requestType, string sourceFileName, string targetFileName, int partition, uint mcuAddr, bool deleteFile, bool lastInSeries = false) { var sw = new Stopwatch(); var sendTargetData = new SendTargetData(meadow, false); try { //---------------------------------------------- if (deleteFile == true) { // No data packets, no end-of-file message and no mcu address sendTargetData.BuildAndSendFileRelatedCommand(requestType, (UInt32)partition, 0, 0, 0, string.Empty, sourceFileName); return; } // If ESP32 file we must also send the MD5 has of the file string md5Hash = string.Empty; if (mcuAddr != 0) { using (var md5 = MD5.Create()) { using (var stream = File.OpenRead(sourceFileName)) { var hash = md5.ComputeHash(stream); md5Hash = BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); } } } // Open, read and close the data file var fileBytes = File.ReadAllBytes(sourceFileName); var fileCrc32 = CrcTools.Crc32part(fileBytes, fileBytes.Length, 0); var fileLength = fileBytes.Length; sw.Start(); sw.Restart(); sendTargetData.SendTheEntireFile(requestType, targetFileName, (uint)partition, fileBytes, mcuAddr, fileCrc32, md5Hash, lastInSeries); sw.Stop(); if (sendTargetData.Verbose) { Console.WriteLine($"It took {sw.ElapsedMilliseconds:N0} millisec to send {fileLength:N0} bytes. FileCrc:{fileCrc32:x08}"); } } catch (Exception ex) { Debug.WriteLine($"TransmitFileInfoToExtFlash threw :{ex}"); throw; } }
public FileCommandBuilder(HcomMeadowRequestType requestType) { RequestType = requestType; if (_predicates.ContainsKey(RequestType)) { CompletionPredicate = _predicates[RequestType]; ResponsePredicate = _predicates[RequestType]; } }
public void SendTheEntireFile(HcomMeadowRequestType requestType, string destFileName, uint partitionId, byte[] fileBytes, UInt32 mcuAddr, UInt32 payloadCrc32, string md5Hash, bool lastInSeries) { _packetCrc32 = 0; try { // Build and send the header BuildAndSendFileRelatedCommand(requestType, partitionId, (UInt32)fileBytes.Length, payloadCrc32, mcuAddr, md5Hash, destFileName); //-------------------------------------------------------------- // Build each data packet int fileBufOffset = 0; int numbToSend; UInt16 sequenceNumber = 1; while (fileBufOffset <= fileBytes.Length - 1) // equal would mean past the end { if ((fileBufOffset + MeadowDeviceManager.MaxAllowableDataBlock) > (fileBytes.Length - 1)) { numbToSend = fileBytes.Length - fileBufOffset; // almost done, last packet } else { numbToSend = MeadowDeviceManager.MaxAllowableDataBlock; } BuildAndSendDataPacketRequest(fileBytes, fileBufOffset, numbToSend, sequenceNumber); fileBufOffset += numbToSend; sequenceNumber++; //if (sequenceNumber % 1000 == 0) // Console.WriteLine("Have sent {0:N0} bytes out of {1:N0} in {2:N0} packets", // fileBufOffset, fileBytes.Length, sequenceNumber); } //-------------------------------------------------------------- // Build and send the trailer BuildAndSendSimpleCommand(HcomMeadowRequestType.HCOM_MDOW_REQUEST_END_FILE_TRANSFER, lastInSeries ? (uint)1 : (uint)0); // set UserData // bufferOffset should point to the byte after the last byte Debug.Assert(fileBufOffset == fileBytes.Length); if (Verbose) { Console.WriteLine($"Total bytes sent {fileBufOffset:N0} in {sequenceNumber:N0} packets. PacketCRC:{_packetCrc32:x08}"); } } catch (Exception except) { Debug.WriteLine("Exception sending to Meadow:{0}", except); throw; } }
public static async Task ProcessCommand(MeadowSerialDevice meadow, HcomMeadowRequestType requestType, Predicate <MeadowMessageEventArgs> filter, uint userData = 0, bool doAcceptedCheck = true, int timeoutMs = 10000) { await new SendTargetData(meadow).SendSimpleCommand(requestType, userData, doAcceptedCheck); var result = await WaitForResponseMessage(meadow, filter, timeoutMs); if (!result) { throw new MeadowDeviceManagerException(requestType); } }
public static void PartitionFileSystem(MeadowSerialDevice meadow, int numberOfPartitions = 2) { if (numberOfPartitions < 1 || numberOfPartitions > 8) { throw new IndexOutOfRangeException("Number of partitions must be between 1 & 8 inclusive"); } meadowRequestType = HcomMeadowRequestType.HCOM_MDOW_REQUEST_PARTITION_FLASH_FS; new SendTargetData(meadow).SendSimpleCommand(meadowRequestType, (uint)numberOfPartitions); }
//providing a numeric (0 = none, 1 = info and 2 = debug) public static void SetTraceLevel(MeadowSerialDevice meadow, int level) { if (level < 0 || level > 3) { throw new System.ArgumentOutOfRangeException(nameof(level), "Trace level must be between 0 & 3 inclusive"); } _meadowRequestType = HcomMeadowRequestType.HCOM_MDOW_REQUEST_CHANGE_TRACE_LEVEL; new SendTargetData(meadow).SendSimpleCommand(_meadowRequestType, (uint)level); }
public static async Task <string> GetDeviceSerialNumber(MeadowSerialDevice meadow, int timeoutMs = 1000) { _meadowRequestType = HcomMeadowRequestType.HCOM_MDOW_REQUEST_GET_DEVICE_INFORMATION; await new SendTargetData(meadow).SendSimpleCommand(_meadowRequestType); var result = await WaitForResponseMessage(meadow, p => p.MessageType == MeadowMessageType.DeviceInfo, millisecondDelay : timeoutMs); if (result.isSuccessful) { return(ParseDeviceInfo(result.message, "Serial Number: ", ",")); } return(string.Empty); }
//========================================================================== // Build and send a "simple" message with data // Added for Visual Studio Debugging internal void BuildAndSendSimpleData(byte[] additionalData, HcomMeadowRequestType requestType, UInt32 userData) { int totalMsgLength = additionalData.Length + HCOM_PROTOCOL_COMMAND_REQUIRED_HEADER_LENGTH; var messageBytes = new byte[totalMsgLength]; // Populate the header BuildMeadowBoundSimpleCommand(requestType, userData, ref messageBytes); // Copy the payload into the message Array.Copy(additionalData, 0, messageBytes, HCOM_PROTOCOL_COMMAND_REQUIRED_HEADER_LENGTH, additionalData.Length); EncodeAndSendPacket(messageBytes, 0, totalMsgLength); }
//========================================================================== internal void BuildAndSendFileRelatedCommand(HcomMeadowRequestType requestType, UInt32 userData, UInt32 fileSize, UInt32 fileCheckSum, UInt32 mcuAddr, string md5Hash, string destFileName) { // Future: Try to use the StructLayout attribute Debug.Assert(md5Hash.Length == 0 || md5Hash.Length == HCOM_PROTOCOL_REQUEST_MD5_HASH_LENGTH); // Allocate the correctly size message buffers byte[] targetFileName = Encoding.UTF8.GetBytes(destFileName); // Using UTF-8 works for ASCII but should be Unicode in nuttx byte[] md5HashBytes = Encoding.UTF8.GetBytes(md5Hash); int optionalDataLength = sizeof(UInt32) + sizeof(UInt32) + sizeof(UInt32) + HCOM_PROTOCOL_REQUEST_MD5_HASH_LENGTH + targetFileName.Length; byte[] messageBytes = new byte[HCOM_PROTOCOL_COMMAND_REQUIRED_HEADER_LENGTH + optionalDataLength]; // Add the required header int offset = BuildMeadowBoundSimpleCommand(requestType, userData, ref messageBytes); // File Size Array.Copy(BitConverter.GetBytes(fileSize), 0, messageBytes, offset, sizeof(UInt32)); offset += sizeof(UInt32); // CRC32 checksum or delete file partition number Array.Copy(BitConverter.GetBytes(fileCheckSum), 0, messageBytes, offset, sizeof(UInt32)); offset += sizeof(UInt32); // MCU address for this file. Used for ESP32 file downloads Array.Copy(BitConverter.GetBytes(mcuAddr), 0, messageBytes, offset, sizeof(UInt32)); offset += sizeof(UInt32); // Include ESP32 MD5 hash if it's needed if (string.IsNullOrEmpty(md5Hash)) { Array.Clear(messageBytes, offset, HCOM_PROTOCOL_REQUEST_MD5_HASH_LENGTH); } else { Array.Copy(md5HashBytes, 0, messageBytes, offset, HCOM_PROTOCOL_REQUEST_MD5_HASH_LENGTH); } offset += HCOM_PROTOCOL_REQUEST_MD5_HASH_LENGTH; // Destination File Name Array.Copy(targetFileName, 0, messageBytes, offset, targetFileName.Length); offset += targetFileName.Length; Debug.Assert(offset == optionalDataLength + HCOM_PROTOCOL_COMMAND_REQUIRED_HEADER_LENGTH); EncodeAndSendPacket(messageBytes, 0, offset); }
public static async Task <bool> WriteFileToFlash(MeadowSerialDevice meadow, string fileName, string targetFileName = null, int partition = 0) { meadowRequestType = HcomMeadowRequestType.HCOM_MDOW_REQUEST_START_FILE_TRANSFER; if (string.IsNullOrWhiteSpace(targetFileName)) { targetFileName = Path.GetFileName(fileName); } // For the STM32F7 on meadow, we need source file and destination file names. string[] csvArray = fileName.Split(','); if (csvArray.Length == 1) { await Task.WhenAll( Task.Run(() => TransmitFileInfoToExtFlash(meadow, meadowRequestType, fileName, targetFileName, partition, 0, false, true)), MeadowDeviceManager.WaitForResponseMessage(meadow, x => x.MessageType == MeadowMessageType.Concluded)); // No CSV, just the source file name. So we'll assume the targetFileName is correct //TransmitFileInfoToExtFlash(meadow, meadowRequestType, fileName, targetFileName, partition, 0, false, true); return(true); } else { // At this point, the fileName field should contain a CSV string containing the source // and destionation file names, always in an even number. if (csvArray.Length % 2 != 0) { Console.WriteLine("Please provide a CSV input with file names \"source, destination, source, destination\""); return(false); } for (int i = 0; i < csvArray.Length; i += 2) { // Send files one-by-one bool lastFile = i == csvArray.Length - 2 ? true : false; TransmitFileInfoToExtFlash(meadow, meadowRequestType, csvArray[i].Trim(), csvArray[i + 1].Trim(), partition, 0, false, lastFile); } } return(false); }
public Command(HcomMeadowRequestType requestType, TimeSpan timeout, uint userData, byte[]?data, Predicate <MeadowMessageEventArgs> responsePredicate, Predicate <MeadowMessageEventArgs> completionPredicate, EventHandler <MeadowMessageEventArgs>?responseHandler, bool isAcknowledged, string commandBuilder) { RequestType = requestType; Timeout = timeout; UserData = userData; Data = data; ResponsePredicate = responsePredicate; CompletionPredicate = completionPredicate; ResponseHandler = responseHandler; IsAcknowledged = isAcknowledged; CommandBuilder = commandBuilder; }
//========================================================================== internal async Task <bool> SendSimpleCommand(HcomMeadowRequestType requestType, uint userData = 0, bool doAcceptedCheck = true) { var tcs = new TaskCompletionSource <bool>(); var received = false; if (!doAcceptedCheck) { BuildAndSendSimpleCommand(requestType, userData); return(true); } EventHandler <MeadowMessageEventArgs> handler = (s, e) => { if (e.MessageType == MeadowMessageType.Accepted) { received = true; tcs.SetResult(true); } }; if (_device.DataProcessor != null) { _device.DataProcessor.OnReceiveData += handler; } BuildAndSendSimpleCommand(requestType, userData); await Task.WhenAny(new Task[] { tcs.Task, Task.Delay(10000) }); if (_device.DataProcessor != null) { _device.DataProcessor.OnReceiveData -= handler; } if (!received) { throw new Exception("Command not accepted."); } return(received); }
// Enter StartDebugging mode. public static async Task StartDebugging(MeadowSerialDevice meadow, int vsDebugPort) { // Tell meadow to start it's debugging server, after restarting. _meadowRequestType = HcomMeadowRequestType.HCOM_MDOW_REQUEST_MONO_START_DBG_SESSION; await new SendTargetData(meadow).SendSimpleCommand(_meadowRequestType); // The previous command caused Meadow to restart. Therefore, we must reestablish // Meadow communication. meadow.AttemptToReconnectToMeadow(); // Create an instance of the TCP socket send/receiver class and // start it receiving. if (vsDebugPort == 0) { Console.WriteLine($"Without '--VSDebugPort' being specified, will assume Visual Studio 2019 using default port {DefaultVS2019DebugPort}"); vsDebugPort = DefaultVS2019DebugPort; } // Start the local Meadow.CLI debugging server debuggingServer = new DebuggingServer(vsDebugPort); debuggingServer.StartListening(meadow); }
internal FileCommand(HcomMeadowRequestType requestType, TimeSpan timeout, string sourceFileName, string destinationFileName, string?md5Hash, uint crc32, int fileSize, uint partition, uint mcuAddress, byte[]?fileBytes, Predicate <MeadowMessageEventArgs> responseHandler, Predicate <MeadowMessageEventArgs> completionHandler, string commandBuilder) : base(requestType, timeout, partition, null, responseHandler, completionHandler, null, true, commandBuilder) { SourceFileName = sourceFileName; DestinationFileName = destinationFileName; Md5Hash = md5Hash ?? string.Empty; Crc32 = crc32; FileSize = fileSize; Partition = partition; McuAddress = mcuAddress; FileBytes = fileBytes; }
public static async Task <bool> GetDeviceInfo(MeadowSerialDevice meadow, int timeoutMs = 1000) { _meadowRequestType = HcomMeadowRequestType.HCOM_MDOW_REQUEST_GET_DEVICE_INFORMATION; await new SendTargetData(meadow).SendSimpleCommand(_meadowRequestType); return(await WaitForResponseMessage(meadow, p => p.MessageType == MeadowMessageType.DeviceInfo, millisecondDelay : timeoutMs)); }
public static void VerifyErasedFlash(MeadowSerialDevice meadow) { meadowRequestType = HcomMeadowRequestType.HCOM_MDOW_REQUEST_VERIFY_ERASED_FLASH; new SendTargetData(meadow).SendSimpleCommand(meadowRequestType); }
// fileName - is the name of the file on this host PC // targetFileName - is the name of the file on the F7 public static async Task WriteFileToEspFlash(MeadowSerialDevice meadow, string fileName, string targetFileName = null, int partition = 0, string mcuDestAddr = null) { meadowRequestType = HcomMeadowRequestType.HCOM_MDOW_REQUEST_START_ESP_FILE_TRANSFER; // For the ESP32 on the meadow, we don't need the target file name, we just need the // MCU's destination address and the file's binary. // Assume if no mcuDestAddr that the fileName is a CSV with both file names and Mcu Addr if (mcuDestAddr != null) { // Since the mcuDestAddr is used we'll assume the fileName field just contains // a single file. if (string.IsNullOrWhiteSpace(targetFileName)) { // While not used by the ESP32 it cost nothing to send it and can help // with debugging targetFileName = Path.GetFileName(fileName); } // Convert mcuDestAddr from a string to a 32-bit unsigned int, but first // insure it starts with 0x UInt32 mcuAddr = 0; if (mcuDestAddr.StartsWith("0x") || mcuDestAddr.StartsWith("0X")) { mcuAddr = UInt32.Parse(mcuDestAddr.Substring(2), System.Globalization.NumberStyles.HexNumber); } else { Console.WriteLine($"The '--McuDestAddr' argument must be followed with an address in the form '0x1800'"); return; } await Task.WhenAll( Task.Run(() => TransmitFileInfoToExtFlash(meadow, meadowRequestType, fileName, targetFileName, partition, mcuAddr, false, true)), MeadowDeviceManager.WaitForResponseMessage(meadow, x => x.MessageType == MeadowMessageType.Concluded)); } else { // At this point, the fileName field should contain a CSV string containing the destination // addresses followed by file's location within the host's file system. // E.g. "0x8000, C:\Blink\partition-table.bin, 0x1000, C:\Blink\bootloader.bin, 0x10000, C:\Blink\blink.bin" string[] fileElement = fileName.Split(','); if (fileElement.Length % 2 != 0) { Console.WriteLine("Please provide a CSV input with \"address, fileName, address, fileName\""); return; } UInt32 mcuAddr; for (int i = 0; i < fileElement.Length; i += 2) { // Trim any white space from this mcu addr and file name fileElement[i] = fileElement[i].Trim(); fileElement[i + 1] = fileElement[i + 1].Trim(); if (fileElement[i].StartsWith("0x") || fileElement[i].StartsWith("0X")) { // Fill in the Mcu Addr mcuAddr = UInt32.Parse(fileElement[i].Substring(2), System.Globalization.NumberStyles.HexNumber); } else { Console.WriteLine("Please provide a CSV input with addresses like 0x1234"); return; } // Meadow.CLI --Esp32WriteFile --SerialPort Com26 --File // "0x8000, C:\Download\Esp32\Hello\partition-table.bin, 0x1000, C:\Download\Esp32\Hello\bootloader.bin, 0x10000, C:\Download\Esp32\Hello\hello-world.bin" // File Path and Name targetFileName = Path.GetFileName(fileElement[i + 1]); bool lastFile = i == fileElement.Length - 2 ? true : false; // this may need need to be awaited? TransmitFileInfoToExtFlash(meadow, meadowRequestType, fileElement[i + 1], targetFileName, partition, mcuAddr, false, lastFile); } } }
//========================================================================== internal void SendSimpleCommand(HcomMeadowRequestType requestType, uint userData = 0) { BuildAndSendSimpleCommand(requestType, userData); }
public static void InitializeFileSystem(MeadowSerialDevice meadow, int partition) { meadowRequestType = HcomMeadowRequestType.HCOM_MDOW_REQUEST_INITIALIZE_FLASH_FS; new SendTargetData(meadow).SendSimpleCommand(meadowRequestType, (uint)partition); }
public static void CreateFileSystem(MeadowSerialDevice meadow) { meadowRequestType = HcomMeadowRequestType.HCOM_MDOW_REQUEST_CREATE_ENTIRE_FLASH_FS; new SendTargetData(meadow).SendSimpleCommand(meadowRequestType); }
public MeadowDeviceManagerException(HcomMeadowRequestType hcomMeadowRequestType, Exception?innerException) : base(null, innerException) { HcomMeadowRequestType = hcomMeadowRequestType; }
public SimpleCommandBuilder(HcomMeadowRequestType requestType) { RequestType = requestType; Timeout = DefaultTimeout; }
public MeadowDeviceManagerException(HcomMeadowRequestType hcomMeadowRequestType) { HcomMeadowRequestType = hcomMeadowRequestType; }
public static async Task ProcessCommand(MeadowSerialDevice meadow, HcomMeadowRequestType requestType, MeadowMessageType responseMessageType = MeadowMessageType.Concluded, uint userData = 0, bool doAcceptedCheck = true, int timeoutMs = 10000) { await ProcessCommand(meadow, requestType, e => e.MessageType == responseMessageType, userData, doAcceptedCheck, timeoutMs); }
// This method is called to sent to Visual Studio debugging to Mono public static void ForwardVisualStudioDataToMono(byte[] debuggingData, MeadowSerialDevice meadow, int userData) { _meadowRequestType = HcomMeadowRequestType.HCOM_MDOW_REQUEST_DEBUGGER_MSG; new SendTargetData(meadow).BuildAndSendSimpleData(debuggingData, _meadowRequestType, (uint)userData); }
public void SendTheEntireFile(HcomMeadowRequestType requestType, string destFileName, uint partitionId, byte[] fileBytes, UInt32 mcuAddr, UInt32 payloadCrc32, string md5Hash, bool lastInSeries) { _packetCrc32 = 0; try { // Build and send the header BuildAndSendFileRelatedCommand(requestType, partitionId, (UInt32)fileBytes.Length, payloadCrc32, mcuAddr, md5Hash, destFileName); //-------------------------------------------------------------- if (requestType == HcomMeadowRequestType.HCOM_MDOW_REQUEST_START_ESP_FILE_TRANSFER) { Console.Write("Erasing ESP32 Flash..."); // For the ESP32 file download, the proceeding command will erase // the ESP32 on chip flash memory before we can download. If the // file is large enough, the time to erase the flash will prevent // data from being downloaded and the 'semaphore timeout' error // will cause the CLI to disconnect. if ((UInt32)fileBytes.Length > 1024 * 200) { // Using 6 ms / kbyte int eraseDelay = (6 * fileBytes.Length) / 1000; // Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}-Large file download delay:{eraseDelay} mSec"); System.Threading.Thread.Sleep(eraseDelay); } Console.WriteLine("done."); } // Build each data packet int fileBufOffset = 0; int numbToSend; UInt16 sequenceNumber = 1; // don't echo the device responses _device.LocalEcho = false; WriteProgress(-1); while (fileBufOffset <= fileBytes.Length - 1) // equal would mean past the end { if ((fileBufOffset + MeadowDeviceManager.MaxAllowableDataBlock) > (fileBytes.Length - 1)) { numbToSend = fileBytes.Length - fileBufOffset; // almost done, last packet } else { numbToSend = MeadowDeviceManager.MaxAllowableDataBlock; } BuildAndSendDataPacketRequest(fileBytes, fileBufOffset, numbToSend, sequenceNumber); var progress = fileBufOffset * 100 / fileBytes.Length; WriteProgress(progress); fileBufOffset += numbToSend; sequenceNumber++; } WriteProgress(101); // echo the device responses Thread.Sleep(250); // if we're too fast, we'll finish and the device will still echo a little _device.LocalEcho = true; //-------------------------------------------------------------- // Build and send the correct trailer switch (requestType) { // Provide the correct message end depending on the reason the file // is being downloaded to the F7 file system. case HcomMeadowRequestType.HCOM_MDOW_REQUEST_START_FILE_TRANSFER: BuildAndSendSimpleCommand(HcomMeadowRequestType.HCOM_MDOW_REQUEST_END_FILE_TRANSFER, lastInSeries ? (uint)1 : (uint)0); // set UserData break; case HcomMeadowRequestType.HCOM_MDOW_REQUEST_MONO_UPDATE_RUNTIME: BuildAndSendSimpleCommand(HcomMeadowRequestType.HCOM_MDOW_REQUEST_MONO_UPDATE_FILE_END, lastInSeries ? (uint)1 : (uint)0); // set UserData break; case HcomMeadowRequestType.HCOM_MDOW_REQUEST_START_ESP_FILE_TRANSFER: BuildAndSendSimpleCommand(HcomMeadowRequestType.HCOM_MDOW_REQUEST_END_ESP_FILE_TRANSFER, lastInSeries ? (uint)1 : (uint)0); // set UserData break; default: Console.WriteLine($"File end Meadow request type of {requestType} not defined"); break; } // bufferOffset should point to the byte after the last byte Debug.Assert(fileBufOffset == fileBytes.Length); if (Verbose) { Console.WriteLine($"Total bytes sent {fileBufOffset:N0} in {sequenceNumber:N0} packets. PacketCRC:{_packetCrc32:x08}"); } } catch (Exception except) { Debug.WriteLine("{DateTime.Now:HH:mm:ss.fff}-Exception sending to Meadow:{0}", except); throw; } }