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