예제 #1
0
        /// <summary>
        /// Changes the request header set on the ELM327.
        /// </summary>
        /// <param name="header">Request header to set.</param>
        /// <returns>True if successful; otherwise, false.</returns>
        protected bool SetRequestHeader(string header)
        {
            string response = String.Empty;

            // Request the Semaphore
            ConnectionSemaphore.WaitOne();

            // Set header
            response = ExecuteATCommand(@"SH" + header);

            // If we were not successful at setting the header, quit.
            if (!(response.Equals("OK")))
            {
                log.Error("Attempt at Set Headers [AT SH " + header + "] failed. Response: " + response.ToString());
                ConnectionSemaphore.Release();
                return(false);
            }

            // Release the Semaphore
            ConnectionSemaphore.Release();

            return(true);
        }
        /// <summary>
        /// Executes one request/response cycle on the port set as this Protocol's connection.
        /// </summary>
        /// <param name="handler">The handler for whom the request response cycle is handled for.</param>
        /// <returns>True if the execution was successful; otherwise, false.</returns>
        public unsafe override bool Execute(IHandler handler)
        {
            // Variables
            uint   idBuffer    = 0x00000000;
            uint   pciBuffer   = 0x00000000;
            bool   returnValue = true;
            string tempString;

            // Single Frame Data Buffer
            byte[] parsingBuffer;
            byte[] multiframeDataBuffer;

            /*
             * --  STEPS  --
             * 1. Set/Clear Headers
             * 2. Transmit request
             * 3. Process responses
             */

            // Reset our stopwatch
            CurrentRunningTime = 0;
            stopwatch.Reset();

            // Reset stop execution flag
            StopExecution = false;

            // If no ECU filter is set and this handler requires custom headers, let's take care of that
            if (SelectedEcuFilter == Global.Constants.NoSelection && handler.IsCustomHeader)
            {
                // Only set the custom header if it is not already set
                if (!(_lastUsedHeader.Equals(handler.Header)))
                {
                    if (!SetRequestHeader(handler.Header))
                    {
                        return(false);
                    }
                    _lastUsedHeader.Clear().Append(handler.Header);
                }
            }
            // If no custom handler is required or an ECU filter is selected...
            else
            {
                // If an ECU filter is selected, apply it if necessary
                if (SelectedEcuFilter != Global.Constants.NoSelection)
                {
                    // Skip this if we're debugging (the emulator doesn't handle the AT SH command)
                    #if !DEBUG
                    if (!(_lastUsedHeader.ToString().Equals(SelectedEcuFilter.RequestAddressString)))
                    {
                        if (!SetRequestHeader(SelectedEcuFilter.RequestAddressString))
                        {
                            return(false);
                        }
                        _lastUsedHeader.Clear().Append(SelectedEcuFilter.RequestAddressString);
                    }
                    #endif
                }
                // If no ECU filter is applied and this handler does not require custom headers,
                // but the last handler did, we MUST clear the custom headers out of the ELM 327 device.
                else if (!(_lastUsedHeader.ToString().Equals("")))
                {
                    if (!SetRequestHeader(EcuAddresses[0].RequestAddressString))
                    {
                        return(false);
                    }
                    _lastUsedHeader.Clear();
                    _incomingResponseBuffer.Clear();
                }
            }

            // Transmit the request
            ConnectionSemaphore.WaitOne();
            Connection.DiscardInBuffer();
            Connection.DiscardOutBuffer();
            ExecuteCommand(handler.Request);

            // Do we expect a response?
            if (handler.ExpectsResponse)
            {
                // Begin listening
                _hasMoreResponses = true;

                try
                {
                    stopwatch.Start();
                    while (_hasMoreResponses && !(StopExecution))
                    {
                        // Clear the buffer
                        _incomingResponseBuffer.Clear();

                        // Grab the incoming message
                        _incomingResponseBuffer.Append(Connection.ReadLine());

                        // Verify a line was received
                        if (_incomingResponseBuffer.Length < 1)
                        {
                            continue;
                        }

                        // Remove the prompt if it exists
                        if (_incomingResponseBuffer[0] == '>')
                        {
                            _incomingResponseBuffer.Remove(0, 1);
                        }

                        // Ensure an error was not received
                        tempString = _incomingResponseBuffer.ToString();
                        if (tempString.Equals(Global.Constants.STOPPED_MESSAGE) || tempString.Equals(Global.Constants.NO_DATA_MESSAGE) || tempString.Equals(Global.Constants.SEARCHING_MESSAGE) || tempString.Equals(Global.Constants.UNABLE_TO_CONNECT_MESSAGE))
                        {
                            continue;
                        }

                        // Convert the hex string to actual bits
                        parsingBuffer = Utility.HexStringToByteArray(tempString);

                        fixed(byte *p1 = parsingBuffer)
                        {
                            // Get the CAN ID (we grab 12 bits to compare the 3 hex characters -- note, the last bit is always 0)
                            idBuffer = (uint)(((parsingBuffer[0] << 8) | parsingBuffer[1]) & BITMASK_ID) >> 4;

                            // Get the PCI Code
                            pciBuffer = (uint)parsingBuffer[1] & BITMASK_PCITYPE;

                            // If an ECU filter is set, confirm the idBuffer equals the ECU's Return Address
                            if (SelectedEcuFilter != Global.Constants.NoSelection && idBuffer != SelectedEcuFilter.ReturnAddress)
                            {
                                log.Error("Filtering for [" + SelectedEcuFilter.ReturnAddressString + "]. Message from [" + idBuffer.ToString("X6") + "] rejected.");
                                returnValue = false;
                                break;
                            }

                            switch (pciBuffer)
                            {
                            case (uint)FrameTypes.SINGLE_FRAME:
                            {
                                try
                                {
                                    // Send the data payload to the handler
                                    handler.ProcessResponse(
                                        ProcessSingleFrameResponse(handler, parsingBuffer)
                                        );

                                    // Exit gracefully
                                    _hasMoreResponses = false;
                                }
                                catch (ProtocolProcessingException e)
                                {
                                    log.Error("Single Frame Processing Exception Occurred for [" + handler.Name + ":" + handler.Request + "]:", e);
                                    returnValue = false;
                                }
                                break;
                            }

                            case (uint)FrameTypes.FIRST_FRAME:
                            {
                                try
                                {
                                    // Process the First Frame. The data bytes and other session information
                                    // for this multiframe response will be stored in the _responseBuffer.
                                    ProcessFirstFrameResponse(idBuffer, handler, parsingBuffer);
                                }
                                catch (ProtocolProcessingException e)
                                {
                                    log.Error("First Frame Processing Exception Occurred for [" + handler.Name + ":" + handler.Request + "]:", e);

                                    // Cancel this Request/Response Cycle
                                    _responseBuffer.Remove(idBuffer);
                                    returnValue = false;
                                }
                                break;
                            }

                            case (uint)FrameTypes.CONSECUTIVE_FRAME:
                            {
                                try
                                {
                                    // Process this frame
                                    multiframeDataBuffer = ProcessConsecutiveFrameResponse(idBuffer, handler, parsingBuffer);

                                    // We're done, so let's deliver the data to the interested Handler
                                    if (multiframeDataBuffer != null)
                                    {
                                        // Send the data to the handler
                                        handler.ProcessResponse(multiframeDataBuffer);

                                        // Remove this response from the response buffer
                                        _responseBuffer.Remove(idBuffer);
                                    }
                                }
                                catch (Exception e)
                                {
                                    log.Error("Consecutive Frame Processing Exception Occurred for [" + handler.Name + ":" + handler.Request + "]:", e);

                                    // Cancel this Request/Response Cycle
                                    _responseBuffer.Remove(idBuffer);
                                    returnValue = false;
                                }

                                break;
                            }
                            }
                        }

                        // Update the running time
                        CurrentRunningTime = stopwatch.ElapsedMilliseconds;

                        // Check if we need to continue listening
                        if (_responseBuffer.Count == 0)
                        {
                            _hasMoreResponses = false;
                        }

                        // Clear the buffer to try again
                        _incomingResponseBuffer.Clear();
                    }
                }
                catch (Exception e)
                {
                    log.Error("Exception occurred while reading responses for [" + handler.Name + ":" + handler.Request + "]: " + e.Message);
                    returnValue = false;
                }

                // Stop the stopwatch, clear the current running time, and broadcast the response time
                stopwatch.Stop();
                CurrentRunningTime = 0;

                if (BroadcastResponseTime != null)
                {
                    BroadcastResponseTime(stopwatch.ElapsedMilliseconds);
                }
            }

            // Release the Semaphore
            ConnectionSemaphore.Release();

            return(returnValue);
        }