OBD packet analyzer
Post by: Brad on August 23rd, 2011 | File Under UncategorizedThe following is an OBD broadcast packet analyzer script written in perl
Using the script
cat scrollback-testing123.txt | analyzedump.pl |less
Sample output
CHANGE: KEY: 10 0D 00 40 OLD=02 00 NEW=00 00 SEEN=26 CHANGES=18 PERMINUTE=42 TRIP=0 CHANGE: KEY: 10 0D 00 40 OLD=00 00 NEW=02 00 SEEN=27 CHANGES=19 PERMINUTE=42 TRIP=0 CHANGE: KEY: 10 0D 00 40 OLD=02 00 NEW=00 00 SEEN=28 CHANGES=20 PERMINUTE=42 TRIP=0 TIME: Fri Mar 12 19:16:08 EST 2010 UNIX=1268439368 Messages/Second=157
The script
#! /usr/bin/perl
#
# This simple Perl script can be used to analyze the data captured from a HSCAN network using ATMA with ATH1 (headers present).
#
# To Use this script, use a command line such as the following:
# $ cat screenlog-obdlink-monitoring-HSCAN-bus.txt | ./analyzedump.pl | less
#
#
# Dependencies:
# parsedate - used to parse a date string into a unix epoch timestamp thingie.
# # perl -MCPAN -e 'install Time::ParseDate'
#
use Time::ParseDate;
# A hashmap where we'll store the Parameter + Data values for each parameter that we see.
my %vals = ();
# a hashmap to store when each PID is last seen.
my %lastseen = ();
# how many data bytes does the key include? most PIDs are probably 0 but some have more.
my %pidkeylen = ();
# will store the number of changes the given PID has changed
my %changecount = ();
# tracks rate of changes for a PID.
my %changerate = ();
# will store the number of times the given PID has been seen regardless of whether the data is changed or not.
my %seencount = ();
# current timestamp as seen by timestamps in the file.
my $currentTime = 0;
my $currentTimeStamp = 0;
my $startTime = 0;
my $lastTime = 0;
my $messageCount = 0;
# trip number. Incremented any time we see two date stamps next to eachother (suggesting no data for at least 60 seconds).
my $currentTripNum = 0;
# populate the pid key lengths hash.
loadPIDKeylens();
# a function for resetting things. Such as when we start a new trip#.
sub resetHashes () {
$messageCount = 0;
%seencount = ();
%changerate = ();
%changecount = ();
%vals = ();
%lastseen = ();
}
# start main loop here:
while (<>) {
# print "line=$_";
# Remove junk.
s/.DATA ERROR//g;
# drop crapp like carriage returns.
s/\r//g;
# Remove date stamps such as:
# Sat Apr 17 15:29:01 EDT 2010
# Fri Mar 12 18:29:02 EST 2010
## check for timestamp. Grab it including its LF.
if (s/([A-Z][a-z][a-z] .+E.T 2010\n)//g or s/([A-Z][a-z][a-z] .+E.T 1999\n)//g) {
$currentTimeStamp = $1;
# remove the LF from the timestamp string.
$currentTimeStamp =~ s/\n//g;
# Get the unix epoch representation of that datetime.
$lastTime = $currentTime;
$currentTime = parsedate ($currentTimeStamp);
# first time seeing a timestamp? Log it.
if ($startTime == 0) {
$startTime = $currentTime;
}
# print it.
# prevent division by zero.
if ($currentTime - $lastTime == 0) {
next;
}
my $messageRate = ($messageCount - $lastMessageCount) / ($currentTime - $lastTime);
$messageRate = int($messageRate);
print "TIME: $currentTimeStamp UNIX=$currentTime Messages/Second=$messageRate\n";
$lastMessageCount = $messageCount;
# If the last line read was also a date stamp then we encountered two date stamps next to eachother, so kick up the trip number.
if ($lastLine =~ /DT.+2010/) {
$currentTripNum++;
# reset hashes for the new trip.
resetHashes();
}
$lastLine=$currentTimeStamp;
next;
}
my $LINE=$_;
$lastLine=$LINE;
$messageCount++;
# if the line contains the necessary stuff, split it out. Otherwise skip it with a next;
if ($LINE =~ m/^(\w\w\w)\W(.+)\W?$/) {
# pass the new data to the newData() function - args: PID, DATA.
newData ($1, $2);
if (length($ADDR) != 3) {
next;
}
}
# 29-bit sniffing hack.
if ($LINE =~ m/^(\w\w \w\w \w\w \w\w)\W(.+)\W?$/) {
newData ($1, $2);
if (length($ADDR) != 11) {
next;
}
}
# Place the Address/Data into the hashmap using a subroutine.
# If the data has changed, print the old and the new top/bottom.
# Also print
}
sub loadPIDKeylens () {
$pidkeylen{"199"} = 1;
$pidkeylen{"0C1"} = 1;
# This is wrong but for now it will do.
# $pidkeylen{"0C5"} = 5;
$pidkeylen{"0F1"} = 1;
$pidkeylen{"0C9"} = 1;
}
# This sub gets called for every message - keep it optimized!
sub newData () {
my $PID=shift;
my $DATA=shift;
my @DATAARRAY=split(/ /,$DATA);
my $KEY=$PID . "-";
if ($pidkeylen{$PID} > 0) {
# Get pidkeylen{$PID} bytes of data, drop spaces, and append to $key.
for ($i=0;$i0) {
$DATA = $DATA . shift(@DATAARRAY) . " ";
}
}
$KEY =~ s/(.+)-$/\1/g;
$DATA =~ s/(.+) $/\1/g;
$seencount{$KEY}++;
# Is this a new PID?
if (! exists $vals{$KEY}) {
print "NEW: KEY: $KEY OLD=$vals{$KEY} NEW=$DATA TRIP=$currentTripNum\n";
$vals {$KEY} = $DATA;
$lastseen {$KEY} = $currentTime;
$changerate{$KEY} = 1;
return;
}
# When was it last seen?
if ($lastseen{$KEY} == $currentTime) {
$messagesThisInterval++;
$changeRate = 0;
} else {
$changeRate = (60 * $changecount{$KEY}) / ($currentTime - $lastseen{$KEY});
$changeRate = int($changeRate);
if ($changeRate > 0) {
$changerate{$KEY} = $changeRate;
# Reset the change count since we hit a new timestamp
$changecount{$KEY} = 0;
}
$messagesThisInterval = 0;
}
# Not a new PID so is the data the same or new?
if ($vals{$KEY} =~ /$DATA/) {
$vals {$KEY} = $DATA;
$lastseen {$KEY} = $currentTime;
return;
} else {
# yup, the data changed. increment counters, print it.
$changecount{$KEY}++;
print "CHANGE: KEY: $KEY OLD=$vals{$KEY} NEW=$DATA SEEN=$seencount{$KEY} CHANGES=$changecount{$KEY} PERMINUTE=$changerate{$KEY} TRIP=$currentTripNum\n";
$vals {$KEY} = $DATA;
$lastseen {$KEY} = $currentTime;
return;
}
}
# Dump all in-memory data to the screen as a final summary.
dumpAllHashData();
# Dump to the screen a full list of all data stored in hashmaps.
sub dumpAllHashData() {
print "################# SUMMARY ####################";
# Dump data starts at _ and ends at _ total duration _
# for example, these columns:
# pidKeyLen, PID/KEY, numchanges, nummessages, changerate, last data
print "################# END OF SUMMARY ####################";
}
Comments (No responses yet)










