start of obd2 refactoring 94/2494/1
authorKevron Rees <kevron_m_rees@linux.intel.com>
Fri, 2 Nov 2012 17:48:56 +0000 (10:48 -0700)
committerKevron Rees <kevron_m_rees@linux.intel.com>
Thu, 15 Nov 2012 00:16:40 +0000 (16:16 -0800)
plugins/demosink/demosinkplugin.h
plugins/examplesink.cpp
plugins/obd2plugin/CMakeLists.txt
plugins/obd2plugin/obd2source.cpp
plugins/obd2plugin/obd2source.h
plugins/obd2plugin/obdlib.cpp
plugins/obd2plugin/obdlib.h
plugins/obd2plugin/obdpid.cpp [new file with mode: 0644]
plugins/obd2plugin/obdpid.h [new file with mode: 0644]

index 02fb191..ffd806c 100644 (file)
@@ -49,13 +49,13 @@ public:
        DemoSinkManager(AbstractRoutingEngine* engine, map<string, string> config)
        :AbstractSinkManager(engine, config)
        {
-
+               DemoSink* sink = new DemoSink(routingEngine, config);
+               sink->setConfiguration(config);
        }
 
        void setConfiguration(map<string, string> config)
        {
-               DemoSink* sink = new DemoSink(routingEngine, config);
-               sink->setConfiguration(config);
+
        }
 };
 
index d3e6c43..56d6c60 100644 (file)
@@ -21,6 +21,9 @@
 #include "abstractroutingengine.h"
 #include "debugout.h"
 
+#include <boost/date_time/posix_time/posix_time.hpp>
+
+
 extern "C" AbstractSinkManager * create(AbstractRoutingEngine* routingengine, map<string, string> config)
 {
        return new ExampleSinkManager(routingengine, config);
@@ -55,6 +58,26 @@ ExampleSink::ExampleSink(AbstractRoutingEngine* engine, map<string, string> conf
 
        routingEngine->getPropertyAsync(batteryVoltageRequest);
 
+       boost::posix_time::ptime start(boost::gregorian::date(2012,10,20));
+       boost::posix_time::ptime end(boost::gregorian::date(2012,10,21));
+
+       AsyncRangePropertyRequest vehicleSpeedFromLastWeek;
+       tm tmStart = boost::posix_time::to_tm(start);
+       tm tmEnd = boost::posix_time::to_tm(end);
+       vehicleSpeedFromLastWeek.begin = mktime(&tmStart);
+       vehicleSpeedFromLastWeek.end = mktime(&tmEnd);
+       vehicleSpeedFromLastWeek.property = VehicleProperty::VehicleSpeed;
+       vehicleSpeedFromLastWeek.completed = [](AsyncRangePropertyReply* reply)
+       {
+               std::list<PropertyValueTime*> values = reply->values;
+               for(auto itr = values.begin(); itr != values.end(); itr++)
+               {
+                       DebugOut(0)<<"Velocity value from last week: "<<(*itr)->value->toString()<<" time: "<<(*itr)->timestamp<<endl;
+               }
+       };
+
+       routingEngine->getRangePropertyAsync(vehicleSpeedFromLastWeek);
+
 }
 
 
index ae2d3c3..2f2bfc1 100644 (file)
@@ -9,8 +9,8 @@ pkg_check_modules(gio-unix REQUIRED gio-unix-2.0)
 
 include_directories(${CMAKE_SOURCE_DIR}/lib ${include_dirs} ${gio_INCLUDE_DIRS} ${gio-unix_INCLUDE_DIRS} )
 
-set(obd2sourceplugin_headers obd2source.h obdlib.h bluetoothmanagerproxy.h  bluetoothadapterproxy.h bluetoothserialproxy.h )
-set(obd2sourceplugin_sources obd2source.cpp obdlib.cpp bluetooth.hpp bluetoothmanagerproxy.c bluetoothadapterproxy.c bluetoothserialproxy.c)
+set(obd2sourceplugin_headers obd2source.h obdlib.h obdpid.h bluetoothmanagerproxy.h  bluetoothadapterproxy.h bluetoothserialproxy.h )
+set(obd2sourceplugin_sources obd2source.cpp obdlib.cpp obdpid.cpp bluetooth.hpp bluetoothmanagerproxy.c bluetoothadapterproxy.c bluetoothserialproxy.c)
 add_library(obd2sourceplugin MODULE ${obd2sourceplugin_sources})
 set_target_properties(obd2sourceplugin PROPERTIES PREFIX "")
 target_link_libraries(obd2sourceplugin amb -L${CMAKE_CURRENT_BINARY_DIR}/lib ${link_libraries} ${gio_LIBRARIES} ${gio-unix_LIBRARIES} )
index 1bb227d..b01c779 100644 (file)
@@ -32,9 +32,8 @@
 #define __SMALLFILE__ std::string(__FILE__).substr(std::string(__FILE__).rfind("/")+1)
 AbstractRoutingEngine *m_re;
 
-uint16_t Obd2Amb::velocity = 0;
-double Obd2Amb::fuelConsumptionOldTime = 0;
-
+std::list<ObdPid*> Obd2Amb::supportedPidsList;
+Obd2Amb *obd2AmbInstance = new Obd2Amb;
 
 int calledPersecond = 0;
 
@@ -58,6 +57,51 @@ bool sendElmCommand(obdLib *obd,std::string command)
        }
 
 }
