/// <summary> /// Send a message, wait for a response, return the response. /// </summary> public override Task <bool> SendMessage(Message message) { //this.Logger.AddDebugMessage("Send request called"); this.Logger.AddDebugMessage("TX: " + message.GetBytes().ToHex()); Response <J2534Err> MyError = SendNetworkMessage(message, TxFlag.NONE); if (MyError.Status != ResponseStatus.Success) { return(Task.FromResult(false)); } return(Task.FromResult(true)); }
/// <summary> /// Ask all of the devices on the VPW bus for permission to switch to 4X speed. /// </summary> private async Task <List <byte> > RequestHighSpeedPermission(ToolPresentNotifier notifier) { Message permissionCheck = this.protocol.CreateHighSpeedPermissionRequest(DeviceId.Broadcast); await this.device.SendMessage(permissionCheck); // Note that as of right now, the AllPro only receives 6 of the 11 responses. // So until that gets fixed, we could miss a 'refuse' response and try to switch // to 4X anyhow. That just results in an aborted read attempt, with no harm done. List <byte> result = new List <byte>(); Message response = null; bool anyRefused = false; while ((response = await this.device.ReceiveMessage()) != null) { this.logger.AddDebugMessage("Parsing " + response.GetBytes().ToHex()); Protocol.HighSpeedPermissionResult parsed = this.protocol.ParseHighSpeedPermissionResponse(response); if (!parsed.IsValid) { await Task.Delay(100); continue; } result.Add(parsed.DeviceId); if (parsed.PermissionGranted) { this.logger.AddUserMessage(string.Format("Module 0x{0:X2} ({1}) has agreed to enter high-speed mode.", parsed.DeviceId, DeviceId.DeviceCategory(parsed.DeviceId))); // Forcing a notification message should help ELM devices receive responses. await notifier.ForceNotify(); await Task.Delay(100); continue; } this.logger.AddUserMessage(string.Format("Module 0x{0:X2} ({1}) has refused to enter high-speed mode.", parsed.DeviceId, DeviceId.DeviceCategory(parsed.DeviceId))); anyRefused = true; } if (anyRefused) { return(null); } return(result); }
/// <summary> /// Convert a Message to an AVT formatted transmit, and send to the interface /// </summary> async private Task <Response <Message> > SendAVTPacket(Message message) { //this.Logger.AddDebugMessage("Trace: SendAVTPacket"); byte[] txb = { 0x12 }; int length = message.GetBytes().Length; if (length > 0xFF) { await this.Port.Send(txb); txb[0] = unchecked ((byte)(length >> 8)); await this.Port.Send(txb); txb[0] = unchecked ((byte)(length & 0xFF)); await this.Port.Send(txb); } else if (length > 0x0F) { txb[0] = (byte)(0x11); await this.Port.Send(txb); txb[0] = unchecked ((byte)(length & 0xFF)); await this.Port.Send(txb); } else { txb[0] = unchecked ((byte)(length & 0x0F)); await this.Port.Send(txb); } //this.Logger.AddDebugMessage("send: " + message.GetBytes().ToHex()); await this.Port.Send(message.GetBytes()); return(Response.Create(ResponseStatus.Success, message)); }
/// <summary> /// Parse the response to a request for permission to switch to 4X mode. /// </summary> public HighSpeedPermissionResult ParseHighSpeedPermissionResponse(Message message) { byte[] actual = message.GetBytes(); byte[] granted = new byte[] { Priority.Physical0, DeviceId.Tool, DeviceId.Pcm, Mode.HighSpeedPrepare + Mode.Response }; // Priority if (actual[0] != granted[0]) { return(new HighSpeedPermissionResult() { IsValid = false }); } // Destination if (actual[1] != granted[1]) { return(new HighSpeedPermissionResult() { IsValid = false }); } // Source byte moduleId = actual[2]; // Permission granted? if (actual[3] == Mode.HighSpeedPrepare + Mode.Response) { return(new HighSpeedPermissionResult() { IsValid = true, DeviceId = moduleId, PermissionGranted = true }); } if ((actual[3] == Mode.Rejected) || (actual[3] == 0x7F)) { return(new HighSpeedPermissionResult() { IsValid = true, DeviceId = moduleId, PermissionGranted = false }); } return(new HighSpeedPermissionResult() { IsValid = false }); }
/// <summary> /// This will process incoming messages for up to 500ms looking for a message /// </summary> public async Task <Response <Message> > FindResponse(Message expected) { //this.Logger.AddDebugMessage("FindResponse called"); for (int iterations = 0; iterations < 5; iterations++) { Message response = await this.ReceiveMessage(); if (Utility.CompareArraysPart(response.GetBytes(), expected.GetBytes())) { return(Response.Create(ResponseStatus.Success, response)); } await Task.Delay(100); } return(Response.Create(ResponseStatus.Timeout, (Message)null)); }
/// <summary> /// Check for an accept/reject message with the given mode byte. /// </summary> /// <remarks> /// TODO: Make this private, use public methods that are tied to a specific message type. /// </remarks> public Response <bool> DoSimpleValidation2(Message message, byte priority, byte mode, byte first, byte more, byte done, params byte[] data) { byte[] actual = message.GetBytes(); ResponseStatus status; byte[] success = new byte[] { priority, DeviceId.Tool, DeviceId.Pcm, (byte)(mode + 0x40), first, more }; byte[] success1 = new byte[] { priority, DeviceId.Tool, DeviceId.Pcm, (byte)(mode + 0x40), first, done }; if (this.TryVerifyInitialBytes1(actual, success, success1, out status)) { if (data != null && data.Length > 0) { for (int index = 0; index < data.Length; index++) { const int headBytes = 4; int actualLength = actual.Length; int expectedLength = data.Length + headBytes; if (actualLength >= expectedLength) { if (actual[headBytes + index] == data[index]) { continue; } else { return(Response.Create(ResponseStatus.UnexpectedResponse, false)); } } else { return(Response.Create(ResponseStatus.Truncated, false)); } } } return(Response.Create(ResponseStatus.Success, true)); } byte[] failure = new byte[] { priority, DeviceId.Tool, DeviceId.Pcm, 0x7F, mode }; if (this.TryVerifyInitialBytes(actual, failure, out status)) { return(Response.Create(ResponseStatus.Refused, false)); } return(Response.Create(ResponseStatus.UnexpectedResponse, false)); }
public Response <string> ParseMECresponse(Message responseMessage) { string result = "Unknown"; ResponseStatus status; byte[] response = responseMessage.GetBytes(); byte[] expected = new byte[] { 0x6C, DeviceId.Tool, DeviceId.Pcm, 0x7C, BlockId.MEC }; if (!TryVerifyInitialBytes(response, expected, out status)) { return(Response.Create(status, result)); } string MEC = response[5].ToString(); return(Response.Create(ResponseStatus.Success, MEC)); }
/// <summary> /// Parse the response to a CRC query. /// </summary> internal Response <UInt32> ParseCrc(Message responseMessage, UInt32 address, UInt32 size) { ResponseStatus status; byte[] expected = new byte[] { 0x6C, DeviceId.Tool, DeviceId.Pcm, 0x7D, 0x02, unchecked ((byte)(size >> 16)), unchecked ((byte)(size >> 8)), unchecked ((byte)size), unchecked ((byte)(address >> 16)), unchecked ((byte)(address >> 8)), unchecked ((byte)address), }; if (!TryVerifyInitialBytes(responseMessage, expected, out status)) { byte[] refused = { 0x6C, DeviceId.Tool, DeviceId.Pcm, 0x7F, 0x3D, 0x02 }; if (TryVerifyInitialBytes(responseMessage, refused, out status)) { return(Response.Create(ResponseStatus.Refused, (UInt32)0)); } return(Response.Create(status, (UInt32)0)); } byte[] responseBytes = responseMessage.GetBytes(); if (responseBytes.Length < 15) { return(Response.Create(ResponseStatus.Truncated, (UInt32)0)); } int crc = (responseBytes[11] << 24) | (responseBytes[12] << 16) | (responseBytes[13] << 8) | responseBytes[14]; return(Response.Create(ResponseStatus.Success, (UInt32)crc)); }
/// <summary> /// Query the PCM's VIN. /// </summary> public async Task <Response <string> > QueryVin() { await this.device.SetTimeout(TimeoutScenario.ReadProperty); this.device.ClearMessageQueue(); if (!await this.device.SendMessage(this.protocol.CreateVinRequest1())) { return(Response.Create(ResponseStatus.Timeout, "Unknown. Request for block 1 failed.")); } Message response1 = await this.device.ReceiveMessage(); if (response1 == null) { return(Response.Create(ResponseStatus.Timeout, "Unknown. No response to request for block 1.")); } if (!await this.device.SendMessage(this.protocol.CreateVinRequest2())) { return(Response.Create(ResponseStatus.Timeout, "Unknown. Request for block 2 failed.")); } Message response2 = await this.device.ReceiveMessage(); if (response2 == null) { return(Response.Create(ResponseStatus.Timeout, "Unknown. No response to request for block 2.")); } if (!await this.device.SendMessage(this.protocol.CreateVinRequest3())) { return(Response.Create(ResponseStatus.Timeout, "Unknown. Request for block 3 failed.")); } Message response3 = await this.device.ReceiveMessage(); if (response3 == null) { return(Response.Create(ResponseStatus.Timeout, "Unknown. No response to request for block 3.")); } return(this.protocol.ParseVinResponses(response1.GetBytes(), response2.GetBytes(), response3.GetBytes())); }
/// <summary> /// Parse the response to an OS ID request. /// </summary> public Response <UInt32> ParseBlockUInt32(Message message) { byte[] bytes = message.GetBytes(); int result = 0; ResponseStatus status; byte[] expected = new byte[] { 0x6C, DeviceId.Tool, DeviceId.Pcm, 0x7C }; if (!TryVerifyInitialBytes(bytes, expected, out status)) { return(Response.Create(ResponseStatus.Error, (UInt32)result)); } result = bytes[5] << 24; result += bytes[6] << 16; result += bytes[7] << 8; result += bytes[8]; return(Response.Create(ResponseStatus.Success, (UInt32)result)); }
/// <summary> /// Check for an accept/reject message with the given mode byte. /// </summary> private Response <bool> DoSimpleValidation(Message message, byte priority, byte mode) { byte[] actual = message.GetBytes(); ResponseStatus status; byte[] success = new byte[] { priority, DeviceId.Tool, DeviceId.Pcm, (byte)(mode + 0x40), }; if (this.TryVerifyInitialBytes(actual, success, out status)) { return(Response.Create(ResponseStatus.Success, true)); } byte[] failure = new byte[] { priority, DeviceId.Tool, DeviceId.Pcm, 0x7F, mode }; if (this.TryVerifyInitialBytes(actual, failure, out status)) { return(Response.Create(ResponseStatus.Success, false)); } return(Response.Create(ResponseStatus.UnexpectedResponse, false)); }
/// <summary> /// Send a message, do not expect a response. /// </summary> public override async Task <bool> SendMessage(Message message) { byte[] messageBytes = message.GetBytes(); string header; string payload; this.ParseMessage(messageBytes, out header, out payload); if (header != this.currentHeader) { string setHeaderResponse = await this.SendRequest("AT SH " + header); this.Logger.AddDebugMessage("Set header response: " + setHeaderResponse); if (setHeaderResponse == "STOPPED") { // Does it help to retry once? setHeaderResponse = await this.SendRequest("AT SH " + header); this.Logger.AddDebugMessage("Set header response: " + setHeaderResponse); } if (!this.ProcessResponse(setHeaderResponse, "set-header command")) { return(false); } this.currentHeader = header; } payload = payload.Replace(" ", ""); string sendMessageResponse = await this.SendRequest(payload + " "); if (!this.ProcessResponse(sendMessageResponse, "message content")) { return(false); } return(true); }
public Response <string> ParseBCCresponse(Message responseMessage) { string result = "Unknown"; ResponseStatus status; byte[] response = responseMessage.GetBytes(); byte[] expected = new byte[] { Priority.Physical0, DeviceId.Tool, DeviceId.Pcm, Mode.ReadBlock + Mode.Response, BlockId.BCC }; if (!TryVerifyInitialBytes(response, expected, out status)) { return(Response.Create(status, result)); } byte[] BCCBytes = new byte[4]; Buffer.BlockCopy(response, 5, BCCBytes, 0, 4); byte[] printableBytes = Utility.GetPrintable(BCCBytes); string BCC = System.Text.Encoding.ASCII.GetString(printableBytes); return(Response.Create(ResponseStatus.Success, BCC)); }
/// <summary> /// Configure AVT to return only packets targeted to the tool (Device ID F0), and disable transmit acks /// </summary> async private Task <Response <Boolean> > AVTSetup() { //this.Logger.AddDebugMessage("AVTSetup called"); this.Logger.AddDebugMessage("Disable AVT Acks"); await this.Port.Send(AVT_DISABLE_TX_ACK.GetBytes()); Response <Message> m = await this.FindResponse(AVT_DISABLE_TX_ACK_OK); if (m.Status == ResponseStatus.Success) { this.Logger.AddDebugMessage("AVT Acks disabled"); } else { this.Logger.AddUserMessage("Could not disable ACKs"); this.Logger.AddDebugMessage("Expected " + AVT_DISABLE_TX_ACK_OK.ToString()); return(Response.Create(ResponseStatus.Error, false)); } this.Logger.AddDebugMessage("Configure AVT filter"); await this.Port.Send(AVT_FILTER_DEST.GetBytes()); m = await this.FindResponse(AVT_FILTER_DEST_OK); if (m.Status == ResponseStatus.Success) { this.Logger.AddDebugMessage("AVT filter configured"); } else { this.Logger.AddUserMessage("Could not configure AVT filter"); this.Logger.AddDebugMessage("Expected " + AVT_FILTER_DEST_OK.ToString()); return(Response.Create(ResponseStatus.Error, false)); } return(Response.Create(ResponseStatus.Success, true)); }
/// <summary> /// Parse a 32-bit value from the first four bytes of a message payload. /// </summary> public Response <UInt32> ParseUInt32(Message message, byte responseMode) { byte[] bytes = message.GetBytes(); int result = 0; ResponseStatus status; byte[] expected = new byte[] { Priority.Physical0, DeviceId.Tool, DeviceId.Pcm, responseMode }; if (!TryVerifyInitialBytes(bytes, expected, out status)) { return(Response.Create(ResponseStatus.Error, (UInt32)result)); } if (bytes.Length < 9) { return(Response.Create(ResponseStatus.Truncated, (UInt32)result)); } result = bytes[5] << 24; result += bytes[6] << 16; result += bytes[7] << 8; result += bytes[8]; return(Response.Create(ResponseStatus.Success, (UInt32)result)); }
public Response <string> ParseOptionsresponse99(Message responseMessage) { string result = "Unknown"; ResponseStatus status; byte[] response = responseMessage.GetBytes(); byte[] expected = new byte[] { 0x6C, DeviceId.Tool, DeviceId.Pcm, 0x7C, BlockIdIPC.Options99 }; if (!TryVerifyInitialBytes(response, expected, out status)) { return(Response.Create(status, result)); } ///string options = response[5].ToString(); ///string options1 = response[6].ToString(); byte[] optionBytes = new byte[2]; Buffer.BlockCopy(response, 5, optionBytes, 0, 2); int resp = (optionBytes[1] << 0) | (optionBytes[0] << 8); var Options = resp.ToString("X4"); ///var Options = string.Concat(options, options1); return(Response.Create(ResponseStatus.Success, Options)); }
/// <summary> /// Convert a Message to an J2534 formatted transmit, and send to the interface /// </summary> private Response <J2534Err> SendNetworkMessage(Message message, TxFlag Flags) { //this.Logger.AddDebugMessage("Trace: Send Network Packet"); PassThruMsg TempMsg = new PassThruMsg(); TempMsg.ProtocolID = Protocol; TempMsg.TxFlags = Flags; TempMsg.SetBytes(message.GetBytes()); int NumMsgs = 1; IntPtr MsgPtr = TempMsg.ToIntPtr(); OBDError = J2534Port.Functions.PassThruWriteMsgs((int)ChannelID, MsgPtr, ref NumMsgs, WriteTimeout); Marshal.FreeHGlobal(MsgPtr); if (OBDError != J2534Err.STATUS_NOERROR) { //Debug messages here...check why failed.. return(Response.Create(ResponseStatus.Error, OBDError)); } return(Response.Create(ResponseStatus.Success, OBDError)); }
/// <summary> /// This will process incoming messages for up to 500ms looking for a message /// </summary> public async Task <Response <Message> > FindResponse(Message expected) { //this.Logger.AddDebugMessage("FindResponse called"); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); while (stopwatch.ElapsedMilliseconds < 3000) { Response <Message> response = await this.ReadAVTPacket(); if (response.Status == ResponseStatus.Success) { if (Utility.CompareArraysPart(response.Value.GetBytes(), expected.GetBytes())) { return(Response.Create(ResponseStatus.Success, (Message)response.Value)); } } await Task.Delay(100); } return(Response.Create(ResponseStatus.Timeout, (Message)null)); }
/// <summary> /// Convert a Message to an DVI formatted transmit, and send to the interface /// </summary> async private Task <Response <Message> > SendDVIPacket(Message message) { int length = message.GetBytes().Length; byte[] RawPacket = message.GetBytes(); byte[] SendPacket = new byte[length + 3]; if (length > 0xFF) { System.Array.Resize(ref SendPacket, SendPacket.Length + 1); SendPacket[0] = 0x11; SendPacket[1] = (byte)(length >> 8); SendPacket[2] = (byte)length; Buffer.BlockCopy(RawPacket, 0, SendPacket, 3, length); } else { SendPacket[0] = 0x10; SendPacket[1] = (byte)length; Buffer.BlockCopy(RawPacket, 0, SendPacket, 2, length); } //Add checksum SendPacket[SendPacket.Length - 1] = CalcChecksum(SendPacket); //Send frame await this.Port.Send(SendPacket); // Wait for confirmation of successful send Response <Message> m = null; for (int attempt = 0; attempt < 10; attempt++) { m = await ReadDVIPacket(500); if (m != null) { if (m.Status == ResponseStatus.Timeout) { continue; } break; } } if (m == null) { // This should never happen, but just in case... this.Logger.AddUserMessage("No response to send attempt. " + message.ToString()); return(Response.Create(ResponseStatus.Error, new Message(new byte[0]))); } if (m.Status == ResponseStatus.Success) { byte[] Val = m.Value.GetBytes(); if (Val[0] == 0x20 && Val[2] == 0x00) { this.Logger.AddDebugMessage("TX: " + message.ToString()); return(Response.Create(ResponseStatus.Success, message)); } else if (Val[0] == 0x21 && Val[2] == 0x00) { this.Logger.AddDebugMessage("TX: " + message.ToString()); return(Response.Create(ResponseStatus.Success, message)); } else { this.Logger.AddUserMessage("Unable to transmit, odd response from device: " + message.ToString()); return(Response.Create(ResponseStatus.Error, message)); } } else { this.Logger.AddUserMessage("Unable to transmit, " + m.Status + ": " + message.ToString()); return(Response.Create(ResponseStatus.Error, message)); } }
/// <summary> /// Send a message, do not expect a response. /// </summary> public override async Task <bool> SendMessage(Message message) { byte[] messageBytes = message.GetBytes(); bool useSTPX = messageBytes.Length > 4; // Not sure why, but STPX is flaky with the clear-codes message at the end of the flash. // So we'll fall back to the old approach for very short messages. if (useSTPX) { StringBuilder builder = new StringBuilder(); builder.Append("STPX H:"); builder.Append(messageBytes[0].ToString("X2")); builder.Append(messageBytes[1].ToString("X2")); builder.Append(messageBytes[2].ToString("X2")); builder.Append(", R:1"); builder.Append(", L:"); int dataLength = messageBytes.Length - 3; builder.Append(dataLength.ToString()); string header = builder.ToString(); for (int attempt = 1; attempt <= 5; attempt++) { string headerResponse = await this.SendRequest(header); if (headerResponse != "DATA") { this.Logger.AddUserMessage("Unexpected response to STPX header: " + headerResponse); continue; } break; } builder = new StringBuilder(); for (int index = 3; index < messageBytes.Length; index++) { builder.Append(messageBytes[index].ToString("X2")); } string data = builder.ToString(); string dataResponse = await this.SendRequest(data); if (!this.ProcessResponse(dataResponse, "STPX data", true)) { this.Logger.AddUserMessage("Unexpected response to STPX data: " + dataResponse); return(false); } } else { string header; string payload; this.ParseMessage(messageBytes, out header, out payload); if (header != this.currentHeader) { string setHeaderResponse = await this.SendRequest("AT SH " + header); this.Logger.AddDebugMessage("Set header response: " + setHeaderResponse); if (setHeaderResponse == "STOPPED") { // Does it help to retry once? setHeaderResponse = await this.SendRequest("AT SH " + header); this.Logger.AddDebugMessage("Set header response: " + setHeaderResponse); } if (!this.ProcessResponse(setHeaderResponse, "set-header command")) { return(false); } this.currentHeader = header; } payload = payload.Replace(" ", ""); string sendMessageResponse = await this.SendRequest(payload + " "); if (!this.ProcessResponse(sendMessageResponse, "message content")) { return(false); } return(true); } return(true); }
/// <summary> /// Confirm that the first portion of the 'actual' array of bytes matches the 'expected' array of bytes. /// </summary> private bool TryVerifyInitialBytes(Message actual, byte[] expected, out ResponseStatus status) { return(TryVerifyInitialBytes(actual.GetBytes(), expected, out status)); }
/// <summary> /// Unlock the PCM by requesting a 'seed' and then sending the corresponding 'key' value. /// </summary> public async Task <bool> UnlockEcu(int keyAlgorithm) { await this.device.SetTimeout(TimeoutScenario.ReadProperty); this.device.ClearMessageQueue(); this.logger.AddDebugMessage("Sending seed request."); Message seedRequest = this.protocol.CreateSeedRequest(); if (!await this.TrySendMessage(seedRequest, "seed request")) { this.logger.AddUserMessage("Unable to send seed request."); return(false); } bool seedReceived = false; UInt16 seedValue = 0; for (int attempt = 1; attempt < MaxReceiveAttempts; attempt++) { Message seedResponse = await this.device.ReceiveMessage(); if (seedResponse == null) { this.logger.AddDebugMessage("No response to seed request."); return(false); } if (this.protocol.IsUnlocked(seedResponse.GetBytes())) { this.logger.AddUserMessage("PCM is already unlocked"); return(true); } this.logger.AddDebugMessage("Parsing seed value."); Response <UInt16> seedValueResponse = this.protocol.ParseSeed(seedResponse.GetBytes()); if (seedValueResponse.Status == ResponseStatus.Success) { seedValue = seedValueResponse.Value; seedReceived = true; break; } this.logger.AddDebugMessage("Unable to parse seed response. Attempt #" + attempt.ToString()); } if (!seedReceived) { this.logger.AddUserMessage("No seed reponse received, unable to unlock PCM."); return(false); } if (seedValue == 0x0000) { this.logger.AddUserMessage("PCM Unlock not required"); return(true); } UInt16 key = KeyAlgorithm.GetKey(keyAlgorithm, seedValue); this.logger.AddDebugMessage("Sending unlock request (" + seedValue.ToString("X4") + ", " + key.ToString("X4") + ")"); Message unlockRequest = this.protocol.CreateUnlockRequest(key); if (!await this.TrySendMessage(unlockRequest, "unlock request")) { this.logger.AddDebugMessage("Unable to send unlock request."); return(false); } for (int attempt = 1; attempt < MaxReceiveAttempts; attempt++) { Message unlockResponse = await this.device.ReceiveMessage(); if (unlockResponse == null) { this.logger.AddDebugMessage("No response to unlock request. Attempt #" + attempt.ToString()); continue; } string errorMessage; Response <bool> result = this.protocol.ParseUnlockResponse(unlockResponse.GetBytes(), out errorMessage); if (errorMessage == null) { return(result.Value); } this.logger.AddUserMessage(errorMessage); } this.logger.AddUserMessage("Unable to process unlock response."); return(false); }
/// <summary> /// Send a message, do not expect a response. /// </summary> /// <remarks> /// This initially used standard ELM commands, however the ScanTool family /// of devices supports an "STPX" command that simplifies things a lot. /// Timeout adjustements are no longer needed, and longer packets are supported. /// </remarks> public override async Task <bool> SendMessage(Message message) { byte[] messageBytes = message.GetBytes(); StringBuilder builder = new StringBuilder(); builder.Append("STPX H:"); builder.Append(messageBytes[0].ToString("X2")); builder.Append(messageBytes[1].ToString("X2")); builder.Append(messageBytes[2].ToString("X2")); int responses; switch (this.TimeoutScenario) { case TimeoutScenario.DataLogging3: responses = 3; break; case TimeoutScenario.DataLogging2: responses = 2; break; case TimeoutScenario.WriteMemoryBlock: responses = 2; break; case TimeoutScenario.SendKernel: responses = 2; break; default: responses = 1; break; } // Special case for tool-present broadcast messages. // TODO: Create a new TimeoutScenario value, maybe call it "TransmitOnly" or something like that. if (Utility.CompareArrays(messageBytes, 0x8C, 0xFE, 0xF0, 0x3F)) { responses = 0; } builder.AppendFormat(", R:{0}", responses); if (messageBytes.Length < 200) { // Short messages can be sent with a single write to the ScanTool. builder.Append(", D:"); for (int index = 3; index < messageBytes.Length; index++) { builder.Append(messageBytes[index].ToString("X2")); } string dataResponse = await this.SendRequest(builder.ToString()); if (!this.ProcessResponse(dataResponse, "STPX with data", allowEmpty: responses == 0)) { if (dataResponse == string.Empty || dataResponse == "STOPPED" || dataResponse == "?") { // These will happen if the bus is quiet, for example right after uploading the kernel. // They are traced during the SendRequest code. No need to repeat that message. } else { this.Logger.AddUserMessage("Unexpected response to STPX with data: " + dataResponse); } return(false); } } else { // Long messages need to be sent in two steps: first the STPX command, then the data payload. builder.Append(", L:"); int dataLength = messageBytes.Length - 3; builder.Append(dataLength.ToString()); string header = builder.ToString(); for (int attempt = 1; attempt <= 5; attempt++) { string headerResponse = await this.SendRequest(header); if (headerResponse != "DATA") { this.Logger.AddUserMessage("Unexpected response to STPX header: " + headerResponse); continue; } break; } builder = new StringBuilder(); for (int index = 3; index < messageBytes.Length; index++) { builder.Append(messageBytes[index].ToString("X2")); } string data = builder.ToString(); string dataResponse = await this.SendRequest(data); if (!this.ProcessResponse(dataResponse, "STPX payload", responses == 0)) { this.Logger.AddUserMessage("Unexpected response to STPX payload: " + dataResponse); return(false); } } return(true); }
/// <summary> /// Send a message, do not expect a response. /// </summary> public override async Task <bool> SendMessage(Message message) { bool useSTPX = false; if (useSTPX) { byte[] messageBytes = message.GetBytes(); StringBuilder builder = new StringBuilder(); builder.Append("STPX H:"); builder.Append(messageBytes[0].ToString("X2")); builder.Append(messageBytes[1].ToString("X2")); builder.Append(messageBytes[2].ToString("X2")); builder.Append(", R:1"); builder.Append(", D:"); for (int index = 3; index < messageBytes.Length; index++) { builder.Append(messageBytes[index].ToString("X2")); } builder.Append("\r"); string sendCommand = builder.ToString(); string sendMessageResponse = await this.SendRequest(sendCommand); if (string.IsNullOrEmpty(sendMessageResponse)) { sendMessageResponse = await this.ReadELMLine(); } if (!this.ProcessResponse(sendMessageResponse, "message content")) { return(false); } } else { byte[] messageBytes = message.GetBytes(); string header; string payload; this.ParseMessage(messageBytes, out header, out payload); if (header != this.currentHeader) { string setHeaderResponse = await this.SendRequest("AT SH " + header); this.Logger.AddDebugMessage("Set header response: " + setHeaderResponse); if (setHeaderResponse == "STOPPED") { // Does it help to retry once? setHeaderResponse = await this.SendRequest("AT SH " + header); this.Logger.AddDebugMessage("Set header response: " + setHeaderResponse); } if (!this.ProcessResponse(setHeaderResponse, "set-header command")) { return(false); } this.currentHeader = header; } payload = payload.Replace(" ", ""); string sendMessageResponse = await this.SendRequest(payload + " "); if (!this.ProcessResponse(sendMessageResponse, "message content")) { return(false); } return(true); } return(true); }
public override async Task <bool> Initialize() { this.Logger.AddDebugMessage("Initializing " + this.ToString()); Response <Message> m; SerialPortConfiguration configuration = new SerialPortConfiguration(); configuration.BaudRate = 115200; await this.Port.OpenAsync(configuration); await this.Port.DiscardBuffers(); this.Logger.AddDebugMessage("Sending 'reset' message."); await this.Port.Send(AvtDevice.AVT_RESET.GetBytes()); m = await ReadAVTPacket(); if (m.Status == ResponseStatus.Success) { switch (m.Value.GetBytes()[0]) { case 0x27: this.Logger.AddUserMessage("AVT 852 Reset OK"); break; case 0x12: this.Logger.AddUserMessage("AVT 842 Reset OK"); break; default: this.Logger.AddUserMessage("Unknown and unsupported AVT device detected. Please add support and submit a patch!"); return(false); } } else { this.Logger.AddUserMessage("AVT device not found or failed reset"); return(false); } this.Logger.AddDebugMessage("Looking for Firmware message"); m = await this.FindResponse(AVT_FIRMWARE); if (m.Status == ResponseStatus.Success) { byte firmware = m.Value.GetBytes()[1]; int major = firmware >> 4; int minor = firmware & 0x0F; this.Logger.AddUserMessage("AVT Firmware " + major + "." + minor); } else { this.Logger.AddUserMessage("Firmware not found or failed reset"); this.Logger.AddDebugMessage("Expected " + AVT_FIRMWARE.GetBytes()); return(false); } await this.Port.Send(AvtDevice.AVT_ENTER_VPW_MODE.GetBytes()); m = await FindResponse(AVT_VPW); if (m.Status == ResponseStatus.Success) { this.Logger.AddDebugMessage("Set VPW Mode"); } else { this.Logger.AddUserMessage("Unable to set AVT device to VPW mode"); this.Logger.AddDebugMessage("Expected " + AvtDevice.AVT_VPW.ToString()); return(false); } await AVTSetup(); return(true); }
/// <summary> /// Parse the payload of a read request. /// </summary> /// <remarks> /// It is the callers responsability to check the ResponseStatus for errors /// </remarks> public Response <byte[]> ParsePayload(Message message, int length, int expectedAddress) { ResponseStatus status; byte[] actual = message.GetBytes(); byte[] expected = new byte[] { 0x6D, 0xF0, 0x10, 0x36 }; if (!TryVerifyInitialBytes(actual, expected, out status)) { return(Response.Create(status, new byte[0])); } // Ensure that we can read the data length and start address from the message. if (actual.Length < 10) { return(Response.Create(ResponseStatus.Truncated, new byte[0])); } // Read the data length. int dataLength = (actual[5] << 8) + actual[6]; // Read and validate the data start address. int actualAddress = ((actual[7] << 16) + (actual[8] << 8) + actual[9]); if (actualAddress != expectedAddress) { return(Response.Create(ResponseStatus.UnexpectedResponse, new byte[0])); } byte[] result = new byte[dataLength]; // Normal block if (actual[4] == 1) { // With normal encoding, data length should be actual length minus header size if (actual.Length - 12 < dataLength) { return(Response.Create(ResponseStatus.Truncated, new byte[0])); } // Verify block checksum UInt16 ValidSum = VpwUtilities.CalcBlockChecksum(actual); int PayloadSum = (actual[dataLength + 10] << 8) + actual[dataLength + 11]; Buffer.BlockCopy(actual, 10, result, 0, dataLength); if (PayloadSum != ValidSum) { return(Response.Create(ResponseStatus.Error, result)); } return(Response.Create(ResponseStatus.Success, result)); } // RLE block else if (actual[4] == 2) { // This isnt going to work with existing kernels... need to support variable length. byte value = actual[10]; for (int index = 0; index < dataLength; index++) { result[index] = value; } return(Response.Create(ResponseStatus.Error, result)); } else { return(Response.Create(ResponseStatus.Error, result)); } }