2 * Copyright (C) 2015, 2016 "IoT.bzh"
3 * Author "Romain Forlot" <romain.forlot@iot.bzh>
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <sys/ioctl.h>
27 #include <linux/can.h>
30 #include <systemd/sd-event.h>
33 #include <json-c/json.h>
34 #include <openxc.pb.h>
36 #include <afb/afb-binding.h>
37 #include <afb/afb-service-itf.h>
39 /*****************************************************************************************/
40 /*****************************************************************************************/
43 /** SECTION: GLOBAL VARIABLES **/
46 /*****************************************************************************************/
47 /*****************************************************************************************/
49 /* max. number of CAN interfaces given on the cmdline */
52 /* buffer sizes for CAN frame string representations */
53 #define CL_ID (sizeof("12345678##1"))
54 #define CL_DATA sizeof(".AA")
55 #define CL_BINDATA sizeof(".10101010")
57 /* CAN FD ASCII hex short representation with DATA_SEPERATORs */
58 #define CL_CFSZ (2*CL_ID + 64*CL_DATA)
61 * the type of position expected
63 * here, this type is the selection of protocol
68 type_DEFAULT = type_CAN,
72 #define type_size sizeof(enum type)-2
75 * each generated event
78 struct event *next; /* link for the same period */
79 const char *name; /* name of the event */
80 struct afb_event event; /* the event for the binder */
81 enum type type; /* the type of data expected */
82 int id; /* id of the event for unsubscribe */
88 struct sockaddr_can txAddress;
91 static __u32 dropcnt[MAXSOCK];
92 static __u32 last_dropcnt[MAXSOCK];
93 char ctrlmsg[CMSG_SPACE(sizeof(struct timeval)) + CMSG_SPACE(sizeof(__u32))];
98 struct canfd_frame can_frame;
100 /*****************************************************************************************/
101 /*****************************************************************************************/
104 /** SECTION: UTILITY FUNCTIONS **/
107 /*****************************************************************************************/
108 /*****************************************************************************************/
110 * Interface between the daemon and the binding
112 static const struct afb_binding_interface *interface;
115 * @brief Retry a function 3 times
117 * @param int function(): function that return an int wihtout any parameter
119 * @ return : 0 if ok, -1 if failed
122 static int retry( int(*func)());
123 static int retry( int(*func)())
138 /*****************************************************************************************/
139 /*****************************************************************************************/
142 /** SECTION: HANDLE CAN DEVICE **/
145 /*****************************************************************************************/
146 /*****************************************************************************************/
150 static const char * const type_NAMES[type_size] = {
156 // Initialize default can_handler values
157 static struct can_handler can_handler = {
163 * Parse the CAN frame data payload as a CAN packet
164 * TODO: parse as an OpenXC Can Message
166 int can_frame_parse(openxc_CanMessage *can_message, struct can_frame *can_frame)
173 * open the can socket
175 static int open_can_dev()
178 struct timeval timeout = {1,0};
180 DEBUG(interface, "open_can_dev: CAN Handler socket : %d", can_handler.socket);
181 close(can_handler.socket);
183 can_handler.socket = socket(PF_CAN, SOCK_RAW, CAN_RAW);
184 if (can_handler.socket < 0)
186 ERROR(interface, "open_can_dev: socket could not be created");
190 // Set timeout for read
191 setsockopt(can_handler.socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
192 // Attempts to open a socket to CAN bus
193 strcpy(ifr.ifr_name, can_handler.device);
194 if(ioctl(can_handler.socket, SIOCGIFINDEX, &ifr) < 0)
196 ERROR(interface, "open_can_dev: ioctl failed");
200 can_handler.txAddress.can_family = AF_CAN;
201 can_handler.txAddress.can_ifindex = ifr.ifr_ifindex;
203 // And bind it to txAddress
204 if (bind(can_handler.socket, (struct sockaddr *)&can_handler.txAddress, sizeof(can_handler.txAddress)) < 0)
206 ERROR(interface, "open_can_dev: bind failed");
210 fcntl(can_handler.socket, F_SETFL, O_NONBLOCK);
214 close(can_handler.socket);
215 can_handler.socket = -1;
220 static int write_can()
224 rc = can_handler.socket;
228 * TODO change old hvac write can frame to generic on_event
230 rc = sendto(can_handler.socket, &can_frame, sizeof(struct can_frame), 0,
231 (struct sockaddr*)&can_handler.txAddress, sizeof(can_handler.txAddress));
234 ERROR(interface, "Sending CAN frame failed.");
239 ERROR(interface, "socket not initialized. Attempt to reopen can device socket.");
246 * Read on CAN bus and return how much bytes has been read.
248 static int read_can(openxc_CanMessage *can_message)
250 int byte_read, maxdlen;
251 iov.iov_base = &can_frame;
252 msg.msg_name = &can_handler.txAddress;
255 msg.msg_control = &ctrlmsg;
257 byte_read = recvmsg(can_handler.socket, &msg, 0);
261 if (errno == ENETDOWN) {
262 ERROR(interface, "%s: interface down", can_handler.device);
264 ERROR(interface, "Error reading CAN bus");
268 // CAN frame integrity check
269 if ((size_t)byte_read == CAN_MTU)
270 maxdlen = CAN_MAX_DLEN;
271 else if ((size_t)byte_read == CANFD_MTU)
272 maxdlen = CANFD_MAX_DLEN;
275 ERROR(interface, "CAN frame incomplete");
279 for ( cmsg = CMSG_FIRSTHDR(&msg);
280 cmsg && (cmsg->cmsg_level == SOL_SOCKET);
281 cmsg = CMSG_NXTHDR(&msg,cmsg))
283 if (cmsg->cmsg_type == SO_TIMESTAMP)
284 tv = *(struct timeval *)CMSG_DATA(cmsg);
285 else if (cmsg->cmsg_type == SO_RXQ_OVFL)
286 dropcnt[can_handler.socket] = *(__u32 *)CMSG_DATA(cmsg);
289 // Check if there is a new CAN frame dropped.
290 if (dropcnt[can_handler.socket] != last_dropcnt[can_handler.socket])
292 __u32 frames = dropcnt[can_handler.socket] - last_dropcnt[can_handler.socket];
293 WARNING(interface, "DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)",
294 frames, (frames > 1)?"s":"", can_handler.device, dropcnt[can_handler.socket]);
296 WARNING(interface, "DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n",
297 frames, (frames > 1)?"s":"", can_handler.device, dropcnt[can_handler.socket]);
299 last_dropcnt[can_handler.socket] = dropcnt[can_handler.socket];
302 can_message->has_id = true;
303 can_message->id = msg.id; // TODO make the parsing to extract id from data and only return left data into msg.msg_iov
304 can_message->has_data = true;
305 can_message->data = msg.msg_iov;
308 /***************************************************************************************/
309 /***************************************************************************************/
312 /** SECTION: MANAGING EVENTS **/
315 /***************************************************************************************/
316 /***************************************************************************************/
317 static int connect_to_event_loop();
320 * called on an event on the CAN bus
322 static int on_event(sd_event_source *s, int fd, uint32_t revents, void *userdata)
324 openxc_CanMessage can_message;
326 /* read available data */
327 if ((revents & EPOLLIN) != 0)
329 read_can(&can_message);
333 /* check if error or hangup */
334 if ((revents & (EPOLLERR|EPOLLRDHUP|EPOLLHUP)) != 0)
336 sd_event_source_unref(s);
338 connect_to_event_loop();
345 * get or create an event handler for the type
346 * TODO: implement function and handle retrieve or create an event as needed
348 static struct event *event_get(enum type type)
353 static struct event *event_of_id(int id)
358 /*****************************************************************************************/
359 /*****************************************************************************************/
362 /** SECTION: BINDING VERBS IMPLEMENTATION **/
365 /*****************************************************************************************/
366 /*****************************************************************************************/
368 * Returns the type corresponding to the given name
370 static enum type type_of_name(const char *name)
375 for (result = 0 ; result < type_size; result++)
376 if (strcmp(type_NAMES[result], name) == 0)
382 * extract a valid type from the request
384 static int get_type_for_req(struct afb_req req, enum type *type)
386 if ((*type = type_of_name(afb_req_value(req, "type"))) != type_INVALID)
388 afb_req_fail(req, "unknown-type", NULL);
393 * subscribe to notification of new CAN messages
395 * parameters of the subscription are:
397 * TODO type: string: choose between CAN and OBDII messages formats.
399 * returns an object with 2 fields:
401 * name: string: the name of the event without its prefix
402 * id: integer: a numeric identifier of the event to be used for unsubscribing
404 static void subscribe(struct afb_req req)
409 struct json_object *json;
411 if (get_type_for_req(req, &type))
413 event = event_get(type);
415 afb_req_fail(req, "out-of-memory", NULL);
416 else if (afb_req_subscribe(req, event->event) != 0)
417 afb_req_fail_f(req, "failed", "afb_req_subscribe returned an error: %m");
420 json = json_object_new_object();
421 json_object_object_add(json, "name", json_object_new_string(event->name));
422 json_object_object_add(json, "id", json_object_new_int(event->id));
423 afb_req_success(req, json, NULL);
429 * unsubscribe a previous subscription
431 * parameters of the unsubscription are:
433 * id: integer: the numeric identifier of the event as returned when subscribing
435 static void unsubscribe(struct afb_req req)
440 id = afb_req_value(req, "id");
442 afb_req_fail(req, "missing-id", NULL);
445 event = event_of_id(atoi(id));
447 afb_req_fail(req, "bad-id", NULL);
450 afb_req_unsubscribe(req, event->event);
451 afb_req_success(req, NULL, NULL);
456 static int connect_to_event_loop()
458 sd_event_source *source;
463 if (can_handler.socket < 0)
465 return can_handler.socket;
468 rc = sd_event_add_io(afb_daemon_get_event_loop(interface->daemon), &source, can_handler.socket, EPOLLIN, on_event, NULL);
471 close(can_handler.socket);
472 ERROR(interface, "Can't connect CAN bus %s to the event loop", can_handler.device);
475 NOTICE(interface, "Connected CAN bus %s to the event loop", can_handler.device);
482 // TODO: Have to change session management flag to AFB_SESSION_CHECK to use token auth
483 static const struct afb_verb_desc_v1 verbs[]=
485 { .name= "subscribe", .session= AFB_SESSION_NONE, .callback= subscribe, .info= "subscribe to notification of CAN bus messages." },
486 { .name= "unsubscribe", .session= AFB_SESSION_NONE, .callback= unsubscribe, .info= "unsubscribe a previous subscription." },
490 static const struct afb_binding binding_desc = {
491 .type = AFB_BINDING_VERSION_1,
493 .info = "CAN bus service",
499 const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf)
503 return &binding_desc;
506 int afbBindingV1ServiceInit(struct afb_service service)
508 return connect_to_event_loop();