/// <inheritdoc /> public override int Serialize(INTV.Core.Utility.BinaryWriter writer) { var protocolCommandBuffer = new byte[CommandRecordSize + ArgumentRecordSize]; // The try/finally pattern avoids potential double-dispose issues with the memory stream. System.IO.MemoryStream commandWithArgsStream = null; try { commandWithArgsStream = new System.IO.MemoryStream(protocolCommandBuffer); using (var tempBinaryWriter = new INTV.Shared.Utility.ASCIIBinaryWriter(commandWithArgsStream)) { commandWithArgsStream = null; tempBinaryWriter.Write(CommandRecordHeadByte); tempBinaryWriter.Write((byte)Command); tempBinaryWriter.Write((byte)(((int)Command) ^ 0xFF)); tempBinaryWriter.Write(CommandRecordTailByte); tempBinaryWriter.Write(Arg0); tempBinaryWriter.Write(Arg1); tempBinaryWriter.Write(Arg2); tempBinaryWriter.Write(Arg3); tempBinaryWriter.Seek(0, SeekOrigin.Begin); Crc = INTV.Core.Utility.Crc32.OfStream(tempBinaryWriter.BaseStream); writer.Write(protocolCommandBuffer, 0, protocolCommandBuffer.Length); #if LOG_COMMAND_DATA var dataSent = new System.Text.StringBuilder(); foreach (var value in protocolCommandBuffer) { dataSent.AppendFormat("{0} ", value.ToString("X2")); } dataSent.AppendFormat("CRC: {0}", Crc.ToString("X8")); _dataSent = dataSent.ToString(); #endif // LOG_COMMAND_DATA } } finally { if (commandWithArgsStream != null) { commandWithArgsStream.Dispose(); } } writer.Write(Crc); return(ProtocolCommandRecordSize); }
private T ExecuteCore <T>(IStreamConnection target, ExecuteDeviceCommandAsyncTaskData taskData, System.IO.Stream sourceDataStream, Func <System.IO.Stream, T> inflate, Action onSuccess, out bool succeeded) { succeeded = false; var errorDetail = string.Empty; var response = default(T); var timedOut = false; #if REPORT_COMMAND_PERFORMANCE var stopwatch = System.Diagnostics.Stopwatch.StartNew(); var reportSuffix = sourceDataStream == null ? "RESP" : "DATA"; try { #endif // REPORT_COMMAND_PERFORMANCE using (target.SetInUse(UpdatePortChunkSizeConfigurations)) { if (taskData != null) { taskData.CurrentlyExecutingCommand = Command; } lock (_lock) { target.LogPortMessage("EXECUTE: " + Command); Exception exception = null; var previousWriteTimeout = -1; if (target.WriteStream.CanTimeout) { previousWriteTimeout = target.WriteStream.WriteTimeout; } try { using (var writer = new INTV.Shared.Utility.ASCIIBinaryWriter(target.WriteStream)) { _dataSent = string.Empty; var commandBytesWritten = Serialize(writer); target.LogPortMessage("EXECUTE: wrote " + commandBytesWritten + " bytes for command: " + Command + ", data sent: " + _dataSent); } if (target.ReadStream.CanTimeout) { target.ReadStream.ReadTimeout = ResponseTimeout; } using (var reader = new INTV.Shared.Utility.ASCIIBinaryReader(target.ReadStream)) { using (var resultStream = new System.IO.MemoryStream()) { var ack = GetCommandAcknowledgement(reader, Command, ref errorDetail, out timedOut); if (ack == Ack) { resultStream.WriteByte(ack); byte[] responseData = null; if (sourceDataStream != null) { SendCommandPayload(target, sourceDataStream, resultStream); } else if (inflate != null) { responseData = ReceiveResponse(reader, resultStream); } var success = GetCommandSuccess(reader); resultStream.WriteByte(success); var crc = GetResponseCrc(reader); succeeded = ValidateResponse(resultStream, crc); if (succeeded && (responseData != null) && (inflate != null)) { using (var responseStream = new MemoryStream(responseData)) { response = inflate(responseStream); } } if (succeeded && (onSuccess != null)) { onSuccess(); } if (success != Success) { var errorMessage = "Command " + Command + " did not succeed: " + success.ToString("X2") + "(" + System.Convert.ToChar(success) + ")"; if (!string.IsNullOrEmpty(errorDetail)) { errorDetail += Environment.NewLine; } errorDetail += errorMessage; target.LogPortMessage(errorMessage); DebugOutput(errorMessage); timedOut = target.WaitForBeacon(WaitForBeaconTimeout); // try to drain any remaining bytes and sync back up again succeeded = false; exception = new DeviceCommandExecuteFailedException(Command, Arg0, Arg1, Arg2, Arg3, success); } } else if (ack == Nak) { var errorMessage = "Command " + Command + " returned NAK!"; target.LogPortMessage(errorMessage); DebugOutput(errorMessage); timedOut = !target.WaitForBeacon(WaitForBeaconTimeout); if (!string.IsNullOrEmpty(errorDetail)) { errorDetail += Environment.NewLine; } errorDetail += errorMessage; } } } } catch (TimeoutException e) { timedOut = true; var errorMessage = "Timed out executing command: " + Command; target.LogPortMessage(errorMessage); DebugOutput(errorMessage); if (!string.IsNullOrEmpty(errorDetail)) { errorDetail += Environment.NewLine; } errorDetail += errorMessage; exception = e; // TODO: Report specific failure message back to user. } catch (System.IO.IOException e) { var errorMessage = "IO Exception executing command: " + Command; target.LogPortMessage(errorMessage); DebugOutput(errorMessage); if (!string.IsNullOrEmpty(errorDetail)) { errorDetail += Environment.NewLine; } errorDetail += errorMessage; exception = e; // TODO: Report specific failure message back to user. // One circumstance in which this occurs, and which we do not wish to report, is when killing the simulator application. } catch (UnauthorizedAccessException e) { var errorMessage = "UnauthorizedAccess Exception executing command: " + Command; target.LogPortMessage(errorMessage); DebugOutput(errorMessage); if (!string.IsNullOrEmpty(errorDetail)) { errorDetail += Environment.NewLine; } errorDetail += errorMessage; exception = e; // TODO: Report specific failure message back to user. // One circumstance in which this occurs, was after unplugging the device, which we may not want to report. } finally { // target.WriteStream may go to null if cord is pulled during communication w/ the device. if ((target.WriteStream != null) && target.WriteStream.CanTimeout) { target.WriteStream.WriteTimeout = previousWriteTimeout; } if (!succeeded) { RecordErrorResult(Command, exception, taskData, errorDetail); if (exception != null) { throw exception; } } } } if (taskData != null) { taskData.Succeeded = succeeded; } } #if REPORT_COMMAND_PERFORMANCE } finally { stopwatch.Stop(); ReportDuration(stopwatch, reportSuffix, target.Name); } #endif // REPORT_COMMAND_PERFORMANCE return(response); }