Add obd2 prefix to signals name to be able to
[apps/low-level-can-service.git] / low-can-binding.cpp
1  */
2
3 #include <unistd.h>
4 #include <sys/types.h>
5 #include <sys/socket.h>
6 #include <sys/ioctl.h>
7 #include <net/if.h>
8 #include <linux/can.h>
9 #include <linux/can/raw.h>
10 #include <fcntl.h>
11 #include <systemd/sd-event.h>
12 #include <errno.h>
13 #include <vector>
14 #include <map>
15 #include <queue>
16 #include <string>
17 #include <functional>
18 #include <memory>
19 #include <thread>
20
21 #include <json-c/json.h>
22 #include <openxc.pb.h>
23
24 #include <afb/afb-binding.h>
25 #include <afb/afb-service-itf.h>
26
27 #include "ll-can-binding.h"
28 #include "obd2.h"
29
30 /*
31  *   Interface between the daemon and the binding
32  */
33 static const struct afb_binding_interface *interface;
34
35 /********************************************************************************
36 *
37 *               CanBus method implementation
38 *
39 *********************************************************************************/
40
41 int CanBus::open()
42 {
43         const int canfd_on = 1;
44         struct ifreq ifr;
45         struct timeval timeout = {1, 0};
46
47         DEBUG(interface, "open_can_dev: CAN Handler socket : %d", socket);
48         if (socket >= 0)
49                 close(socket);
50
51         socket = socket(PF_CAN, SOCK_RAW, CAN_RAW);
52         if (socket < 0)
53         {
54                 ERROR(interface, "open_can_dev: socket could not be created");
55         }
56         else
57         {
58                 /* Set timeout for read */
59                 setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
60                 /* try to switch the socket into CAN_FD mode */
61                 if (setsockopt(socket, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on)) < 0)
62                 {
63                         NOTICE(interface, "open_can_dev: Can not switch into CAN Extended frame format.");
64                         is_fdmode_on = false;
65                 } else {
66                         is_fdmode_on = true;
67                 }
68
69                 /* Attempts to open a socket to CAN bus */
70                 strcpy(ifr.ifr_name, device);
71                 if(ioctl(socket, SIOCGIFINDEX, &ifr) < 0)
72                         ERROR(interface, "open_can_dev: ioctl failed");
73                 else
74                 {
75                         txAddress.can_family = AF_CAN;
76                         txAddress.can_ifindex = ifr.ifr_ifindex;
77
78                         /* And bind it to txAddress */
79                         if (bind(socket, (struct sockaddr *)&txAddress, sizeof(txAddress)) < 0)
80                         {
81                                 ERROR(interface, "open_can_dev: bind failed");
82                         }
83                         else
84                         {
85                                 fcntl(socket, F_SETFL, O_NONBLOCK);
86                                 return 0;
87                         }
88                 }
89                 close(socket);
90                 socket = -1;
91         }
92         return -1;
93 }
94
95 int CanBus::close()
96 {
97         close(socket);
98         socket = -1;
99 }
100
101 void CanBus::start_threads()
102 {
103     std::queue <canfd_frame> canfd_frame_queue;
104     std::queue <openxc_can_message_type> can_message_queue;
105
106     th_reading = std::thread(can_reader, interface, socket, canfd_frame_queue);
107     th_decoding = std::thread(can_decoder, interface, canfd_frame_queue, can_message_queue);
108     th_pushing = std::thread(can_event_push, interface, can_message_queue);
109 }
110
111 /********************************************************************************
112 *
113 *               Event management
114 *
115 *********************************************************************************/
116
117 /*
118  * TBF TBF TBF
119  * called on an event on the CAN bus
120  */
121 static int on_event(sd_event_source *s, int fd, uint32_t revents, void *userdata)
122 {
123         openxc_CanMessage can_message;
124
125         can_message = openxc_CanMessage_init_default;
126
127         /* read available data */
128         if ((revents & EPOLLIN) != 0)
129         {
130                 read_can(&can_message);
131                 send_event();
132         }
133
134         /* check if error or hangup */
135         if ((revents & (EPOLLERR|EPOLLRDHUP|EPOLLHUP)) != 0)
136         {
137                 sd_event_source_unref(s);
138                 close(fd);
139                 connect_to_event_loop();
140         }
141
142         return 0;
143 }
144
145 /*
146  * Get the event loop running.
147  * Will trigger on_event function on EPOLLIN event on socket
148  *
149  * Return 0 or positive value on success. Else negative value for failure.
150  */
151 static int connect_to_event_loop(CanBus &CanBus_handler)
152 {
153         sd_event *event_loop;
154         sd_event_source *source;
155         int rc;
156
157         if (CanBus_handler.socket < 0)
158         {
159                 return CanBus_handler.socket;
160         }
161
162         event_loop = afb_daemon_get_event_loop(interface->daemon);
163         rc = sd_event_add_io(event_loop, &source, CanBus_handler.socket, EPOLLIN, on_event, NULL);
164         if (rc < 0)
165         {
166                 CanBus_handler.close();
167                 ERROR(interface, "Can't connect CAN bus %s to the event loop", CanBus_handler.device);
168         } else
169         {
170                 NOTICE(interface, "Connected CAN bus %s to the event loop", CanBus_handler.device);
171         }
172
173         return rc;
174 }
175
176 /********************************************************************************
177 *
178 *               Subscription and unsubscription
179 *
180 *********************************************************************************/
181
182 static int subscribe_unsubscribe_sig(struct afb_req request, int subscribe, struct signal *sig)
183 {
184         if (!afb_event_is_valid(sig->event)) {
185                 if (!subscribe)
186                         return 1;
187                 sig->event = afb_daemon_make_event(afbitf->daemon, sig->name);
188                 if (!afb_event_is_valid(sig->event)) {
189                         return 0;
190                 }
191         }
192
193         if (((subscribe ? afb_req_subscribe : afb_req_unsubscribe)(request, sig->event)) < 0) {
194                 return 0;
195         }
196
197         return 1;
198 }
199
200 static int subscribe_unsubscribe_all(struct afb_req request, int subscribe)
201 {
202         int i, n, e;
203
204         n = sizeof OBD2_PIDS / sizeof * OBD2_PIDS;
205         e = 0;
206         for (i = 0 ; i < n ; i++)
207                 e += !subscribe_unsubscribe_sig(request, subscribe, &OBD2_PIDS[i]);
208         return e == 0;
209 }
210
211 static int subscribe_unsubscribe_name(struct afb_req request, int subscribe, const char *name)
212 {
213         struct signal *sig;
214
215         if (0 == strcmp(name, "*"))
216                 return subscribe_unsubscribe_all(request, subscribe);
217
218         sig = getsig(name);
219         if (sig == NULL) {
220                 return 0;
221         }
222
223         return subscribe_unsubscribe_sig(request, subscribe, sig);
224 }
225
226 static void subscribe_unsubscribe(struct afb_req request, int subscribe)
227 {
228         int ok, i, n;
229         struct json_object *args, *a, *x;
230
231         /* makes the subscription/unsubscription */
232         args = afb_req_json(request);
233         if (args == NULL || !json_object_object_get_ex(args, "event", &a)) {
234                 ok = subscribe_unsubscribe_all(request, subscribe);
235         } else if (json_object_get_type(a) != json_type_array) {
236                 ok = subscribe_unsubscribe_name(request, subscribe, json_object_get_string(a));
237         } else {
238                 n = json_object_array_length(a);
239                 ok = 0;
240                 for (i = 0 ; i < n ; i++) {
241                         x = json_object_array_get_idx(a, i);
242                         if (subscribe_unsubscribe_name(request, subscribe, json_object_get_string(x)))
243                                 ok++;
244                 }
245                 ok = (ok == n);
246         }
247
248         /* send the report */
249         if (ok)
250                 afb_req_success(request, NULL, NULL);
251         else
252                 afb_req_fail(request, "error", NULL);
253 }
254
255 static void subscribe(struct afb_req request)
256 {
257         subscribe_unsubscribe(request, 1);
258 }
259
260 static void unsubscribe(struct afb_req request)
261 {
262         subscribe_unsubscribe(request, 0);
263 }
264 static const struct afb_verb_desc_v1 verbs[]=
265 {
266   { .name= "subscribe",    .session= AFB_SESSION_NONE, .callback= subscribe,    .info= "subscribe to notification of CAN bus messages." },
267   { .name= "unsubscribe",  .session= AFB_SESSION_NONE, .callback= unsubscribe,  .info= "unsubscribe a previous subscription." },
268         {NULL}
269 };
270
271 static const struct afb_binding binding_desc = {
272         .type = AFB_BINDING_VERSION_1,
273         .v1 = {
274                 .info = "CAN bus service",
275                 .prefix = "can",
276                 .verbs = verbs
277         }
278 };
279
280 const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf)
281 {
282         interface = itf;
283
284         return &binding_desc;
285 }
286
287 int afbBindingV1ServiceInit(struct afb_service service)
288 {
289         /* Open JSON conf file */
290
291         /* Open CAN socket */
292         CanBus_handler.open();
293     CanBus_handler.start_threads();
294
295         return connect_to_event_loop(CanBus_handler);
296 }