/// <inheritdoc /> public void Send(string serialNumber, ICommandList commands) { if (!commands.CanSend) { InvalidOperationException e = new("CommandList was not made ready before Send was called"); _logger.LogError(e, "Send failed."); throw e; } Location?location = _devices.GetLocation(serialNumber); if (location == null) { throw new InvalidOperationException("Location was null when sending to serial number."); } lock (_deviceLocker[location.Value]) { const int delayInMilliseconds = 10; double?millisecondsSinceLastSend = null; if (_lastSends.ContainsKey(location.Value)) { millisecondsSinceLastSend = (DateTime.UtcNow - _lastSends[location.Value]).TotalMilliseconds; } if (millisecondsSinceLastSend != null && millisecondsSinceLastSend < delayInMilliseconds) { Thread.Sleep(delayInMilliseconds - (int)millisecondsSinceLastSend); } _ = _devices.TryGetValue(location.Value, out IUsbDevice? device); if (device == null) { _logger.LogCritical("Device was null when getting it using location."); return; } bool shouldRetry = false; int retryCount = 0; int currentFrameNumber = 0; Error writeResult = Error.Other; do { for (int frameNumber = currentFrameNumber; frameNumber < commands.TotalFrames;) { // Generate the write buffer and write to PM byte[] writeBuffer = commands.GetFrame(frameNumber).Select(b => (byte)b).ToArray(); UsbEndpointWriter writer = device.OpenEndpointWriter(LibUsbDotNet.Main.WriteEndpointID.Ep02); try { writeResult = writer.Write(writeBuffer, 100, out int writeBufferSize); if (writeResult == Error.Io) { CloseAndOpen(device); shouldRetry = retryCount++ < 2; continue; } shouldRetry = false; frameNumber++; } catch (Exception e) { _logger.LogWarning(e, "Exception occurred during writing. Buffer: [{WriteBuffer}]", writeBuffer); } finally { _lastSends[location.Value] = DateTime.UtcNow; } } } while (shouldRetry); if (writeResult != Error.Success) { _logger.LogWarning("An error occurred while writing. Result: [{WriteResult}])", writeResult); return; } byte[] readBuffer = new byte[1024]; Error readResult = Error.Other; retryCount = 0; shouldRetry = false; do { UsbEndpointReader reader = device.OpenEndpointReader(LibUsbDotNet.Main.ReadEndpointID.Ep01); try { readResult = reader.Read(readBuffer, 100, out int responseDataSize); if (readResult == Error.Io) { CloseAndOpen(device); shouldRetry = retryCount++ < 2; continue; } if (commands.TotalFrames > 1) { // This is required if there was more than one packet. // TODO: Improve this so that results from each packet are read in. reader.ReadFlush(); } shouldRetry = false; } catch (Exception e) { _logger.LogWarning(e, "Exception occurred during reading. Buffer: [{ReadBuffer}]", readBuffer); return; } } while (shouldRetry); if (readResult != Error.Success) { _logger.LogWarning("An error occurred while reading. Result: [{ReadResult}])", readResult); return; } IResponseReader responseReader = new ResponseReader(readBuffer.Select(b => (uint)b)); bool responseReaderSuccess = commands.Read(responseReader); if (!responseReaderSuccess) { _logger.LogWarning("An error occurred while consuming the read buffer. Result: [{ResponseReadResult}])", responseReaderSuccess); return; } } }