Cleaning the code for now unused functions
[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 <wrap-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(afb_req_t 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 is not null) */
118         if(request &&
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 This will determine if an event handle needs to be created and checks if
142 /// we got a valid afb_event to get subscribe or unsubscribe. After that launch the subscription or unsubscription
143 /// against the application framework using that event handle.
144 static int subscribe_unsubscribe_signal(afb_req_t 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                 s[sub_index] = can_subscription;
165                 ret = create_event_handle(can_subscription, s);
166         }
167
168         // Checks if the event handler is correctly created, if it is, it
169         // performs the subscription or unsubscription operations.
170         if (ret < 0)
171                 return ret;
172         return make_subscription_unsubscription(request, can_subscription, s, subscribe);
173 }
174
175 static int add_to_event_loop(std::shared_ptr<low_can_subscription_t>& can_subscription)
176 {
177                 struct sd_event_source* event_source = nullptr;
178                 return ( sd_event_add_io(afb_daemon_get_event_loop(),
179                         &event_source,
180                         can_subscription->get_socket().socket(),
181                         EPOLLIN,
182                         read_message,
183                         can_subscription.get()));
184 }
185
186 static int subscribe_unsubscribe_diagnostic_messages(afb_req_t request,
187                                                      bool subscribe,
188                                                      std::vector<std::shared_ptr<diagnostic_message_t> > diagnostic_messages,
189                                                      struct event_filter_t& event_filter,
190                                                      std::map<int, std::shared_ptr<low_can_subscription_t> >& s,
191                                                      bool perm_rec_diag_req)
192 {
193         int rets = 0;
194         application_t& app = application_t::instance();
195         diagnostic_manager_t& diag_m = app.get_diagnostic_manager();
196
197         for(const auto& sig : diagnostic_messages)
198         {
199                 DiagnosticRequest* diag_req = new DiagnosticRequest(sig->build_diagnostic_request());
200                 event_filter.frequency = event_filter.frequency == 0 ? sig->get_frequency() : event_filter.frequency;
201                 std::shared_ptr<low_can_subscription_t> can_subscription;
202
203                 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());});
204                 can_subscription = it != s.end() ?
205                         it->second :
206                         std::make_shared<low_can_subscription_t>(low_can_subscription_t(event_filter));
207                 // If the requested diagnostic message is not supported by the car then unsubcribe it
208                 // no matter what we want, worst case will be a failed unsubscription but at least we won't
209                 // poll a PID for nothing.
210                 if(sig->get_supported() && subscribe)
211                 {
212                         if (!app.isEngineOn())
213                                 AFB_WARNING("signal: Engine is off, %s won't received responses until it's on",  sig->get_name().c_str());
214
215                         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);
216                         if(can_subscription->create_rx_filter(sig) < 0)
217                                 {return -1;}
218                         AFB_DEBUG("Signal: %s subscribed", sig->get_name().c_str());
219                         if(it == s.end() && add_to_event_loop(can_subscription) < 0)
220                         {
221                                 diag_m.cleanup_request(
222                                         diag_m.find_recurring_request(*diag_req), true);
223                                 AFB_WARNING("signal: %s isn't supported. Canceling operation.",  sig->get_name().c_str());
224                                 return -1;
225                         }
226                 }
227                 else
228                 {
229                         if(sig->get_supported())
230                         {AFB_DEBUG("%s cancelled due to unsubscribe", sig->get_name().c_str());}
231                         else
232                         {
233                                 AFB_WARNING("signal: %s isn't supported. Canceling operation.", sig->get_name().c_str());
234                                 return -1;
235                         }
236                 }
237                 int ret = subscribe_unsubscribe_signal(request, subscribe, can_subscription, s);
238                 if(ret < 0)
239                         return ret;
240
241                 rets++;
242         }
243
244         return rets;
245 }
246
247 static int subscribe_unsubscribe_can_signals(afb_req_t request,
248                                              bool subscribe,
249                                              std::vector<std::shared_ptr<can_signal_t> > can_signals,
250                                              struct event_filter_t& event_filter,
251                                              std::map<int, std::shared_ptr<low_can_subscription_t> >& s)
252 {
253         int rets = 0;
254         for(const auto& sig: can_signals)
255         {
256                 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) ; });
257                 std::shared_ptr<low_can_subscription_t> can_subscription;
258                 if(it != s.end())
259                         {can_subscription = it->second;}
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 : contains original request use to subscribe or unsubscribe
282 /// @param[in] subscribe boolean value, which chooses 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(afb_req_t 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(afb_req_t 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(afb_req_t 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(afb_req_t 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(afb_req_t request)
393 {
394         afb_req_session_set_LOA(request, 1);
395         afb_req_success(request, NULL, NULL);
396 }
397
398 void subscribe(afb_req_t request)
399 {
400         do_subscribe_unsubscribe(request, true);
401 }
402
403 void unsubscribe(afb_req_t request)
404 {
405         do_subscribe_unsubscribe(request, false);
406 }
407
408 static int send_frame(struct canfd_frame& cfd, const std::string& bus_name)
409 {
410         if(bus_name.empty()) {
411                 return -1;
412         }
413
414         std::map<std::string, std::shared_ptr<low_can_socket_t> >& cd = application_t::instance().get_can_devices();
415
416         if( cd.count(bus_name) == 0)
417                 {cd[bus_name] = std::make_shared<low_can_socket_t>(low_can_socket_t());}
418
419         return cd[bus_name]->tx_send(cfd, bus_name);
420 }
421
422 static void write_raw_frame(afb_req_t request, const std::string& bus_name, json_object *json_value)
423 {
424         struct canfd_frame cfd;
425         struct json_object *can_data = nullptr;
426
427         ::memset(&cfd, 0, sizeof(cfd));
428
429         if(wrap_json_unpack(json_value, "{si, si, so !}",
430                               "can_id", &cfd.can_id,
431                               "can_dlc", &cfd.len,
432                               "can_data", &can_data))
433         {
434                 afb_req_fail(request, "Invalid", "Frame object malformed");
435                 return;
436         }
437
438         if(cfd.len <= 8 && cfd.len > 0)
439         {
440                 for (int i = 0 ; i < cfd.len ; i++)
441                 {
442                         struct json_object *one_can_data = json_object_array_get_idx(can_data, i);
443                         cfd.data[i] = (json_object_is_type(one_can_data, json_type_int)) ?
444                                         (uint8_t)json_object_get_int(one_can_data) : 0;
445                 }
446         }
447         else
448         {
449                 afb_req_fail(request, "Invalid", "Data array must hold 1 to 8 values.");
450                 return;
451         }
452
453         if(! send_frame(cfd, application_t::instance().get_can_bus_manager().get_can_device_name(bus_name)))
454                 afb_req_success(request, nullptr, "Message correctly sent");
455         else
456                 afb_req_fail(request, "Error", "sending the message. See the log for more details.");
457 }
458
459 static void write_signal(afb_req_t request, const std::string& name, json_object *json_value)
460 {
461         struct canfd_frame cfd;
462         struct utils::signals_found sf;
463         signal_encoder encoder = nullptr;
464         bool send = true;
465
466         ::memset(&cfd, 0, sizeof(cfd));
467
468         openxc_DynamicField search_key = build_DynamicField(name);
469         sf = utils::signals_manager_t::instance().find_signals(search_key);
470         openxc_DynamicField dynafield_value = build_DynamicField(json_value);
471
472         if (sf.can_signals.empty())
473         {
474                 afb_req_fail_f(request, "No signal(s) found for %s. Message not sent.", name.c_str());
475                 return;
476         }
477
478         std::shared_ptr<can_signal_t>& sig = sf.can_signals[0];
479         if(! sig->get_writable())
480         {
481                 afb_req_fail_f(request, "%s isn't writable. Message not sent.", sig->get_name().c_str());
482                 return;
483         }
484
485         uint64_t value = (encoder = sig->get_encoder()) ?
486                         encoder(*sig, dynafield_value, &send) :
487                         encoder_t::encode_DynamicField(*sig, dynafield_value, &send);
488
489         cfd = encoder_t::build_frame(sig, value);
490         if(! send_frame(cfd, sig->get_message()->get_bus_device_name()) && send)
491                 afb_req_success(request, nullptr, "Message correctly sent");
492         else
493                 afb_req_fail(request, "Error", "Sending the message. See the log for more details.");
494 }
495
496 void write(afb_req_t request)
497 {
498         struct json_object* args = nullptr, *json_value = nullptr;
499         const char *name = nullptr;
500
501         args = afb_req_json(request);
502
503         // Process about Raw CAN message on CAN bus directly
504         if (args != NULL && ! wrap_json_unpack(args, "{ss, so !}",
505                                                "bus_name", &name,
506                                                "frame", &json_value))
507                 write_raw_frame(request, name, json_value);
508
509         // Search signal then encode value.
510         else if(args != NULL &&
511                 ! wrap_json_unpack(args, "{ss, so !}",
512                                    "signal_name", &name,
513                                    "signal_value", &json_value))
514                 write_signal(request, std::string(name), json_value);
515         else
516                 afb_req_fail(request, "Error", "Request argument malformed");
517 }
518
519 static struct json_object *get_signals_value(const std::string& name)
520 {
521         struct utils::signals_found sf;
522         struct json_object *ans = nullptr;
523
524         openxc_DynamicField search_key = build_DynamicField(name);
525         sf = utils::signals_manager_t::instance().find_signals(search_key);
526
527         if (sf.can_signals.empty())
528         {
529                 AFB_WARNING("No signal(s) found for %s.", name.c_str());
530                 return NULL;
531         }
532         ans = json_object_new_array();
533         for(const auto& sig: sf.can_signals)
534         {
535                 struct json_object *jobj = json_object_new_object();
536                 json_object_object_add(jobj, "event", json_object_new_string(sig->get_name().c_str()));
537                 json_object_object_add(jobj, "value", json_object_new_double(sig->get_last_value()));
538                 json_object_array_add(ans, jobj);
539         }
540
541         return ans;
542 }
543 void get(afb_req_t request)
544 {
545         int rc = 0;
546         struct json_object* args = nullptr,
547                 *json_name = nullptr;
548         json_object *ans = nullptr;
549
550         args = afb_req_json(request);
551
552         // Process about Raw CAN message on CAN bus directly
553         if (args != nullptr &&
554                 (json_object_object_get_ex(args, "event", &json_name) && json_object_is_type(json_name, json_type_string) ))
555         {
556                 ans = get_signals_value(json_object_get_string(json_name));
557                 if (!ans)
558                         rc = -1;
559         }
560         else
561         {
562                 AFB_ERROR("Request argument malformed. Please use the following syntax:");
563                 rc = -1;
564         }
565
566         if (rc >= 0)
567                 afb_req_success(request, ans, NULL);
568         else
569                 afb_req_fail(request, "error", NULL);
570 }
571
572
573 static struct json_object *list_can_message(const std::string& name)
574 {
575         struct utils::signals_found sf;
576         struct json_object *ans = nullptr;
577
578         openxc_DynamicField search_key = build_DynamicField(name);
579         sf = utils::signals_manager_t::instance().find_signals(search_key);
580
581         if (sf.can_signals.empty() && sf.diagnostic_messages.empty())
582         {
583                 AFB_WARNING("No signal(s) found for %s.", name.c_str());
584                 return NULL;
585         }
586         ans = json_object_new_array();
587         for(const auto& sig: sf.can_signals)
588         {
589                 json_object_array_add(ans,
590                         json_object_new_string(sig->get_name().c_str()));
591         }
592         for(const auto& sig: sf.diagnostic_messages)
593         {
594                 json_object_array_add(ans,
595                         json_object_new_string(sig->get_name().c_str()));
596         }
597
598         return ans;
599 }
600
601 void list(afb_req_t request)
602 {
603         int rc = 0;
604         json_object *ans = nullptr;
605         struct json_object* args = nullptr,
606                 *json_name = nullptr;
607         args = afb_req_json(request);
608         const char *name;
609         if ((args != nullptr) &&
610                 (json_object_object_get_ex(args, "event", &json_name) && json_object_is_type(json_name, json_type_string)))
611         {
612                 name = json_object_get_string(json_name);
613         }
614         else
615         {
616                 name = "*";
617         }
618
619         ans = list_can_message(name);
620         if (!ans)
621                 rc = -1;
622
623         if (rc >= 0)
624                 afb_req_success(request, ans, NULL);
625         else
626                 afb_req_fail(request, "error", NULL);
627 }
628
629 /// @brief Initialize the binding.
630 ///
631 /// @param[in] service Structure which represent the Application Framework Binder.
632 ///
633 /// @return Exit code, zero if success.
634 int init_binding(afb_api_t api)
635 {
636         uint32_t ret = 1;
637         can_bus_t& can_bus_manager = application_t::instance().get_can_bus_manager();
638
639         can_bus_manager.set_can_devices();
640         can_bus_manager.start_threads();
641
642         /// Initialize Diagnostic manager that will handle obd2 requests.
643         /// We pass by default the first CAN bus device to its Initialization.
644         /// TODO: be able to choose the CAN bus device that will be use as Diagnostic bus.
645         if(application_t::instance().get_diagnostic_manager().initialize())
646                 ret = 0;
647
648         // Add a recurring dignostic message request to get engine speed at all times.
649         openxc_DynamicField search_key = build_DynamicField("diagnostic_messages.engine.speed");
650         struct utils::signals_found sf = utils::signals_manager_t::instance().find_signals(search_key);
651
652         if(sf.can_signals.empty() && sf.diagnostic_messages.size() == 1)
653         {
654                 afb_req_t request = nullptr;
655
656                 struct event_filter_t event_filter;
657                 event_filter.frequency = sf.diagnostic_messages.front()->get_frequency();
658
659                 utils::signals_manager_t& sm = utils::signals_manager_t::instance();
660                 std::map<int, std::shared_ptr<low_can_subscription_t> >& s = sm.get_subscribed_signals();
661
662                 subscribe_unsubscribe_diagnostic_messages(request, true, sf.diagnostic_messages, event_filter, s, true);
663         }
664
665         if(ret)
666                 AFB_ERROR("There was something wrong with CAN device Initialization.");
667
668         return ret;
669 }