database plugin works
[profile/ivi/automotive-message-broker.git] / plugins / obd2plugin / obd2source.cpp
1 /*
2         Copyright (C) 2012  Intel Corporation
3
4         This library is free software; you can redistribute it and/or
5         modify it under the terms of the GNU Lesser General Public
6         License as published by the Free Software Foundation; either
7         version 2.1 of the License, or (at your option) any later version.
8
9         This library is distributed in the hope that it will be useful,
10         but WITHOUT ANY WARRANTY; without even the implied warranty of
11         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12         Lesser General Public License for more details.
13
14         You should have received a copy of the GNU Lesser General Public
15         License along with this library; if not, write to the Free Software
16         Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18
19
20 #include "obd2source.h"
21 #include <iostream>
22 #include <boost/assert.hpp>
23 #include <boost/lexical_cast.hpp>
24 #include <glib.h>
25 #include <sstream>
26 #include <json-glib/json-glib.h>
27 #include <listplusplus.h>
28 #include "debugout.h"
29 #include "bluetooth.hpp"
30 #include "timestamp.h"
31
32 #define __SMALLFILE__ std::string(__FILE__).substr(std::string(__FILE__).rfind("/")+1)
33 AbstractRoutingEngine *m_re;
34
35 //std::list<ObdPid*> Obd2Amb::supportedPidsList;
36 Obd2Amb *obd2AmbInstance = new Obd2Amb;
37
38 int calledPersecond = 0;
39
40 bool sendElmCommand(obdLib *obd,std::string command)
41 {
42         std::vector<unsigned char> replyVector;
43         std::string reply;
44         obd->sendObdRequestString(command.append("\r").c_str(),command.length()+1,&replyVector,10,3);
45         for (unsigned int i=0;i<replyVector.size();i++)
46         {
47                 reply += replyVector[i];
48         }
49         if (reply.find("OK") == -1)
50         {
51                 //No OK reply found
52                 return false;
53         }
54         else
55         {
56                 return true;
57         }
58
59 }
60
61 void connect(obdLib* obd, std::string device, std::string strbaud)
62 {
63         //printf("First: %s\nSecond: %s\n",req->arg.substr(0,req->arg.find(':')).c_str(),req->arg.substr(req->arg.find(':')+1).c_str());
64         std::string port = device;
65         DebugOut() << "Obd2Source::Connect()" << device << strbaud << "\n";
66         int baud = boost::lexical_cast<int>(strbaud);
67         obd->openPort(port.c_str(),baud);
68 ObdPid::ByteArray replyVector;
69 std::string reply;
70         obd->sendObdRequestString("ATZ\r",4,&replyVector,500,3);
71         for (unsigned int i=0;i<replyVector.size();i++)
72         {
73                 reply += replyVector[i];
74         }
75         if (reply.find("ELM") == -1)
76         {
77                 //No reply found
78                 //printf("Error!\n");
79                 DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error resetting ELM\n";
80         }
81         else
82         {
83                 //printf("Reply to reset: %s\n",reply.c_str());
84         }
85         if (!sendElmCommand(obd,"ATSP0"))
86         {
87                 //printf("Error sending echo\n");
88                 DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error setting auto protocol"<<endl;
89         }
90         if (!sendElmCommand(obd,"ATE0"))
91         {
92                 //printf("Error sending echo\n");
93                 DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error turning off echo"<<endl;
94         }
95         if (!sendElmCommand(obd,"ATH0"))
96         {
97                 //printf("Error sending headers off\n");
98                 DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error turning off headers"<<endl;
99         }
100         if (!sendElmCommand(obd,"ATL0"))
101         {
102                 //printf("Error turning linefeeds off\n");
103                 DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error turning off linefeeds"<<endl;
104         }
105         obd->sendObdRequestString("010C1\r",6,&replyVector,500,5);
106 }
107
108 void threadLoop(gpointer data)
109 {
110         GAsyncQueue *privCommandQueue = g_async_queue_ref(((OBD2Source*)data)->commandQueue);
111         GAsyncQueue *privResponseQueue = g_async_queue_ref(((OBD2Source*)data)->responseQueue);
112         GAsyncQueue *privSingleShotQueue = g_async_queue_ref(((OBD2Source*)data)->singleShotQueue);
113         GAsyncQueue *privSubscriptionAddQueue = g_async_queue_ref(((OBD2Source*)data)->subscriptionAddQueue);
114         GAsyncQueue *privSubscriptionRemoveQueue = g_async_queue_ref(((OBD2Source*)data)->subscriptionRemoveQueue);
115         obdLib *obd = new obdLib();
116         OBD2Source *source = (OBD2Source*)data;
117
118         obd->setCommsCallback([](const char* mssg, void* data) { DebugOut(6)<<mssg<<endl; },NULL);
119         obd->setDebugCallback([](const char* mssg, void* data, obdLib::DebugLevel debugLevel) { DebugOut(debugLevel)<<mssg<<endl; },NULL);
120         
121         std::list<ObdPid*> reqList;
122         std::list<ObdPid*> repeatReqList;
123         ObdPid::ByteArray replyVector;
124         std::string reply;
125         std::string port;
126         std::string baud;
127         bool connected=false;
128         int emptycount = 0;
129         int timeoutCount = 0;
130         while (source->m_threadLive)
131         {
132                 //gpointer query = g_async_queue_pop(privCommandQueue);
133                 
134                 
135                 gpointer query = g_async_queue_try_pop(privSingleShotQueue);
136                 if (query != nullptr)
137                 {
138                         //printf("Got request!\n");
139                         DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Got single shot request!"<<endl;
140                         ObdPid *req = (ObdPid*)query;
141                         repeatReqList.push_back(req);
142                 }
143                 query = g_async_queue_try_pop(privSubscriptionAddQueue);
144                 if (query != nullptr)
145                 {
146
147                         ObdPid *req = (ObdPid*)query;
148                         //DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Got subscription request for "<<req->req<<endl;
149                         reqList.push_back(req);
150                 }
151                 query = g_async_queue_try_pop(privCommandQueue);
152                 if (query != nullptr)
153                 {
154                         //ObdPid *req = (ObdPid*)query;
155                         CommandRequest *req = (CommandRequest*)query;
156                         //commandMap[req->req] = req->arg;
157                         //printf("Command: %s\n",req->req.c_str());
158                         DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Command:" << req->req << endl;
159                         if (req->req == "connect")
160                         {
161                                 
162                                 if (source->m_isBluetooth)
163                                 {
164                                         ObdBluetoothDevice bt;
165                                         std::string tempPort = bt.getDeviceForAddress(source->m_btDeviceAddress, source->m_btAdapterAddress);
166                                         if(tempPort != "")
167                                         {
168                                                 DebugOut(3)<<"Using bluetooth device \""<<source->m_btDeviceAddress<<"\" bound to: "<<tempPort<<endl;
169                                                 port = tempPort;
170                                         }
171                                 }
172                                 else
173                                 {
174                                         port = req->arglist[0];
175                                         baud = req->arglist[1];
176                                 }
177                                 connect(obd,port,baud);
178                                 connected = true;
179                         }
180                         else if (req->req == "connectifnot")
181                         {
182                                 if (!connected)
183                                 {
184                                         if (source->m_isBluetooth)
185                                         {
186                                                 ObdBluetoothDevice bt;
187                                                 std::string tempPort = bt.getDeviceForAddress(source->m_btDeviceAddress, source->m_btAdapterAddress);
188                                                 if(tempPort != "")
189                                                 {
190                                                         DebugOut(3)<<"Using bluetooth device \""<<source->m_btDeviceAddress<<"\" bound to: "<<tempPort<<endl;
191                                                         port = tempPort;
192                                                 }
193                                         }
194                                         connect(obd,port,baud);
195                                         connected = true;
196                                 }
197                         }
198                         else if (req->req == "setportandbaud")
199                         {
200                                 port = req->arglist[0];
201                                 baud = req->arglist[1];
202                         }
203                         else if (req->req == "disconnect")
204                         {
205                                 DebugOut() << __SMALLFILE__ << ":" << __LINE__ << "Using queued disconnect" << (ulong)req << "\n";
206                                 obd->closePort();
207                                 ObdBluetoothDevice bt;
208                                 bt.disconnect(source->m_btDeviceAddress, source->m_btAdapterAddress);
209                                 connected = false;
210                         }
211                         delete req;
212                 }
213                 query = g_async_queue_try_pop(privSubscriptionRemoveQueue);
214                 if (query != nullptr)
215                 {
216                         DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Got unsubscription request\n";
217                         ObdPid *req = (ObdPid*)query;
218                         for (std::list<ObdPid*>::iterator i=reqList.begin();i!= reqList.end();i++)
219                         {
220                                 if ((*i)->property == req->property)
221                                 {
222                                         reqList.erase(i);
223                                         delete (*i);
224                                         i--;
225                                 }
226                         }
227                         //reqList.push_back(req->req);
228                         delete req;
229                 }
230                 if (reqList.size() > 0 && !connected)
231                 {
232                         /*CommandRequest *req = new CommandRequest();
233                         req->req = "connect";
234                         req->arglist.push_back(port);
235                         req->arglist.push_back(baud);
236                         g_async_queue_push(privCommandQueue,req);
237                         continue;*/
238                 }
239                 else if (reqList.size() == 0 && connected)
240                 {
241                         emptycount++;
242                         if (emptycount < 1000)
243                         {
244                                 usleep(10000);
245                                 continue;
246                         }
247                         emptycount = 0;
248                         CommandRequest *req = new CommandRequest();
249                         req->req = "disconnect";
250                         g_async_queue_push(privCommandQueue,req);
251                         continue;
252                 }
253                 if (!connected)
254                 {
255                         usleep(10000);
256                         continue;
257                 }
258                 for (std::list<ObdPid*>::iterator i=reqList.begin();i!= reqList.end();i++)
259                 {
260                         repeatReqList.push_back(*i);
261                 }
262                 int badloop = 0;
263                 for (std::list<ObdPid*>::iterator i=repeatReqList.begin();i!= repeatReqList.end();i++)
264                 {
265                         if (source->m_blacklistPidCountMap.find((*i)->pid) != source->m_blacklistPidCountMap.end())
266                         {
267                                 //Don't erase the pid, just skip over it.
268                                 int count = (*source->m_blacklistPidCountMap.find((*i)->pid)).second;
269                                 if (count > 10)
270                                 {
271                                         continue;
272                                 }
273                         }
274                         badloop++;
275                         if (!obd->sendObdRequestString((*i)->pid.c_str(),(*i)->pid.length(),&replyVector))
276                         {
277                                 //This only happens during a error with the com port. Close it and re-open it later.
278                                 DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Unable to send request:" << (*i)->pid << "!\n";
279                                 if (obd->lastError() == obdLib::NODATA)
280                                 {
281                                         DebugOut() << __SMALLFILE__ << ":" << __LINE__ << "OBDLib::NODATA for pid" << (*i)->pid << "\n";
282                                         if (source->m_blacklistPidCountMap.find((*i)->pid) != source->m_blacklistPidCountMap.end())
283                                         {
284                                                 //pid value i not yet in the list.
285                                                 int count = (*source->m_blacklistPidCountMap.find((*i)->pid)).second;
286                                                 if (count > 10)
287                                                 {
288                                                         
289                                                 }
290                                                 source->m_blacklistPidCountMap.erase(source->m_blacklistPidCountMap.find((*i)->pid));
291                                                 source->m_blacklistPidCountMap.insert(pair<std::string,int>((*i)->pid,count));
292                                         }
293                                         else
294                                         {
295                                                 source->m_blacklistPidCountMap.insert(pair<std::string,int>((*i)->pid,1));
296                                         }
297                                         continue;
298                                 }
299                                 else if (obd->lastError() == obdLib::TIMEOUT)
300                                 {
301                                         timeoutCount++;
302                                         if (timeoutCount < 2)
303                                         {
304                                                 DebugOut() << __SMALLFILE__ << ":" << __LINE__ << "OBDLib::TIMEOUT for pid" << (*i)->pid << "\n";
305                                                 continue;
306                                         }
307                                 }
308                                 else
309                                 {
310                                 }
311                                 
312                                 CommandRequest *req = new CommandRequest();
313                                 DebugOut() << __SMALLFILE__ << ":" << __LINE__ << "Queuing up a disconnect" << (ulong)req << "\n";
314                                 req->req = "disconnect";
315                                 g_async_queue_push(privCommandQueue,req);
316                                 i = repeatReqList.end();
317                                 i--;
318                                 continue;
319                         }
320                         if (source->m_blacklistPidCountMap.find((*i)->pid) != source->m_blacklistPidCountMap.end())
321                         {
322                                 //If we get the pid response, then we want to clear out the blacklist list.
323                                 source->m_blacklistPidCountMap.erase(source->m_blacklistPidCountMap.find((*i)->pid));
324                         }
325                         timeoutCount = 0;
326                         //ObdPid *pid = ObdPid::pidFromReply(replyVector);
327                         ObdPid *pid = obd2AmbInstance->createPidFromReply(replyVector);
328                         if (!pid)
329                         {
330                                 //Invalid reply
331                                 DebugOut() << "Invalid reply"<<endl;
332                                 continue;
333                         }
334                         g_async_queue_push(privResponseQueue,pid);
335                         //printf("Req: %s\n",(*i).c_str());
336                         /*if ((*i) == "ATRV\r")
337                         {
338                                 //printf("Requesting voltage...\n");
339                                 if (!obd->sendObdRequestString((*i).c_str(),(*i).length(),&replyVector))
340                                 {
341                                         //printf("Unable to request voltage!!!\n");
342                                         DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Unable to request voltage!\n";
343                                         continue;
344                                 }
345                                 std::string replystring = "";
346                                 for (int j=0;j<replyVector.size();j++)
347                                 {
348                                         replystring += replyVector[j];
349                                 }
350                                 //printf("Voltage reply: %s\n",replystring.c_str());
351                                 replystring.substr(0,replystring.find("V"));*/
352                                 /*ObdReply *rep = new ObdReply();
353                                 rep->req = "ATRV\r";
354                                 rep->reply = replystring;
355                                 g_async_queue_push(privResponseQueue,rep);*/
356                         /*}
357                         if (!obd->sendObdRequest((*i).c_str(),(*i).length(),&replyVector))
358                         {
359                                 //printf("Error sending obd2 request\n");
360                                 DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error sending OBD2 request\n";
361                                 continue;
362                         }*/
363                         //printf("Reply: %i %i\n",replyVector[0],replyVector[1]);
364                                 /*
365                         /*
366                         else if (replyVector[0] == 0x49)
367                         {
368                           /*
369                                 49 02 01 00 00 00 31 
370                                 49 02 02 47 31 4A 43 
371                                 49 02 03 35 34 34 34 
372                                 49 02 04 52 37 32 35 
373                                 49 02 05 32 33 36 37 
374                                 //VIN number reply
375                                 string vinstring;
376                                 for (int j=0;j<replyVector.size();j++)
377                                 {
378                                         if(replyVector[j] == 0x49 && replyVector[j+1] == 0x02)
379                                         {
380                                                 //We're at a reply header
381                                                 j+=3;
382                                         }
383                                         if (replyVector[j] != 0x00)
384                                         {
385                                                 vinstring += (char)replyVector[j];
386                                                 //printf("VIN: %i %c\n",replyVector[j],replyVector[j]);
387                                         }
388                                 }
389                                 /*ObdReply *rep = new ObdReply();
390                                 rep->req = "0902";
391                                 rep->reply = vinstring;
392                                 g_async_queue_push(privResponseQueue,rep);*/
393                                 
394                         //DebugOut()<<"Reply: "<<replyVector[2]<<" "<<replyVector[3]<<endl;
395                 }
396                 if (badloop == 0)
397                 {
398                         //We had zero non-blacklisted events. Pause for a moment here to keep from burning CPU.
399                         usleep(10000);
400                 }
401                 repeatReqList.clear();
402                 
403         }
404         if (connected)
405         {
406                 obd->closePort();
407         }
408 }
409
410 static int updateProperties(/*gpointer retval,*/ gpointer data)
411 {
412
413         OBD2Source* src = (OBD2Source*)data;
414         
415         while(gpointer retval = g_async_queue_try_pop(src->responseQueue))
416         {
417                 ObdPid *reply = (ObdPid*)retval;
418
419                 
420                 AbstractPropertyType* value = VehicleProperty::getPropertyTypeForPropertyNameValue(reply->property, reply->value);
421                 src->updateProperty(reply->property, value);
422
423                 /*if (reply->req == "05")
424                 {
425                         VehicleProperty::EngineCoolantTemperatureType speed(reply->reply);
426                         src->updateProperty(VehicleProperty::EngineCoolantTemperature,&speed);
427                 }
428                 else if (reply->req == "0C")
429                 {
430                         VehicleProperty::EngineSpeedType speed(reply->reply);
431                         src->updateProperty(VehicleProperty::EngineSpeed,&speed); 
432                 }
433                 else if (reply->req == "0D")
434                 {
435                         VehicleProperty::VehicleSpeedType speed(reply->reply);
436                         src->updateProperty(VehicleProperty::VehicleSpeed,&speed);
437                 }
438                 else if (reply->req == "10")
439                 {
440                         VehicleProperty::MassAirFlowType mass(reply->reply);
441                         src->updateProperty(VehicleProperty::MassAirFlow,&mass);
442                 }
443                 else if (reply->req == "ATRV\r")
444                 {
445                         VehicleProperty::BatteryVoltageType volts(reply->reply);
446                         src->updateProperty(VehicleProperty::BatteryVoltage,&volts);
447                         
448                 }
449                 else if (reply->req == "0902")
450                 {
451                         //VIN number and WMI
452                         VehicleProperty::VINType vin(reply->reply);
453                         src->updateProperty(VehicleProperty::VIN,&vin);
454                         VehicleProperty::WMIType wmi(reply->reply.substr(0,3));
455                         src->updateProperty(VehicleProperty::WMI,&wmi);
456                 }
457                 else if (reply->req == "5C")
458                 {
459                         VehicleProperty::EngineCoolantTemperatureType ect(reply->reply);
460                         src->updateProperty(VehicleProperty::EngineCoolantTemperature,&ect);
461                 }
462                 else if (reply->req == "46")
463                 {
464                         VehicleProperty::InteriorTemperatureType temp(reply->reply);
465                         src->updateProperty(VehicleProperty::InteriorTemperature,&temp);
466                 }
467                 //5C -- engine oil temp
468                 //46 interior temp*/
469
470                 delete reply;
471         }
472
473         return true;
474 }
475
476 void OBD2Source::updateProperty(VehicleProperty::Property property,AbstractPropertyType* value)
477 {
478         //m_re->updateProperty(property,&value);
479         
480         if (propertyReplyMap.find(property) != propertyReplyMap.end())
481         {
482                 propertyReplyMap[property]->value = value;
483                 propertyReplyMap[property]->completed(propertyReplyMap[property]);
484                 propertyReplyMap.erase(property);
485         }
486         else
487         {
488                 m_re->updateProperty(property,value,uuid());
489         }
490 }
491
492 void OBD2Source::setSupported(PropertyList list)
493 {
494         m_supportedProperties = list;
495         m_re->updateSupported(list,PropertyList());
496 }
497 /*void OBD2Source::propertySignal(VehicleProperty::Property property,boost::any value)
498 {
499 }
500 void OBD2Source::checkProperty()
501 {
502 }*/
503 void OBD2Source::setConfiguration(map<string, string> config)
504 {
505 //      //Config has been passed, let's start stuff up.
506         configuration = config;
507         
508         //Default values
509         std::string port = "/dev/ttyUSB0";
510         std::string baud = "115200";
511         std::string btadapter = "";
512         m_isBluetooth = false;
513         
514         //Try to load config
515         //printf("OBD2Source::setConfiguration\n");
516         for (map<string,string>::iterator i=configuration.begin();i!=configuration.end();i++)
517         {
518                 //printf("Incoming setting: %s:%s\n",(*i).first.c_str(),(*i).second.c_str());
519                 DebugOut(5) << __SMALLFILE__ <<":"<< __LINE__ << "Incoming setting:" << (*i).first << ":" << (*i).second << "\n";
520                 if ((*i).first == "device")
521                 {
522                         port = (*i).second;
523                 }
524                 else if ((*i).first == "baud")
525                 {
526                         baud = (*i).second;
527                 }
528
529                 else if ((*i).first == "bluetoothAdapter")
530                 {
531                         btadapter = (*i).second;
532                 }
533         }
534
535         if(port.find(":") != string::npos)
536         {
537                 m_btDeviceAddress = port;
538                 m_btAdapterAddress = btadapter;
539                 m_isBluetooth = true;
540                 ///TODO: bluetooth!!
541                 DebugOut()<<"bluetooth device?"<<endl;
542                 ObdBluetoothDevice bt;
543
544                 std::string tempPort = bt.getDeviceForAddress(port, btadapter);
545                 if(tempPort != "")
546                 {
547                         DebugOut(3)<<"Using bluetooth device \""<<port<<"\" bound to: "<<tempPort<<endl;
548                         port = tempPort;
549                 }
550                 else
551                 {
552                         DebugOut(0)<<"Device Error"<<endl;
553                         ///Don't throw here.
554                         //throw std::runtime_error("Device Error");
555                 }
556         }
557
558         //connect(obd, port, baud);
559         CommandRequest *req = new CommandRequest();
560         req->req = "setportandbaud";
561         req->arglist.push_back(port);
562         req->arglist.push_back(baud);
563         g_async_queue_push(commandQueue,req);
564         
565         m_port = port;
566         m_baud = baud;
567         m_gThread = g_thread_new("mythread",(GThreadFunc)&threadLoop,this);
568         //g_idle_add(updateProperties, this);
569         g_timeout_add(10,updateProperties,this);
570 }
571
572 OBD2Source::OBD2Source(AbstractRoutingEngine *re, map<string, string> config)
573         : AbstractSource(re, config), Obd2Connect("Obd2Connect")
574 {
575         VehicleProperty::registerProperty(Obd2Connect,[](){ return new Obd2ConnectType(false); });
576         clientConnected = false;
577         m_re = re;  
578
579         m_threadLive = true;
580         Obd2Amb obd2amb;
581         obd = new obdLib();
582
583         for(auto itr = obd2amb.supportedPidsList.begin(); itr != obd2amb.supportedPidsList.end(); itr++)
584         {
585                 m_supportedProperties.push_back((*itr)->property);
586         }
587
588         re->setSupported(supported(), this);
589         /*if (openPort(std::string("/dev/pts/7"),115200))
590         {
591           printf("Error opening OBD2 port\n");
592         }*/
593         commandQueue = g_async_queue_new();
594         subscriptionAddQueue = g_async_queue_new();
595         subscriptionRemoveQueue = g_async_queue_new();
596         responseQueue = g_async_queue_new();
597         singleShotQueue = g_async_queue_new();
598
599         setConfiguration(config);
600 }
601 OBD2Source::~OBD2Source()
602 {
603         DebugOut() << "OBD2Source Destructor called!!!"<<endl;
604         m_threadLive = false;
605         g_thread_join(m_gThread);
606 }
607
608 PropertyList OBD2Source::supported()
609 {
610         return m_supportedProperties;
611 }
612
613 int OBD2Source::supportedOperations()
614 {
615         return Get | Set;
616 }
617
618 extern "C" AbstractSource * create(AbstractRoutingEngine* routingengine, map<string, string> config)
619 {
620         return new OBD2Source(routingengine, config);
621         
622 }
623 string OBD2Source::uuid()
624 {
625         return "f77af740-f1f8-11e1-aff1-0800200c9a66";
626 }
627 void OBD2Source::subscribeToPropertyChanges(VehicleProperty::Property property)
628 {
629         /*//printf("Subscribed to property: %s\n",property.c_str());
630         if (property == VehicleProperty::EngineSpeed)
631         {
632                 ObdRequest *requ = new ObdRequest();
633                 requ->req = "010C1\r";
634                 g_async_queue_push(subscriptionAddQueue,requ);
635         }
636         else if (property == VehicleProperty::MassAirFlow)
637         {
638                 ObdRequest *requ = new ObdRequest();
639                 requ->req = "01101\r";
640                 g_async_queue_push(subscriptionAddQueue,requ);
641         }
642         else if (property == VehicleProperty::VehicleSpeed)
643         {
644                 ObdRequest *requ = new ObdRequest();
645                 requ->req = "010D1\r";
646                 g_async_queue_push(subscriptionAddQueue,requ);
647         }
648         else if (property == VehicleProperty::EngineCoolantTemperature)
649         {
650                 ObdRequest *requ = new ObdRequest();
651                 requ->req = "01051\r";
652                 g_async_queue_push(subscriptionAddQueue,requ);
653         }
654         else if (property == VehicleProperty::VIN)
655         {
656                 DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "VIN subscription requested... but there's no point!\n";
657         }
658         else if (property == VehicleProperty::WMI)
659         {
660                 DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "WMI subscription requested... but there's no point!\n";
661         }
662         else if (property == VehicleProperty::EngineOilTemperature)
663         {
664                 ObdRequest *requ = new ObdRequest();
665                 requ->req = "015C1\r";
666                 g_async_queue_push(subscriptionAddQueue,requ);
667         }
668         else if (property == VehicleProperty::InteriorTemperature)
669         {
670                 ObdRequest *requ = new ObdRequest();
671                 requ->req = "01461\r";
672                 g_async_queue_push(subscriptionAddQueue,requ);
673         }
674         else if (property == VehicleProperty::BatteryVoltage)
675         {
676                 ObdRequest *requ = new ObdRequest();
677                 requ->req = "ATRV\r";
678                 g_async_queue_push(subscriptionAddQueue,requ);
679         }
680         /*m_supportedProperties.push_back(VehicleProperty::VIN);
681         m_supportedProperties.push_back(VehicleProperty::WMI);
682         m_supportedProperties.push_back(VehicleProperty::EngineOilTemperature);
683         m_supportedProperties.push_back(VehicleProperty::InteriorTemperature);
684         m_supportedProperties.push_back(VehicleProperty::BatteryVoltage);*/
685         /*else
686         {
687                 //printf("Unsupported property: %s\n",property.c_str());
688                 DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Unsupported property requested:" << property << "\n";
689         }*/
690
691         if (property == VehicleProperty::VIN)
692         {
693                 DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "VIN subscription requested... but there's no point!"<<endl;
694         }
695         else if (property == VehicleProperty::WMI)
696         {
697                 DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "WMI subscription requested... but there's no point!"<<endl;
698         }
699         else
700         {
701                 if(!ListPlusPlus<VehicleProperty::Property>(&m_supportedProperties).contains(property))
702                 {
703                         DebugOut(0)<<"obd plugin does not support: "<<property<<endl;
704                         return;
705                 }
706
707
708                 ObdPid *pid = obd2AmbInstance->createPidforProperty(property);
709
710                 if(!pid)
711                 {
712                         return;
713                 }
714                 
715                 //If the pid is currently in the blacklist map, erase it. This allows for applications
716                 //to "un-blacklist" a pid by re-subscribing to it.
717                 if (m_blacklistPidCountMap.find(pid->pid) != m_blacklistPidCountMap.end())
718                 {
719                         m_blacklistPidCountMap.erase(m_blacklistPidCountMap.find(pid->pid));
720                 }
721                                         
722                                         
723                 g_async_queue_push(subscriptionAddQueue,pid);
724                 CommandRequest *req = new CommandRequest();
725                 req->req = "connectifnot";
726                 g_async_queue_push(commandQueue,req);
727         }
728 }
729
730
731 void OBD2Source::unsubscribeToPropertyChanges(VehicleProperty::Property property)
732 {
733         //
734         /*if (property == VehicleProperty::EngineSpeed)
735         {
736                 ObdRequest *requ = new ObdRequest();
737                 requ->req = "010C1\r";
738                 g_async_queue_push(subscriptionRemoveQueue,requ);
739         }
740         else if (property == VehicleProperty::MassAirFlow)
741         {
742                 ObdRequest *requ = new ObdRequest();
743                 requ->req = "01101\r";
744                 g_async_queue_push(subscriptionRemoveQueue,requ);
745         }
746         else if (property == VehicleProperty::VehicleSpeed)
747         {
748                 ObdRequest *requ = new ObdRequest();
749                 requ->req = "010D1\r";
750                 g_async_queue_push(subscriptionRemoveQueue,requ);
751         }
752         else if (property == VehicleProperty::EngineCoolantTemperature)
753         {
754                 ObdRequest *requ = new ObdRequest();
755                 requ->req = "01051\r";
756                 g_async_queue_push(subscriptionRemoveQueue,requ);
757         }
758         else if (property == VehicleProperty::VIN)
759         {
760                 ObdRequest *requ = new ObdRequest();
761                 requ->req = "0902\r";
762                 g_async_queue_push(subscriptionRemoveQueue,requ);
763         }
764         else if (property == VehicleProperty::WMI)
765         {
766                 ObdRequest *requ = new ObdRequest();
767                 requ->req = "0902\r";
768                 g_async_queue_push(subscriptionRemoveQueue,requ);
769         }
770         else if (property == VehicleProperty::EngineOilTemperature)
771         {
772                 ObdRequest *requ = new ObdRequest();
773                 requ->req = "015C1\r";
774                 g_async_queue_push(subscriptionRemoveQueue,requ);
775         }
776         else if (property == VehicleProperty::InteriorTemperature)
777         {
778                 ObdRequest *requ = new ObdRequest();
779                 requ->req = "01461\r";
780                 g_async_queue_push(subscriptionRemoveQueue,requ);
781         }
782         else if (property == VehicleProperty::BatteryVoltage)
783         {
784                 ObdRequest *requ = new ObdRequest();
785                 requ->req = "ATRV\r";
786                 g_async_queue_push(subscriptionRemoveQueue,requ);
787         }
788         */
789
790         if(!ListPlusPlus<VehicleProperty::Property>(&m_supportedProperties).contains(property))
791         {
792                 DebugOut(0)<<"obd plugin does not support: "<<property<<endl;
793                 return;
794         }
795
796         ObdPid *pid = obd2AmbInstance->createPidforProperty(property);
797         g_async_queue_push(subscriptionRemoveQueue,pid);
798 }
799
800
801 void OBD2Source::getPropertyAsync(AsyncPropertyReply *reply)
802 {
803         propertyReplyMap[reply->property] = reply;
804         VehicleProperty::Property property = reply->property;
805
806         //TODO: There is a much better way to do this, but for now it's hardcoded.
807         /*if (property == VehicleProperty::EngineSpeed)
808         {
809                 ObdRequest *requ = new ObdRequest();
810                 requ->req = "010C\r";
811                 g_async_queue_push(singleShotQueue,requ);
812         }
813         else if (property == VehicleProperty::MassAirFlow)
814         {
815                 ObdRequest *requ = new ObdRequest();
816                 requ->req = "0110\r";
817                 g_async_queue_push(singleShotQueue,requ);
818         }
819         else if (property == VehicleProperty::VehicleSpeed)
820         {
821                 ObdRequest *requ = new ObdRequest();
822                 requ->req = "010D\r";
823                 g_async_queue_push(singleShotQueue,requ);
824         }
825         else if (property == VehicleProperty::EngineCoolantTemperature)
826         {
827                 ObdRequest *requ = new ObdRequest();
828                 requ->req = "0105\r";
829                 g_async_queue_push(singleShotQueue,requ);
830         }
831         else if (property == VehicleProperty::VIN)
832         {
833                 ObdRequest *requ = new ObdRequest();
834                 requ->req = "0902\r";
835                 g_async_queue_push(singleShotQueue,requ);
836         }
837         else if (property == VehicleProperty::WMI)
838         {
839                 ObdRequest *requ = new ObdRequest();
840                 requ->req = "0902\r";
841                 g_async_queue_push(singleShotQueue,requ);
842         }
843         else if (property == VehicleProperty::EngineOilTemperature)
844         {
845                 ObdRequest *requ = new ObdRequest();
846                 requ->req = "015C\r";
847                 g_async_queue_push(singleShotQueue,requ);
848         }
849         else if (property == VehicleProperty::InteriorTemperature)
850         {
851                 ObdRequest *requ = new ObdRequest();
852                 requ->req = "0146\r";
853                 g_async_queue_push(singleShotQueue,requ);
854         }
855         else if (property == VehicleProperty::BatteryVoltage)
856         {
857                 ObdRequest *requ = new ObdRequest();
858                 requ->req = "ATRV\r";
859                 g_async_queue_push(singleShotQueue,requ);
860         }
861         */
862
863         ///Here's a better way:
864
865         if(!ListPlusPlus<VehicleProperty::Property>(&m_supportedProperties).contains(property))
866         {
867                 DebugOut(0)<<"obd plugin does not support: "<<property<<endl;
868                 return;
869         }
870
871         ObdPid* requ = obd2AmbInstance->createPidforProperty(property);
872         g_async_queue_push(singleShotQueue,requ);
873         CommandRequest *req = new CommandRequest();
874         req->req = "connectifnot";
875         g_async_queue_push(commandQueue,req);
876 }
877
878 AsyncPropertyReply *OBD2Source::setProperty(AsyncSetPropertyRequest request )
879 {
880         AsyncPropertyReply* reply = new AsyncPropertyReply (request);
881         reply->success = false;
882         try
883         {
884                 reply->completed(reply);
885         }
886         catch (...)
887         {
888
889         }
890         return reply;
891 }