4 * @brief the FRESCAN protocol
15 * This file contains the implementation of the FRESCAN protocol
19 //----------------------------------------------------------------------
20 // Copyright (C) 2006 - 2009 by the FRESCOR consortium:
22 // Universidad de Cantabria, SPAIN
23 // University of York, UK
24 // Scuola Superiore Sant'Anna, ITALY
25 // Kaiserslautern University, GERMANY
26 // Univ. Politecnica 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
36 // The 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
42 // based on previous work (FSF) done in the FIRST project
44 // Copyright (C) 2005 Mälardalen University, SWEDEN
45 // Scuola Superiore S.Anna, ITALY
46 // Universidad de Cantabria, SPAIN
47 // University of York, UK
49 // This file is part of FNA (Frescor Network Adaptation)
51 // FNA is free software; you can redistribute it and/or modify it
52 // under terms of the GNU General Public License as published by the
53 // Free Software Foundation; either version 2, or (at your option) any
54 // later version. FNA is distributed in the hope that it will be
55 // useful, but WITHOUT ANY WARRANTY; without even the implied warranty
56 // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
57 // General Public License for more details. You should have received a
58 // copy of the GNU General Public License along with FNA; see file
59 // COPYING. If not, write to the Free Software Foundation, 675 Mass Ave,
60 // Cambridge, MA 02139, USA.
62 // As a special exception, including FNA header files in a file,
63 // instantiating FNA generics or templates, or linking other files
64 // with FNA objects to produce an executable application, does not
65 // by itself cause the resulting executable application to be covered
66 // by the GNU General Public License. This exception does not
67 // however invalidate any other reasons why the executable file might be
68 // covered by the GNU Public License.
69 // -----------------------------------------------------------------------
73 #include <sys/marte_configuration_parameters.h> // PATH_MX
74 #include <fcntl.h> // open
75 #include <unistd.h> // ioctl
76 #include <stdlib.h> // malloc
77 #include <string.h> // memcpy
80 #include <drivers/can.h> // can_chip_t, can_frame_t
81 #include "frescan.h" // frescan_init_params_t, frescan_send_params_t
82 #include "frescan_queues.h" // init, enqueue, requeue
83 #include "frescan_data.h" // init, frescan_data
84 #include "frescan_servers.h" // init, frame_sent
85 #include "frescan_debug.h" // DEBUG
86 #include "frescan_id.h" // frescan_id_set_field, frescan_id_get_field
87 #include "frescan_hw_buffer.h" // frescan_hw_buffer_update
88 #include "frescan_packets.h"
90 static int frescan_hook_frame_recv (const struct can_chip_t *chip,
91 struct can_frame_t *frame);
93 static int frescan_hook_frame_sent(const struct can_chip_t *chip);
95 static int frescan_hook_frame_aborted(const struct can_chip_t *chip);
98 * frescan_init - initializes the network and the internal structures
100 * @params: the initialization parameters
102 * This function initializes the frescan network protocol.
104 * First it opens and configures the corresponding CAN chip device. For the
105 * CAN chip acceptance filter we use a dual filter configuration. The first
106 * filter is to set my local address address and the second one is to allow
107 * broadcast messages.
109 * Once the CAN chip is configured we call the initialization functions of
110 * the rest of modules of frescan.
114 int frescan_init(frescan_init_params_t *params)
117 char can_path[PATH_MX];
118 struct ioctl_filters_t ioctl_filters;
119 struct can_filter_t filters[2];
121 snprintf(can_path, PATH_MX, "/dev/can%u", params->net);
123 DEBUG(FRESCAN_INIT_ENABLE_DEBUG, "open %s\n", can_path);
125 fd = open (can_path, O_RDWR);
127 FRESCAN_ERROR ("could not open /dev/can%u\n", params->net);
128 FRESCAN_ERROR ("hint: check driver or card installation\n");
132 DEBUG(FRESCAN_INIT_ENABLE_DEBUG, "set acceptance filters\n");
134 filters[0].mask = 0xFFFFFFFF;
135 frescan_id_set_field(&filters[0].mask, FRESCAN_FIELD_DEST,0x00);
137 frescan_id_set_field(&filters[0].code, FRESCAN_FIELD_DEST,params->node);
139 filters[1].mask = filters[0].mask;
141 frescan_id_set_field(&filters[1].code,
143 FRESCAN_BROADCAST_ADDR);
145 ioctl_filters.filters = filters;
146 ioctl_filters.len = 2;
148 ret = ioctl(fd, CAN_IOCTL_SET_FILTERS, &ioctl_filters);
150 FRESCAN_ERROR ("ioctl CAN_IOCTL_SET_FILTERS failed /dev/can%u\n",
155 DEBUG(FRESCAN_INIT_ENABLE_DEBUG, "set tx, rx, abort hooks\n");
157 ret = ioctl(fd, CAN_IOCTL_SET_TX_HOOK, frescan_hook_frame_sent);
159 FRESCAN_ERROR ("ioctl CAN_IOCTL_SET_TX_HOOK failed /dev/can%u\n",
164 ret = ioctl(fd, CAN_IOCTL_SET_RX_HOOK, frescan_hook_frame_recv);
166 FRESCAN_ERROR ("ioctl CAN_IOCTL_SET_RX_HOOK failed /dev/can%u\n",
171 ret = ioctl(fd, CAN_IOCTL_SET_AB_HOOK, frescan_hook_frame_aborted);
173 FRESCAN_ERROR ("ioctl CAN_IOCTL_SET_AB_HOOK failed /dev/can%u\n",
178 DEBUG(FRESCAN_INIT_ENABLE_DEBUG, "init the rest of modules\n");
180 ret = frescan_data_init(fd, params);
182 FRESCAN_ERROR("could not initialize the global data\n");
186 ret = frescan_packets_init();
188 FRESCAN_ERROR("could not initialize the packets pool\n");
192 ret = frescan_queues_init(&frescan_data[params->net].queues, params);
194 FRESCAN_ERROR("could not initialize the queues\n");
198 ret = frescan_servers_init(params->net);
200 FRESCAN_ERROR("could not initialize the servers\n");
208 * frescan_send - send a message
210 * @params: the parameters needed by the protocol to send the message
211 * @msg: the message buffer
212 * @size: the size of the message
214 * This is one of the main functions of the protocol and it provides the
215 * means to send a message through the protocol stack.
218 int frescan_send(const frescan_send_params_t *params,
223 frescan_packet_t *packet;
224 frescan_prio_queue_t *pqueue;
226 DEBUG(FRESCAN_SEND_ENABLE_DEBUG || FRESCAN_FRAG_ENABLE_DEBUG,
227 "checking arguments (msg size=%d)\n", size);
229 if ((params == NULL) || (msg == NULL) || (size == 0)) {
230 FRESCAN_ERROR("arguments are not ok\n");
234 DEBUG(FRESCAN_SEND_ENABLE_DEBUG, "allocating a packet\n");
236 FRESCAN_ACQUIRE_LOCK(&frescan_data[params->net].lock);
237 packet = frescan_packets_alloc();
238 FRESCAN_RELEASE_LOCK(&frescan_data[params->net].lock);
240 if (packet == NULL) {
241 FRESCAN_ERROR("could not allocate packet\n");
244 packet->flags = params->flags; // set the flags (to remember them)
246 DEBUG(FRESCAN_SEND_ENABLE_DEBUG, "allocating a frame\n");
248 FRESCAN_ACQUIRE_LOCK(&frescan_data[params->net].lock);
249 packet->frame = can_framespool_alloc();
250 FRESCAN_RELEASE_LOCK(&frescan_data[params->net].lock);
252 if (packet->frame == NULL) {
253 FRESCAN_ERROR("could not allocate frame\n");
257 DEBUG(FRESCAN_SEND_ENABLE_DEBUG, "set values for the frame header\n");
258 packet->frame->is_extended_format = true;
259 packet->frame->is_rtr = false;
261 if (params->flags & FRESCAN_FP) {
262 // NOTE: frag id for fp is: FRESCAN_MX_IDS, so the servers can
263 // have IDs in the range (0 .. FRESCAN_MX_IDS-1)
264 frescan_id_set_field(&packet->frame->id,
265 FRESCAN_FIELD_FRAG_ID,
266 (uint32_t)FRESCAN_MX_IDS);
268 frescan_id_set_field(&packet->frame->id,
270 (uint32_t)params->prio);
272 // NOTE: the priority is put when the packet is dequeued
273 // and it is the priority of th server
274 frescan_id_set_field(&packet->frame->id,
275 FRESCAN_FIELD_FRAG_ID,
276 (uint32_t)params->ss);
279 frescan_id_set_field(&packet->frame->id,
281 (uint32_t)params->to);
283 frescan_id_set_field(&packet->frame->id,
285 (uint32_t)frescan_data[params->net].local_node);
287 frescan_id_set_field(&packet->frame->id,
289 (uint32_t)params->channel);
291 DEBUG(FRESCAN_SEND_ENABLE_DEBUG, "set the packet data bytes\n");
292 if (params->flags & FRESCAN_ASYNC) {
293 // allocate a buffer and copy the data
294 // NOTE: instead of this we could use a chain of frames but
295 // i think it would be inefficient since each one can only
296 // hold 8 user bytes and we need to write its headers.
297 FRESCAN_ACQUIRE_LOCK(&frescan_data[params->net].lock);
298 packet->buffer_head = (uint8_t *)malloc(size*sizeof(uint8_t)); // TODO: FREE IT!!!
299 FRESCAN_RELEASE_LOCK(&frescan_data[params->net].lock);
300 memcpy(packet->buffer_head, msg, size);
302 packet->buffer_head = (uint8_t *)msg;
305 packet->buffer_read_pointer = packet->buffer_head;
306 packet->buffer_pending_bytes = size;
307 pqueue = frescan_data[params->net].queues.tx_fp_queue;
309 DEBUG(FRESCAN_SEND_ENABLE_DEBUG, "enqueue the packet\n");
310 if (packet->flags & FRESCAN_FP) {
311 FRESCAN_ACQUIRE_LOCK(&frescan_data[params->net].lock);
312 ret = frescan_pqueue_enqueue(pqueue, packet, params->prio);
313 FRESCAN_RELEASE_LOCK(&frescan_data[params->net].lock);
316 FRESCAN_ERROR("could not enqueue the packet\n");
320 FRESCAN_ACQUIRE_LOCK(&frescan_data[params->net].lock);
321 ret = frescan_servers_enqueue(params->net, params->ss, packet);
322 FRESCAN_RELEASE_LOCK(&frescan_data[params->net].lock);
325 FRESCAN_ERROR("could not enqueue the packet\n");
330 FRESCAN_ACQUIRE_LOCK(&frescan_data[params->net].lock);
331 ret = frescan_hw_buffer_update(params->net);
332 FRESCAN_RELEASE_LOCK(&frescan_data[params->net].lock);
335 FRESCAN_ERROR("could not update hw buffer\n");
343 * frescan_recv - receive a message
345 * @params: the parameters needed by the protocol to receive the message
346 * @msg: the message buffer
347 * @size: the size of the message buffer
348 * @recv_bytes: the number of bytes received
349 * @from: the node that sent the message
350 * @prio: the priority of the message
352 * This is one of the main functions of the protocol and it provides the
353 * means to receive a message through the protocol stack.
356 int frescan_recv(const frescan_recv_params_t *params,
360 frescan_node_t *from,
361 frescan_prio_t *prio)
364 frescan_prio_queue_t *pqueue;
366 frescan_packet_t *head, *packet;
368 if (params->flags & FRESCAN_SYNC) {
369 DEBUG(FRESCAN_RECV_ENABLE_DEBUG,
370 "receive a packet in blocking mode\n");
373 DEBUG(FRESCAN_RECV_ENABLE_DEBUG,
374 "receive a packet in non-blocking mode\n");
378 pqueue = frescan_data[params->net].queues.rx_channel_queues
381 ret = frescan_pqueue_dequeue(pqueue, &head, prio, blocking);
383 FRESCAN_ERROR ("could not dequeue packet\n");
388 if (blocking == false) {
389 DEBUG(FRESCAN_RECV_ENABLE_DEBUG,
390 "blocking false, no packets\n");
394 FRESCAN_ERROR ("blocking true, and packet = null\n");
399 DEBUG(FRESCAN_RECV_ENABLE_DEBUG,
400 "traverse the list of packets for this message\n");
404 FRESCAN_ACQUIRE_LOCK(&frescan_data[params->net].lock);
406 list_for_each_entry(packet, &head->msg_list, msg_list) {
407 // TODO: memory checks, delete the packets
408 memcpy(msg + *recv_bytes,
411 *recv_bytes += packet->frame->dlc;
413 *from = (frescan_node_t)frescan_id_get_field(packet->frame->id,
415 DEBUG(FRESCAN_RECV_ENABLE_DEBUG,
416 "ID Packet, dlc: %u, frame pool pos: %u, from:%u\n",
417 packet->frame->dlc, packet->frame->pool_pos, *from);
419 ret = can_framespool_free(packet->frame);
421 FRESCAN_ERROR("could not free frame\n");
425 ret = frescan_packets_free(packet);
427 FRESCAN_ERROR("could not free packet\n");
432 ret = frescan_packets_free(head);
434 FRESCAN_RELEASE_LOCK(&frescan_data[params->net].lock);
437 FRESCAN_ERROR("could not free head packet\n");
441 DEBUG(FRESCAN_RECV_ENABLE_DEBUG,
442 "received bytes: %u\n", *recv_bytes);
449 * frescan_hook_frame_recv - frame received hook
451 * This function will be called by the CAN driver's IRQ handler when a frame
452 * is received so we can store it in an appropiate queue.
454 * NOTE: in the future it could consist simply of signaling a semaphore to
455 * let a bottom half thread do the hard work.
459 static int frescan_hook_frame_recv (const struct can_chip_t *chip,
460 struct can_frame_t *frame)
463 uint32_t prio, dest, src, channel, frag_id, frag_flag;
464 frescan_packet_t *packet, *head;
465 frescan_prio_queue_t *pqueue;
470 DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG, "received a frame, net=%d\n", net);
471 DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG || FRESCAN_FRAG_ENABLE_DEBUG,
472 "%s %s, id=0x%X, dlc=%u, pool:%u\n",
473 (frame->is_extended_format) ? "Ext" : "Stnd",
474 (frame->is_rtr) ? "RTR Frame" : "DATA Frame",
479 for (i=0; i<frame->dlc; i++) {
480 DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG,
481 "data[%d] = 0x%X;\n", i, frame->data[i]);
484 prio = frescan_id_get_field(frame->id, FRESCAN_FIELD_PRIO);
485 dest = frescan_id_get_field(frame->id, FRESCAN_FIELD_DEST);
486 src = frescan_id_get_field(frame->id, FRESCAN_FIELD_SRC);
487 channel = frescan_id_get_field(frame->id, FRESCAN_FIELD_CHAN);
488 frag_id = frescan_id_get_field(frame->id, FRESCAN_FIELD_FRAG_ID);
489 frag_flag = frescan_id_get_field(frame->id, FRESCAN_FIELD_FRAG_FLAG);
491 DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG || FRESCAN_FRAG_ENABLE_DEBUG,
492 "prio:%u dest:%u src:%u chan:%u id:%u flag:%u\n",
493 prio, dest, src, channel, frag_id, frag_flag);
494 DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG,
495 "enqueue the packet in ID queue\n");
497 packet = frescan_packets_alloc();
498 if (packet == NULL) {
499 FRESCAN_ERROR("could not allocate packet\n");
503 packet->frame = frame;
505 if (frag_id == FRESCAN_MX_IDS) {
506 head = frescan_data[net].id_fp_queues[src][prio];
508 head = frescan_data[net].id_queues[src][frag_id];
512 DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG ||
513 FRESCAN_FRAG_ENABLE_DEBUG,
514 "allocate head for id=%u\n", frag_id);
515 head = frescan_packets_alloc();
517 FRESCAN_ERROR("could not allocate packet\n");
521 INIT_LIST_HEAD(&head->msg_list);
523 if (frag_id == FRESCAN_MX_IDS) {
524 frescan_data[net].id_fp_queues[src][prio] = head;
526 frescan_data[net].id_queues[src][frag_id] = head;
530 list_add_tail(&packet->msg_list, &head->msg_list);
532 if (frag_flag == false) {
533 DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG ||
534 FRESCAN_FRAG_ENABLE_DEBUG,
535 "message complete, move msg to channel\n");
536 // TODO: select the highest priority??
537 pqueue = frescan_data[net].queues.rx_channel_queues[channel];
538 ret = frescan_pqueue_enqueue(pqueue, head, prio);
540 FRESCAN_ERROR("could not enqueue message in channel queue\n");
544 if (frag_id == FRESCAN_MX_IDS) {
545 frescan_data[net].id_fp_queues[src][prio] = NULL;
547 frescan_data[net].id_queues[src][frag_id] = NULL;
551 DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG ||
552 FRESCAN_FRAG_ENABLE_DEBUG,
553 "message not complete, wait for more fragments\n");
556 // NOTE: don't forget to free the frame and the packet when it is
557 // read by the user application
563 * frescan_hook_frame_sent - frame sent hook
565 * This function will be called by the CAN driver's IRQ handler when a frame
566 * is sent through the CAN bus so we can enqueue another one, signal a
567 * semaphore, consume sporadic server capacity...
570 static int frescan_hook_frame_sent(const struct can_chip_t *chip)
573 frescan_packet_t *packet;
574 frescan_prio_queue_t *pqueue;
578 packet = frescan_data[chip->minor].last_packet;
579 assert(packet != NULL);
581 id = frescan_id_get_field(packet->frame->id,
582 FRESCAN_FIELD_FRAG_ID);
584 DEBUG(FRESCAN_SENT_HOOK_ENABLE_DEBUG,
585 "frame sent, minor:%u flags:0x%X frag_id:0x%X\n",
586 chip->minor, packet->flags, id);
588 if (packet->flags & FRESCAN_SS) {
589 DEBUG(FRESCAN_SENT_HOOK_ENABLE_DEBUG,
590 "calling frame_sent + program repl for id:%u\n", id);
592 ret = frescan_servers_frame_sent(chip->minor, id, packet);
594 FRESCAN_ERROR("could not let the server a frame was sent\n");
599 DEBUG(FRESCAN_SENT_HOOK_ENABLE_DEBUG || FRESCAN_FRAG_ENABLE_DEBUG,
600 "last packet buffer_pending_bytes=%u\n",
601 packet->buffer_pending_bytes);
603 if (packet->buffer_pending_bytes > 0) {
604 if (packet->flags & FRESCAN_FP) {
605 prio = frescan_id_get_field(packet->frame->id,
608 DEBUG(FRESCAN_FRAG_ENABLE_DEBUG,
609 "requeue fp packet, prio:%u\n", prio);
611 pqueue = frescan_data[chip->minor].queues.tx_fp_queue;
612 ret = frescan_pqueue_requeue(pqueue, packet, prio);
614 FRESCAN_ERROR("could not requeue the packet packet:%p flags:0x%X\n", packet, packet->flags);
617 } else if (packet->flags & FRESCAN_SS) {
618 DEBUG(FRESCAN_FRAG_ENABLE_DEBUG,
619 "requeue server %u packet\n", id);
620 ret = frescan_servers_requeue(chip->minor, id, packet);
622 FRESCAN_ERROR("could not requeue the packet\n");
626 FRESCAN_ERROR("flags are not correct\n");
630 DEBUG(FRESCAN_FRAG_ENABLE_DEBUG,
631 "all packet fragmets sent, freeing the packet\n");
633 ret = can_framespool_free(packet->frame);
635 FRESCAN_ERROR ("could not free the frame\n");
639 ret = frescan_packets_free(packet);
641 FRESCAN_ERROR ("could not free the packet\n");
645 // TODO: signal semaphore for send_sync
648 frescan_data[chip->minor].last_packet = NULL;
650 ret = frescan_hw_buffer_update(chip->minor);
652 FRESCAN_ERROR("could not update hw buffer\n");
660 * frescan_hook_frame_aborted - frame frame aborted hook
662 * This function will be called by the CAN driver's IRQ handler when a frame
663 * is aborted (because another frame with higher priority is waiting). We
664 * have to requeue the frame and update the buffer.
667 static int frescan_hook_frame_aborted(const struct can_chip_t *chip)
670 frescan_packet_t *packet;
671 frescan_prio_queue_t *pqueue;
675 packet = frescan_data[chip->minor].last_packet;
677 id = frescan_id_get_field(packet->frame->id,
678 FRESCAN_FIELD_FRAG_ID);
680 DEBUG(FRESCAN_SENT_HOOK_ENABLE_DEBUG,
681 "frame aborted, minor:%u flags:0x%X frag_id:0x%X\n",
682 chip->minor, packet->flags, id);
684 if (packet->flags & FRESCAN_FP) {
685 prio = frescan_id_get_field(packet->frame->id,
688 DEBUG(FRESCAN_FRAG_ENABLE_DEBUG,
689 "requeue fp packet, prio:%u\n", prio);
691 pqueue = frescan_data[chip->minor].queues.tx_fp_queue;
692 ret = frescan_pqueue_requeue(pqueue, packet, prio);
694 FRESCAN_ERROR("could not requeue the packet\n");
697 } else if (packet->flags & FRESCAN_SS) {
698 DEBUG(FRESCAN_FRAG_ENABLE_DEBUG,
699 "requeue server %u packet\n", id);
701 ret = frescan_servers_requeue(chip->minor, id, packet);
703 FRESCAN_ERROR("could not requeue the packet\n");
707 FRESCAN_ERROR("flags are not correct\n");
711 frescan_data[chip->minor].last_packet = NULL;
713 ret = frescan_hw_buffer_update(chip->minor);
715 FRESCAN_ERROR("could not update hw buffer\n");