+
+void connect(obdLib* obd, std::string device, std::string strbaud)
+{
+       //printf("First: %s\nSecond: %s\n",req->arg.substr(0,req->arg.find(':')).c_str(),req->arg.substr(req->arg.find(':')+1).c_str());
+       std::string port = device;
+       int baud = boost::lexical_cast<int>(strbaud);
+       obd->openPort(port.c_str(),baud);
+
+       obd->sendObdRequestString("ATZ\r",4,&replyVector,500,3);
+       for (unsigned int i=0;i<replyVector.size();i++)
+       {
+               reply += replyVector[i];
+       }
+       if (reply.find("ELM") == -1)
+       {
+               //No reply found
+               //printf("Error!\n");
+               DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error resetting ELM\n";
+       }
+       else
+       {
+               //printf("Reply to reset: %s\n",reply.c_str());
+       }
+       if (!sendElmCommand(obd,"ATSP0"))
+       {
+               //printf("Error sending echo\n");
+               DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error setting auto protocol"<<endl;
+       }
+       if (!sendElmCommand(obd,"ATE0"))
+       {
+               //printf("Error sending echo\n");
+               DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error turning off echo"<<endl;
+       }
+       if (!sendElmCommand(obd,"ATH0"))
+       {
+               //printf("Error sending headers off\n");
+               DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error turning off headers"<<endl;
+       }
+       if (!sendElmCommand(obd,"ATL0"))
+       {
+               //printf("Error turning linefeeds off\n");
+               DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error turning off linefeeds"<<endl;
+       }
+}
+
 void threadLoop(gpointer data)
 {
        GAsyncQueue *privCommandQueue = g_async_queue_ref(((OBD2Source*)data)->commandQueue);
@@ -70,10 +114,9 @@ void threadLoop(gpointer data)
        obd->setCommsCallback([](const char* mssg, void* data) { DebugOut(6)<<mssg<<endl; },NULL);
        obd->setDebugCallback([](const char* mssg, void* data, obdLib::DebugLevel debugLevel) { DebugOut(debugLevel)<<mssg<<endl; },NULL);
        
-       std::list<std::string> reqList;
-       std::list<std::string> repeatReqList;
-       std::map<std::string,std::string> commandMap;
-       std::vector<unsigned char> replyVector;
+       std::list<ObdPid*> reqList;
+       std::list<ObdPid*> repeatReqList;
+       ObdPid::ByteArray replyVector;
        std::string reply;
        while (true)
        {
@@ -85,68 +128,27 @@ void threadLoop(gpointer data)
                {
                        //printf("Got request!\n");
                        DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Got single shot request!"<<endl;
-                       ObdRequest *req = (ObdRequest*)query;
-                       repeatReqList.push_back(req->req);
-                       delete req;
+                       ObdPid *req = (ObdPid*)query;
+                       repeatReqList.push_back(req);
                }
                query = g_async_queue_try_pop(privSubscriptionAddQueue);
                if (query != nullptr)
                {
 
-                       ObdRequest *req = (ObdRequest*)query;
+                       ObdPid *req = (ObdPid*)query;
                        DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Got subscription request for "<<req->req<<endl;
-                       reqList.push_back(req->req);
-                       delete req;
+                       reqList.push_back(req);
                }
                query = g_async_queue_try_pop(privCommandQueue);
                if (query != nullptr)
                {
-                       ObdRequest *req = (ObdRequest*)query;
+                       ObdPid *req = (ObdPid*)query;
                        //commandMap[req->req] = req->arg;
                        //printf("Command: %s\n",req->req.c_str());
-                       DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Command:" << req->req << endl;
-                       if (req->req == "connect")
+                       DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Command:" << req->property << endl;
+                       if (req->property == "connect")
                        {
-                               //printf("First: %s\nSecond: %s\n",req->arg.substr(0,req->arg.find(':')).c_str(),req->arg.substr(req->arg.find(':')+1).c_str());
-                               std::string port = req->arg.substr(0,req->arg.find(':'));
-                               int baud = boost::lexical_cast<int>(req->arg.substr(req->arg.find(':')+1));
-                               obd->openPort(port.c_str(),baud);
-                               
-                               obd->sendObdRequestString("ATZ\r",4,&replyVector,500,3);
-                               for (unsigned int i=0;i<replyVector.size();i++)
-                               {
-                                       reply += replyVector[i];
-                               }
-                               if (reply.find("ELM") == -1)
-                               {
-                                       //No reply found
-                                       //printf("Error!\n");
-                                       DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error resetting ELM\n";
-                               }
-                               else
-                               {
-                                       //printf("Reply to reset: %s\n",reply.c_str());
-                               }
-                               if (!sendElmCommand(obd,"ATSP0"))
-                               {
-                                       //printf("Error sending echo\n");
-                                       DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error setting auto protocol"<<endl;
-                               }
-                               if (!sendElmCommand(obd,"ATE0"))
-                               {
-                                       //printf("Error sending echo\n");
-                                       DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error turning off echo"<<endl;
-                               }
-                               if (!sendElmCommand(obd,"ATH0"))
-                               {
-                                       //printf("Error sending headers off\n");
-                                       DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error turning off headers"<<endl;
-                               }
-                               if (!sendElmCommand(obd,"ATL0"))
-                               {
-                                       //printf("Error turning linefeeds off\n");
-                                       DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error turning off linefeeds"<<endl;
-                               }
+                               connect(obd);
                        }
                        delete req;
                }
@@ -294,23 +296,11 @@ static int updateProperties(/*gpointer retval,*/ gpointer data)
        
        while(gpointer retval = g_async_queue_try_pop(src->responseQueue))
        {
-               ObdReply *reply = (ObdReply*)retval;
+               ObdPid *reply = (ObdPid*)retval;
 
-               Obd2Amb obd2amb;
+               AbstractPropertyType* value = VehicleProperty::getPropertyTypeForPropertyNameValue(reply->property, reply->value);
+               src->updateProperty(reply->property, value);
 
-               if(obd2amb.propertyPidMap.count(reply->property) != 0)
-               {
-                       std::string convValue = reply->reply;
-
-                       if(obd2amb.propertyConversionMap.count(reply->property))
-                       {
-                               convValue = obd2amb.propertyConversionMap[reply->property](reply->reply);
-                       }
-
-
-                       AbstractPropertyType* value = VehicleProperty::getPropertyTypeForPropertyNameValue(reply->property, convValue);
-                       src->updateProperty(reply->property, value);
-               }
 
                /*if (reply->req == "05")
                {
@@ -452,10 +442,9 @@ void OBD2Source::setConfiguration(map<string, string> config)
                else throw std::runtime_error("Device Error");
        }
 
-       ObdRequest *requ = new ObdRequest();
-       requ->req = "connect";
-       requ->arg = port + ":" + baud;
-       g_async_queue_push(commandQueue,requ);
+       connect(obd, port, baud);
+       g_thread_new("mythread",(GThreadFunc)&threadLoop,this);
+       g_idle_add(updateProperties, this);
 }
 
 OBD2Source::OBD2Source(AbstractRoutingEngine *re, map<string, string> config) : AbstractSource(re, config)
@@ -464,10 +453,11 @@ OBD2Source::OBD2Source(AbstractRoutingEngine *re, map<string, string> config) :
        m_re = re;  
 
        Obd2Amb obd2amb;
+       obd = new obdLib();
 
-       for(auto itr = obd2amb.propertyPidMap.begin(); itr != obd2amb.propertyPidMap.end(); itr++)
+       for(auto itr = obd2amb.supportedPidsList.begin(); itr != obd2amb.supportedPidsList.end(); itr++)
        {
-               m_supportedProperties.push_back((*itr).first);
+               m_supportedProperties.push_back((*itr)->property);
        }
 
        re->setSupported(supported(), this);
@@ -480,16 +470,8 @@ OBD2Source::OBD2Source(AbstractRoutingEngine *re, map<string, string> config) :
        subscriptionRemoveQueue = g_async_queue_new();
        responseQueue = g_async_queue_new();
        singleShotQueue = g_async_queue_new();
-       g_thread_new("mythread",(GThreadFunc)&threadLoop,this);
 
        setConfiguration(config);
-
-       //AsyncQueueWatcher * watcher = new AsyncQueueWatcher(responseQueue, (AsyncQueueWatcherCallback) updateProperties, this);
-
-       //g_timeout_add(1,updateProperties, this);
-       g_idle_add(updateProperties, this);
-       //g_timeout_add(1000,calcCPS,NULL);
-
 }
 
 PropertyList OBD2Source::supported()
@@ -585,10 +567,9 @@ void OBD2Source::subscribeToPropertyChanges(VehicleProperty::Property property)
                        return;
                }
 
-               Obd2Amb obd2amb;
-               ObdRequest *requ = new ObdRequest();
-               requ->req = obd2amb.propertyPidMap[property];
-               g_async_queue_push(subscriptionAddQueue,requ);
+
+               ObdPid *pid = Obd2Amb::createPidforProperty(property);
+               g_async_queue_push(subscriptionAddQueue,pid);
        }
 }
 
@@ -658,11 +639,8 @@ void OBD2Source::unsubscribeToPropertyChanges(VehicleProperty::Property property
                return;
        }
 
-       Obd2Amb obd2amb;
-       ObdRequest *requ = new ObdRequest();
-       requ->property = property;
-       requ->req = obd2amb.propertyPidMap[property];
-       g_async_queue_push(subscriptionRemoveQueue,requ);
+       ObdPid *pid = Obd2Amb::createPidforProperty(property);
+       g_async_queue_push(subscriptionRemoveQueue,pid);
 }
 
 
@@ -736,10 +714,7 @@ void OBD2Source::getPropertyAsync(AsyncPropertyReply *reply)
                return;
        }
 
-       Obd2Amb obd2amb;
-       ObdRequest *requ = new ObdRequest();
-       requ->property = property;
-       requ->req = obd2amb.propertyPidMap[property];
+       ObdPid* requ = Obd2Amb::createPidforProperty(property);
        g_async_queue_push(singleShotQueue,requ);
 }
 
index 603133d..482be63 100644 (file)
@@ -33,23 +33,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 #include "obdlib.h"
 #include <glib.h>
 
-
-class ObdRequest
-{
-public:
-  VehicleProperty::Property property;
-  std::string req;
-  std::string arg;
-};
-
-class ObdReply
-{
-public:
-  VehicleProperty::Property property;
-  std::string req;
-  std::string reply;
-};
-
+#include "obdpid.h"
 
 class Obd2Amb
 {
@@ -57,64 +41,31 @@ public:
 
        typedef function<std::string (std::string)> ConversionFunction;
 
+
        Obd2Amb()
        {
-               propertyPidMap[VehicleProperty::VehicleSpeed] = "010D1\r";
-               propertyPidMap[VehicleProperty::EngineSpeed] = "010C1\r";
-               propertyPidMap[VehicleProperty::MassAirFlow] = "01101\r";
-               propertyPidMap[VehicleProperty::AirIntakeTemperature] = "010F1\r";
-               propertyPidMap[VehicleProperty::ThrottlePosition] = "01111\r";
-               propertyPidMap[VehicleProperty::BatteryVoltage] = "ATRV\r";
-               propertyPidMap[VehicleProperty::EngineCoolantTemperature]  = "0105a\r";
-               propertyPidMap[VehicleProperty::EngineLoad] = "01041/r";
-               propertyPidMap[VehicleProperty::VIN] = "0902/r";
-               propertyPidMap[VehicleProperty::WMI] = "0902/r";
-               propertyPidMap[VehicleProperty::EngineOilTemperature] = "015C1\r";
-               propertyPidMap[VehicleProperty::InteriorTemperature] = "01461\r";
-               propertyPidMap[VehicleProperty::FuelConsumption] = "01101\r";
-
-
-
-               propertyConversionMap[VehicleProperty::VehicleSpeed] = [](std::string input)
-               {
-                       ///velocity is used in other equations.  We'll save it off in a static variable:
-                       stringstream vssConvert(input);
-
-                       vssConvert>>velocity;
-
-                       return input;
-               };
-
-               propertyConversionMap[VehicleProperty::WMI] = [](std::string input)
-               {
-                       return input.substr(0,3);
-               };
+               supportedPidsList.push_back(new VehicleSpeedPid());
+               supportedPidsList.push_back(new EngineSpeedPid());
+               supportedPidsList.push_back(new MassAirFlowPid());
+               supportedPidsList.push_back(new VinPid());
+               supportedPidsList.push_back(new WmiPid());
+               supportedPidsList.push_back(new FuelConsumptionPid());
+               supportedPidsList.push_back(new EngineCoolantPid());
+       }
 
-               propertyConversionMap[VehicleProperty::FuelConsumption] = [](std::string input)
+       static ObdPid* createPidforProperty(VehicleProperty::Property property)
+       {
+               for(auto itr = supportedPidsList.begin(); itr != supportedPidsList.end(); itr++)
                {
-                       double maf;
-                       stringstream mafConvert(input);
-
-                       mafConvert>>maf;
-
-                       mafConvert<<1 / (14.75 * 6.26) * maf * 0/60;
-
-                       return mafConvert.str();
-               };
-
-
-
+                       if((*itr)->property == property)
+                       {
+                               ObdPid* obj = *itr;
+                               return obj->create();
+                       }
+               }
        }
 
-
-
-       map<VehicleProperty::Property, std::string> propertyPidMap;
-       map<VehicleProperty::Property, ConversionFunction> propertyConversionMap;
-
-private:
-
-       static uint16_t velocity;
-       static double fuelConsumptionOldTime;
+       static std::list<ObdPid*> supportedPidsList;
 };
 
 class OBD2Source : public AbstractSource
@@ -151,6 +102,8 @@ public:
        std::string m_port;
        map<VehicleProperty::Property,AsyncPropertyReply*> propertyReplyMap;
        void updateProperty(VehicleProperty::Property property,AbstractPropertyType *value);
+       obdLib * obd;
+
 private:
        PropertyList m_supportedProperties;
        GMutex *threadQueueMutex;
index 32bb43d..9939cd7 100644 (file)
@@ -213,6 +213,12 @@ int obdLib::closePort()
        #endif\r
        return 0;\r
 }\r
+\r
+bool obdLib::connected()\r
+{\r
+\r
+}\r
+\r
 int obdLib::initPort()\r
 {\r
        sendObdRequest("atz\r",4);\r
@@ -372,11 +378,9 @@ bool obdLib::sendObdRequestString(const char *req,int length,std::vector<byte> *
 #endif\r
        if (len < 0)\r
        {\r
-               printf("No Write\n");\r
-               //delete tmp;\r
-               //delete totalReply;\r
-               //m_lastError = SERIALWRITEERROR;\r
-               //return false;\r
+               debug(obdLib::DEBUG_ERROR,"Serial write error: %s", strerror(errno));\r
+\r
+               return false;\r
        }\r
        if (sleeptime == -1)\r
        {\r
index 7fdb99a..5c3cc2b 100644 (file)
@@ -105,6 +105,7 @@ public:
        void setPortHandle(HANDLE hdnl);
        int initPort();
        int closePort();
+       bool connected();
        void flush();
        void setDebugCallback(void (*callbackptr)(const char*,void*,obdLib::DebugLevel),void *);
        void setCommsCallback(void (*callbackptr)(const char*,void*),void*);
diff --git a/plugins/obd2plugin/obdpid.cpp b/plugins/obd2plugin/obdpid.cpp
new file mode 100644 (file)
index 0000000..81f12c4
--- /dev/null
@@ -0,0 +1,4 @@
+#include "obdpid.h"
+
+
+double FuelConsumptionPid::oldTime=0;
diff --git a/plugins/obd2plugin/obdpid.h b/plugins/obd2plugin/obdpid.h
new file mode 100644 (file)
index 0000000..b21c81f
--- /dev/null
@@ -0,0 +1,204 @@
+#ifndef _OBDPID_H__H_H_
+#define _OBDPID_H__H_H_
+
+#include <vector>
+#include <string>
+#include <vehicleproperty.h>
+#include <time.h>
+
+class ObdPid
+{
+public:
+       typedef std::vector<unsigned char> ByteArray;
+
+       ObdPid(VehicleProperty::Property prop, std::string p, int i)
+               :property(prop), pid(p), id(i), type(0x41)
+       {
+
+       }
+
+       virtual ObdPid* create() = 0;
+
+       virtual void parse(ByteArray replyVector) = 0;
+
+       VehicleProperty::Property property;
+       std::string pid;
+       int id;
+       int type;
+       std::string value;
+};
+
+template <class T>
+class CopyMe: public ObdPid
+{
+public:
+
+       CopyMe(VehicleProperty::Property prop, std::string p, int i)
+               :ObdPid(prop, p, i)
+       {
+
+       }
+
+       ObdPid* create()
+       {
+               return new T();
+       }
+};
+
+
+class VehicleSpeedPid: public CopyMe<VehicleSpeedPid>
+{
+public:
+
+       VehicleSpeedPid()
+               :CopyMe(VehicleProperty::VehicleSpeed, "010D1\r", 0x0D)
+       {
+
+       }
+
+       void parse(ByteArray replyVector)
+       {
+               int mph = replyVector[2];
+               value = boost::lexical_cast<std::string>(mph);
+       }
+};
+
+class EngineSpeedPid: public CopyMe<EngineSpeedPid>
+{
+public:
+
+       EngineSpeedPid()
+               :CopyMe(VehicleProperty::VehicleSpeed,"010C1\r",0x0D)
+       {
+
+       }
+
+       void parse(ByteArray replyVector)
+       {
+               double rpm = ((replyVector[2] << 8) + replyVector[3]) / 4.0;
+               value = boost::lexical_cast<std::string>(rpm);
+       }
+};
+
+class EngineCoolantPid: public CopyMe<EngineCoolantPid>
+{
+public:
+
+       EngineCoolantPid()
+               :CopyMe(VehicleProperty::VehicleSpeed,"01051\r",0x0D)
+       {
+
+       }
+
+       void parse(ByteArray replyVector)
+       {
+               int temp = replyVector[2] - 40;
+               value = boost::lexical_cast<std::string>(temp);
+       }
+};
+
+class MassAirFlowPid: public CopyMe<MassAirFlowPid>
+{
+public:
+
+       MassAirFlowPid()
+               :CopyMe(VehicleProperty::VehicleSpeed,"01101\r",0x0D)
+       {
+
+       }
+
+       virtual void parse(ByteArray replyVector)
+       {
+               maf = ((replyVector[2] << 8) + replyVector[3]) / 100.0;
+               value = boost::lexical_cast<std::string>(maf);
+       }
+
+protected:
+       double maf;
+};
+
+
+class FuelConsumptionPid: public MassAirFlowPid
+{
+public:
+       FuelConsumptionPid()
+
+       {
+
+       }
+
+       virtual void parse(ByteArray replyVector)
+       {
+               MassAirFlowPid::parse(replyVector);
+               timespec t;
+               clock_gettime(CLOCK_REALTIME, &t);
+
+               double currentTime = t.tv_sec + t.tv_nsec / 1000000;
+
+               double diffTime = currentTime - oldTime;
+               oldTime = currentTime;
+
+               double consumption = 1 / (14.75 * 6.26) * maf * diffTime/60;
+
+               value = boost::lexical_cast<std::string>(consumption);
+       }
+
+private:
+
+       static double oldTime;
+};
+
+
+class VinPid: public CopyMe<VinPid>
+{
+public:
+
+       VinPid()
+               :CopyMe(VehicleProperty::VIN,"0902\r",0x0D)
+       {
+               type = 0x49;
+       }
+
+       virtual void parse(ByteArray replyVector)
+       {
+               std::string vinstring;
+               for (int j=0;j<replyVector.size();j++)
+               {
+                       if(replyVector[j] == 0x49 && replyVector[j+1] == 0x02)
+                       {
+                               //We're at a reply header
+                               j+=3;
+                       }
+                       if (replyVector[j] != 0x00)
+                       {
+                               vinstring += (char)replyVector[j];
+                               //printf("VIN: %i %c\n",replyVector[j],replyVector[j]);
+                       }
+               }
+
+               value = vinstring;
+       }
+
+};
+
+class WmiPid: public VinPid
+{
+public:
+
+       WmiPid()
+               :VinPid()
+       {
+               property = VehicleProperty::WMI;
+       }
+
+       virtual void parse(ByteArray replyVector)
+       {
+               VinPid::parse(replyVector);
+
+               value = value.substr(0,3);
+       }
+
+};
+
+
+#endif