Change uds-c library location
[apps/agl-service-can-low-level.git] / low-can-binding.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 <unistd.h>
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <sys/ioctl.h>
23 #include <net/if.h>
24 #include <linux/can.h>
25 #include <linux/can/raw.h>
26 #include <fcntl.h>
27 #include <systemd/sd-event.h>
28 #include <errno.h>
29 #include <vector>
30 #include <map>
31 #include <queue>
32 #include <string>
33 #include <functional>
34 #include <memory>
35 #include <thread>
36
37 #include <json-c/json.h>
38 #include <openxc.pb.h>
39
40 #include <afb/afb-binding.h>
41 #include <afb/afb-service-itf.h>
42
43 #include "ll-can-binding.h"
44 #include "obd2.h"
45
46 /*
47  *   Interface between the daemon and the binding
48  */
49 static const struct afb_binding_interface *interface;
50
51
52 /********************************************************************************
53 *
54 *               Event management
55 *
56 *********************************************************************************/
57
58 /*
59  * TBF TBF TBF
60  * called on an event on the CAN bus
61  */
62 static int on_event(sd_event_source *s, int fd, uint32_t revents, void *userdata)
63 {
64         openxc_CanMessage can_message;
65
66         can_message = openxc_CanMessage_init_default;
67
68         /* read available data */
69         if ((revents & EPOLLIN) != 0)
70         {
71                 read_can(&can_message);
72                 send_event();
73         }
74
75         /* check if error or hangup */
76         if ((revents & (EPOLLERR|EPOLLRDHUP|EPOLLHUP)) != 0)
77         {
78                 sd_event_source_unref(s);
79                 close(fd);
80                 connect_to_event_loop();
81         }
82
83         return 0;
84 }
85
86 /*
87  * Get the event loop running.
88  * Will trigger on_event function on EPOLLIN event on socket
89  *
90  * Return 0 or positive value on success. Else negative value for failure.
91  */
92 static int connect_to_event_loop(CanBus &CanBus_handler)
93 {
94         sd_event *event_loop;
95         sd_event_source *source;
96         int rc;
97
98         if (CanBus_handler.socket < 0)
99         {
100                 return CanBus_handler.socket;
101         }
102
103         event_loop = afb_daemon_get_event_loop(interface->daemon);
104         rc = sd_event_add_io(event_loop, &source, CanBus_handler.socket, EPOLLIN, on_event, NULL);
105         if (rc < 0)
106         {
107                 CanBus_handler.close();
108                 ERROR(interface, "Can't connect CAN bus %s to the event loop", CanBus_handler.device);
109         } else
110         {
111                 NOTICE(interface, "Connected CAN bus %s to the event loop", CanBus_handler.device);
112         }
113
114         return rc;
115 }
116
117 /********************************************************************************
118 *
119 *               Subscription and unsubscription
120 *
121 *********************************************************************************/
122
123 static int subscribe_unsubscribe_sig(struct afb_req request, int subscribe, struct signal *sig)
124 {
125         if (!afb_event_is_valid(sig->event)) {
126                 if (!subscribe)
127                         return 1;
128                 sig->event = afb_daemon_make_event(afbitf->daemon, sig->name);
129                 if (!afb_event_is_valid(sig->event)) {
130                         return 0;
131                 }
132         }
133
134         if (((subscribe ? afb_req_subscribe : afb_req_unsubscribe)(request, sig->event)) < 0) {
135                 return 0;
136         }
137
138         return 1;
139 }
140
141 static int subscribe_unsubscribe_all(struct afb_req request, int subscribe)
142 {
143         int i, n, e;
144
145         n = sizeof OBD2_PIDS / sizeof * OBD2_PIDS;
146         e = 0;
147         for (i = 0 ; i < n ; i++)
148                 e += !subscribe_unsubscribe_sig(request, subscribe, &OBD2_PIDS[i]);
149         return e == 0;
150 }
151
152 static int subscribe_unsubscribe_name(struct afb_req request, int subscribe, const char *name)
153 {
154         struct signal *sig;
155
156         if (0 == strcmp(name, "*"))
157                 return subscribe_unsubscribe_all(request, subscribe);
158
159         sig = getsig(name);
160         if (sig == NULL) {
161                 return 0;
162         }
163
164         return subscribe_unsubscribe_sig(request, subscribe, sig);
165 }
166
167 static void subscribe_unsubscribe(struct afb_req request, int subscribe)
168 {
169         int ok, i, n;
170         struct json_object *args, *a, *x;
171
172         /* makes the subscription/unsubscription */
173         args = afb_req_json(request);
174         if (args == NULL || !json_object_object_get_ex(args, "event", &a)) {
175                 ok = subscribe_unsubscribe_all(request, subscribe);
176         } else if (json_object_get_type(a) != json_type_array) {
177                 ok = subscribe_unsubscribe_name(request, subscribe, json_object_get_string(a));
178         } else {
179                 n = json_object_array_length(a);
180                 ok = 0;
181                 for (i = 0 ; i < n ; i++) {
182                         x = json_object_array_get_idx(a, i);
183                         if (subscribe_unsubscribe_name(request, subscribe, json_object_get_string(x)))
184                                 ok++;
185                 }
186                 ok = (ok == n);
187         }
188
189         /* send the report */
190         if (ok)
191                 afb_req_success(request, NULL, NULL);
192         else
193                 afb_req_fail(request, "error", NULL);
194 }
195
196 static void subscribe(struct afb_req request)
197 {
198         subscribe_unsubscribe(request, 1);
199 }
200
201 static void unsubscribe(struct afb_req request)
202 {
203         subscribe_unsubscribe(request, 0);
204 }
205 static const struct afb_verb_desc_v1 verbs[]=
206 {
207   { .name= "subscribe",    .session= AFB_SESSION_NONE, .callback= subscribe,    .info= "subscribe to notification of CAN bus messages." },
208   { .name= "unsubscribe",  .session= AFB_SESSION_NONE, .callback= unsubscribe,  .info= "unsubscribe a previous subscription." },
209         {NULL}
210 };
211
212 static const struct afb_binding binding_desc = {
213         .type = AFB_BINDING_VERSION_1,
214         .v1 = {
215                 .info = "CAN bus service",
216                 .prefix = "can",
217                 .verbs = verbs
218         }
219 };
220
221 const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf)
222 {
223         interface = itf;
224
225         return &binding_desc;
226 }
227
228 int afbBindingV1ServiceInit(struct afb_service service)
229 {
230         /* Open JSON conf file */
231
232         /* Open CAN socket */
233         CanBus_t CanBus_handler;
234         CanBus_handler.open();
235     CanBus_handler.start_threads();
236
237         return connect_to_event_loop(CanBus_handler);
238 }