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
76 #include <drivers/can.h> // can_chip_t, can_frame_t
77 #include "frescan.h" // frescan_init_params_t, frescan_send_params_t
78 #include "frescan_queues.h" // init, enqueue, requeue
79 #include "frescan_data.h" // init, frescan_data
80 #include "frescan_servers.h" // init, frame_sent
81 #include "frescan_debug.h" // DEBUG
82 #include "frescan_id.h" // frescan_id_set_field, frescan_id_get_field
83 #include "frescan_hw_buffer.h" // frescan_hw_buffer_update
84 #include "frescan_packets.h"
86 static int frescan_hook_frame_recv (const struct can_chip_t *chip,
87 struct can_frame_t *frame);
89 static int frescan_hook_frame_sent(const struct can_chip_t *chip);
91 static int frescan_hook_frame_aborted(const struct can_chip_t *chip);
94 * frescan_init - initializes the network and the internal structures
96 * @params: the initialization parameters
98 * This function initializes the frescan network protocol.
100 * First it opens and configures the corresponding CAN chip device. For the
101 * CAN chip acceptance filter we use a dual filter configuration. The first
102 * filter is to set my local address address and the second one is to allow
103 * broadcast messages.
105 * Once the CAN chip is configured we call the initialization functions of
106 * the rest of modules of frescan.
110 int frescan_init(frescan_init_params_t *params)
113 char can_path[PATH_MX];
114 struct ioctl_filters_t ioctl_filters;
115 struct can_filter_t filters[2];
117 snprintf(can_path, PATH_MX, "/dev/can%u", params->net);
119 DEBUG(FRESCAN_INIT_ENABLE_DEBUG, "open %s\n", can_path);
121 fd = open (can_path, O_RDWR);
123 FRESCAN_ERROR ("could not open /dev/can%u\n", params->net);
127 DEBUG(FRESCAN_INIT_ENABLE_DEBUG, "set acceptance filters\n");
129 filters[0].mask = 0xFFFFFFFF;
130 frescan_id_set_field(&filters[0].mask, FRESCAN_FIELD_DEST,0x00);
132 frescan_id_set_field(&filters[0].code, FRESCAN_FIELD_DEST,params->node);
134 filters[1].mask = filters[0].mask;
136 frescan_id_set_field(&filters[1].code,
138 FRESCAN_BROADCAST_ADDR);
140 ioctl_filters.filters = filters;
141 ioctl_filters.len = 2;
143 ret = ioctl(fd, CAN_IOCTL_SET_FILTERS, &ioctl_filters);
145 FRESCAN_ERROR ("ioctl CAN_IOCTL_SET_FILTERS failed /dev/can%u\n",
150 DEBUG(FRESCAN_INIT_ENABLE_DEBUG, "set tx, rx, abort hooks\n");
152 ret = ioctl(fd, CAN_IOCTL_SET_TX_HOOK, frescan_hook_frame_sent);
154 FRESCAN_ERROR ("ioctl CAN_IOCTL_SET_TX_HOOK failed /dev/can%u\n",
159 ret = ioctl(fd, CAN_IOCTL_SET_RX_HOOK, frescan_hook_frame_recv);
161 FRESCAN_ERROR ("ioctl CAN_IOCTL_SET_RX_HOOK failed /dev/can%u\n",
166 ret = ioctl(fd, CAN_IOCTL_SET_AB_HOOK, frescan_hook_frame_aborted);
168 FRESCAN_ERROR ("ioctl CAN_IOCTL_SET_AB_HOOK failed /dev/can%u\n",
173 DEBUG(FRESCAN_INIT_ENABLE_DEBUG, "init the rest of modules\n");
175 ret = frescan_data_init(fd, params);
177 FRESCAN_ERROR("could not initialize the global data\n");
181 ret = frescan_packets_init();
183 FRESCAN_ERROR("could not initialize the packets pool\n");
187 ret = frescan_queues_init(&frescan_data[params->net].queues, params);
189 FRESCAN_ERROR("could not initialize the queues\n");
193 ret = frescan_servers_init(params->net);
195 FRESCAN_ERROR("could not initialize the servers\n");
203 * frescan_send - send a message
205 * @params: the parameters needed by the protocol to send the message
206 * @msg: the message buffer
207 * @size: the size of the message
209 * This is one of the main functions of the protocol and it provides the
210 * means to send a message through the protocol stack.
213 int frescan_send(const frescan_send_params_t *params,
218 frescan_packet_t *packet;
219 frescan_prio_queue_t *pqueue;
221 DEBUG(FRESCAN_SEND_ENABLE_DEBUG || FRESCAN_FRAG_ENABLE_DEBUG,
222 "checking arguments (msg size=%d)\n", size);
224 if ((params == NULL) || (msg == NULL) || (size == 0)) {
225 FRESCAN_ERROR("arguments are not ok\n");
229 DEBUG(FRESCAN_SEND_ENABLE_DEBUG, "allocating a packet\n");
231 FRESCAN_ACQUIRE_LOCK(&frescan_data[params->net].lock);
232 packet = frescan_packets_alloc();
233 FRESCAN_RELEASE_LOCK(&frescan_data[params->net].lock);
235 if (packet == NULL) {
236 FRESCAN_ERROR("could not allocate packet\n");
239 packet->flags = params->flags; // set the flags (to remember them)
241 DEBUG(FRESCAN_SEND_ENABLE_DEBUG, "allocating a frame\n");
243 FRESCAN_ACQUIRE_LOCK(&frescan_data[params->net].lock);
244 packet->frame = can_framespool_alloc();
245 FRESCAN_RELEASE_LOCK(&frescan_data[params->net].lock);
247 if (packet->frame == NULL) {
248 FRESCAN_ERROR("could not allocate frame\n");
252 DEBUG(FRESCAN_SEND_ENABLE_DEBUG, "set values for the frame header\n");
253 packet->frame->is_extended_format = true;
254 packet->frame->is_rtr = false;
256 if (params->flags & FRESCAN_FP) {
257 // NOTE: frag id for fp is: FRESCAN_MX_IDS, so the servers can
258 // have IDs in the range (0 .. FRESCAN_MX_IDS-1)
259 frescan_id_set_field(&packet->frame->id,
260 FRESCAN_FIELD_FRAG_ID,
261 (uint32_t)FRESCAN_MX_IDS);
263 frescan_id_set_field(&packet->frame->id,
265 (uint32_t)params->prio);
267 // NOTE: the priority is put when the packet is dequeued
268 // and it is the priority of th server
269 frescan_id_set_field(&packet->frame->id,
270 FRESCAN_FIELD_FRAG_ID,
271 (uint32_t)params->ss);
274 frescan_id_set_field(&packet->frame->id,
276 (uint32_t)params->to);
278 frescan_id_set_field(&packet->frame->id,
280 (uint32_t)frescan_data[params->net].local_node);
282 frescan_id_set_field(&packet->frame->id,
284 (uint32_t)params->channel);
286 DEBUG(FRESCAN_SEND_ENABLE_DEBUG, "set the packet data bytes\n");
287 if (params->flags & FRESCAN_ASYNC) {
288 // allocate a buffer and copy the data
289 // NOTE: instead of this we could use a chain of frames but
290 // i think it would be inefficient since each one can only
291 // hold 8 user bytes and we need to write its headers.
292 FRESCAN_ACQUIRE_LOCK(&frescan_data[params->net].lock);
293 packet->buffer_head = (uint8_t *)malloc(size*sizeof(uint8_t)); // TODO: FREE IT!!!
294 FRESCAN_RELEASE_LOCK(&frescan_data[params->net].lock);
295 memcpy(packet->buffer_head, msg, size);
297 packet->buffer_head = (uint8_t *)msg;
300 packet->buffer_read_pointer = packet->buffer_head;
301 packet->buffer_pending_bytes = size;
302 pqueue = frescan_data[params->net].queues.tx_fp_queue;
304 DEBUG(FRESCAN_SEND_ENABLE_DEBUG, "enqueue the packet\n");
305 if (packet->flags & FRESCAN_FP) {
306 FRESCAN_ACQUIRE_LOCK(&frescan_data[params->net].lock);
307 ret = frescan_pqueue_enqueue(pqueue, packet, params->prio);
308 FRESCAN_RELEASE_LOCK(&frescan_data[params->net].lock);
311 FRESCAN_ERROR("could not enqueue the packet\n");
315 FRESCAN_ACQUIRE_LOCK(&frescan_data[params->net].lock);
316 ret = frescan_servers_enqueue(params->net, params->ss, packet);
317 FRESCAN_RELEASE_LOCK(&frescan_data[params->net].lock);
320 FRESCAN_ERROR("could not enqueue the packet\n");
325 FRESCAN_ACQUIRE_LOCK(&frescan_data[params->net].lock);
326 ret = frescan_hw_buffer_update(params->net);
327 FRESCAN_RELEASE_LOCK(&frescan_data[params->net].lock);
330 FRESCAN_ERROR("could not update hw buffer\n");
338 * frescan_recv - receive a message
340 * @params: the parameters needed by the protocol to receive the message
341 * @msg: the message buffer
342 * @size: the size of the message buffer
343 * @recv_bytes: the number of bytes received
344 * @from: the node that sent the message
345 * @prio: the priority of the message
347 * This is one of the main functions of the protocol and it provides the
348 * means to receive a message through the protocol stack.
351 int frescan_recv(const frescan_recv_params_t *params,
355 frescan_node_t *from,
356 frescan_prio_t *prio)
359 frescan_prio_queue_t *pqueue;
361 frescan_packet_t *head, *packet;
363 if (params->flags & FRESCAN_SYNC) {
364 DEBUG(FRESCAN_RECV_ENABLE_DEBUG,
365 "receive a packet in blocking mode\n");
368 DEBUG(FRESCAN_RECV_ENABLE_DEBUG,
369 "receive a packet in non-blocking mode\n");
373 pqueue = frescan_data[params->net].queues.rx_channel_queues
376 ret = frescan_pqueue_dequeue(pqueue, &head, prio, blocking);
378 FRESCAN_ERROR ("could not dequeue packet\n");
383 if (blocking == false) {
384 DEBUG(FRESCAN_RECV_ENABLE_DEBUG,
385 "blocking false, no packets\n");
389 FRESCAN_ERROR ("blocking true, and packet = null\n");
394 DEBUG(FRESCAN_RECV_ENABLE_DEBUG,
395 "traverse the list of packets for this message\n");
399 FRESCAN_ACQUIRE_LOCK(&frescan_data[params->net].lock);
401 list_for_each_entry(packet, &head->msg_list, msg_list) {
402 // TODO: memory checks, delete the packets
403 memcpy(msg + *recv_bytes,
406 *recv_bytes += packet->frame->dlc;
408 *from = (frescan_node_t)frescan_id_get_field(packet->frame->id,
410 DEBUG(FRESCAN_RECV_ENABLE_DEBUG,
411 "ID Packet, dlc: %u, frame pool pos: %u, from:%u\n",
412 packet->frame->dlc, packet->frame->pool_pos, *from);
414 ret = can_framespool_free(packet->frame);
416 FRESCAN_ERROR("could not free frame\n");
420 ret = frescan_packets_free(packet);
422 FRESCAN_ERROR("could not free packet\n");
427 ret = frescan_packets_free(head);
429 FRESCAN_RELEASE_LOCK(&frescan_data[params->net].lock);
432 FRESCAN_ERROR("could not free head packet\n");
436 DEBUG(FRESCAN_RECV_ENABLE_DEBUG,
437 "received bytes: %u\n", *recv_bytes);
444 * frescan_hook_frame_recv - frame received hook
446 * This function will be called by the CAN driver's IRQ handler when a frame
447 * is received so we can store it in an appropiate queue.
449 * NOTE: in the future it could consist simply of signaling a semaphore to
450 * let a bottom half thread do the hard work.
454 static int frescan_hook_frame_recv (const struct can_chip_t *chip,
455 struct can_frame_t *frame)
458 uint32_t prio, dest, src, channel, frag_id, frag_flag;
459 frescan_packet_t *packet, *head;
460 frescan_prio_queue_t *pqueue;
465 DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG, "received a frame, net=%d\n", net);
466 DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG || FRESCAN_FRAG_ENABLE_DEBUG,
467 "%s %s, id=0x%X, dlc=%u, pool:%u\n",
468 (frame->is_extended_format) ? "Ext" : "Stnd",
469 (frame->is_rtr) ? "RTR Frame" : "DATA Frame",
474 for (i=0; i<frame->dlc; i++) {
475 DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG,
476 "data[%d] = 0x%X;\n", i, frame->data[i]);
479 prio = frescan_id_get_field(frame->id, FRESCAN_FIELD_PRIO);
480 dest = frescan_id_get_field(frame->id, FRESCAN_FIELD_DEST);
481 src = frescan_id_get_field(frame->id, FRESCAN_FIELD_SRC);
482 channel = frescan_id_get_field(frame->id, FRESCAN_FIELD_CHAN);
483 frag_id = frescan_id_get_field(frame->id, FRESCAN_FIELD_FRAG_ID);
484 frag_flag = frescan_id_get_field(frame->id, FRESCAN_FIELD_FRAG_FLAG);
486 DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG || FRESCAN_FRAG_ENABLE_DEBUG,
487 "prio:%u dest:%u src:%u chan:%u id:%u flag:%u\n",
488 prio, dest, src, channel, frag_id, frag_flag);
490 DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG,
491 "enqueue the packet in ID queue\n");
492 packet = frescan_packets_alloc();
493 packet->frame = frame;
495 if (frag_id == FRESCAN_MX_IDS) {
496 head = frescan_data[net].id_fp_queues[src][prio];
498 head = frescan_data[net].id_queues[src][frag_id];
502 DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG ||
503 FRESCAN_FRAG_ENABLE_DEBUG,
504 "allocate head for id=%u\n", frag_id);
505 head = frescan_packets_alloc();
506 INIT_LIST_HEAD(&head->msg_list);
508 if (frag_id == FRESCAN_MX_IDS) {
509 frescan_data[net].id_fp_queues[src][prio] = head;
511 frescan_data[net].id_queues[src][frag_id] = head;
515 list_add_tail(&packet->msg_list, &head->msg_list);
517 if (frag_flag == false) {
518 DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG ||
519 FRESCAN_FRAG_ENABLE_DEBUG,
520 "message complete, move msg to channel\n");
521 // TODO: select the highest priority??
522 pqueue = frescan_data[net].queues.rx_channel_queues[channel];
523 ret = frescan_pqueue_enqueue(pqueue, head, prio);
525 FRESCAN_ERROR("could not enqueue message in channel queue\n");
529 if (frag_id == FRESCAN_MX_IDS) {
530 frescan_data[net].id_fp_queues[src][prio] = NULL;
532 frescan_data[net].id_queues[src][frag_id] = NULL;
536 DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG ||
537 FRESCAN_FRAG_ENABLE_DEBUG,
538 "message not complete, wait for more fragments\n");
541 // NOTE: don't forget to free the frame and the packet when it is
542 // read by the user application
548 * frescan_hook_frame_sent - frame sent hook
550 * This function will be called by the CAN driver's IRQ handler when a frame
551 * is sent through the CAN bus so we can enqueue another one, signal a
552 * semaphore, consume sporadic server capacity...
555 static int frescan_hook_frame_sent(const struct can_chip_t *chip)
558 frescan_packet_t *packet;
559 frescan_prio_queue_t *pqueue;
563 packet = frescan_data[chip->minor].last_packet;
564 assert(packet != NULL);
566 id = frescan_id_get_field(packet->frame->id,
567 FRESCAN_FIELD_FRAG_ID);
569 DEBUG(FRESCAN_SENT_HOOK_ENABLE_DEBUG,
570 "frame sent, minor:%u flags:0x%X frag_id:0x%X\n",
571 chip->minor, packet->flags, id);
573 if (packet->flags & FRESCAN_SS) {
574 DEBUG(FRESCAN_SENT_HOOK_ENABLE_DEBUG,
575 "calling frame_sent + program repl for id:%u\n", id);
577 ret = frescan_servers_frame_sent(chip->minor, id, packet);
579 FRESCAN_ERROR("could not let the server a frame was sent\n");
584 DEBUG(FRESCAN_SENT_HOOK_ENABLE_DEBUG || FRESCAN_FRAG_ENABLE_DEBUG,
585 "last packet buffer_pending_bytes=%u\n",
586 packet->buffer_pending_bytes);
588 if (packet->buffer_pending_bytes > 0) {
589 if (packet->flags & FRESCAN_FP) {
590 prio = frescan_id_get_field(packet->frame->id,
593 DEBUG(FRESCAN_FRAG_ENABLE_DEBUG,
594 "requeue fp packet, prio:%u\n", prio);
596 pqueue = frescan_data[chip->minor].queues.tx_fp_queue;
597 ret = frescan_pqueue_requeue(pqueue, packet, prio);
599 FRESCAN_ERROR("could not requeue the packet packet:%p flags:0x%X\n", packet, packet->flags);
602 } else if (packet->flags & FRESCAN_SS) {
603 DEBUG(FRESCAN_FRAG_ENABLE_DEBUG,
604 "requeue server %u packet\n", id);
605 ret = frescan_servers_requeue(chip->minor, id, packet);
607 FRESCAN_ERROR("could not requeue the packet\n");
611 FRESCAN_ERROR("flags are not correct\n");
615 DEBUG(FRESCAN_FRAG_ENABLE_DEBUG,
616 "all packet fragmets sent, freeing the packet\n");
618 ret = can_framespool_free(packet->frame);
620 FRESCAN_ERROR ("could not free the frame\n");
624 ret = frescan_packets_free(packet);
626 FRESCAN_ERROR ("could not free the packet\n");
630 // TODO: signal semaphore for send_sync
633 frescan_data[chip->minor].last_packet = NULL;
635 ret = frescan_hw_buffer_update(chip->minor);
637 FRESCAN_ERROR("could not update hw buffer\n");
645 * frescan_hook_frame_aborted - frame frame aborted hook
647 * This function will be called by the CAN driver's IRQ handler when a frame
648 * is aborted (because another frame with higher priority is waiting). We
649 * have to requeue the frame and update the buffer.
652 static int frescan_hook_frame_aborted(const struct can_chip_t *chip)
655 frescan_packet_t *packet;
656 frescan_prio_queue_t *pqueue;
660 packet = frescan_data[chip->minor].last_packet;
662 id = frescan_id_get_field(packet->frame->id,
663 FRESCAN_FIELD_FRAG_ID);
665 DEBUG(FRESCAN_SENT_HOOK_ENABLE_DEBUG,
666 "frame aborted, minor:%u flags:0x%X frag_id:0x%X\n",
667 chip->minor, packet->flags, id);
669 if (packet->flags & FRESCAN_FP) {
670 prio = frescan_id_get_field(packet->frame->id,
673 DEBUG(FRESCAN_FRAG_ENABLE_DEBUG,
674 "requeue fp packet, prio:%u\n", prio);
676 pqueue = frescan_data[chip->minor].queues.tx_fp_queue;
677 ret = frescan_pqueue_requeue(pqueue, packet, prio);
679 FRESCAN_ERROR("could not requeue the packet\n");
682 } else if (packet->flags & FRESCAN_SS) {
683 DEBUG(FRESCAN_FRAG_ENABLE_DEBUG,
684 "requeue server %u packet\n", id);
686 ret = frescan_servers_requeue(chip->minor, id, packet);
688 FRESCAN_ERROR("could not requeue the packet\n");
692 FRESCAN_ERROR("flags are not correct\n");
696 frescan_data[chip->minor].last_packet = NULL;
698 ret = frescan_hw_buffer_update(chip->minor);
700 FRESCAN_ERROR("could not update hw buffer\n");