4 * @brief the FRESCAN protocol
15 * This file contains the implementation of the FRESCAN protocol
19 * -----------------------------------------------------------------------
20 * Copyright (C) 2006 - 2008 FRESCOR consortium partners:
22 * Universidad de Cantabria, SPAIN
23 * University of York, UK
24 * Scuola Superiore Sant'Anna, ITALY
25 * Kaiserslautern University, GERMANY
26 * Univ. Politécnica Valencia, SPAIN
27 * Czech Technical University in Prague, CZECH REPUBLIC
29 * Thales Communication S.A. FRANCE
30 * Visual Tools S.A. SPAIN
31 * Rapita Systems Ltd UK
34 * See http://www.frescor.org for a link to partners' websites
36 * FRESCOR project (FP6/2005/IST/5-034026) is funded
37 * in part by the European Union Sixth Framework Programme
38 * The European Union is not liable of any use that may be
41 * This file is part of FRESCAN
43 * FRESCAN is free software; you can redistribute it and/or modify
44 * it under the terms of the GNU General Public License as published by
45 * the Free Software Foundation; either version 2, or (at your option)
48 * FRESCAN is distributed in the hope that it will be useful, but
49 * WITHOUT ANY WARRANTY; without even the implied warranty of
50 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
51 * General Public License for more details.
53 * You should have received a copy of the GNU General Public License
54 * distributed with FRESCAN; see file COPYING. If not, write to the
55 * Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
58 * As a special exception, including FRESCAN header files in a file,
59 * instantiating FRESCAN generics or templates, or linking other files
60 * with FRESCAN objects to produce an executable application, does not
61 * by itself cause the resulting executable application to be covered
62 * by the GNU General Public License. This exception does not
63 * however invalidate any other reasons why the executable file might be
64 * covered by the GNU Public License.
65 * -----------------------------------------------------------------------
69 #include <sys/marte_configuration_parameters.h> // PATH_MX
70 #include <fcntl.h> // open
71 #include <unistd.h> // ioctl
72 #include <stdlib.h> // malloc
73 #include <string.h> // memcpy
75 #include <drivers/can.h> // can_chip_t, can_frame_t
76 #include "frescan.h" // frescan_init_params_t, frescan_send_params_t
77 #include "frescan_queues.h" // init, enqueue, requeue
78 #include "frescan_data.h" // init, the_networks
79 #include "frescan_servers.h" // init, frame_sent
80 #include "frescan_debug.h" // DEBUG
81 #include "frescan_id.h" // frescan_id_set_field, frescan_id_get_field
82 #include "frescan_hw_buffer.h" // frescan_hw_buffer_update
83 #include "frescan_packets.h"
85 static int frescan_hook_frame_recv (const struct can_chip_t *chip,
86 struct can_frame_t *frame);
88 static int frescan_hook_frame_sent(const struct can_chip_t *chip);
90 static int frescan_hook_frame_aborted(const struct can_chip_t *chip);
93 * frescan_init - initializes the network and the internal structures
95 * @params: the initialization parameters
97 * This function initializes the frescan network protocol.
99 * First it opens and configures the corresponding CAN chip device. For the
100 * CAN chip acceptance filter we use a dual filter configuration. The first
101 * filter is to set my local address address and the second one is to allow
102 * broadcast messages.
104 * Once the CAN chip is configured we call the initialization functions of
105 * the rest of modules of frescan.
109 int frescan_init(frescan_init_params_t *params)
112 char can_path[PATH_MX];
113 struct ioctl_filters_t ioctl_filters;
114 struct can_filter_t filters[2];
116 snprintf(can_path, PATH_MX, "/dev/can%u", params->net);
118 DEBUG(FRESCAN_INIT_ENABLE_DEBUG, "open %s\n", can_path);
120 fd = open (can_path, O_RDWR);
122 ERROR ("could not open /dev/can%u\n", params->net);
126 DEBUG(FRESCAN_INIT_ENABLE_DEBUG, "set acceptance filters\n");
128 filters[0].mask = 0xFFFFFFFF;
129 frescan_id_set_field(&filters[0].mask, FRESCAN_FIELD_DEST,0x00);
131 frescan_id_set_field(&filters[0].code, FRESCAN_FIELD_DEST,params->node);
133 filters[1].mask = filters[0].mask;
135 frescan_id_set_field(&filters[1].code,
137 FRESCAN_BROADCAST_ADDR);
139 ioctl_filters.filters = filters;
140 ioctl_filters.len = 2;
142 ret = ioctl(fd, CAN_IOCTL_SET_FILTERS, &ioctl_filters);
144 ERROR ("ioctl CAN_IOCTL_SET_FILTERS failed /dev/can%u\n",
149 DEBUG(FRESCAN_INIT_ENABLE_DEBUG, "set tx, rx, abort hooks\n");
151 ret = ioctl(fd, CAN_IOCTL_SET_TX_HOOK, frescan_hook_frame_sent);
153 ERROR ("ioctl CAN_IOCTL_SET_TX_HOOK failed /dev/can%u\n",
158 ret = ioctl(fd, CAN_IOCTL_SET_RX_HOOK, frescan_hook_frame_recv);
160 ERROR ("ioctl CAN_IOCTL_SET_RX_HOOK failed /dev/can%u\n",
165 ret = ioctl(fd, CAN_IOCTL_SET_AB_HOOK, frescan_hook_frame_aborted);
167 ERROR ("ioctl CAN_IOCTL_SET_AB_HOOK failed /dev/can%u\n",
172 DEBUG(FRESCAN_INIT_ENABLE_DEBUG, "init the rest of modules\n");
174 ret = frescan_data_init(fd, params);
176 ERROR("could not initialize the global data\n");
180 ret = frescan_packets_init();
182 ERROR("could not initialize the packets pool\n");
186 ret = frescan_queues_init(&the_networks[params->net].queues, params);
188 ERROR("could not initialize the queues\n");
192 ret = frescan_servers_init(params->net);
194 ERROR("could not initialize the servers\n");
202 * frescan_send - send a message
204 * @params: the parameters needed by the protocol to send the message
205 * @msg: the message buffer
206 * @size: the size of the message
208 * This is one of the main functions of the protocol and it provides the
209 * means to send a message through the protocol stack.
212 int frescan_send(const frescan_send_params_t *params,
217 frescan_packet_t *packet;
218 frescan_prio_queue_t *pqueue;
220 DEBUG(FRESCAN_SEND_ENABLE_DEBUG || FRESCAN_FRAG_ENABLE_DEBUG,
221 "checking arguments (msg size=%d)\n", size);
223 if ((params == NULL) || (msg == NULL) || (size == 0)) {
224 ERROR("arguments are not ok\n");
228 DEBUG(FRESCAN_SEND_ENABLE_DEBUG, "allocating a packet\n");
230 FRESCAN_ACQUIRE_LOCK(&the_networks[params->net].lock);
231 packet = frescan_packets_alloc();
232 FRESCAN_RELEASE_LOCK(&the_networks[params->net].lock);
234 if (packet == NULL) {
235 ERROR("could not allocate packet\n");
238 packet->flags = params->flags; // set the flags (to remember them)
240 DEBUG(FRESCAN_SEND_ENABLE_DEBUG, "allocating a frame\n");
242 FRESCAN_ACQUIRE_LOCK(&the_networks[params->net].lock);
243 packet->frame = can_framespool_alloc();
244 FRESCAN_RELEASE_LOCK(&the_networks[params->net].lock);
246 if (packet->frame == NULL) {
247 ERROR("could not allocate frame\n");
251 DEBUG(FRESCAN_SEND_ENABLE_DEBUG, "set values for the frame header\n");
252 packet->frame->is_extended_format = true;
253 packet->frame->is_rtr = false;
255 if (params->flags & FRESCAN_FP) {
256 // NOTE: frag id for fp is: FRESCAN_MX_IDS, so the servers can
257 // have IDs in the range (0 .. FRESCAN_MX_IDS-1)
258 frescan_id_set_field(&packet->frame->id,
259 FRESCAN_FIELD_FRAG_ID,
260 (uint32_t)FRESCAN_MX_IDS);
262 frescan_id_set_field(&packet->frame->id,
264 (uint32_t)params->prio);
266 // NOTE: the priority is put when the packet is dequeued
267 // and it is the priority of th server
268 frescan_id_set_field(&packet->frame->id,
269 FRESCAN_FIELD_FRAG_ID,
270 (uint32_t)params->ss);
273 frescan_id_set_field(&packet->frame->id,
275 (uint32_t)params->to);
277 frescan_id_set_field(&packet->frame->id,
279 (uint32_t)the_networks[params->net].local_node);
281 frescan_id_set_field(&packet->frame->id,
283 (uint32_t)params->channel);
285 DEBUG(FRESCAN_SEND_ENABLE_DEBUG, "set the packet data bytes\n");
286 if (params->flags & FRESCAN_ASYNC) {
287 // allocate a buffer and copy the data
288 // NOTE: instead of this we could use a chain of frames but
289 // i think it would be inefficient since each one can only
290 // hold 8 user bytes and we need to write its headers.
291 packet->buffer_head = (uint8_t *)malloc(size*sizeof(uint8_t));
292 memcpy(packet->buffer_head, msg, size);
294 packet->buffer_head = (uint8_t *)msg;
297 packet->buffer_read_pointer = packet->buffer_head;
298 packet->buffer_pending_bytes = size;
299 pqueue = the_networks[params->net].queues.tx_fp_queue;
301 DEBUG(FRESCAN_SEND_ENABLE_DEBUG, "enqueue the packet\n");
302 if (packet->flags & FRESCAN_FP) {
303 FRESCAN_ACQUIRE_LOCK(&the_networks[params->net].lock);
304 ret = frescan_pqueue_enqueue(pqueue, packet, params->prio);
305 FRESCAN_RELEASE_LOCK(&the_networks[params->net].lock);
308 ERROR("could not enqueue the packet\n");
312 FRESCAN_ACQUIRE_LOCK(&the_networks[params->net].lock);
313 ret = frescan_servers_enqueue(params->net, params->ss, packet);
314 FRESCAN_RELEASE_LOCK(&the_networks[params->net].lock);
317 ERROR("could not enqueue the packet\n");
322 FRESCAN_ACQUIRE_LOCK(&the_networks[params->net].lock);
323 ret = frescan_hw_buffer_update(params->net);
324 FRESCAN_RELEASE_LOCK(&the_networks[params->net].lock);
327 ERROR("could not update hw buffer\n");
335 * frescan_recv - receive a message
337 * @params: the parameters needed by the protocol to receive the message
338 * @msg: the message buffer
339 * @size: the size of the message buffer
340 * @recv_bytes: the number of bytes received
341 * @from: the node that sent the message
342 * @prio: the priority of the message
344 * This is one of the main functions of the protocol and it provides the
345 * means to receive a message through the protocol stack.
348 int frescan_recv(const frescan_recv_params_t *params,
352 frescan_node_t *from,
353 frescan_prio_t *prio)
356 frescan_prio_queue_t *pqueue;
358 frescan_packet_t *head, *packet;
360 if (params->flags & FRESCAN_SYNC) {
361 DEBUG(FRESCAN_RECV_ENABLE_DEBUG,
362 "receive a packet in blocking mode\n");
365 DEBUG(FRESCAN_RECV_ENABLE_DEBUG,
366 "receive a packet in non-blocking mode\n");
370 pqueue = the_networks[params->net].queues.rx_channel_queues
373 ret = frescan_pqueue_dequeue(pqueue, &head, prio, blocking);
375 ERROR ("could not dequeue packet\n");
380 if (blocking == false) {
381 DEBUG(FRESCAN_RECV_ENABLE_DEBUG,
382 "blocking false, no packets\n");
386 ERROR ("blocking true, and packet = null\n");
391 DEBUG(FRESCAN_RECV_ENABLE_DEBUG,
392 "traverse the list of packets for this message\n");
396 FRESCAN_ACQUIRE_LOCK(&the_networks[params->net].lock);
398 list_for_each_entry(packet, &head->msg_list, msg_list) {
399 // TODO: memory checks, delete the packets
400 memcpy(msg + *recv_bytes,
403 *recv_bytes += packet->frame->dlc;
405 *from = (frescan_node_t)frescan_id_get_field(packet->frame->id,
407 DEBUG(FRESCAN_RECV_ENABLE_DEBUG,
408 "ID Packet, dlc: %u, frame pool pos: %u, from:%u\n",
409 packet->frame->dlc, packet->frame->pool_pos, *from);
411 ret = can_framespool_free(packet->frame);
413 ERROR("could not free frame\n");
417 ret = frescan_packets_free(packet);
419 ERROR("could not free packet\n");
424 ret = frescan_packets_free(head);
426 FRESCAN_RELEASE_LOCK(&the_networks[params->net].lock);
429 ERROR("could not free head packet\n");
433 DEBUG(FRESCAN_RECV_ENABLE_DEBUG,
434 "received bytes: %u\n", *recv_bytes);
441 * frescan_hook_frame_recv - frame received hook
443 * This function will be called by the CAN driver's IRQ handler when a frame
444 * is received so we can store it in an appropiate queue.
446 * NOTE: in the future it could consist simply of signaling a semaphore to
447 * let a bottom half thread do the hard work.
451 static int frescan_hook_frame_recv (const struct can_chip_t *chip,
452 struct can_frame_t *frame)
455 uint32_t prio, dest, src, channel, frag_id, frag_flag;
456 frescan_packet_t *packet, *head;
457 frescan_prio_queue_t *pqueue;
462 DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG, "received a frame, net=%d\n", net);
463 DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG || FRESCAN_FRAG_ENABLE_DEBUG,
464 "%s %s, id=0x%X, dlc=%u, pool:%u\n",
465 (frame->is_extended_format) ? "Ext" : "Stnd",
466 (frame->is_rtr) ? "RTR Frame" : "DATA Frame",
471 for (i=0; i<frame->dlc; i++) {
472 DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG,
473 "data[%d] = 0x%X;\n", i, frame->data[i]);
476 prio = frescan_id_get_field(frame->id, FRESCAN_FIELD_PRIO);
477 dest = frescan_id_get_field(frame->id, FRESCAN_FIELD_DEST);
478 src = frescan_id_get_field(frame->id, FRESCAN_FIELD_SRC);
479 channel = frescan_id_get_field(frame->id, FRESCAN_FIELD_CHAN);
480 frag_id = frescan_id_get_field(frame->id, FRESCAN_FIELD_FRAG_ID);
481 frag_flag = frescan_id_get_field(frame->id, FRESCAN_FIELD_FRAG_FLAG);
483 DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG || FRESCAN_FRAG_ENABLE_DEBUG,
484 "prio:%u dest:%u src:%u chan:%u id:%u flag:%u\n",
485 prio, dest, src, channel, frag_id, frag_flag);
487 DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG,
488 "enqueue the packet in ID queue\n");
489 packet = frescan_packets_alloc();
490 packet->frame = frame;
492 if (frag_id == FRESCAN_MX_IDS) {
493 head = the_networks[net].id_fp_queues[src][prio];
495 head = the_networks[net].id_queues[src][frag_id];
499 DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG ||
500 FRESCAN_FRAG_ENABLE_DEBUG,
501 "allocate head for id=%u\n", frag_id);
502 head = frescan_packets_alloc();
503 INIT_LIST_HEAD(&head->msg_list);
505 if (frag_id == FRESCAN_MX_IDS) {
506 the_networks[net].id_fp_queues[src][prio] = head;
508 the_networks[net].id_queues[src][frag_id] = head;
512 list_add_tail(&packet->msg_list, &head->msg_list);
514 if (frag_flag == false) {
515 DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG ||
516 FRESCAN_FRAG_ENABLE_DEBUG,
517 "message complete, move msg to channel\n");
518 // TODO: select the highest priority??
519 pqueue = the_networks[net].queues.rx_channel_queues[channel];
520 ret = frescan_pqueue_enqueue(pqueue, head, prio);
522 ERROR("could not enqueue message in channel queue\n");
526 if (frag_id == FRESCAN_MX_IDS) {
527 the_networks[net].id_fp_queues[src][prio] = NULL;
529 the_networks[net].id_queues[src][frag_id] = NULL;
533 DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG ||
534 FRESCAN_FRAG_ENABLE_DEBUG,
535 "message not complete, wait for more fragments\n");
538 // NOTE: don't forget to free the frame and the packet when it is
539 // read by the user application
545 * frescan_hook_frame_sent - frame sent hook
547 * This function will be called by the CAN driver's IRQ handler when a frame
548 * is sent through the CAN bus so we can enqueue another one, signal a
549 * semaphore, consume sporadic server capacity...
552 static int frescan_hook_frame_sent(const struct can_chip_t *chip)
555 frescan_packet_t *packet;
556 frescan_prio_queue_t *pqueue;
560 packet = the_networks[chip->minor].last_packet;
562 id = frescan_id_get_field(packet->frame->id,
563 FRESCAN_FIELD_FRAG_ID);
565 DEBUG(FRESCAN_SENT_HOOK_ENABLE_DEBUG,
566 "frame sent, minor:%u flags:0x%X frag_id:0x%X\n",
567 chip->minor, packet->flags, id);
569 if (packet->flags & FRESCAN_SS) {
570 DEBUG(FRESCAN_SENT_HOOK_ENABLE_DEBUG,
571 "calling frame_sent + program repl for id:%u\n", id);
573 ret = frescan_servers_frame_sent(chip->minor, id, packet);
575 ERROR("could not let the server a frame was sent\n");
580 DEBUG(FRESCAN_SENT_HOOK_ENABLE_DEBUG || FRESCAN_FRAG_ENABLE_DEBUG,
581 "last packet buffer_pending_bytes=%u\n",
582 packet->buffer_pending_bytes);
584 if (packet->buffer_pending_bytes > 0) {
585 if (packet->flags & FRESCAN_FP) {
586 prio = frescan_id_get_field(packet->frame->id,
589 DEBUG(FRESCAN_FRAG_ENABLE_DEBUG,
590 "requeue fp packet, prio:%u\n", prio);
592 pqueue = the_networks[chip->minor].queues.tx_fp_queue;
593 ret = frescan_pqueue_requeue(pqueue, packet, prio);
595 ERROR("could not requeue the packet\n");
598 } else if (packet->flags & FRESCAN_SS) {
599 DEBUG(FRESCAN_FRAG_ENABLE_DEBUG,
600 "requeue server %u packet\n", id);
601 ret = frescan_servers_requeue(chip->minor, id, packet);
603 ERROR("could not requeue the packet\n");
607 ERROR("flags are not correct\n");
611 DEBUG(FRESCAN_FRAG_ENABLE_DEBUG,
612 "all packet fragmets sent, freeing the packet\n");
614 ret = can_framespool_free(packet->frame);
616 ERROR ("could not free the frame\n");
620 ret = frescan_packets_free(packet);
622 ERROR ("could not free the packet\n");
626 // TODO: signal semaphore for send_sync
629 the_networks[chip->minor].last_packet = NULL;
631 ret = frescan_hw_buffer_update(chip->minor);
633 ERROR("could not update hw buffer\n");
641 * frescan_hook_frame_aborted - frame frame aborted hook
643 * This function will be called by the CAN driver's IRQ handler when a frame
644 * is aborted (because another frame with higher priority is waiting). We
645 * have to requeue the frame and update the buffer.
648 static int frescan_hook_frame_aborted(const struct can_chip_t *chip)
651 frescan_packet_t *packet;
652 frescan_prio_queue_t *pqueue;
656 packet = the_networks[chip->minor].last_packet;
658 id = frescan_id_get_field(packet->frame->id,
659 FRESCAN_FIELD_FRAG_ID);
661 DEBUG(FRESCAN_SENT_HOOK_ENABLE_DEBUG,
662 "frame aborted, minor:%u flags:0x%X frag_id:0x%X\n",
663 chip->minor, packet->flags, id);
665 if (packet->flags & FRESCAN_FP) {
666 prio = frescan_id_get_field(packet->frame->id,
669 DEBUG(FRESCAN_FRAG_ENABLE_DEBUG,
670 "requeue fp packet, prio:%u\n", prio);
672 pqueue = the_networks[chip->minor].queues.tx_fp_queue;
673 ret = frescan_pqueue_requeue(pqueue, packet, prio);
675 ERROR("could not requeue the packet\n");
678 } else if (packet->flags & FRESCAN_SS) {
679 DEBUG(FRESCAN_FRAG_ENABLE_DEBUG,
680 "requeue server %u packet\n", id);
682 ret = frescan_servers_requeue(chip->minor, id, packet);
684 ERROR("could not requeue the packet\n");
688 ERROR("flags are not correct\n");
692 the_networks[chip->minor].last_packet = NULL;
694 ret = frescan_hw_buffer_update(chip->minor);
696 ERROR("could not update hw buffer\n");