Add possibility to subscribe to a recurring request permanently
[apps/agl-service-can-low-level.git] / low-can-binding / binding / low-can-cb.cpp
1 /*
2  * Copyright (C) 2015, 2016 "IoT.bzh"
3  * Author "Romain Forlot" <romain.forlot@iot.bzh>
4  * Author "Loic Collignon" <loic.collignon@iot.bzh>
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *       http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include "low-can-hat.hpp"
20 #include "low-can-apidef.h"
21
22 #include <map>
23 #include <queue>
24 #include <mutex>
25 #include <vector>
26 #include <thread>
27 #include <json-c/json.h>
28 #include <systemd/sd-event.h>
29
30 #include "openxc.pb.h"
31 #include "application.hpp"
32 #include "../can/can-encoder.hpp"
33 #include "../can/can-bus.hpp"
34 #include "../can/can-signals.hpp"
35 #include "../can/can-message.hpp"
36 #include "../utils/signals.hpp"
37 #include "../diagnostic/diagnostic-message.hpp"
38 #include "../utils/openxc-utils.hpp"
39
40 ///******************************************************************************
41 ///
42 ///             SystemD event loop Callbacks
43 ///
44 ///*******************************************************************************/
45
46 void on_no_clients(std::shared_ptr<low_can_subscription_t> can_subscription, uint32_t pid, std::map<int, std::shared_ptr<low_can_subscription_t> >& s)
47 {
48         bool is_permanent_recurring_request = false;
49
50         if( ! can_subscription->get_diagnostic_message().empty() && can_subscription->get_diagnostic_message(pid) != nullptr)
51         {
52                 DiagnosticRequest diag_req = can_subscription->get_diagnostic_message(pid)->build_diagnostic_request();
53                 active_diagnostic_request_t* adr = application_t::instance().get_diagnostic_manager().find_recurring_request(diag_req);
54                 if( adr != nullptr)
55                 {
56                         is_permanent_recurring_request = adr->get_permanent();
57
58                         if(! is_permanent_recurring_request)
59                                 application_t::instance().get_diagnostic_manager().cleanup_request(adr, true);
60                 }
61         }
62
63         if(! is_permanent_recurring_request)
64                 on_no_clients(can_subscription, s);
65 }
66
67 void on_no_clients(std::shared_ptr<low_can_subscription_t> can_subscription, std::map<int, std::shared_ptr<low_can_subscription_t> >& s)
68 {
69         auto it = s.find(can_subscription->get_index());
70         s.erase(it);
71 }
72
73 static void push_n_notify(const can_message_t& cm)
74 {
75         can_bus_t& cbm = application_t::instance().get_can_bus_manager();
76         {
77                 std::lock_guard<std::mutex> can_message_lock(cbm.get_can_message_mutex());
78                 cbm.push_new_can_message(cm);
79         }
80         cbm.get_new_can_message_cv().notify_one();
81 }
82
83 int read_message(sd_event_source *event_source, int fd, uint32_t revents, void *userdata)
84 {
85         low_can_subscription_t* can_subscription = (low_can_subscription_t*)userdata;
86         if ((revents & EPOLLIN) != 0)
87         {
88                 can_message_t cm;
89                 utils::socketcan_bcm_t& s = can_subscription->get_socket();
90                 s >> cm;
91
92                 // Sure we got a valid CAN message ?
93                 if(! cm.get_id() == 0 && ! cm.get_length() == 0)
94                         {push_n_notify(cm);}
95         }
96
97         // check if error or hangup
98         if ((revents & (EPOLLERR|EPOLLRDHUP|EPOLLHUP)) != 0)
99         {
100                 sd_event_source_unref(event_source);
101                 can_subscription->get_socket().close();
102         }
103         return 0;
104 }
105
106 ///******************************************************************************
107 ///
108 ///             Subscription and unsubscription
109 ///
110 ///*******************************************************************************/
111
112 static int make_subscription_unsubscription(struct afb_req request,
113                                                                                         std::shared_ptr<low_can_subscription_t>& can_subscription,
114                                                                                         std::map<int, std::shared_ptr<low_can_subscription_t> >& s,
115                                                                                         bool subscribe)
116 {
117         /* Make the subscription or unsubscription to the event (if request contents are not null) */
118         if(request.itf && request.closure &&
119            ((subscribe ? afb_req_subscribe : afb_req_unsubscribe)(request, s[can_subscription->get_index()]->get_event())) < 0)
120         {
121                 AFB_ERROR("Operation goes wrong for signal: %s", can_subscription->get_name().c_str());
122                 return -1;
123         }
124         return 0;
125 }
126
127 static int create_event_handle(std::shared_ptr<low_can_subscription_t>& can_subscription,
128                                                         std::map<int, std::shared_ptr<low_can_subscription_t> >& s)
129 {
130         int sub_index = can_subscription->get_index();
131         can_subscription->set_event(afb_daemon_make_event(can_subscription->get_name().c_str()));
132         s[sub_index] = can_subscription;
133         if (!afb_event_is_valid(s[sub_index]->get_event()))
134         {
135                 AFB_ERROR("Can't create an event for %s, something goes wrong.", can_subscription->get_name().c_str());
136                 return -1;
137         }
138         return 0;
139 }
140
141 /// @brief Will determine if it is needed or not to create the event handle and checks it to be sure that
142 /// we got a valid afb_event to get subscribe or unsubscribe. Then launch the subscription or unsubscription
143 /// against the application framework using that event handle.
144 static int subscribe_unsubscribe_signal(struct afb_req request,
145                                                                                 bool subscribe,
146                                                                                 std::shared_ptr<low_can_subscription_t>& can_subscription,
147                                                                                 std::map<int, std::shared_ptr<low_can_subscription_t> >& s)
148 {
149         int ret = -1;
150         int sub_index = can_subscription->get_index();
151
152         if (can_subscription && s.find(sub_index) != s.end())
153         {
154                 if (!afb_event_is_valid(s[sub_index]->get_event()) && !subscribe)
155                 {
156                         AFB_NOTICE("Event isn't valid, no need to unsubscribed.");
157                         ret = -1;
158                 }
159                 ret = 0;
160         }
161         else
162         {
163                 /* Event doesn't exist , so let's create it */
164                 can_subscription->set_event({nullptr, nullptr});
165                 s[sub_index] = can_subscription;
166                 ret = create_event_handle(can_subscription, s);
167         }
168
169         // Check whether or not the event handler has been correctly created and
170         // make the subscription/unsubscription operation is so.
171         if (ret < 0)
172                 return ret;
173         return make_subscription_unsubscription(request, can_subscription, s, subscribe);
174 }
175
176 static int add_to_event_loop(std::shared_ptr<low_can_subscription_t>& can_subscription)
177 {
178                 struct sd_event_source* event_source = nullptr;
179                 return ( sd_event_add_io(afb_daemon_get_event_loop(),
180                         &event_source,
181                         can_subscription->get_socket().socket(),
182                         EPOLLIN,
183                         read_message,
184                         can_subscription.get()));
185 }
186
187 static int subscribe_unsubscribe_diagnostic_messages(struct afb_req request,
188                                                                                                         bool subscribe,
189                                                                                                         std::vector<std::shared_ptr<diagnostic_message_t> > diagnostic_messages,
190                                                                                                         struct event_filter_t& event_filter,
191                                                                                                         std::map<int, std::shared_ptr<low_can_subscription_t> >& s,
192                                                                                                         bool perm_rec_diag_req)
193 {
194         int rets = 0;
195         application_t& app = application_t::instance();
196         diagnostic_manager_t& diag_m = app.get_diagnostic_manager();
197
198         for(const auto& sig : diagnostic_messages)
199         {
200                 DiagnosticRequest* diag_req = new DiagnosticRequest(sig->build_diagnostic_request());
201                 event_filter.frequency = event_filter.frequency == 0 ? sig->get_frequency() : event_filter.frequency;
202                 std::shared_ptr<low_can_subscription_t> can_subscription;
203
204                 auto it =  std::find_if(s.begin(), s.end(), [&sig](std::pair<int, std::shared_ptr<low_can_subscription_t> > sub){ return (! sub.second->get_diagnostic_message().empty());});
205                 can_subscription = it != s.end() ?
206                         it->second :
207                         std::make_shared<low_can_subscription_t>(low_can_subscription_t(event_filter));
208                 // If the requested diagnostic message isn't supported by the car then unsubcribe it
209                 // no matter what we want, worse case will be a fail unsubscription but at least we don't
210                 // poll a PID for nothing.
211                 if(sig->get_supported() && subscribe)
212                 {
213                         diag_m.add_recurring_request(diag_req, sig->get_name().c_str(), false, sig->get_decoder(), sig->get_callback(), event_filter.frequency, perm_rec_diag_req);
214                         if(can_subscription->create_rx_filter(sig) < 0)
215                                 {return -1;}
216                         AFB_DEBUG("Signal: %s subscribed", sig->get_name().c_str());
217                         if(it == s.end() && add_to_event_loop(can_subscription) < 0)
218                         {
219                                 diag_m.cleanup_request(
220                                         diag_m.find_recurring_request(*diag_req), true);
221                                 AFB_WARNING("signal: %s isn't supported. Canceling operation.",  sig->get_name().c_str());
222                                 return -1;
223                         }
224                 }
225                 else
226                 {
227                         if(sig->get_supported())
228                         {AFB_DEBUG("%s cancelled due to unsubscribe", sig->get_name().c_str());}
229                         else
230                         {
231                                 AFB_WARNING("signal: %s isn't supported. Canceling operation.", sig->get_name().c_str());
232                                 return -1;
233                         }
234                 }
235                 int ret = subscribe_unsubscribe_signal(request, subscribe, can_subscription, s);
236                 if(ret < 0)
237                         return ret;
238
239                 rets++;
240         }
241
242         return rets;
243 }
244
245 static int subscribe_unsubscribe_can_signals(struct afb_req request,
246                                                                                         bool subscribe,
247                                                                                         std::vector<std::shared_ptr<can_signal_t> > can_signals,
248                                                                                         struct event_filter_t& event_filter,
249                                                                                         std::map<int, std::shared_ptr<low_can_subscription_t> >& s)
250 {
251         int rets = 0;
252         for(const auto& sig: can_signals)
253         {
254                 auto it =  std::find_if(s.begin(), s.end(), [&sig, &event_filter](std::pair<int, std::shared_ptr<low_can_subscription_t> > sub){ return sub.second->is_signal_subscription_corresponding(sig, event_filter) ; });
255                 std::shared_ptr<low_can_subscription_t> can_subscription;
256                 if(it != s.end())
257                 {
258                          can_subscription = it->second;
259                 }
260                 else
261                 {
262                          can_subscription = std::make_shared<low_can_subscription_t>(low_can_subscription_t(event_filter));
263                         if(can_subscription->create_rx_filter(sig) < 0)
264                                 {return -1;}
265                         if(add_to_event_loop(can_subscription) < 0)
266                                 {return -1;}
267                 }
268
269                 if(subscribe_unsubscribe_signal(request, subscribe, can_subscription, s) < 0)
270                         {return -1;}
271
272                 rets++;
273                 AFB_DEBUG("signal: %s subscribed", sig->get_name().c_str());
274         }
275         return rets;
276 }
277
278 ///
279 /// @brief subscribe to all signals in the vector signals
280 ///
281 /// @param[in] afb_req request : contain original request use to subscribe or unsubscribe
282 /// @param[in] subscribe boolean value used to chose between a subscription operation or an unsubscription
283 /// @param[in] signals -  struct containing vectors with can_signal_t and diagnostic_messages to subscribe
284 ///
285 /// @return Number of correctly subscribed signal
286 ///
287 static int subscribe_unsubscribe_signals(struct afb_req request,
288                                                                                 bool subscribe,
289                                                                                 const struct utils::signals_found& signals,
290                                                                                 struct event_filter_t& event_filter)
291 {
292         int rets = 0;
293         utils::signals_manager_t& sm = utils::signals_manager_t::instance();
294
295         std::lock_guard<std::mutex> subscribed_signals_lock(sm.get_subscribed_signals_mutex());
296         std::map<int, std::shared_ptr<low_can_subscription_t> >& s = sm.get_subscribed_signals();
297
298         rets += subscribe_unsubscribe_diagnostic_messages(request, subscribe, signals.diagnostic_messages, event_filter, s, false);
299         rets += subscribe_unsubscribe_can_signals(request, subscribe, signals.can_signals, event_filter, s);
300
301         return rets;
302 }
303
304 static int one_subscribe_unsubscribe(struct afb_req request,
305                                                                         bool subscribe,
306                                                                         const std::string& tag,
307                                                                         json_object* args)
308 {
309         int ret = 0;
310         struct event_filter_t event_filter;
311         struct json_object  *filter, *obj;
312         struct utils::signals_found sf;
313
314         // computes the filter
315         if (json_object_object_get_ex(args, "filter", &filter))
316         {
317                 if (json_object_object_get_ex(filter, "frequency", &obj)
318                 && (json_object_is_type(obj, json_type_double) || json_object_is_type(obj, json_type_int)))
319                         {event_filter.frequency = (float)json_object_get_double(obj);}
320                 if (json_object_object_get_ex(filter, "min", &obj)
321                 && (json_object_is_type(obj, json_type_double) || json_object_is_type(obj, json_type_int)))
322                         {event_filter.min = (float)json_object_get_double(obj);}
323                 if (json_object_object_get_ex(filter, "max", &obj)
324                 && (json_object_is_type(obj, json_type_double) || json_object_is_type(obj, json_type_int)))
325                         {event_filter.max = (float)json_object_get_double(obj);}
326         }
327
328         // subscribe or unsubscribe
329         openxc_DynamicField search_key = build_DynamicField(tag);
330         sf = utils::signals_manager_t::instance().find_signals(search_key);
331         if (sf.can_signals.empty() && sf.diagnostic_messages.empty())
332         {
333                 AFB_NOTICE("No signal(s) found for %s.", tag.c_str());
334                 ret = -1;
335         }
336         else
337                 {ret = subscribe_unsubscribe_signals(request, subscribe, sf, event_filter);}
338
339         return ret;
340 }
341 static int process_one_subscribe_args(struct afb_req request, bool subscribe, json_object *args)
342 {
343         int rc = 0, rc2=0;
344         json_object *x = nullptr, *event = nullptr;
345         if(args == NULL ||
346                 !json_object_object_get_ex(args, "event", &event))
347         {
348                 rc = one_subscribe_unsubscribe(request, subscribe, "*", args);
349         }
350         else if (json_object_get_type(event) != json_type_array)
351         {
352                 rc = one_subscribe_unsubscribe(request, subscribe, json_object_get_string(event), args);
353         }
354         else
355         {
356                 for (int i = 0 ; i < json_object_array_length(event); i++)
357                 {
358                         x = json_object_array_get_idx(event, i);
359                         rc2 = one_subscribe_unsubscribe(request, subscribe, json_object_get_string(x), args);
360                         if (rc >= 0)
361                                 rc = rc2 >= 0 ? rc + rc2 : rc2;
362                 }
363         }
364         return rc;
365 }
366
367 static void do_subscribe_unsubscribe(struct afb_req request, bool subscribe)
368 {
369         int rc = 0;
370         struct json_object *args, *x;
371
372         args = afb_req_json(request);
373         if (json_object_get_type(args) == json_type_array)
374         {
375                 for(int i = 0; i < json_object_array_length(args); i++)
376                 {
377                         x = json_object_array_get_idx(args, i);
378                         rc += process_one_subscribe_args(request, subscribe, x);
379                 }
380         }
381         else
382         {
383                 rc += process_one_subscribe_args(request, subscribe, args);
384         }
385
386         if (rc >= 0)
387                 afb_req_success(request, NULL, NULL);
388         else
389                 afb_req_fail(request, "error", NULL);
390 }
391
392 void auth(struct afb_req request)
393 {
394         afb_req_session_set_LOA(request, 1);
395         afb_req_success(request, NULL, NULL);
396 }
397
398 void subscribe(struct afb_req request)
399 {
400         do_subscribe_unsubscribe(request, true);
401 }
402
403 void unsubscribe(struct afb_req request)
404 {
405         do_subscribe_unsubscribe(request, false);
406 }
407
408 static int send_frame(const std::string& bus_name, const struct can_frame& cf)
409 {
410         std::map<std::string, std::shared_ptr<low_can_socket_t> >& cd = application_t::instance().get_can_devices();
411
412         if( cd.count(bus_name) == 0)
413                 {cd[bus_name] = std::make_shared<low_can_socket_t>(low_can_socket_t());}
414
415         return cd[bus_name]->tx_send(cf, bus_name);
416 }
417
418 static int write_raw_frame(const std::string& bus_name, uint32_t can_id, uint8_t can_dlc, struct json_object* can_data)
419 {
420         int rc = 0;
421         struct can_frame cf;
422
423         ::memset(&cf, 0, sizeof(cf));
424
425         cf.can_id = can_id;
426         cf.can_dlc = can_dlc;
427
428         struct json_object *x;
429         int n = json_object_array_length(can_data);
430         if(n <= 8)
431         {
432                 for (int i = 0 ; i < n ; i++)
433                 {
434                         x = json_object_array_get_idx(can_data, i);
435                         cf.data[i] = json_object_get_type(x) == json_type_int ? (uint8_t)json_object_get_int(x) : 0;
436                 }
437         }
438
439         const std::string found_device = application_t::instance().get_can_bus_manager().get_can_device_name(bus_name);
440         if( ! found_device.empty())
441         {
442                 rc = send_frame(found_device, cf);
443         }
444
445         return rc;
446 }
447 static int write_signal(const std::string& name, uint64_t value)
448 {
449         int rc = 0;
450         struct can_frame cf;
451         struct utils::signals_found sf;
452
453         ::memset(&cf, 0, sizeof(cf));
454
455         openxc_DynamicField search_key = build_DynamicField(name);
456         sf = utils::signals_manager_t::instance().find_signals(search_key);
457
458         if (sf.can_signals.empty())
459         {
460                 AFB_WARNING("No signal(s) found for %s. Message not sent.", name.c_str());
461                 rc = -1;
462         }
463         else
464         {
465                 for(const auto& sig: sf.can_signals)
466                 {
467                         if(sig->get_writable())
468                         {
469                                 cf = encoder_t::build_frame(sig, value);
470                                 const std::string bus_name = sig->get_message()->get_bus_device_name();
471                                 rc = send_frame(bus_name, cf);
472                         }
473                         else
474                         {
475                                 AFB_WARNING("%s isn't writable. Message not sent.", sig->get_name().c_str());
476                                 return -1;
477                         }
478                 }
479         }
480
481         return rc;
482 }
483
484 void write(struct afb_req request)
485 {
486         int rc = 0;
487         struct json_object* args = nullptr,
488                 *json_name = nullptr,
489                 *json_value = nullptr;
490
491         args = afb_req_json(request);
492
493         // Process about Raw CAN message on CAN bus directly
494         if (args != NULL &&
495                 (json_object_object_get_ex(args, "bus_name", &json_name) && json_object_is_type(json_name, json_type_string) ) &&
496                 (json_object_object_get_ex(args, "frame", &json_value) && json_object_is_type(json_value, json_type_object) ))
497         {
498                 struct json_object* json_can_id = nullptr,
499                         *json_can_dlc = nullptr,
500                         *json_can_data = nullptr;
501
502                 if( (json_object_object_get_ex(json_value, "can_id", &json_can_id) && (json_object_is_type(json_can_id, json_type_double) || json_object_is_type(json_can_id, json_type_int))) &&
503                         (json_object_object_get_ex(json_value, "can_dlc", &json_can_dlc) && (json_object_is_type(json_can_dlc, json_type_double) || json_object_is_type(json_can_dlc, json_type_int))) &&
504                         (json_object_object_get_ex(json_value, "can_data", &json_can_data) && json_object_is_type(json_can_data, json_type_array) ))
505                 {
506                         rc = write_raw_frame(json_object_get_string(json_name),
507                                 json_object_get_int(json_can_id),
508                                 (uint8_t)json_object_get_int(json_can_dlc),
509                                 json_can_data);
510                 }
511                 else
512                 {
513                         AFB_ERROR("Frame object malformed (must be \n \"frame\": {\"can_id\": int, \"can_dlc\": int, \"can_data\": [ int, int , int, int ,int , int ,int ,int]}");
514                         rc = -1;
515                 }
516         }
517         // Search signal then encode value.
518         else if(args != NULL &&
519                 (json_object_object_get_ex(args, "signal_name", &json_name) && json_object_is_type(json_name, json_type_string)) &&
520                 (json_object_object_get_ex(args, "signal_value", &json_value) && (json_object_is_type(json_value, json_type_double) || json_object_is_type(json_value, json_type_int))))
521         {
522                 rc = write_signal(json_object_get_string(json_name),
523                         (uint64_t)json_object_get_double(json_value));
524         }
525         else
526         {
527                 AFB_ERROR("Request argument malformed. Please use the following syntax:");
528                 rc = -1;
529         }
530
531         if (rc >= 0)
532                 afb_req_success(request, NULL, NULL);
533         else
534                 afb_req_fail(request, "error", NULL);
535 }
536
537 static struct json_object *get_signals_value(const std::string& name)
538 {
539         struct utils::signals_found sf;
540         struct json_object *ans = nullptr;
541
542         openxc_DynamicField search_key = build_DynamicField(name);
543         sf = utils::signals_manager_t::instance().find_signals(search_key);
544
545         if (sf.can_signals.empty())
546         {
547                 AFB_WARNING("No signal(s) found for %s.", name.c_str());
548                 return NULL;
549         }
550         ans = json_object_new_array();
551         for(const auto& sig: sf.can_signals)
552         {
553                 struct json_object *jobj = json_object_new_object();
554                 json_object_object_add(jobj, "event", json_object_new_string(sig->get_name().c_str()));
555                 json_object_object_add(jobj, "value", json_object_new_double(sig->get_last_value()));
556                 json_object_array_add(ans, jobj);
557         }
558
559         return ans;
560 }
561 void get(struct afb_req request)
562 {
563         int rc = 0;
564         struct json_object* args = nullptr,
565                 *json_name = nullptr;
566         json_object *ans = nullptr;
567
568         args = afb_req_json(request);
569
570         // Process about Raw CAN message on CAN bus directly
571         if (args != nullptr &&
572                 (json_object_object_get_ex(args, "event", &json_name) && json_object_is_type(json_name, json_type_string) ))
573         {
574                 ans = get_signals_value(json_object_get_string(json_name));
575                 if (!ans)
576                         rc = -1;
577         }
578         else
579         {
580                 AFB_ERROR("Request argument malformed. Please use the following syntax:");
581                 rc = -1;
582         }
583
584         if (rc >= 0)
585                 afb_req_success(request, ans, NULL);
586         else
587                 afb_req_fail(request, "error", NULL);
588 }
589
590
591 static struct json_object *list_can_message(const std::string& name)
592 {
593         struct utils::signals_found sf;
594         struct json_object *ans = nullptr;
595
596         openxc_DynamicField search_key = build_DynamicField(name);
597         sf = utils::signals_manager_t::instance().find_signals(search_key);
598
599         if (sf.can_signals.empty() && sf.diagnostic_messages.empty())
600         {
601                 AFB_WARNING("No signal(s) found for %s.", name.c_str());
602                 return NULL;
603         }
604         ans = json_object_new_array();
605         for(const auto& sig: sf.can_signals)
606         {
607                 json_object_array_add(ans,
608                         json_object_new_string(sig->get_name().c_str()));
609         }
610         for(const auto& sig: sf.diagnostic_messages)
611         {
612                 json_object_array_add(ans,
613                         json_object_new_string(sig->get_name().c_str()));
614         }
615
616         return ans;
617 }
618
619 void list(struct afb_req request)
620 {
621         int rc = 0;
622         json_object *ans = nullptr;
623         struct json_object* args = nullptr,
624                 *json_name = nullptr;
625         args = afb_req_json(request);
626         const char *name;
627         if ((args != nullptr) &&
628                 (json_object_object_get_ex(args, "event", &json_name) && json_object_is_type(json_name, json_type_string)))
629         {
630                 name = json_object_get_string(json_name);
631         }
632         else
633         {
634                 name = "*";
635         }
636
637         ans = list_can_message(name);
638         if (!ans)
639                 rc = -1;
640
641         if (rc >= 0)
642                 afb_req_success(request, ans, NULL);
643         else
644                 afb_req_fail(request, "error", NULL);
645 }
646
647 /// @brief Initialize the binding.
648 ///
649 /// @param[in] service Structure which represent the Application Framework Binder.
650 ///
651 /// @return Exit code, zero if success.
652 int initv2()
653 {
654         can_bus_t& can_bus_manager = application_t::instance().get_can_bus_manager();
655
656         can_bus_manager.set_can_devices();
657         can_bus_manager.start_threads();
658
659         /// Initialize Diagnostic manager that will handle obd2 requests.
660         /// We pass by default the first CAN bus device to its Initialization.
661         /// TODO: be able to choose the CAN bus device that will be use as Diagnostic bus.
662         if(application_t::instance().get_diagnostic_manager().initialize())
663                 return 0;
664
665         AFB_ERROR("There was something wrong with CAN device Initialization.");
666         return 1;
667 }