CAN FD implementation
[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                 {
260                          can_subscription = it->second;
261                 }
262                 else
263                 {
264                          can_subscription = std::make_shared<low_can_subscription_t>(low_can_subscription_t(event_filter));
265                         if(can_subscription->create_rx_filter(sig) < 0)
266                                 {return -1;}
267                         if(add_to_event_loop(can_subscription) < 0)
268                                 {return -1;}
269                 }
270
271                 if(subscribe_unsubscribe_signal(request, subscribe, can_subscription, s) < 0)
272                         {return -1;}
273
274                 rets++;
275                 AFB_DEBUG("signal: %s subscribed", sig->get_name().c_str());
276         }
277         return rets;
278 }
279
280 ///
281 /// @brief subscribe to all signals in the vector signals
282 ///
283 /// @param[in] afb_req request : contains original request use to subscribe or unsubscribe
284 /// @param[in] subscribe boolean value, which chooses between a subscription operation or an unsubscription
285 /// @param[in] signals -  struct containing vectors with can_signal_t and diagnostic_messages to subscribe
286 ///
287 /// @return Number of correctly subscribed signal
288 ///
289 static int subscribe_unsubscribe_signals(afb_req_t request,
290                                          bool subscribe,
291                                          const struct utils::signals_found& signals,
292                                          struct event_filter_t& event_filter)
293 {
294         int rets = 0;
295         utils::signals_manager_t& sm = utils::signals_manager_t::instance();
296
297         std::lock_guard<std::mutex> subscribed_signals_lock(sm.get_subscribed_signals_mutex());
298         std::map<int, std::shared_ptr<low_can_subscription_t> >& s = sm.get_subscribed_signals();
299
300         rets += subscribe_unsubscribe_diagnostic_messages(request, subscribe, signals.diagnostic_messages, event_filter, s, false);
301         rets += subscribe_unsubscribe_can_signals(request, subscribe, signals.can_signals, event_filter, s);
302
303         return rets;
304 }
305
306 static int one_subscribe_unsubscribe(afb_req_t request,
307                                      bool subscribe,
308                                      const std::string& tag,
309                                      json_object* args)
310 {
311         int ret = 0;
312         struct event_filter_t event_filter;
313         struct json_object  *filter, *obj;
314         struct utils::signals_found sf;
315
316         // computes the filter
317         if (json_object_object_get_ex(args, "filter", &filter))
318         {
319                 if (json_object_object_get_ex(filter, "frequency", &obj)
320                 && (json_object_is_type(obj, json_type_double) || json_object_is_type(obj, json_type_int)))
321                         {event_filter.frequency = (float)json_object_get_double(obj);}
322                 if (json_object_object_get_ex(filter, "min", &obj)
323                 && (json_object_is_type(obj, json_type_double) || json_object_is_type(obj, json_type_int)))
324                         {event_filter.min = (float)json_object_get_double(obj);}
325                 if (json_object_object_get_ex(filter, "max", &obj)
326                 && (json_object_is_type(obj, json_type_double) || json_object_is_type(obj, json_type_int)))
327                         {event_filter.max = (float)json_object_get_double(obj);}
328         }
329
330         // subscribe or unsubscribe
331         openxc_DynamicField search_key = build_DynamicField(tag);
332         sf = utils::signals_manager_t::instance().find_signals(search_key);
333         if (sf.can_signals.empty() && sf.diagnostic_messages.empty())
334         {
335                 AFB_NOTICE("No signal(s) found for %s.", tag.c_str());
336                 ret = -1;
337         }
338         else
339                 {ret = subscribe_unsubscribe_signals(request, subscribe, sf, event_filter);}
340
341         return ret;
342 }
343 static int process_one_subscribe_args(afb_req_t request, bool subscribe, json_object *args)
344 {
345         int rc = 0, rc2=0;
346         json_object *x = nullptr, *event = nullptr;
347         if(args == NULL ||
348                 !json_object_object_get_ex(args, "event", &event))
349         {
350                 rc = one_subscribe_unsubscribe(request, subscribe, "*", args);
351         }
352         else if (json_object_get_type(event) != json_type_array)
353         {
354                 rc = one_subscribe_unsubscribe(request, subscribe, json_object_get_string(event), args);
355         }
356         else
357         {
358                 for (int i = 0 ; i < json_object_array_length(event); i++)
359                 {
360                         x = json_object_array_get_idx(event, i);
361                         rc2 = one_subscribe_unsubscribe(request, subscribe, json_object_get_string(x), args);
362                         if (rc >= 0)
363                                 rc = rc2 >= 0 ? rc + rc2 : rc2;
364                 }
365         }
366         return rc;
367 }
368
369 static void do_subscribe_unsubscribe(afb_req_t request, bool subscribe)
370 {
371         int rc = 0;
372         struct json_object *args, *x;
373
374         args = afb_req_json(request);
375         if (json_object_get_type(args) == json_type_array)
376         {
377                 for(int i = 0; i < json_object_array_length(args); i++)
378                 {
379                         x = json_object_array_get_idx(args, i);
380                         rc += process_one_subscribe_args(request, subscribe, x);
381                 }
382         }
383         else
384         {
385                 rc += process_one_subscribe_args(request, subscribe, args);
386         }
387
388         if (rc >= 0)
389                 afb_req_success(request, NULL, NULL);
390         else
391                 afb_req_fail(request, "error", NULL);
392 }
393
394 void auth(afb_req_t request)
395 {
396         afb_req_session_set_LOA(request, 1);
397         afb_req_success(request, NULL, NULL);
398 }
399
400 void subscribe(afb_req_t request)
401 {
402         do_subscribe_unsubscribe(request, true);
403 }
404
405 void unsubscribe(afb_req_t request)
406 {
407         do_subscribe_unsubscribe(request, false);
408 }
409
410 static int send_frame(struct canfd_frame& cfd, const std::string& bus_name)
411 {
412         if(bus_name.empty()) {
413                 return -1;
414         }
415
416         std::map<std::string, std::shared_ptr<low_can_socket_t> >& cd = application_t::instance().get_can_devices();
417
418         if( cd.count(bus_name) == 0)
419                 {cd[bus_name] = std::make_shared<low_can_socket_t>(low_can_socket_t());}
420
421         return cd[bus_name]->tx_send(cfd, bus_name);
422 }
423
424 static void write_raw_frame(afb_req_t request, const std::string& bus_name, json_object *json_value)
425 {
426         struct canfd_frame cfd;
427         struct json_object *can_data = nullptr;
428
429         ::memset(&cfd, 0, sizeof(cfd));
430
431         if(wrap_json_unpack(json_value, "{si, si, so !}",
432                               "can_id", &cfd.can_id,
433                               "can_dlc", &cfd.len,
434                               "can_data", &can_data))
435         {
436                 afb_req_fail(request, "Invalid", "Frame object malformed");
437                 return;
438         }
439
440         if(cfd.len <= 8 && cfd.len > 0)
441         {
442                 for (int i = 0 ; i < cfd.len ; i++)
443                 {
444                         struct json_object *one_can_data = json_object_array_get_idx(can_data, i);
445                         cfd.data[i] = (json_object_is_type(one_can_data, json_type_int)) ?
446                                         (uint8_t)json_object_get_int(one_can_data) : 0;
447                 }
448         }
449         else
450         {
451                 afb_req_fail(request, "Invalid", "Data array must hold 1 to 8 values.");
452                 return;
453         }
454
455         if(! send_frame(cfd, application_t::instance().get_can_bus_manager().get_can_device_name(bus_name)))
456                 afb_req_success(request, nullptr, "Message correctly sent");
457         else
458                 afb_req_fail(request, "Error", "sending the message. See the log for more details.");
459 }
460
461 static void write_signal(afb_req_t request, const std::string& name, json_object *json_value)
462 {
463         struct canfd_frame cfd;
464         struct utils::signals_found sf;
465         signal_encoder encoder = nullptr;
466         bool send = true;
467
468         ::memset(&cfd, 0, sizeof(cfd));
469
470         openxc_DynamicField search_key = build_DynamicField(name);
471         sf = utils::signals_manager_t::instance().find_signals(search_key);
472         openxc_DynamicField dynafield_value = build_DynamicField(json_value);
473
474         if (sf.can_signals.empty())
475         {
476                 afb_req_fail_f(request, "No signal(s) found for %s. Message not sent.", name.c_str());
477                 return;
478         }
479
480         std::shared_ptr<can_signal_t>& sig = sf.can_signals[0];
481         if(! sig->get_writable())
482         {
483                 afb_req_fail_f(request, "%s isn't writable. Message not sent.", sig->get_name().c_str());
484                 return;
485         }
486
487         uint64_t value = (encoder = sig->get_encoder()) ?
488                         encoder(*sig, dynafield_value, &send) :
489                         encoder_t::encode_DynamicField(*sig, dynafield_value, &send);
490
491         cfd = encoder_t::build_frame(sig, value);
492         if(! send_frame(cfd, sig->get_message()->get_bus_device_name()) && send)
493                 afb_req_success(request, nullptr, "Message correctly sent");
494         else
495                 afb_req_fail(request, "Error", "Sending the message. See the log for more details.");
496 }
497
498 void write(afb_req_t request)
499 {
500         struct json_object* args = nullptr, *json_value = nullptr;
501         const char *name = nullptr;
502
503         args = afb_req_json(request);
504
505         // Process about Raw CAN message on CAN bus directly
506         if (args != NULL && ! wrap_json_unpack(args, "{ss, so !}",
507                                                "bus_name", &name,
508                                                "frame", &json_value))
509                 write_raw_frame(request, name, json_value);
510
511         // Search signal then encode value.
512         else if(args != NULL &&
513                 ! wrap_json_unpack(args, "{ss, so !}",
514                                    "signal_name", &name,
515                                    "signal_value", &json_value))
516                 write_signal(request, std::string(name), json_value);
517         else
518                 afb_req_fail(request, "Error", "Request argument malformed");
519 }
520
521 static struct json_object *get_signals_value(const std::string& name)
522 {
523         struct utils::signals_found sf;
524         struct json_object *ans = nullptr;
525
526         openxc_DynamicField search_key = build_DynamicField(name);
527         sf = utils::signals_manager_t::instance().find_signals(search_key);
528
529         if (sf.can_signals.empty())
530         {
531                 AFB_WARNING("No signal(s) found for %s.", name.c_str());
532                 return NULL;
533         }
534         ans = json_object_new_array();
535         for(const auto& sig: sf.can_signals)
536         {
537                 struct json_object *jobj = json_object_new_object();
538                 json_object_object_add(jobj, "event", json_object_new_string(sig->get_name().c_str()));
539                 json_object_object_add(jobj, "value", json_object_new_double(sig->get_last_value()));
540                 json_object_array_add(ans, jobj);
541         }
542
543         return ans;
544 }
545 void get(afb_req_t request)
546 {
547         int rc = 0;
548         struct json_object* args = nullptr,
549                 *json_name = nullptr;
550         json_object *ans = nullptr;
551
552         args = afb_req_json(request);
553
554         // Process about Raw CAN message on CAN bus directly
555         if (args != nullptr &&
556                 (json_object_object_get_ex(args, "event", &json_name) && json_object_is_type(json_name, json_type_string) ))
557         {
558                 ans = get_signals_value(json_object_get_string(json_name));
559                 if (!ans)
560                         rc = -1;
561         }
562         else
563         {
564                 AFB_ERROR("Request argument malformed. Please use the following syntax:");
565                 rc = -1;
566         }
567
568         if (rc >= 0)
569                 afb_req_success(request, ans, NULL);
570         else
571                 afb_req_fail(request, "error", NULL);
572 }
573
574
575 static struct json_object *list_can_message(const std::string& name)
576 {
577         struct utils::signals_found sf;
578         struct json_object *ans = nullptr;
579
580         openxc_DynamicField search_key = build_DynamicField(name);
581         sf = utils::signals_manager_t::instance().find_signals(search_key);
582
583         if (sf.can_signals.empty() && sf.diagnostic_messages.empty())
584         {
585                 AFB_WARNING("No signal(s) found for %s.", name.c_str());
586                 return NULL;
587         }
588         ans = json_object_new_array();
589         for(const auto& sig: sf.can_signals)
590         {
591                 json_object_array_add(ans,
592                         json_object_new_string(sig->get_name().c_str()));
593         }
594         for(const auto& sig: sf.diagnostic_messages)
595         {
596                 json_object_array_add(ans,
597                         json_object_new_string(sig->get_name().c_str()));
598         }
599
600         return ans;
601 }
602
603 void list(afb_req_t request)
604 {
605         int rc = 0;
606         json_object *ans = nullptr;
607         struct json_object* args = nullptr,
608                 *json_name = nullptr;
609         args = afb_req_json(request);
610         const char *name;
611         if ((args != nullptr) &&
612                 (json_object_object_get_ex(args, "event", &json_name) && json_object_is_type(json_name, json_type_string)))
613         {
614                 name = json_object_get_string(json_name);
615         }
616         else
617         {
618                 name = "*";
619         }
620
621         ans = list_can_message(name);
622         if (!ans)
623                 rc = -1;
624
625         if (rc >= 0)
626                 afb_req_success(request, ans, NULL);
627         else
628                 afb_req_fail(request, "error", NULL);
629 }
630
631 /// @brief Initialize the binding.
632 ///
633 /// @param[in] service Structure which represent the Application Framework Binder.
634 ///
635 /// @return Exit code, zero if success.
636 int init_binding(afb_api_t api)
637 {
638         uint32_t ret = 1;
639         can_bus_t& can_bus_manager = application_t::instance().get_can_bus_manager();
640
641         can_bus_manager.set_can_devices();
642         can_bus_manager.start_threads();
643
644         /// Initialize Diagnostic manager that will handle obd2 requests.
645         /// We pass by default the first CAN bus device to its Initialization.
646         /// TODO: be able to choose the CAN bus device that will be use as Diagnostic bus.
647         if(application_t::instance().get_diagnostic_manager().initialize())
648                 ret = 0;
649
650         // Add a recurring dignostic message request to get engine speed at all times.
651         openxc_DynamicField search_key = build_DynamicField("diagnostic_messages.engine.speed");
652         struct utils::signals_found sf = utils::signals_manager_t::instance().find_signals(search_key);
653
654         if(sf.can_signals.empty() && sf.diagnostic_messages.size() == 1)
655         {
656                 afb_req_t request = nullptr;
657
658                 struct event_filter_t event_filter;
659                 event_filter.frequency = sf.diagnostic_messages.front()->get_frequency();
660
661                 utils::signals_manager_t& sm = utils::signals_manager_t::instance();
662                 std::map<int, std::shared_ptr<low_can_subscription_t> >& s = sm.get_subscribed_signals();
663
664                 subscribe_unsubscribe_diagnostic_messages(request, true, sf.diagnostic_messages, event_filter, s, true);
665         }
666
667         if(ret)
668                 AFB_ERROR("There was something wrong with CAN device Initialization.");
669
670         return ret;
671 }