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