Example #1
0
        /// <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));
        }
Example #2
0
        /// <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);
        }
Example #3
0
        /// <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));
        }
Example #4
0
        /// <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
            });
        }
Example #5
0
        /// <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));
        }
Example #6
0
        /// <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));
        }
Example #8
0
        /// <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()));
        }
Example #10
0
        /// <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));
        }
Example #11
0
        /// <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));
        }
Example #12
0
        /// <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));
        }
Example #14
0
        /// <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));
        }
Example #17
0
        /// <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));
        }
Example #18
0
        /// <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));
        }
Example #19
0
        /// <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));
            }
        }
Example #20
0
        /// <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);
        }
Example #21
0
 /// <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));
 }
Example #22
0
        /// <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);
        }
Example #25
0
        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);
        }
Example #26
0
        /// <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));
            }
        }