//----------------------------------------------------------------------- // // Copyright © 2012 Nils Hammar. All rights reserved. // //----------------------------------------------------------------------- /* * Software to access vehicle information via the OBD-II connector. * * Copyright © 2012 Nils Hammar * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Alternative licensing is possible, see the licensing document. * * The above text may not be removed or modified. */ namespace Protocol.OBD { using System; using System.Collections.Generic; using System.Linq; using System.Text; using global::SharedObjects; using global::SharedObjects.Misc; /// /// Request matching engine where responses /// are matched to an earlier request in order to improve /// parsing. /// public class RequestMatcher : IRequestMatcher { /// /// Gets the number of requests that we wait for answer on. /// public int openRequests { get { return this.requestDataList.Count; } } /// /// Request data to help with parsing. /// private IDictionary requestDataList = new Dictionary(); /// /// Event logging instance. /// private ILogging iLogging; /// /// Initializes a new instance of the class. /// /// Event logging instance. public RequestMatcher(ILogging iLogging) { this.iLogging = iLogging; } /// /// Set request data to help with parsing the received data in some cases. /// /// Request data to set. /// 'true' on success. public bool addRequestData(IRequestData requestData) { bool success = false; if (requestData != null) { long t1 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; lock (this.requestDataList) { requestData.timestamp = t1; uint destAddr = 0; if (requestData.destinationAddress != null) { destAddr = (uint)requestData.destinationAddress; } /* * Delete old request if it exists. * Shall normally only impact functional address requests. */ if (this.requestDataList.ContainsKey(destAddr)) { this.requestDataList.Remove(destAddr); } this.requestDataList.Add(destAddr, requestData); success = true; } } return success; } /// /// Check if address already is listed. /// /// This method will also set 'false' if the time waiting for answer exceeds 2 seconds. /// /// /// Address to check. /// 'true' if waiting for answer from ECU. public bool hasListedAddress(uint address) { bool match = false; lock (this.requestDataList) { match = this.requestDataList.ContainsKey(address); if (match) { IRequestData msg = this.requestDataList[address]; if (((DateTime.Now.Ticks - msg.txTimestamp) / TimeSpan.TicksPerMillisecond) > 2000) { this.requestDataList.Remove(address); match = false; } } } return match; } /// /// Find a matching request for the data we got. /// /// Destination address to send to. /// Current mode. /// Payload data. /// Matched request data. public IRequestData getMatchingRequest(uint? destinationAddress, byte mode, byte[] payload) { IRequestData rqd = null; int expectedPid = 0; uint destAddr = (destinationAddress != null) ? (uint)destinationAddress : 0; /* * Look up a matching request, requests with address 0 are functional requests * that can return multiple answers so we never delete those but assume it's the * last functional request that got answered. It's also a last resort, even if it * may be wrong in some hopefully rare cases. */ lock (this.requestDataList) { if (this.requestDataList.Count > 0) { if (this.requestDataList.ContainsKey(destAddr)) { rqd = this.requestDataList[destAddr]; if (destAddr != 0) { this.requestDataList.Remove(destAddr); } } else { if (this.requestDataList.ContainsKey(0)) { rqd = this.requestDataList[0]; } } } } if (rqd == null) { string str = string.Empty; if (payload != null) { foreach (byte b1 in payload) { if (!string.IsNullOrEmpty(str)) { str += " "; } str += b1.ToString("x2"); } } this.iLogging.appendText("No matching request for mode_int=0x" + mode.ToString("x2") + ", expectedPid=0x" + expectedPid.ToString("x2") + ", data=[" + str + "]\r\n"); } return rqd; } } }