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