7b9b60ec57d1dfc1213a87351e18f25e2340817b
[apps/agl-service-can-low-level.git] / low-can-binding / binding / low-can-cb.cpp
1 /*
2  * Copyright (C) 2015, 2018 "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 #include <ctl-config.h>
30 #include "openxc.pb.h"
31 #include "application.hpp"
32 #include "../can/can-encoder.hpp"
33 #include "../can/can-bus.hpp"
34 #include "../can/signals.hpp"
35 #include "../can/message/message.hpp"
36 #include "../utils/signals.hpp"
37 #include "../diagnostic/diagnostic-message.hpp"
38 #include "../utils/openxc-utils.hpp"
39 #include "../utils/signals.hpp"
40
41 #ifdef USE_FEATURE_J1939
42         #include "../can/message/j1939-message.hpp"
43         #include <linux/can/j1939.h>
44 #endif
45
46 ///*****************************************************************************
47 ///
48 ///             Controller Definitions and Callbacks
49 ///
50 ///****************************************************************************/
51
52 int config_low_can(afb_api_t apiHandle, CtlSectionT *section, json_object *json_obj)
53 {
54         AFB_DEBUG("Config %s", json_object_to_json_string(json_obj));
55         CtlConfigT *ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle);
56         int active_message_set = 0;
57         json_object *dev_mapping = nullptr;
58         const char *diagnotic_bus = nullptr;
59
60         if(! ctrlConfig || ! ctrlConfig->external)
61                 return -1;
62
63         application_t *application = (application_t*) ctrlConfig->external;
64
65         if(wrap_json_unpack(json_obj, "{si, ss}",
66                               "active_message_set", &active_message_set,
67                               "diagnostic_bus", &diagnotic_bus))
68                 return -1;
69
70         application->set_active_message_set((uint8_t)active_message_set);
71
72         if(wrap_json_unpack(json_obj, "{so}",
73                             "dev-mapping", &dev_mapping))
74                 return -1;
75
76         application->get_can_bus_manager().set_can_devices(dev_mapping);
77
78         /// Initialize Diagnostic manager that will handle obd2 requests.
79         /// We pass by default the first CAN bus device to its Initialization.
80         if(! application_t::instance().get_diagnostic_manager().initialize(diagnotic_bus))
81         {
82                 AFB_ERROR("Diagnostic Manager: error at initialization");
83                 return -1;
84         }
85
86         return 0;
87 }
88
89 CtlSectionT ctlSections_[] = {
90         [0]={.key="config" , .uid="config", .info=nullptr, .prefix=nullptr,
91                  .loadCB=config_low_can,
92                  .handle=nullptr,
93                  .actions=nullptr},
94         [1]={.key="plugins" , .uid="plugins", .info=nullptr, .prefix=nullptr,
95                 .loadCB=PluginConfig,
96                 .handle=nullptr,
97                 .actions=nullptr},
98         [2]={.key=nullptr , .uid=nullptr, .info=nullptr, .prefix=nullptr,
99                 .loadCB=PluginConfig,
100                 .handle=nullptr,
101                 .actions=nullptr},
102 };
103
104 ///*****************************************************************************
105 ///
106 ///             Subscription and unsubscription
107 ///
108 ///****************************************************************************/
109
110 /// @brief This will determine if an event handle needs to be created and checks if
111 /// we got a valid afb_event to get subscribe or unsubscribe. After that launch the subscription or unsubscription
112 /// against the application framework using that event handle.
113 static int subscribe_unsubscribe_signal(afb_req_t request,
114                                         bool subscribe,
115                                         std::shared_ptr<low_can_subscription_t>& can_subscription,
116                                         map_subscription& s)
117 {
118         int ret = 0;
119         int sub_index = can_subscription->get_index();
120         bool subscription_exists = s.count(sub_index);
121
122         // Susbcription part
123         if(subscribe)
124         {
125                 /* There is no valid request to subscribe so this must be an
126                  * internal permanent diagnostic request. Skip the subscription
127                  * part and don't register it into the current "low-can"
128                  * subsciptions.
129                  */
130                 if(! request)
131                 {
132                         return 0;
133                 }
134
135                 // Event doesn't exist , so let's create it
136                 if ((ret = can_subscription->subscribe(request)) < 0)
137                         return ret;
138
139                 if(! subscription_exists)
140                                 s[sub_index] = can_subscription;
141
142                 return ret;
143         }
144
145         // Unsubscrition part
146         if(! subscription_exists)
147         {
148                 AFB_NOTICE("There isn't any valid subscriptions for that request.");
149                 return ret;
150         }
151         else if (subscription_exists &&
152                  ! afb_event_is_valid(s[sub_index]->get_event()) )
153         {
154                 AFB_NOTICE("Event isn't valid, no need to unsubscribed.");
155                 return ret;
156         }
157
158         if( (ret = s[sub_index]->unsubscribe(request)) < 0)
159                 return ret;
160         s.find(sub_index)->second->set_index(-1);
161         s.erase(sub_index);
162         return ret;
163 }
164
165 static int add_to_event_loop(std::shared_ptr<low_can_subscription_t>& can_subscription)
166 {
167                 struct sd_event_source* event_source = nullptr;
168                 return ( sd_event_add_io(afb_daemon_get_event_loop(),
169                         &event_source,
170                         can_subscription->get_socket()->socket(),
171                         EPOLLIN,
172                         read_message,
173                         can_subscription.get()));
174 }
175
176 static int subscribe_unsubscribe_diagnostic_messages(afb_req_t request,
177                                                      bool subscribe,
178                                                      list_ptr_diag_msg_t diagnostic_messages,
179                                                      struct event_filter_t& event_filter,
180                                                      map_subscription& s,
181                                                      bool perm_rec_diag_req)
182 {
183         int rets = 0;
184         application_t& app = application_t::instance();
185         diagnostic_manager_t& diag_m = app.get_diagnostic_manager();
186
187         for(const auto& sig : diagnostic_messages)
188         {
189                 DiagnosticRequest* diag_req = new DiagnosticRequest(sig->build_diagnostic_request());
190                 event_filter.frequency = event_filter.frequency == 0 ? sig->get_frequency() : event_filter.frequency;
191                 std::shared_ptr<low_can_subscription_t> can_subscription;
192
193                 auto it = std::find_if(s.begin(), s.end(), [&sig](std::pair<int, std::shared_ptr<low_can_subscription_t> > sub)
194                 {
195                         return (! sub.second->get_diagnostic_message().empty());
196                 });
197                 can_subscription = it != s.end() ?
198                         it->second :
199                         std::make_shared<low_can_subscription_t>(low_can_subscription_t(event_filter));
200                 // If the requested diagnostic message is not supported by the car then unsubcribe it
201                 // no matter what we want, worst case will be a failed unsubscription but at least we won't
202                 // poll a PID for nothing.
203                 if(sig->get_supported() && subscribe)
204                 {
205                         if (!app.is_engine_on())
206                                 AFB_WARNING("signal: Engine is off, %s won't received responses until it's on",  sig->get_name().c_str());
207
208                         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);
209                         if(can_subscription->create_rx_filter(sig) < 0)
210                                 return -1;
211                         AFB_DEBUG("Signal: %s subscribed", sig->get_name().c_str());
212                         if(it == s.end() && add_to_event_loop(can_subscription) < 0)
213                         {
214                                 diag_m.cleanup_request(
215                                         diag_m.find_recurring_request(*diag_req), true);
216                                 AFB_WARNING("signal: %s isn't supported. Canceling operation.",  sig->get_name().c_str());
217                                 return -1;
218                         }
219                 }
220                 else
221                 {
222                         if(sig->get_supported())
223                         {
224                                 AFB_DEBUG("%s cancelled due to unsubscribe", sig->get_name().c_str());
225                         }
226                         else
227                         {
228                                 AFB_WARNING("signal: %s isn't supported. Canceling operation.", sig->get_name().c_str());
229                                 return -1;
230                         }
231                 }
232                 int ret = subscribe_unsubscribe_signal(request, subscribe, can_subscription, s);
233                 if(ret < 0)
234                         return ret;
235
236                 rets++;
237         }
238         return rets;
239 }
240
241 static int subscribe_unsubscribe_signals(afb_req_t request,
242                                          bool subscribe,
243                                          list_ptr_signal_t signals,
244                                          struct event_filter_t& event_filter,
245                                          map_subscription& s)
246 {
247         int rets = 0;
248         for(const auto& sig: signals)
249         {
250                 auto it =  std::find_if(s.begin(), s.end(), [&sig, &event_filter](std::pair<int, std::shared_ptr<low_can_subscription_t> > sub)
251                 {
252                         return sub.second->is_signal_subscription_corresponding(sig, event_filter) ;
253                 });
254                 std::shared_ptr<low_can_subscription_t> can_subscription;
255                 if(it != s.end())
256                         can_subscription = it->second;
257                 else
258                 {
259                         can_subscription = std::make_shared<low_can_subscription_t>(low_can_subscription_t(event_filter));
260                         if(can_subscription->create_rx_filter(sig) < 0)
261                                 return -1;
262                         if(add_to_event_loop(can_subscription) < 0)
263                                 return -1;
264                 }
265
266                 if(subscribe_unsubscribe_signal(request, subscribe, can_subscription, s) < 0)
267                         return -1;
268
269                 rets++;
270                 AFB_DEBUG("%s Signal: %s %ssubscribed", sig->get_message()->is_fd() ? "FD": "", sig->get_name().c_str(), subscribe ? "":"un");
271         }
272         return rets;
273 }
274
275 ///
276 /// @brief subscribe to all signals in the vector signals
277 ///
278 /// @param[in] afb_req request : contains original request use to subscribe or unsubscribe
279 /// @param[in] subscribe boolean value, which chooses between a subscription operation or an unsubscription
280 /// @param[in] signals -  struct containing vectors with signal_t and diagnostic_messages to subscribe
281 /// @param[in] event_filter - stuct containing filter on the signal
282 ///
283 /// @return Number of correctly subscribed signal
284 ///
285 static int subscribe_unsubscribe_signals(afb_req_t request,
286                                          bool subscribe,
287                                          const struct utils::signals_found& signals,
288                                          struct event_filter_t& event_filter)
289 {
290         int rets = 0;
291         utils::signals_manager_t& sm = utils::signals_manager_t::instance();
292
293         std::lock_guard<std::mutex> subscribed_signals_lock(sm.get_subscribed_signals_mutex());
294         map_subscription& s = sm.get_subscribed_signals();
295
296         rets += subscribe_unsubscribe_diagnostic_messages(request, subscribe, signals.diagnostic_messages, event_filter, s, false);
297         rets += subscribe_unsubscribe_signals(request, subscribe, signals.signals, event_filter, s);
298
299         return rets;
300 }
301
302 static event_filter_t generate_filter(json_object* args)
303 {
304         event_filter_t event_filter;
305         struct json_object  *filter, *obj;
306
307                 // computes the filter
308         if (json_object_object_get_ex(args, "filter", &filter))
309         {
310                 if (json_object_object_get_ex(filter, "frequency", &obj)
311                 && (json_object_is_type(obj, json_type_double) || json_object_is_type(obj, json_type_int)))
312                         event_filter.frequency = (float)json_object_get_double(obj);
313                 if (json_object_object_get_ex(filter, "min", &obj)
314                 && (json_object_is_type(obj, json_type_double) || json_object_is_type(obj, json_type_int)))
315                         event_filter.min = (float)json_object_get_double(obj);
316                 if (json_object_object_get_ex(filter, "max", &obj)
317                 && (json_object_is_type(obj, json_type_double) || json_object_is_type(obj, json_type_int)))
318                         event_filter.max = (float)json_object_get_double(obj);
319                 if (json_object_object_get_ex(filter, "rx_id", &obj)
320                 && (json_object_is_type(obj, json_type_int)))
321                         event_filter.rx_id = (canid_t) json_object_get_int(obj);
322                 if (json_object_object_get_ex(filter, "tx_id", &obj)
323                 && (json_object_is_type(obj, json_type_int)))
324                         event_filter.tx_id = (canid_t) json_object_get_int(obj);
325         }
326         return event_filter;
327 }
328
329
330 static int one_subscribe_unsubscribe_events(afb_req_t request, bool subscribe, const std::string& tag, json_object* args)
331 {
332         int ret = 0;
333         struct utils::signals_found sf;
334
335         // subscribe or unsubscribe
336         openxc_DynamicField search_key = build_DynamicField(tag);
337         sf = utils::signals_manager_t::instance().find_signals(search_key);
338
339
340 #ifdef USE_FEATURE_ISOTP
341         if(sf.signals.size() > 1)
342         {
343                 sf.signals.remove_if([](std::shared_ptr<signal_t> x){
344                         bool isotp = x->get_message()->is_isotp();
345                         if(isotp)
346                                 AFB_NOTICE("ISO TP messages need to be subscribed one by one (rx, tx)");
347
348                         return isotp;
349                 });
350         }
351 #endif
352
353         if (sf.signals.empty() && sf.diagnostic_messages.empty())
354         {
355                 AFB_NOTICE("No signal(s) found for %s.", tag.c_str());
356                 ret = -1;
357         }
358         else
359         {
360                 event_filter_t event_filter = generate_filter(args);
361                 ret = subscribe_unsubscribe_signals(request, subscribe, sf, event_filter);
362         }
363         return ret;
364 }
365
366 static int one_subscribe_unsubscribe_id(afb_req_t request, bool subscribe, const uint32_t& id, json_object *args)
367 {
368         int ret = 0;
369         std::shared_ptr<message_definition_t> message_definition = application_t::instance().get_message_definition(id);
370         struct utils::signals_found sf;
371
372         if(message_definition)
373                 sf.signals = list_ptr_signal_t(message_definition->get_signals().begin(), message_definition->get_signals().end());
374
375         if(sf.signals.empty())
376         {
377                 AFB_NOTICE("No signal(s) found for %d.", id);
378                 ret = -1;
379         }
380         else
381         {
382                 event_filter_t event_filter = generate_filter(args);
383                 ret = subscribe_unsubscribe_signals(request, subscribe, sf, event_filter);
384         }
385
386         return ret;
387 }
388
389
390 static int process_one_subscribe_args(afb_req_t request, bool subscribe, json_object *args)
391 {
392         int rc = 0, rc2=0;
393         json_object *x = nullptr, *event = nullptr, *id = nullptr;
394
395
396         // 2 cases : ID(PGN) and event
397
398         json_object_object_get_ex(args,"event",&event);
399         json_bool test_id = json_object_object_get_ex(args,"id",&id);
400         if(!test_id)
401                 test_id = json_object_object_get_ex(args,"pgn",&id);
402
403         if(     args == NULL || (id && ((std::string)json_object_get_string(id)).compare("*") == 0))
404         {
405                 rc = one_subscribe_unsubscribe_events(request, subscribe, "*", args);
406         }
407         else
408         {
409                 if(event)
410                 {
411                         if (json_object_get_type(event) != json_type_array) // event is set before and check if it's an array
412                         {
413                                 rc = one_subscribe_unsubscribe_events(request, subscribe, json_object_get_string(event), args);
414                         }
415                         else // event is set and it's not an array
416                         {
417                                 for (int i = 0 ; i < json_object_array_length(event); i++)
418                                 {
419                                         x = json_object_array_get_idx(event, i);
420                                         rc2 = one_subscribe_unsubscribe_events(request, subscribe, json_object_get_string(x), args);
421                                         if (rc >= 0)
422                                                 rc = rc2 >= 0 ? rc + rc2 : rc2;
423                                 }
424                         }
425                 }
426
427                 if(id)
428                 {
429                         if (json_object_get_type(id) != json_type_array) // id is set before and check if it's an array
430                         {
431                                 rc = one_subscribe_unsubscribe_id(request, subscribe, json_object_get_int(id), args);
432                         }
433                         else // event is set and it's not an array
434                         {
435                                 for (int i = 0 ; i < json_object_array_length(id); i++)
436                                 {
437                                         x = json_object_array_get_idx(id, i);
438                                         rc2 = one_subscribe_unsubscribe_id(request, subscribe, json_object_get_int(x), args);
439                                         if (rc >= 0)
440                                                 rc = rc2 >= 0 ? rc + rc2 : rc2;
441                                 }
442                         }
443                 }
444         }
445         return rc;
446 }
447
448 static void do_subscribe_unsubscribe(afb_req_t request, bool subscribe)
449 {
450         int rc = 0;
451         struct json_object *args, *x;
452
453         args = afb_req_json(request);
454         if (json_object_get_type(args) == json_type_array)
455         {
456                 for(int i = 0; i < json_object_array_length(args); i++)
457                 {
458                         x = json_object_array_get_idx(args, i);
459                         rc += process_one_subscribe_args(request, subscribe, x);
460                 }
461         }
462         else
463         {
464                 rc += process_one_subscribe_args(request, subscribe, args);
465         }
466
467         if (rc >= 0)
468                 afb_req_success(request, NULL, NULL);
469         else
470                 afb_req_fail(request, "error", NULL);
471 }
472
473 void auth(afb_req_t request)
474 {
475         afb_req_session_set_LOA(request, 1);
476         afb_req_success(request, NULL, NULL);
477 }
478
479 void subscribe(afb_req_t request)
480 {
481         do_subscribe_unsubscribe(request, true);
482 }
483
484 void unsubscribe(afb_req_t request)
485 {
486         do_subscribe_unsubscribe(request, false);
487 }
488
489 /*
490 static int send_frame(struct canfd_frame& cfd, const std::string& bus_name, socket_type type)
491 {
492         if(bus_name.empty())
493         {
494                 return -1;
495         }
496
497         std::map<std::string, std::shared_ptr<low_can_subscription_t> >& cd = application_t::instance().get_can_devices();
498
499         if( cd.count(bus_name) == 0)
500         {
501                 cd[bus_name] = std::make_shared<low_can_subscription_t>(low_can_subscription_t());
502         }
503
504
505         if(type == socket_type::BCM)
506         {
507                 return low_can_subscription_t::tx_send(*cd[bus_name], cfd, bus_name);
508         }
509         else if(type == socket_type::J1939)
510         {
511                 return low_can_subscription_t::j1939_send(*cd[bus_name], cfd, bus_name);
512         }
513         else{
514                 return -1;
515         }
516 }
517 */
518 static int send_message(message_t *message, const std::string& bus_name, uint32_t flags, event_filter_t &event_filter, std::shared_ptr<signal_t> signal)
519 {
520         if(bus_name.empty())
521                 return -1;
522
523         std::map<std::string, std::shared_ptr<low_can_subscription_t> >& cd = application_t::instance().get_can_devices();
524
525         if( cd.count(bus_name) == 0)
526                 cd[bus_name] = std::make_shared<low_can_subscription_t>(low_can_subscription_t(event_filter));
527
528         cd[bus_name]->set_signal(signal);
529
530
531         if(flags&CAN_PROTOCOL)
532                 return low_can_subscription_t::tx_send(*cd[bus_name], message, bus_name);
533 #ifdef USE_FEATURE_ISOTP
534         else if(flags&ISOTP_PROTOCOL)
535                 return low_can_subscription_t::isotp_send(*cd[bus_name], message, bus_name);
536 #endif
537 #ifdef USE_FEATURE_J1939
538         else if(flags&J1939_PROTOCOL)
539                 return low_can_subscription_t::j1939_send(*cd[bus_name], message, bus_name);
540 #endif
541         else
542                 return -1;
543 }
544
545
546 static void write_raw_frame(afb_req_t request, const std::string& bus_name, message_t *message,
547                             struct json_object *can_data, uint32_t flags, event_filter_t &event_filter)
548 {
549
550         struct utils::signals_found sf;
551
552         utils::signals_manager_t::instance().lookup_signals_by_id(message->get_id(), application_t::instance().get_all_signals(), sf.signals);
553
554         if( !sf.signals.empty() )
555         {
556                 AFB_DEBUG("ID WRITE RAW : %d", sf.signals.front()->get_message()->get_id());
557                 if(flags & CAN_PROTOCOL)
558                 {
559                         if(sf.signals.front()->get_message()->is_fd())
560                         {
561                                 AFB_DEBUG("CANFD_MAX_DLEN");
562                                 message->set_flags(CAN_PROTOCOL_WITH_FD_FRAME);
563                                 message->set_maxdlen(CANFD_MAX_DLEN);
564                         }
565                         else
566                         {
567                                 AFB_DEBUG("CAN_MAX_DLEN");
568                                 message->set_maxdlen(CAN_MAX_DLEN);
569                         }
570
571                         if(sf.signals.front()->get_message()->is_isotp())
572                         {
573                                 flags = ISOTP_PROTOCOL;
574                                 message->set_maxdlen(MAX_ISOTP_FRAMES * message->get_maxdlen());
575                         }
576                 }
577
578 #ifdef USE_FEATURE_J1939
579                 if(flags&J1939_PROTOCOL)
580                         message->set_maxdlen(J1939_MAX_DLEN);
581 #endif
582
583                 if(message->get_length() > 0 && message->get_length() <= message->get_maxdlen())
584                 {
585                         std::vector<uint8_t> data;
586                         for (int i = 0 ; i < message->get_length() ; i++)
587                         {
588                                 struct json_object *one_can_data = json_object_array_get_idx(can_data, i);
589                                 data.push_back((json_object_is_type(one_can_data, json_type_int)) ?
590                                                 (uint8_t)json_object_get_int(one_can_data) : 0);
591                         }
592                         message->set_data(data);
593                 }
594                 else
595                 {
596                         if(flags&CAN_PROTOCOL)
597                                 afb_req_fail(request, "Invalid", "Frame BCM");
598                         else if(flags&J1939_PROTOCOL)
599                                 afb_req_fail(request, "Invalid", "Frame J1939");
600                         else if(flags&ISOTP_PROTOCOL)
601                                 afb_req_fail(request, "Invalid", "Frame ISOTP");
602                         else
603                                 afb_req_fail(request, "Invalid", "Frame");
604
605                         return;
606                 }
607
608                 if(! send_message(message, application_t::instance().get_can_bus_manager().get_can_device_name(bus_name), flags, event_filter, sf.signals.front()))
609                         afb_req_success(request, nullptr, "Message correctly sent");
610                 else
611                         afb_req_fail(request, "Error", "sending the message. See the log for more details.");
612         }
613         else
614         {
615                 afb_req_fail(request, "Error", "no find id in signals. See the log for more details.");
616         }
617
618 }
619
620 static void write_frame(afb_req_t request, const std::string& bus_name, json_object *json_value, event_filter_t &event_filter)
621 {
622         message_t *message;
623         uint32_t id;
624         uint32_t length;
625         struct json_object *can_data = nullptr;
626         std::vector<uint8_t> data;
627
628         AFB_DEBUG("JSON content %s", json_object_get_string(json_value));
629
630         if(!wrap_json_unpack(json_value, "{si, si, so !}",
631                                   "can_id", &id,
632                                   "can_dlc", &length,
633                                   "can_data", &can_data))
634         {
635                 message = new can_message_t(0, id, length, false, 0, data, 0);
636                 write_raw_frame(request, bus_name, message, can_data, CAN_PROTOCOL, event_filter);
637         }
638 #ifdef USE_FEATURE_J1939
639         else if(!wrap_json_unpack(json_value, "{si, si, so !}",
640                                   "pgn", &id,
641                                   "length", &length,
642                                   "data", &can_data))
643         {
644                 message = new j1939_message_t(length, data, 0, J1939_NO_NAME, (pgn_t)id, J1939_NO_ADDR);
645                 write_raw_frame(request, bus_name, message, can_data, J1939_PROTOCOL, event_filter);
646         }
647 #endif
648         else
649         {
650                 afb_req_fail(request, "Invalid", "Frame object malformed");
651                 return;
652         }
653         delete message;
654 }
655
656 static void write_signal(afb_req_t request, const std::string& name, json_object *json_value, event_filter_t &event_filter)
657 {
658         struct canfd_frame cfd;
659         struct utils::signals_found sf;
660         signal_encoder encoder = nullptr;
661         bool send = true;
662
663         ::memset(&cfd, 0, sizeof(cfd));
664
665         openxc_DynamicField search_key = build_DynamicField(name);
666         sf = utils::signals_manager_t::instance().find_signals(search_key);
667         openxc_DynamicField dynafield_value = build_DynamicField(json_value);
668
669         if (sf.signals.empty())
670         {
671                 afb_req_fail_f(request, "No signal(s) found for %s. Message not sent.", name.c_str());
672                 return;
673         }
674
675         std::shared_ptr<signal_t> sig = sf.signals.front();
676         if(! sig->get_writable())
677         {
678                 afb_req_fail_f(request, "%s isn't writable. Message not sent.", sig->get_name().c_str());
679                 return;
680         }
681
682         uint64_t value = (encoder = sig->get_encoder()) ?
683                         encoder(*sig, dynafield_value, &send) :
684                         encoder_t::encode_DynamicField(*sig, dynafield_value, &send);
685
686         uint32_t flags = INVALID_FLAG;
687
688         if(sig->get_message()->is_j1939())
689                 flags = J1939_PROTOCOL;
690         else if(sig->get_message()->is_isotp())
691                 flags = ISOTP_PROTOCOL;
692         else
693                 flags = CAN_PROTOCOL;
694
695 //      cfd = encoder_t::build_frame(sig, value);
696         message_t *message = encoder_t::build_message(sig, value, false, false);
697
698         if(! send_message(message, sig->get_message()->get_bus_device_name(), flags, event_filter, sig) && send)
699                 afb_req_success(request, nullptr, "Message correctly sent");
700         else
701                 afb_req_fail(request, "Error", "Sending the message. See the log for more details.");
702
703         if(sig->get_message()->is_j1939())
704 #ifdef USE_FEATURE_J1939
705                 delete (j1939_message_t*) message;
706 #else
707                 afb_req_fail(request, "Warning", "J1939 not implemented in your kernel.");
708 #endif
709         else
710                 delete (can_message_t*) message;
711 }
712
713 void write(afb_req_t request)
714 {
715         struct json_object* args = nullptr, *json_value = nullptr, *name = nullptr;
716         args = afb_req_json(request);
717
718         if(args != NULL)
719         {
720                 event_filter_t event_filter = generate_filter(args);
721
722                 if(json_object_object_get_ex(args,"bus_name",&name))
723                 {
724                         if(json_object_object_get_ex(args,"frame",&json_value))
725                                 write_frame(request, (std::string)json_object_get_string(name), json_value, event_filter);
726                         else
727                                 afb_req_fail(request, "Error", "Request argument malformed");
728                 }
729                 else if(json_object_object_get_ex(args,"signal_name",&name))
730                 {
731                         if(json_object_object_get_ex(args,"signal_value",&json_value))
732                                 write_signal(request, (std::string)json_object_get_string(name), json_value, event_filter);
733                         else
734                                 afb_req_fail(request, "Error", "Request argument malformed");
735                 }
736                 else
737                 {
738                         afb_req_fail(request, "Error", "Request argument malformed");
739                 }
740         }
741         else
742         {
743                 afb_req_fail(request, "Error", "Request argument null");
744         }
745 }
746
747 static struct json_object *get_signals_value(const std::string& name)
748 {
749         struct utils::signals_found sf;
750         struct json_object *ans = nullptr;
751
752         openxc_DynamicField search_key = build_DynamicField(name);
753         sf = utils::signals_manager_t::instance().find_signals(search_key);
754
755         if (sf.signals.empty())
756         {
757                 AFB_WARNING("No signal(s) found for %s.", name.c_str());
758                 return NULL;
759         }
760         ans = json_object_new_array();
761         for(const auto& sig: sf.signals)
762         {
763                 struct json_object *jobj = json_object_new_object();
764                 json_object_object_add(jobj, "event", json_object_new_string(sig->get_name().c_str()));
765                 json_object_object_add(jobj, "value", json_object_new_double(sig->get_last_value()));
766                 json_object_array_add(ans, jobj);
767         }
768
769         return ans;
770 }
771 void get(afb_req_t request)
772 {
773         int rc = 0;
774         struct json_object* args = nullptr,
775                 *json_name = nullptr;
776         json_object *ans = nullptr;
777
778         args = afb_req_json(request);
779
780         // Process about Raw CAN message on CAN bus directly
781         if (args != nullptr &&
782                 (json_object_object_get_ex(args, "event", &json_name) && json_object_is_type(json_name, json_type_string) ))
783         {
784                 ans = get_signals_value(json_object_get_string(json_name));
785                 if (!ans)
786                         rc = -1;
787         }
788         else
789         {
790                 AFB_ERROR("Request argument malformed. Please use the following syntax:");
791                 rc = -1;
792         }
793
794         if (rc >= 0)
795                 afb_req_success(request, ans, NULL);
796         else
797                 afb_req_fail(request, "error", NULL);
798 }
799
800
801 static struct json_object *list_can_message(const std::string& name)
802 {
803         struct utils::signals_found sf;
804         struct json_object *ans = nullptr;
805
806         openxc_DynamicField search_key = build_DynamicField(name);
807         sf = utils::signals_manager_t::instance().find_signals(search_key);
808
809         if (sf.signals.empty() && sf.diagnostic_messages.empty())
810         {
811                 AFB_WARNING("No signal(s) found for %s.", name.c_str());
812                 return NULL;
813         }
814         ans = json_object_new_array();
815         for(const auto& sig: sf.signals)
816         {
817                 json_object_array_add(ans,
818                         json_object_new_string(sig->get_name().c_str()));
819         }
820         for(const auto& sig: sf.diagnostic_messages)
821         {
822                 json_object_array_add(ans,
823                         json_object_new_string(sig->get_name().c_str()));
824         }
825
826         return ans;
827 }
828
829 void list(afb_req_t request)
830 {
831         int rc = 0;
832         json_object *ans = nullptr;
833         struct json_object* args = nullptr,
834                 *json_name = nullptr;
835         args = afb_req_json(request);
836         const char *name;
837         if ((args != nullptr) &&
838                 (json_object_object_get_ex(args, "event", &json_name) && json_object_is_type(json_name, json_type_string)))
839                 name = json_object_get_string(json_name);
840         else
841                 name = "*";
842
843         ans = list_can_message(name);
844         if (!ans)
845                 rc = -1;
846
847         if (rc >= 0)
848                 afb_req_success(request, ans, NULL);
849         else
850                 afb_req_fail(request, "error", NULL);
851 }
852
853 /// @brief Initialize the binding.
854 ///
855 /// @param[in] service Structure which represent the Application Framework Binder.
856 ///
857 /// @return Exit code, zero if success.
858 int init_binding(afb_api_t api)
859 {
860         int ret = 1;
861         application_t& application = application_t::instance();
862         can_bus_t& can_bus_manager = application.get_can_bus_manager();
863
864         if(application.get_message_set().empty())
865         {
866                 AFB_ERROR("No message_set defined");
867                 return -1;
868         }
869
870         can_bus_manager.start_threads();
871         utils::signals_manager_t& sm = utils::signals_manager_t::instance();
872
873         // Add a recurring dignostic message request to get engine speed at all times.
874         openxc_DynamicField search_key = build_DynamicField("diagnostic_messages.engine.speed");
875         struct utils::signals_found sf = sm.find_signals(search_key);
876
877         if(sf.signals.empty() && sf.diagnostic_messages.size() == 1)
878         {
879                 afb_req_t request = nullptr;
880
881                 struct event_filter_t event_filter;
882                 event_filter.frequency = sf.diagnostic_messages.front()->get_frequency();
883
884                 map_subscription& s = sm.get_subscribed_signals();
885
886                 subscribe_unsubscribe_diagnostic_messages(request, true, sf.diagnostic_messages, event_filter, s, true);
887         }
888
889
890 #ifdef USE_FEATURE_J1939
891         std::string j1939_bus;
892         vect_ptr_msg_def_t current_messages_definition = application.get_messages_definition();
893         for(std::shared_ptr<message_definition_t> message_definition: current_messages_definition)
894         {
895                 if(message_definition->is_j1939())
896                 {
897                         if (j1939_bus == message_definition->get_bus_device_name() )
898                                 continue;
899                         j1939_bus = message_definition->get_bus_device_name();
900
901                         std::shared_ptr<low_can_subscription_t> low_can_j1939 = std::make_shared<low_can_subscription_t>();
902                         application.set_subscription_address_claiming(low_can_j1939);
903
904                         ret = low_can_subscription_t::open_socket(*low_can_j1939,
905                                                                   j1939_bus,
906                                                                   J1939_ADDR_CLAIM_PROTOCOL);
907
908                         if(ret < 0)
909                         {
910                                 AFB_ERROR("Error open socket address claiming for j1939 protocol");
911                                 return -1;
912                         }
913                         add_to_event_loop(low_can_j1939);
914                         break;
915                 }
916         }
917 #endif
918
919         if(ret)
920                 AFB_ERROR("There was something wrong with CAN device Initialization.");
921
922         return ret;
923 }
924
925 int load_config(afb_api_t api)
926 {
927         int ret = 0;
928         CtlConfigT *ctlConfig;
929         const char *dirList = getenv("CONTROL_CONFIG_PATH");
930         std::string bindingDirPath = GetBindingDirPath(api);
931         std::string filepath = bindingDirPath + "/etc";
932
933         if (!dirList)
934                 dirList=CONTROL_CONFIG_PATH;
935
936         filepath.append(":");
937         filepath.append(dirList);
938         const char *configPath = CtlConfigSearch(api, filepath.c_str(), "control");
939
940         if (!configPath)
941         {
942                 AFB_ERROR_V3("CtlPreInit: No control-* config found invalid JSON %s ", filepath.c_str());
943                 return -1;
944         }
945
946         // create one API per file
947         ctlConfig = CtlLoadMetaData(api, configPath);
948         if (!ctlConfig)
949         {
950                 AFB_ERROR_V3("CtrlPreInit No valid control config file in:\n-- %s", configPath);
951                 return -1;
952         }
953
954         // Save the config in the api userdata field
955         afb_api_set_userdata(api, ctlConfig);
956
957         setExternalData(ctlConfig, (void*) &application_t::instance());
958         ret= CtlLoadSections(api, ctlConfig, ctlSections_);
959
960         return ret;
961 }