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