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