//-----------------------------------------------------------------------
//
// 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 ObdSimulator.Protocol
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using global::SharedObjects;
using global::SharedObjects.Protocol;
///
/// Implements the ISO9141 protocol.
///
public class DataParser : IDataParser
{
///
/// Data buffer.
///
private string buf = string.Empty;
///
/// Received data without header (payload part).
///
private List rxData = new List();
///
/// Checksum Byte.
///
private byte checkSum = 0;
///
/// Next byte shall be checksum.
///
private bool dataComplete = false;
///
/// Event logging instance.
///
private ILogging iLogging;
///
/// 'true' if checksum shall be expected.
///
private bool expectChecksum;
///
/// Data bytes to expect for complete command.
///
private int dataBytes = 0;
///
/// List of received data bytes.
///
private List dataRecord = new List();
///
/// Array of transmitted data.
///
private byte[] txDataArray = null;
///
/// Lock object to avoid race conditions.
///
private object lockObject = new object();
///
/// Data packet logging.
///
private IDataLogging iDataLogging;
///
/// Session layer list.
///
private IList iSessionLayerList;
///
/// Initializes a new instance of the class.
///
/// Event logging instance.
/// 'true' if checksum shall be expected.
/// Data transmitter instance.
public DataParser(ILogging iLogging, IDataLogging iDataLogging, IList iSessionLayerList, bool expectChecksum)
{
this.iLogging = iLogging;
this.iDataLogging = iDataLogging;
this.iSessionLayerList = iSessionLayerList;
this.expectChecksum = expectChecksum;
}
///
/// Handle dispose of object.
///
public void Dispose()
{
this.Dispose(true);
}
///
/// Handle dispose of object.
///
///
public void Dispose(bool disposing)
{
}
///
/// Parse data.
///
/// Character to use in parser.
public void parse(byte ch)
{
this.dataRecord.Add(ch);
if (this.expectChecksum && this.dataComplete)
{
if (this.checkSum != ch)
{
this.iLogging.appendText("Invalid checksum, calculated=0x" + this.checkSum.ToString("x2") + ", expected=0x" + ch.ToString("x2"));
}
else
{
this.activateServiceParser();
}
}
else
{
this.checkSum += ch;
if (this.buf.Length == 0 && ch == 0x68)
{
this.checkSum = ch;
this.buf += ch.ToString("X2");
}
else
{
if (this.buf.Length == 2 && ch == 0x6a)
{
this.buf += ch.ToString("X2");
}
else
{
if (this.buf.Length == 4 && ch == 0xf1)
{
this.buf += ch.ToString("X2");
}
else
{
if (this.buf.Length >= 6)
{
this.buf += ch.ToString("X2");
this.rxData.Add(ch);
if (this.dataBytes == 0)
{
this.selectService(ch);
}
if (this.buf.Length == ((this.dataBytes * 2) + 6))
{
this.dataComplete = true;
}
}
else
{
this.buf = string.Empty;
this.rxData.Clear();
this.dataBytes = 0;
this.dataComplete = false;
}
}
}
}
if (!this.expectChecksum && this.dataComplete)
{
this.activateServiceParser();
}
}
}
///
/// Select service depending on byte value.
///
/// Service to select.
private void selectService(byte ch)
{
switch (ch)
{
case 0x01:
this.dataBytes = 2;
break;
case 0x02:
this.dataBytes = 3;
break;
case 0x03:
this.dataBytes = 1;
break;
case 0x04:
this.dataBytes = 1;
break;
case 0x05:
this.dataBytes = 3;
break;
case 0x06:
this.dataBytes = 2;
break;
case 0x07:
this.dataBytes = 1;
break;
case 0x08:
this.dataBytes = 7;
break;
case 0x09:
this.dataBytes = 2;
break;
case 0x0a:
this.dataBytes = 1;
break;
case 0x22:
this.dataBytes = 3;
break;
case 0xAA:
this.dataBytes = 1;
break;
default:
this.buf = string.Empty;
this.rxData.Clear();
this.dataBytes = 0;
this.dataComplete = false;
break;
}
}
///
/// Activate service parser and parse payload data.
///
private void activateServiceParser()
{
byte[] ba = this.dataRecord.ToArray();
this.dataRecord.Clear();
lock (this.lockObject)
{
if (this.txDataArray != null)
{
int n = ba.Length - this.txDataArray.Length;
if (n > 0)
{
byte[] ba2 = new byte[n];
Array.Copy(ba, this.txDataArray.Length, ba2, 0, n);
ba = ba2;
}
}
this.iDataLogging.appendRow("In", ba);
}
if (this.rxData.Count > 0)
{
byte[] payload = this.rxData.ToArray();
foreach (ISessionLayer sessionLayer in this.iSessionLayerList)
{
sessionLayer.receiveData(0x00, payload, 0x00, 0x00, 0x00);
}
}
this.buf = string.Empty;
this.rxData.Clear();
this.dataBytes = 0;
this.dataComplete = false;
}
}
}