/// <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); }