added overload for subscribe that includes a zone filter. it is unimplemented in...
[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 VehicleProperty::Property Obd2Connected = "Obd2Connected";
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 bool beginsWith(std::string a, std::string b)
62 {
63         return (a.compare(0, b.length(), b) == 0);
64 }
65
66 bool connect(obdLib* obd, std::string device, std::string strbaud)
67 {
68         //printf("First: %s\nSecond: %s\n",req->arg.substr(0,req->arg.find(':')).c_str(),req->arg.substr(req->arg.find(':')+1).c_str());
69         std::string port = device;
70         DebugOut() << "Obd2Source::Connect()" << device << strbaud << endl;
71         int baud = boost::lexical_cast<int>(strbaud);
72
73         if(obd->openPort(port.c_str(),baud) == -1)
74                 return false;
75
76         ObdPid::ByteArray replyVector;
77         std::string reply;
78         obd->sendObdRequestString("ATZ\r",4,&replyVector,500,3);
79         for (unsigned int i=0;i<replyVector.size();i++)
80         {
81                 reply += replyVector[i];
82         }
83         if (reply.find("ELM") == -1)
84         {
85                 //No reply found
86                 //printf("Error!\n");
87                 DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error resetting ELM"<<endl;
88                 return false;
89         }
90         else
91         {
92                 //printf("Reply to reset: %s\n",reply.c_str());
93         }
94         if (!sendElmCommand(obd,"ATSP0"))
95         {
96                 //printf("Error sending echo\n");
97                 DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error setting auto protocol"<<endl;
98                 return false;
99         }
100         if (!sendElmCommand(obd,"ATE0"))
101         {
102                 //printf("Error sending echo\n");
103                 DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error turning off echo"<<endl;
104                 return false;
105         }
106         if (!sendElmCommand(obd,"ATH0"))
107         {
108                 //printf("Error sending headers off\n");
109                 DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error turning off headers"<<endl;
110                 return false;
111         }
112         if (!sendElmCommand(obd,"ATL0"))
113         {
114                 //printf("Error turning linefeeds off\n");
115                 DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Error turning off linefeeds"<<endl;
116                 return false;
117         }
118         obd->sendObdRequestString("010C1\r",6,&replyVector,500,5);
119
120         return true;
121 }
122
123 void threadLoop(gpointer data)
124 {
125         GAsyncQueue *privCommandQueue = g_async_queue_ref(((OBD2Source*)data)->commandQueue);
126         GAsyncQueue *privResponseQueue = g_async_queue_ref(((OBD2Source*)data)->responseQueue);
127         GAsyncQueue *privSingleShotQueue = g_async_queue_ref(((OBD2Source*)data)->singleShotQueue);
128         GAsyncQueue *privSubscriptionAddQueue = g_async_queue_ref(((OBD2Source*)data)->subscriptionAddQueue);
129         GAsyncQueue *privSubscriptionRemoveQueue = g_async_queue_ref(((OBD2Source*)data)->subscriptionRemoveQueue);
130         GAsyncQueue *privStatusQueue = g_async_queue_ref(((OBD2Source*)data)->statusQueue);
131         
132         obdLib *obd = new obdLib();
133         OBD2Source *source = (OBD2Source*)data;
134
135         obd->setCommsCallback([](const char* mssg, void* data) { DebugOut(6)<<mssg<<endl; },NULL);
136         obd->setDebugCallback([](const char* mssg, void* data, obdLib::DebugLevel debugLevel) { DebugOut(debugLevel)<<mssg<<endl; },NULL);
137         
138         std::list<ObdPid*> reqList;
139         std::list<ObdPid*> repeatReqList;
140         ObdPid::ByteArray replyVector;
141         std::string reply;
142         std::string port;
143         std::string baud;
144         bool connected=false;
145         int emptycount = 0;
146         int timeoutCount = 0;
147         while (source->m_threadLive)
148         {
149                 //gpointer query = g_async_queue_pop(privCommandQueue);
150                 
151                 
152                 gpointer query = g_async_queue_try_pop(privSingleShotQueue);
153                 if (query != nullptr)
154                 {
155                         //printf("Got request!\n");
156                         
157                         ObdPid *req = (ObdPid*)query;
158                         DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Got single shot request: " << req->pid.substr(0,req->pid.length()-1) << ":" << req->property <<endl;
159                         repeatReqList.push_back(req);
160                 }
161                 query = g_async_queue_try_pop(privSubscriptionAddQueue);
162                 if (query != nullptr)
163                 {
164
165                         ObdPid *req = (ObdPid*)query;
166                         //DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Got subscription request for "<<req->req<<endl;
167                         reqList.push_back(req);
168                 }
169                 query = g_async_queue_try_pop(privCommandQueue);
170                 if (query != nullptr)
171                 {
172                         //ObdPid *req = (ObdPid*)query;
173                         CommandRequest *req = (CommandRequest*)query;
174                         //commandMap[req->req] = req->arg;
175                         //printf("Command: %s\n",req->req.c_str());
176                         DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Command:" << req->req << endl;
177                         if (req->req == "connect" )
178                         {
179
180                                 if (source->m_isBluetooth)
181                                 {
182                                         ObdBluetoothDevice bt;
183                                         std::string tempPort = bt.getDeviceForAddress(source->m_btDeviceAddress, source->m_btAdapterAddress);
184                                         if(tempPort != "")
185                                         {
186                                                 DebugOut(3)<<"Using bluetooth device \""<<source->m_btDeviceAddress<<"\" bound to: "<<tempPort<<endl;
187                                                 port = tempPort;
188                                         }
189                                 }
190                                 else
191                                 {
192                                         port = req->arglist[0];
193                                         baud = req->arglist[1];
194                                 }
195                                 connected = connect(obd,port,baud);
196
197                                 if(connected)
198                                 {
199                                         StatusMessage *statusreq = new StatusMessage();
200                                         statusreq->statusStr = "connected";
201                                         g_async_queue_push(privStatusQueue,statusreq);
202                                 }
203                                 else
204                                 {
205                                         StatusMessage *statusreq = new StatusMessage();
206                                         statusreq->statusStr = "disconnected";
207                                         g_async_queue_push(privStatusQueue,statusreq);
208                                 }
209                                 
210                         }
211                         else if (req->req == "connectifnot")
212                         {
213                                 if (!connected)
214                                 {
215                                         if (source->m_isBluetooth)
216                                         {
217                                                 ObdBluetoothDevice bt;
218                                                 std::string tempPort = bt.getDeviceForAddress(source->m_btDeviceAddress, source->m_btAdapterAddress);
219                                                 if(tempPort != "")
220                                                 {
221                                                         DebugOut(3)<<"Using bluetooth device \""<<source->m_btDeviceAddress<<"\" bound to: "<<tempPort<<endl;
222                                                         port = tempPort;
223                                                 }
224                                                 else
225                                                 {
226                                                         DebugOut(DebugOut::Error)<<"Error creating bluetooth device"<<endl;
227                                                 }
228                                         }
229                                         connected = connect(obd,port,baud);
230
231                                         if(connected)
232                                         {
233                                                 StatusMessage *statusreq = new StatusMessage();
234                                                 statusreq->statusStr = "connected";
235                                                 g_async_queue_push(privStatusQueue,statusreq);
236                                         }
237                                         else
238                                         {
239                                                 StatusMessage *statusreq = new StatusMessage();
240                                                 statusreq->statusStr = "disconnected";
241                                                 g_async_queue_push(privStatusQueue,statusreq);
242                                         }
243                                 }
244                         }
245                         else if (req->req == "setportandbaud")
246                         {
247                                 port = req->arglist[0];
248                                 baud = req->arglist[1];
249                         }
250                         else if (req->req == "disconnect")
251                         {
252                                 DebugOut() << __SMALLFILE__ << ":" << __LINE__ << "Using queued disconnect" << (ulong)req << endl;
253                                 obd->closePort();
254                                 ObdBluetoothDevice bt;
255                                 bt.disconnect(source->m_btDeviceAddress, source->m_btAdapterAddress);
256                                 connected = false;
257                                 StatusMessage *statusreq = new StatusMessage();
258                                 statusreq->statusStr = "disconnected";
259                                 g_async_queue_push(privStatusQueue,statusreq);
260                         }
261                         delete req;
262                 }
263                 query = g_async_queue_try_pop(privSubscriptionRemoveQueue);
264                 if (query != nullptr)
265                 {
266                         DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Got unsubscription request"<<endl;
267                         ObdPid *req = (ObdPid*)query;
268                         for (std::list<ObdPid*>::iterator i=reqList.begin();i!= reqList.end();i++)
269                         {
270                                 if ((*i)->property == req->property)
271                                 {
272                                         reqList.erase(i);
273                                         delete (*i);
274                                         i--;
275                                         if (reqList.size() == 0)
276                                         {
277                                                 break;
278                                         }
279                                 }
280                         }
281                         //reqList.push_back(req->req);
282                         delete req;
283                 }
284                 if (reqList.size() > 0 && !connected)
285                 {
286                         /*CommandRequest *req = new CommandRequest();
287                         req->req = "connect";
288                         req->arglist.push_back(port);
289                         req->arglist.push_back(baud);
290                         g_async_queue_push(privCommandQueue,req);
291                         continue;*/
292                 }
293                 else if (reqList.size() == 0 && connected)
294                 {
295                         emptycount++;
296                         if (emptycount < 1000)
297                         {
298                                 usleep(10000);
299                                 continue;
300                         }
301                         emptycount = 0;
302                         CommandRequest *req = new CommandRequest();
303                         req->req = "disconnect";
304                         g_async_queue_push(privCommandQueue,req);
305                         continue;
306                 }
307                 if (!connected)
308                 {
309                         usleep(10000);
310                         continue;
311                 }
312                 for (std::list<ObdPid*>::iterator i=reqList.begin();i!= reqList.end();i++)
313                 {
314                         repeatReqList.push_back(*i);
315                 }
316                 int badloop = 0;
317                 for (std::list<ObdPid*>::iterator i=repeatReqList.begin();i!= repeatReqList.end();i++)
318                 {
319                         DebugOut(10) << __SMALLFILE__ << ":" << __LINE__ << "Requesting pid: " << (*i)->pid.substr(0,(*i)->pid.length()-1) << (*i)->property << endl;
320                         if (source->m_blacklistPidCountMap.find((*i)->pid) != source->m_blacklistPidCountMap.end())
321                         {
322                                 //Don't erase the pid, just skip over it.
323                                 int count = (*source->m_blacklistPidCountMap.find((*i)->pid)).second;
324                                 if (count > 10)
325                                 {
326                                         continue;
327                                 }
328                         }
329                         badloop++;
330
331                         bool result = false;
332
333                         if(beginsWith((*i)->pid,"AT") || beginsWith((*i)->pid, "ST"))
334                         {
335                                 result = obd->sendObdRequestString((*i)->pid.c_str(),(*i)->pid.length(),&replyVector);
336                         }
337                         else result = obd->sendObdRequestString((*i)->pid.c_str(),(*i)->pid.length(),&replyVector,5,3);
338
339                         if (!result)
340                         {
341                                 //This only happens during a error with the com port. Close it and re-open it later.
342                                 DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Unable to send request:" << (*i)->pid.substr(0,(*i)->pid.length()-1) << endl;
343                                 if (obd->lastError() == obdLib::NODATA)
344                                 {
345                                         DebugOut() << __SMALLFILE__ << ":" << __LINE__ << "OBDLib::NODATA for pid" << (*i)->pid.substr(0,(*i)->pid.length()-1) << " expected property: " << (*i)->property << endl;
346                                         if (source->m_blacklistPidCountMap.find((*i)->pid) != source->m_blacklistPidCountMap.end())
347                                         {
348                                                 //pid value i not yet in the list.
349                                                 int count = (*source->m_blacklistPidCountMap.find((*i)->pid)).second;
350                                                 if (count > 10)
351                                                 {
352                                                         
353                                                 }
354                                                 source->m_blacklistPidCountMap.erase(source->m_blacklistPidCountMap.find((*i)->pid));
355                                                 source->m_blacklistPidCountMap.insert(pair<std::string,int>((*i)->pid,count));
356                                         }
357                                         else
358                                         {
359                                                 source->m_blacklistPidCountMap.insert(pair<std::string,int>((*i)->pid,1));
360                                         }
361                                         StatusMessage *statusreq = new StatusMessage();
362                                         statusreq->statusStr = "error:nodata";
363                                         statusreq->property = (*i)->property;
364                                         g_async_queue_push(privStatusQueue,statusreq);
365                                         continue;
366                                 }
367                                 else if (obd->lastError() == obdLib::TIMEOUT)
368                                 {
369                                         timeoutCount++;
370                                         if (timeoutCount < 2)
371                                         {
372                                                 DebugOut() << __SMALLFILE__ << ":" << __LINE__ << "OBDLib::TIMEOUT for pid" << (*i)->pid << endl;
373                                                 StatusMessage *statusreq = new StatusMessage();
374                                                 statusreq->statusStr = "error:timeout";
375                                                 g_async_queue_push(privStatusQueue,statusreq);
376                                                 continue;
377                                         }
378                                 }
379                                 else
380                                 {
381                                         DebugOut() << __SMALLFILE__ << ":" << __LINE__ << "OBD Other error:" << obd->lastError() << endl;
382                                 }
383                                 
384                                 CommandRequest *req = new CommandRequest();
385                                 DebugOut() << __SMALLFILE__ << ":" << __LINE__ << "Queuing up a disconnect" << (ulong)req << endl;
386                                 req->req = "disconnect";
387                                 g_async_queue_push(privCommandQueue,req);
388                                 i = repeatReqList.end();
389                                 i--;
390                                 continue;
391                         }
392                         if (source->m_blacklistPidCountMap.find((*i)->pid) != source->m_blacklistPidCountMap.end())
393                         {
394                                 //If we get the pid response, then we want to clear out the blacklist list.
395                                 source->m_blacklistPidCountMap.erase(source->m_blacklistPidCountMap.find((*i)->pid));
396                         }
397                         timeoutCount = 0;
398                         //ObdPid *pid = ObdPid::pidFromReply(replyVector);
399                         ObdPid *pid = obd2AmbInstance->createPidFromReply(replyVector);
400                         if (!pid)
401                         {
402                                 //Invalid reply
403                                 DebugOut() << "Invalid reply"<<endl;
404                                 continue;
405                         }
406                         else
407                         {
408                                 DebugOut(11) << __SMALLFILE__ <<":"<< __LINE__ << "Reply recieved and queued for:" << (*i)->pid.substr(0,(*i)->pid.length()-1) << endl;
409                                 std::string repstr;
410                                 for (int i=0;i<replyVector.size();i++)
411                                 {
412                                   if (replyVector[i] != 13)
413                                   {
414                                   repstr += (char)replyVector[i];
415                                   }
416                                         //DebugOut(11) << replyVector[i];
417                                 }
418                                 DebugOut(11) << "Reply:" << repstr << endl;
419                         }
420                         g_async_queue_push(privResponseQueue,pid);
421                 }
422                 if (badloop == 0)
423                 {
424                         //We had zero non-blacklisted events. Pause for a moment here to keep from burning CPU.
425                         //usleep(10000);
426                 }
427                 repeatReqList.clear();
428                 
429         }
430         if (connected)
431         {
432                 obd->closePort();
433         }
434 }
435 static int updateProperties( gpointer data)
436 {
437
438         OBD2Source* src = (OBD2Source*)data;
439         
440         while (gpointer retval = g_async_queue_try_pop(src->statusQueue))
441         {
442                 StatusMessage *reply = (StatusMessage*)retval;
443                 if (reply->statusStr == "disconnected")
444                 {
445                         OBD2Source::Obd2ConnectType val(Obd2Connected,false);
446                         src->updateProperty(Obd2Connected,&val);
447                 }
448                 else if (reply->statusStr == "connected")
449                 {
450                         OBD2Source::Obd2ConnectType val(Obd2Connected, true);
451                         src->updateProperty(Obd2Connected,&val);
452                 }
453                 else if (reply->statusStr == "error:nodata" || reply->statusStr == "error:timeout")
454                 {
455                         if (src->propertyReplyMap.find(reply->property) != src->propertyReplyMap.end())
456                         {
457                                 DebugOut(5) << __SMALLFILE__ <<":"<< __LINE__ << reply->statusStr << " on property:" << reply->property << endl;
458                                 src->propertyReplyMap[reply->property]->success = false;
459                                 src->propertyReplyMap[reply->property]->completed(src->propertyReplyMap[reply->property]);
460                                 src->propertyReplyMap.erase(reply->property);
461                         }
462                         else
463                         {
464                                 DebugOut(5) << __SMALLFILE__ <<":"<< __LINE__ << reply->statusStr << " on unrequested property:" << reply->property << endl;
465                         }
466                 }
467                 delete reply;
468         }
469         while(gpointer retval = g_async_queue_try_pop(src->responseQueue))
470         {
471                 ObdPid *reply = (ObdPid*)retval;
472
473                 
474                 AbstractPropertyType* value = VehicleProperty::getPropertyTypeForPropertyNameValue(reply->property, reply->value);
475                 src->updateProperty(reply->property, value);
476                 delete value;
477                 delete reply;
478         }
479
480         return true;
481 }
482
483 void OBD2Source::updateProperty(VehicleProperty::Property property,AbstractPropertyType* value)
484 {
485
486         
487         if (propertyReplyMap.find(property) != propertyReplyMap.end())
488         {
489                 propertyReplyMap[property]->value = value;
490                 propertyReplyMap[property]->success = true;
491                 try {
492                         propertyReplyMap[property]->completed(propertyReplyMap[property]);
493                 }catch(...)
494                 {
495                         DebugOut(DebugOut::Error)<<"failed to call reply completed callback"<<endl;
496                 }
497
498                 propertyReplyMap.erase(property);
499         }
500         else
501         {
502                 if(oldValueMap.find(property) != oldValueMap.end())
503                 {
504                         AbstractPropertyType* old = oldValueMap[property];
505
506                         if((*old) == (*value))
507                         {
508                                 return;
509                         }
510
511                         delete old;
512                 }
513
514                 oldValueMap[property] = value->copy();
515
516                 m_re->updateProperty(property,value,uuid());
517         }
518 }
519
520 void OBD2Source::setSupported(PropertyList list)
521 {
522         m_supportedProperties = list;
523         m_re->updateSupported(list,PropertyList());
524 }
525 /*void OBD2Source::propertySignal(VehicleProperty::Property property,boost::any value)
526 {
527 }
528 void OBD2Source::checkProperty()
529 {
530 }*/
531 void OBD2Source::setConfiguration(map<string, string> config)
532 {
533 //      //Config has been passed, let's start stuff up.
534         configuration = config;
535         
536         //Default values
537         std::string port = "/dev/ttyUSB0";
538         std::string baud = "115200";
539         std::string btadapter = "";
540         m_isBluetooth = false;
541         
542         //Try to load config
543         //printf("OBD2Source::setConfiguration\n");
544         for (map<string,string>::iterator i=configuration.begin();i!=configuration.end();i++)
545         {
546                 //printf("Incoming setting: %s:%s\n",(*i).first.c_str(),(*i).second.c_str());
547                 DebugOut(5) << __SMALLFILE__ <<":"<< __LINE__ << "Incoming setting:" << (*i).first << ":" << (*i).second << endl;
548                 if ((*i).first == "device")
549                 {
550                         port = (*i).second;
551                 }
552                 else if ((*i).first == "baud")
553                 {
554                         if((*i).second != "")
555                                 baud = (*i).second;
556                 }
557
558                 else if ((*i).first == "bluetoothAdapter")
559                 {
560                         btadapter = (*i).second;
561                 }
562         }
563
564         if(port.find(":") != string::npos)
565         {
566                 m_btDeviceAddress = port;
567                 m_btAdapterAddress = btadapter;
568                 m_isBluetooth = true;
569                 ///TODO: bluetooth!!
570                 DebugOut()<<"bluetooth device?"<<endl;
571                 ObdBluetoothDevice bt;
572
573                 std::string tempPort = bt.getDeviceForAddress(port, btadapter);
574                 if(tempPort != "")
575                 {
576                         DebugOut(3)<<"Using bluetooth device \""<<port<<"\" bound to: "<<tempPort<<endl;
577                         port = tempPort;
578                 }
579                 else
580                 {
581                         DebugOut(0)<<"Device Error"<<endl;
582                         ///Don't throw here.
583                         //throw std::runtime_error("Device Error");
584                 }
585         }
586
587         //connect(obd, port, baud);
588         CommandRequest *req = new CommandRequest();
589         req->req = "setportandbaud";
590         req->arglist.push_back(port);
591         req->arglist.push_back(baud);
592         g_async_queue_push(commandQueue,req);
593         
594         m_port = port;
595         m_baud = baud;
596         m_gThread = g_thread_new("mythread",(GThreadFunc)&threadLoop,this);
597         //g_idle_add(updateProperties, this);
598         g_timeout_add(5,updateProperties,this);
599 }
600
601 OBD2Source::OBD2Source(AbstractRoutingEngine *re, map<string, string> config)
602         : AbstractSource(re, config)
603 {
604         bool success = VehicleProperty::registerProperty(Obd2Connected,[](){ return new Obd2ConnectType(Obd2Connected,false); });
605
606         if(!success)
607         {
608                 ///ERROR!
609         }
610
611         clientConnected = false;
612         m_re = re;  
613
614         m_threadLive = true;
615         Obd2Amb obd2amb;
616         obd = new obdLib();
617
618         for(auto itr = obd2amb.supportedPidsList.begin(); itr != obd2amb.supportedPidsList.end(); itr++)
619         {
620                 m_supportedProperties.push_back((*itr)->property);
621         }
622
623         m_supportedProperties.push_back(Obd2Connected);
624
625         re->setSupported(supported(), this);
626         /*if (openPort(std::string("/dev/pts/7"),115200))
627         {
628           printf("Error opening OBD2 port\n");
629         }*/
630         statusQueue = g_async_queue_new();
631         commandQueue = g_async_queue_new();
632         subscriptionAddQueue = g_async_queue_new();
633         subscriptionRemoveQueue = g_async_queue_new();
634         responseQueue = g_async_queue_new();
635         singleShotQueue = g_async_queue_new();
636
637         setConfiguration(config);
638 }
639 OBD2Source::~OBD2Source()
640 {
641         DebugOut() << "OBD2Source Destructor called!!!"<<endl;
642         m_threadLive = false;
643         g_thread_join(m_gThread);
644 }
645
646 PropertyList OBD2Source::supported()
647 {
648         return m_supportedProperties;
649 }
650
651 int OBD2Source::supportedOperations()
652 {
653         return Get | Set;
654 }
655
656 extern "C" AbstractSource * create(AbstractRoutingEngine* routingengine, map<string, string> config)
657 {
658         return new OBD2Source(routingengine, config);
659         
660 }
661 string OBD2Source::uuid()
662 {
663         return "f77af740-f1f8-11e1-aff1-0800200c9a66";
664 }
665 void OBD2Source::subscribeToPropertyChanges(VehicleProperty::Property property)
666 {
667         if (property == VehicleProperty::VIN)
668         {
669                 DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "VIN subscription requested... but there's no point!"<<endl;
670         }
671         else if (property == VehicleProperty::WMI)
672         {
673                 DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "WMI subscription requested... but there's no point!"<<endl;
674         }
675         else
676         {
677                 if(!ListPlusPlus<VehicleProperty::Property>(&m_supportedProperties).contains(property))
678                 {
679                         DebugOut(0)<<"obd plugin does not support: "<<property<<endl;
680                         return;
681                 }
682
683
684                 ObdPid *pid = obd2AmbInstance->createPidforProperty(property);
685
686                 if(!pid)
687                 {
688                         return;
689                 }
690                 
691                 //If the pid is currently in the blacklist map, erase it. This allows for applications
692                 //to "un-blacklist" a pid by re-subscribing to it.
693                 if (m_blacklistPidCountMap.find(pid->pid) != m_blacklistPidCountMap.end())
694                 {
695                         m_blacklistPidCountMap.erase(m_blacklistPidCountMap.find(pid->pid));
696                 }
697                                         
698                                         
699                 g_async_queue_push(subscriptionAddQueue,pid);
700                 CommandRequest *req = new CommandRequest();
701                 req->req = "connectifnot";
702                 g_async_queue_push(commandQueue,req);
703         }
704 }
705
706
707 void OBD2Source::unsubscribeToPropertyChanges(VehicleProperty::Property property)
708 {
709         if(!ListPlusPlus<VehicleProperty::Property>(&m_supportedProperties).contains(property))
710         {
711                 DebugOut(0)<<"obd plugin does not support: "<<property<<endl;
712                 return;
713         }
714
715         ObdPid *pid = obd2AmbInstance->createPidforProperty(property);
716         g_async_queue_push(subscriptionRemoveQueue,pid);
717 }
718
719
720 void OBD2Source::getPropertyAsync(AsyncPropertyReply *reply)
721 {
722         DebugOut(5) << __SMALLFILE__ <<":"<< __LINE__ << "getPropertyAsync requested for " << reply->property << endl;
723
724         VehicleProperty::Property property = reply->property;
725
726
727         if(!ListPlusPlus<VehicleProperty::Property>(&m_supportedProperties).contains(property))
728         {
729                 DebugOut(0)<<"obd plugin does not support: "<<property<<endl;
730                 return;
731         }
732
733         propertyReplyMap[reply->property] = reply;
734
735         ObdPid* requ = obd2AmbInstance->createPidforProperty(property);
736         g_async_queue_push(singleShotQueue,requ);
737         CommandRequest *req = new CommandRequest();
738         req->req = "connectifnot";
739         g_async_queue_push(commandQueue,req);
740 }
741
742 AsyncPropertyReply *OBD2Source::setProperty(AsyncSetPropertyRequest request )
743 {
744         AsyncPropertyReply* reply = new AsyncPropertyReply (request);
745
746
747
748         if(request.property == Obd2Connected)
749         {
750                 propertyReplyMap[reply->property] = reply;
751                 reply->success = true;
752
753                 if(request.value->value<bool>() == true)
754                 {
755                         CommandRequest *req = new CommandRequest();
756                         req->req = "connectifnot";
757                         g_async_queue_push(commandQueue,req);
758                 }
759                 else
760                 {
761                         CommandRequest *req = new CommandRequest();
762                         req->req = "disconnect";
763                         g_async_queue_push(commandQueue,req);
764                 }
765
766         }
767
768         else
769         {
770                 reply->success = false;
771                 try
772                 {
773                         reply->completed(reply);
774                 }
775                 catch (...)
776                 {
777
778                 }
779         }
780
781
782         return reply;
783 }