]> rtime.felk.cvut.cz Git - frescor/fna.git/commitdiff
added frescan sources
authorsangorrin <sangorrin@35b4ef3e-fd22-0410-ab77-dab3279adceb>
Mon, 31 Mar 2008 10:24:03 +0000 (10:24 +0000)
committersangorrin <sangorrin@35b4ef3e-fd22-0410-ab77-dab3279adceb>
Mon, 31 Mar 2008 10:24:03 +0000 (10:24 +0000)
git-svn-id: http://www.frescor.org/private/svn/frescor/fna/trunk@1051 35b4ef3e-fd22-0410-ab77-dab3279adceb

23 files changed:
src_frescan/Makefile [new file with mode: 0644]
src_frescan/README [new file with mode: 0644]
src_frescan/frescan.c [new file with mode: 0644]
src_frescan/frescan_config.h [new file with mode: 0644]
src_frescan/frescan_data.c [new file with mode: 0644]
src_frescan/frescan_data.h [new file with mode: 0644]
src_frescan/frescan_debug.h [new file with mode: 0644]
src_frescan/frescan_hw_buffer.c [new file with mode: 0644]
src_frescan/frescan_hw_buffer.h [new file with mode: 0644]
src_frescan/frescan_id.c [new file with mode: 0644]
src_frescan/frescan_id.h [new file with mode: 0644]
src_frescan/frescan_packets.c [new file with mode: 0644]
src_frescan/frescan_packets.h [new file with mode: 0644]
src_frescan/frescan_queues.c [new file with mode: 0644]
src_frescan/frescan_queues.h [new file with mode: 0644]
src_frescan/frescan_servers.c [new file with mode: 0644]
src_frescan/frescan_servers.h [new file with mode: 0644]
src_frescan/frescan_servers_replenishments.c [new file with mode: 0644]
src_frescan/frescan_servers_replenishments.h [new file with mode: 0644]
src_frescan/test_frescan_init.c [new file with mode: 0644]
src_frescan/test_frescan_queues.c [new file with mode: 0644]
src_frescan/test_frescan_send_basic.c [new file with mode: 0644]
src_frescan/test_frescan_servers_send_basic.c [new file with mode: 0644]

diff --git a/src_frescan/Makefile b/src_frescan/Makefile
new file mode 100644 (file)
index 0000000..f2fed04
--- /dev/null
@@ -0,0 +1,27 @@
+.PHONY: none frescan clean cleanall
+
+include ../config.mk
+include ../rules.mk
+
+CC = mgcc
+CFLAGS = -g -Wall
+LDFLAGS = -L./ -lfrescan
+
+SRCS := $(wildcard *.c)
+OBJS := $(patsubst %.c,%.o,$(wildcard *.c))
+HDRS := $(wildcard *.h)
+
+frescan:  $(OBJS)
+       @exec echo -e "\n>> Generating libfrescan.a.. [OK]";
+       ar -rc libfrescan.a *.o
+
+%.o: %.c $(SRCS) $(HDRS)
+       @$(CC) $(CFLAGS) -c $< # 1> /dev/null
+
+%.exe: %.c
+       @exec echo -e "\n>> Building $@: ";
+       @if [ -f $< ]; \
+       then \
+               $(CC) $(CFLAGS) $< $(LDFLAGS) -o $@; \
+       fi;
+       @exec echo ">> End Building $@";
diff --git a/src_frescan/README b/src_frescan/README
new file mode 100644 (file)
index 0000000..ad9ff38
--- /dev/null
@@ -0,0 +1,25 @@
+
+                     FRESCAN protocol
+                    ==================
+                    by Daniel Sangorrin
+
+1. Introduction
+===============
+
+This folder contains the implementation of the FRESCAN protocol. The design,
+arquitecture and description of the FRESCAN protocol is explained in the
+FRESCOR D-ND1 deliverable about Fieldbus systems. The protocol is based on
+the CAN bus, and it includes support for prioritized task-oriented message
+communication either with fixed priorities or sporadic servers.
+
+2. Requirements
+===============
+
+MaRTE OS with the CAN driver bus installed.
+
+3. Support
+==========
+
+The protocol implementation does not have official support, it is distributed
+as it is without any warranty and the license is the same as MaRTE OS license.
+You can ask any question in the MaRTE OS Website forum.
diff --git a/src_frescan/frescan.c b/src_frescan/frescan.c
new file mode 100644 (file)
index 0000000..ae6134d
--- /dev/null
@@ -0,0 +1,597 @@
+/*!
+ * @file frescan.c
+ *
+ * @brief the FRESCAN protocol
+ *
+ * @version 0.01
+ *
+ * @date 20-Feb-2008
+ *
+ * @author
+ *      Daniel Sangorrin
+ *
+ * @comments
+ *
+ * This file contains the implementation of the FRESCAN protocol
+ *
+ * @license
+ *
+ * See MaRTE OS license
+ *
+ */
+
+#include <sys/marte_configuration_parameters.h> // PATH_MX
+#include <fcntl.h>  // open
+#include <unistd.h> // ioctl
+#include <stdlib.h> // malloc
+#include <string.h> // memcpy
+
+#include <drivers/can.h>       // can_chip_t, can_frame_t
+#include <drivers/frescan.h>   // frescan_init_params_t, frescan_send_params_t
+#include "frescan_queues.h"    // init, enqueue, requeue
+#include "frescan_data.h"      // init, the_networks
+#include "frescan_servers.h"   // init, frame_sent
+#include "frescan_debug.h"     // DEBUG
+#include "frescan_id.h"        // frescan_id_set_field, frescan_id_get_field
+#include "frescan_hw_buffer.h" // frescan_hw_buffer_update
+#include "frescan_servers_replenishments.h" // frescan_replenishments_xxx
+
+static int frescan_hook_frame_recv (const struct can_chip_t *chip,
+                                    struct can_frame_t *frame);
+
+static int frescan_hook_frame_sent(const struct can_chip_t *chip);
+
+/**
+ * frescan_init - initializes the network and the internal structures
+ *
+ * @params: the initialization parameters
+ *
+ * This function initializes the frescan network protocol.
+ *
+ * First it opens and configures the corresponding CAN chip device. For the
+ * CAN chip acceptance filter we use a dual filter configuration. The first
+ * filter is to set my local address address and the second one is to allow
+ * broadcast messages.
+ *
+ * Once the CAN chip is configured we call the initialization functions of
+ * the rest of modules of frescan.
+ *
+ */
+
+int frescan_init(frescan_init_params_t *params)
+{
+        int fd, ret;
+        char can_path[PATH_MX];
+        struct ioctl_filters_t ioctl_filters;
+        struct can_filter_t filters[2];
+
+        snprintf(can_path, PATH_MX, "/dev/can%u", params->net);
+
+        DEBUG(FRESCAN_INIT_ENABLE_DEBUG, "open %s\n", can_path);
+
+        fd = open (can_path, O_RDWR);
+        if (fd == -1) {
+                ERROR ("could not open /dev/can%u\n", params->net);
+                return -1;
+        }
+
+        DEBUG(FRESCAN_INIT_ENABLE_DEBUG, "set acceptance filters\n");
+
+        filters[0].mask = 0xFFFFFFFF;
+        frescan_id_set_field(&filters[0].mask, FRESCAN_FIELD_DEST,0x00);
+        filters[0].code = 0;
+        frescan_id_set_field(&filters[0].code, FRESCAN_FIELD_DEST,params->node);
+
+        filters[1].mask = filters[0].mask;
+        filters[1].code = 0;
+        frescan_id_set_field(&filters[1].code,
+                             FRESCAN_FIELD_DEST,
+                             FRESCAN_BROADCAST_ADDR);
+
+        ioctl_filters.filters = filters;
+        ioctl_filters.len = 2;
+
+        ret = ioctl(fd, CAN_IOCTL_SET_FILTERS, &ioctl_filters);
+        if (ret == -1) {
+                ERROR ("ioctl CAN_IOCTL_SET_FILTERS failed /dev/can%u\n",
+                       params->net);
+                return -1;
+        }
+
+        DEBUG(FRESCAN_INIT_ENABLE_DEBUG, "set tx and rx hooks\n");
+
+        ret = ioctl(fd, CAN_IOCTL_SET_TX_HOOK, frescan_hook_frame_sent);
+        if (ret == -1) {
+                ERROR ("ioctl CAN_IOCTL_SET_TX_HOOK failed /dev/can%u\n",
+                       params->net);
+                return -1;
+        }
+
+        ret = ioctl(fd, CAN_IOCTL_SET_RX_HOOK, frescan_hook_frame_recv);
+        if (ret == -1) {
+                ERROR ("ioctl CAN_IOCTL_SET_RX_HOOK failed /dev/can%u\n",
+                       params->net);
+                return -1;
+        }
+
+        DEBUG(FRESCAN_INIT_ENABLE_DEBUG, "init the rest of modules\n");
+
+        ret = frescan_data_init(fd, params);
+        if (ret != 0) {
+                ERROR("could not initialize the global data\n");
+                return -1;
+        }
+
+        ret = frescan_packets_init();
+        if (ret != 0) {
+                ERROR("could not initialize the packets pool\n");
+                return -1;
+        }
+
+        ret = frescan_queues_init(&the_networks[params->net].queues, params);
+        if (ret != 0) {
+                ERROR("could not initialize the queues\n");
+                return -1;
+        }
+
+        ret = frescan_servers_init(params->net);
+        if (ret != 0) {
+                ERROR("could not initialize the servers\n");
+                return -1;
+        }
+
+        ret = frescan_replenishments_init(params->net);
+        if (ret != 0) {
+                ERROR("could not initialize the replenishments\n");
+                return -1;
+        }
+
+        return 0;
+}
+
+/**
+ * frescan_send - send a message
+ *
+ * @params: the parameters needed by the protocol to send the message
+ * @msg: the message buffer
+ * @size: the size of the message
+ *
+ * This is one of the main functions of the protocol and it provides the
+ * means to send a message through the protocol stack.
+ */
+
+int frescan_send(const frescan_send_params_t *params,
+                 const uint8_t *msg,
+                 const size_t size)
+{
+        int ret;
+        frescan_packet_t *packet;
+        frescan_prio_queue_t *pqueue;
+
+        DEBUG(FRESCAN_SEND_ENABLE_DEBUG || FRESCAN_FRAG_ENABLE_DEBUG,
+              "checking arguments (msg size=%d)\n", size);
+
+        if ((params == NULL) || (msg == NULL) || (size == 0)) {
+                ERROR("arguments are not ok\n");
+                return -1;
+        }
+
+        DEBUG(FRESCAN_SEND_ENABLE_DEBUG, "allocating a packet\n");
+
+        FRESCAN_ACQUIRE_LOCK(&the_networks[params->net].lock);
+        packet = frescan_packets_alloc();
+        FRESCAN_RELEASE_LOCK(&the_networks[params->net].lock);
+
+        if (packet == NULL) {
+                ERROR("could not allocate packet\n");
+                return -1;
+        }
+        packet->flags = params->flags; // set the flags (to remember them)
+
+        DEBUG(FRESCAN_SEND_ENABLE_DEBUG, "allocating a frame\n");
+
+        FRESCAN_ACQUIRE_LOCK(&the_networks[params->net].lock);
+        packet->frame = can_framespool_alloc();
+        FRESCAN_RELEASE_LOCK(&the_networks[params->net].lock);
+
+        if (packet->frame == NULL) {
+                ERROR("could not allocate frame\n");
+                return -1;
+        }
+
+        DEBUG(FRESCAN_SEND_ENABLE_DEBUG, "set values for the frame header\n");
+        packet->frame->is_extended_format = true;
+        packet->frame->is_rtr = false;
+
+        if (params->flags & FRESCAN_FP) {
+                // NOTE: frag id for fp is: FRESCAN_MX_IDS, so the servers can
+                // have IDs in the range (0 .. FRESCAN_MX_IDS-1)
+                frescan_id_set_field(&packet->frame->id,
+                                     FRESCAN_FIELD_FRAG_ID,
+                                     (uint32_t)FRESCAN_MX_IDS);
+
+                frescan_id_set_field(&packet->frame->id,
+                                      FRESCAN_FIELD_PRIO,
+                                      (uint32_t)params->prio);
+        } else {
+                // NOTE: the priority is put when the packet is dequeued
+                // and it is the priority of th server
+                frescan_id_set_field(&packet->frame->id,
+                                     FRESCAN_FIELD_FRAG_ID,
+                                     (uint32_t)params->ss);
+        }
+
+        frescan_id_set_field(&packet->frame->id,
+                             FRESCAN_FIELD_DEST,
+                             (uint32_t)params->to);
+
+        frescan_id_set_field(&packet->frame->id,
+                             FRESCAN_FIELD_SRC,
+                             (uint32_t)the_networks[params->net].local_node);
+
+        frescan_id_set_field(&packet->frame->id,
+                              FRESCAN_FIELD_CHAN,
+                              (uint32_t)params->channel);
+
+        DEBUG(FRESCAN_SEND_ENABLE_DEBUG, "set the packet data bytes\n");
+        if (params->flags & FRESCAN_ASYNC) {
+                // allocate a buffer and copy the data
+                // NOTE: instead of this we could use a chain of frames but
+                // i think it would be inefficient since each one can only
+                // hold 8 user bytes and we need to write its headers.
+                packet->buffer_head = (uint8_t *)malloc(size*sizeof(uint8_t));
+                memcpy(packet->buffer_head, msg, size);
+        } else {
+                packet->buffer_head = (uint8_t *)msg;
+        }
+
+        packet->buffer_read_pointer = packet->buffer_head;
+        packet->buffer_pending_bytes = size;
+        pqueue = the_networks[params->net].queues.tx_fp_queue;
+
+        DEBUG(FRESCAN_SEND_ENABLE_DEBUG, "enqueue the packet\n");
+        if (packet->flags & FRESCAN_FP) {
+                FRESCAN_ACQUIRE_LOCK(&the_networks[params->net].lock);
+                ret = frescan_pqueue_enqueue(pqueue, packet, params->prio);
+                FRESCAN_RELEASE_LOCK(&the_networks[params->net].lock);
+
+                if (ret != 0) {
+                        ERROR("could not enqueue the packet\n");
+                        return -1;
+                }
+        } else {
+                FRESCAN_ACQUIRE_LOCK(&the_networks[params->net].lock);
+                ret = frescan_servers_enqueue(params->net, params->ss, packet);
+                FRESCAN_RELEASE_LOCK(&the_networks[params->net].lock);
+
+                if (ret != 0) {
+                        ERROR("could not enqueue the packet\n");
+                        return -1;
+                }
+        }
+
+        FRESCAN_ACQUIRE_LOCK(&the_networks[params->net].lock);
+        ret = frescan_hw_buffer_update(params->net);
+        FRESCAN_RELEASE_LOCK(&the_networks[params->net].lock);
+
+        if (ret != 0) {
+                ERROR("could not update hw buffer\n");
+                return -1;
+        }
+
+        return 0;
+}
+
+/**
+ * frescan_recv - receive a message
+ *
+ * @params: the parameters needed by the protocol to receive the message
+ * @msg: the message buffer
+ * @size: the size of the message buffer
+ * @recv_bytes: the number of bytes received
+ * @from: the node that sent the message
+ * @prio: the priority of the message
+ *
+ * This is one of the main functions of the protocol and it provides the
+ * means to receive a message through the protocol stack.
+ */
+
+int frescan_recv(const frescan_recv_params_t *params,
+                 uint8_t *msg,
+                 const size_t size,
+                 size_t *recv_bytes,
+                 frescan_node_t *from,
+                 frescan_prio_t *prio)
+{
+        int ret;
+        frescan_prio_queue_t *pqueue;
+        bool blocking;
+        frescan_packet_t *head, *packet;
+
+        if (params->flags & FRESCAN_SYNC) {
+                DEBUG(FRESCAN_RECV_ENABLE_DEBUG,
+                      "receive a packet in blocking mode\n");
+                blocking = true;
+        } else {
+                DEBUG(FRESCAN_RECV_ENABLE_DEBUG,
+                      "receive a packet in non-blocking mode\n");
+                blocking = false;
+        }
+
+        pqueue = the_networks[params->net].queues.rx_channel_queues
+                                                             [params->channel];
+
+        FRESCAN_ACQUIRE_LOCK(&the_networks[params->net].lock);
+        ret = frescan_pqueue_dequeue(pqueue, &head, prio, blocking);
+        FRESCAN_RELEASE_LOCK(&the_networks[params->net].lock);
+
+        if (ret != 0) {
+                ERROR ("could not dequeue packet\n");
+                return -1;
+        }
+
+        if (head == NULL) {
+                if (blocking == false) {
+                        DEBUG(FRESCAN_RECV_ENABLE_DEBUG,
+                              "blocking false, no packets\n");
+                        *recv_bytes = 0;
+                        return 0;
+                } else {
+                        ERROR ("blocking true, and packet = null\n");
+                        return -1;
+                }
+        }
+
+        DEBUG(FRESCAN_RECV_ENABLE_DEBUG,
+              "traverse the list of packets for this message\n");
+
+        *recv_bytes = 0;
+
+        FRESCAN_ACQUIRE_LOCK(&the_networks[params->net].lock);
+
+        list_for_each_entry(packet, &head->msg_list, msg_list) {
+                // TODO: memory checks, delete the packets
+                memcpy(msg + *recv_bytes,
+                       packet->frame->data,
+                       packet->frame->dlc);
+                *recv_bytes += packet->frame->dlc;
+
+                DEBUG(FRESCAN_RECV_ENABLE_DEBUG,
+                      "ID Packet, dlc: %u, frame pool pos: %u\n",
+                      packet->frame->dlc, packet->frame->pool_pos);
+
+                ret = can_framespool_free(packet->frame);
+                if (ret != 0) {
+                        ERROR("could not free frame\n");
+                        return -1;
+                }
+
+                ret = frescan_packets_free(packet);
+                if (ret != 0) {
+                        ERROR("could not free packet\n");
+                        return -1;
+                }
+        }
+
+        ret = frescan_packets_free(head);
+
+        FRESCAN_RELEASE_LOCK(&the_networks[params->net].lock);
+
+        if (ret != 0) {
+                ERROR("could not free head packet\n");
+                return -1;
+        }
+
+        DEBUG(FRESCAN_RECV_ENABLE_DEBUG,
+              "received bytes: %u\n", *recv_bytes);
+
+        return 0;
+}
+
+
+/**
+ * frescan_hook_frame_recv - frame received hook
+ *
+ * This function will be called by the CAN driver's IRQ handler when a frame
+ * is received so we can store it in an appropiate queue.
+ *
+ * NOTE: in the future it could consist simply of signaling a semaphore to
+ * let a bottom half thread do the hard work.
+ */
+
+
+static int frescan_hook_frame_recv (const struct can_chip_t *chip,
+                                    struct can_frame_t *frame)
+{
+        int i, ret;
+        uint32_t prio, dest, src, channel, frag_id, frag_flag;
+        frescan_packet_t *packet, *head;
+        frescan_prio_queue_t *pqueue;
+        int net;
+
+        net = chip->minor;
+
+        DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG, "received a frame, net=%d\n", net);
+        DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG || FRESCAN_FRAG_ENABLE_DEBUG,
+              "%s %s, id=0x%X, dlc=%u, pool:%u\n",
+              (frame->is_extended_format) ? "Ext" : "Stnd",
+              (frame->is_rtr) ? "RTR Frame" : "DATA Frame",
+              frame->id,
+              frame->dlc,
+              frame->pool_pos);
+
+        for (i=0; i<frame->dlc; i++) {
+                DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG,
+                      "data[%d] = 0x%X;\n", i, frame->data[i]);
+        }
+
+        prio      = frescan_id_get_field(frame->id, FRESCAN_FIELD_PRIO);
+        dest      = frescan_id_get_field(frame->id, FRESCAN_FIELD_DEST);
+        src       = frescan_id_get_field(frame->id, FRESCAN_FIELD_SRC);
+        channel   = frescan_id_get_field(frame->id, FRESCAN_FIELD_CHAN);
+        frag_id   = frescan_id_get_field(frame->id, FRESCAN_FIELD_FRAG_ID);
+        frag_flag = frescan_id_get_field(frame->id, FRESCAN_FIELD_FRAG_FLAG);
+
+        DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG || FRESCAN_FRAG_ENABLE_DEBUG,
+              "prio:%u dest:%u src:%u chan:%u id:%u flag:%u\n",
+              prio, dest, src, channel, frag_id, frag_flag);
+
+        DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG,
+              "enqueue the packet in ID queue\n");
+        packet = frescan_packets_alloc();
+        packet->frame = frame;
+
+        if (frag_id == 0) {
+                head = the_networks[net].id_fp_queues[prio];
+        } else {
+                head = the_networks[net].id_queues[frag_id];
+        }
+
+        if (head == NULL) {
+                DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG ||
+                                FRESCAN_FRAG_ENABLE_DEBUG,
+                "allocate head for id=%u\n", frag_id);
+                head = frescan_packets_alloc();
+                INIT_LIST_HEAD(&head->msg_list);
+
+                if (frag_id == 0) {
+                        the_networks[net].id_fp_queues[prio] = head;
+                } else {
+                        the_networks[net].id_queues[frag_id] = head;
+                }
+        }
+
+        list_add_tail(&packet->msg_list, &head->msg_list);
+
+        if (frag_flag == false) {
+                DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG ||
+                                FRESCAN_FRAG_ENABLE_DEBUG,
+                "message complete, move msg to channel\n");
+                // TODO: select the highest priority??
+                pqueue = the_networks[net].queues.rx_channel_queues[channel];
+                ret = frescan_pqueue_enqueue(pqueue, head, prio);
+                if (ret != 0) {
+                        ERROR("could not enqueue message in channel queue\n");
+                        return -1;
+                }
+
+                if (frag_id == 0) {
+                        the_networks[net].id_fp_queues[prio] = NULL;
+                } else {
+                        the_networks[net].id_queues[frag_id] = NULL;
+                }
+
+        } else {
+                DEBUG(FRESCAN_RX_HOOK_ENABLE_DEBUG ||
+                                FRESCAN_FRAG_ENABLE_DEBUG,
+                "message not complete, wait for more fragments\n");
+        }
+
+        // NOTE: don't forget to free the frame and the packet when it is
+        // read by the user application
+
+        return 0;
+};
+
+
+/**
+ * frescan_hook_frame_sent - frame sent hook
+ *
+ * This function will be called by the CAN driver's IRQ handler when a frame
+ * is sent through the CAN bus so we can enqueue another one, signal a
+ * semaphore, consume sporadic server capacity...
+ */
+
+static int frescan_hook_frame_sent(const struct can_chip_t *chip)
+{
+        int ret;
+        frescan_packet_t *packet;
+        frescan_prio_queue_t *pqueue;
+        frescan_prio_t prio;
+        frescan_ss_t id;
+
+        packet = the_networks[chip->minor].last_packet;
+
+        DEBUG(FRESCAN_SENT_HOOK_ENABLE_DEBUG,
+              "frame sent, minor:%u flags:0x%X\n",
+              chip->minor, packet->flags);
+
+        if (packet->flags & FRESCAN_SS) {
+                id = frescan_id_get_field(packet->frame->id,
+                                          FRESCAN_FIELD_FRAG_ID);
+
+                DEBUG(FRESCAN_SENT_HOOK_ENABLE_DEBUG,
+                      "calling frame_sent + program repl for id:%u\n", id);
+
+                ret = frescan_replenishment_program(chip->minor, id);
+                if (ret != 0) {
+                        ERROR("could not program replenishment\n");
+                        return -1;
+                }
+
+                ret = frescan_servers_frame_sent(chip->minor, id);
+                if (ret != 0) {
+                        ERROR("could not let the server a frame was sent\n");
+                        return -1;
+                }
+        }
+
+        DEBUG(FRESCAN_SENT_HOOK_ENABLE_DEBUG || FRESCAN_FRAG_ENABLE_DEBUG,
+              "last packet buffer_pending_bytes=%u\n",
+              packet->buffer_pending_bytes);
+
+        if (packet->buffer_pending_bytes > 0) {
+                if (packet->flags & FRESCAN_FP) {
+                        prio = frescan_id_get_field(packet->frame->id,
+                                        FRESCAN_FIELD_PRIO);
+
+                        DEBUG(FRESCAN_FRAG_ENABLE_DEBUG,
+                              "requeue fp packet, prio:%u\n", prio);
+
+                        pqueue = the_networks[chip->minor].queues.tx_fp_queue;
+                        ret = frescan_pqueue_requeue(pqueue, packet, prio);
+                        if (ret != 0) {
+                                ERROR("could not requeue the packet\n");
+                                return -1;
+                        }
+                } else if (packet->flags & FRESCAN_SS) {
+                        DEBUG(FRESCAN_FRAG_ENABLE_DEBUG,
+                              "requeue server %u packet\n", id);
+                        ret = frescan_servers_requeue(chip->minor, id, packet);
+                        if (ret != 0) {
+                                ERROR("could not requeue the packet\n");
+                                return -1;
+                        }
+                } else {
+                        ERROR("flags are not correct\n");
+                        return -1;
+                }
+        } else {
+                DEBUG(FRESCAN_FRAG_ENABLE_DEBUG,
+                      "all packet fragmets sent, freeing the packet\n");
+
+                ret = can_framespool_free(packet->frame);
+                if (ret != 0)  {
+                        ERROR ("could not free the frame\n");
+                        return ret;
+                }
+
+                ret = frescan_packets_free(packet);
+                if (ret != 0)  {
+                        ERROR ("could not free the packet\n");
+                        return ret;
+                }
+
+                // TODO: signal semaphores, server consume budget...
+        }
+
+        the_networks[chip->minor].last_packet = NULL;
+
+        ret = frescan_hw_buffer_update(chip->minor);
+        if (ret != 0) {
+                ERROR("could not update hw buffer\n");
+                return -1;
+        }
+
+        return 0;
+};
diff --git a/src_frescan/frescan_config.h b/src_frescan/frescan_config.h
new file mode 100644 (file)
index 0000000..f029763
--- /dev/null
@@ -0,0 +1,45 @@
+/*!
+ * @file frecan_config.h
+ *
+ * @brief constants to configure the frescan protocol
+ *
+ * @version 0.01
+ *
+ * @date 12-Mar-2008
+ *
+ * @author
+ *      Daniel Sangorrin
+ *
+ * @comments
+ *
+ * This module contains some constants and macros to configure the
+ * frescan protocol. For example, the size of the packets pool, etc...
+ *
+ * @license
+ *
+ * See MaRTE OS license
+ *
+ */
+
+#ifndef _MARTE_FRESCAN_CONFIG_H_
+#define _MARTE_FRESCAN_CONFIG_H_
+
+#include <signal.h>      // SIGRTMIN
+#include <sys/kernel.h>  // kernel_enter_critic_section
+
+#define FRESCAN_MX_REPL_OPS       100
+#define FRESCAN_MX_NETWORKS       2
+#define FRESCAN_BROADCAST_ADDR    0xF
+#define FRESCAN_MX_IDS            255
+#define FRESCAN_MX_PRIOS          32
+#define FRESCAN_REPL_SIGNAL_NUM   SIGRTMIN + 5 // real-time signal
+#define FRESCAN_BACKGROUND_PRIO   0
+#define FRESCAN_MX_REPLY_OBJECTS  40
+
+#define FRESCAN_MLOCK_T            unsigned
+#define FRESCAN_CREATE_LOCK(l)
+#define FRESCAN_DESTROY_LOCK(l)
+#define FRESCAN_ACQUIRE_LOCK(l)    kernel_enter_critic_section(l)
+#define FRESCAN_RELEASE_LOCK(l)    kernel_leave_critic_section(*(l))
+
+#endif // _MARTE_FRESCAN_CONFIG_H_
diff --git a/src_frescan/frescan_data.c b/src_frescan/frescan_data.c
new file mode 100644 (file)
index 0000000..cc063d2
--- /dev/null
@@ -0,0 +1,58 @@
+/*!
+ * @file frescan_data.c
+ *
+ * @brief global data used from different modules in frescan
+ *
+ * @version 0.01
+ *
+ * @date 12-Mar-2008
+ *
+ * @author
+ *      Daniel Sangorrin
+ *
+ * @comments
+ *
+ * In frescan_data module we store global data to FRESCAN to make the protocol
+ * easier and efficient to implement.
+ *
+ * @license
+ *
+ * See MaRTE OS license
+ *
+ */
+
+#include "frescan_data.h"
+#include "frescan_debug.h"
+
+frescan_network_data_t the_networks[FRESCAN_MX_NETWORKS];
+frescan_server_data_t the_servers_pool[FRESCAN_MX_NETWORKS][FRESCAN_MX_IDS];
+freelist_t the_servers_pool_freelist[FRESCAN_MX_NETWORKS];
+frescan_server_data_t the_active_servers[FRESCAN_MX_NETWORKS];
+
+/**
+ * frescan_data_init() - init the data global variables
+ *
+ */
+
+int frescan_data_init(int fd, frescan_init_params_t *params)
+{
+        frescan_ss_t id;
+        frescan_prio_t prio;
+
+        the_networks[params->net].fd = fd;
+        the_networks[params->net].local_node = params->node;
+        the_networks[params->net].last_packet = NULL;
+        the_networks[params->net].last_packet_prio = 0;
+
+        FRESCAN_CREATE_LOCK(&the_networks[params->net].lock);
+
+        for(id=0; id<FRESCAN_MX_IDS; id++) {
+                the_networks[params->net].id_queues[id] = NULL;
+        }
+
+        for(prio=0; prio<FRESCAN_MX_PRIOS; prio++) {
+                the_networks[params->net].id_fp_queues[prio] = NULL;
+        }
+
+        return 0;
+}
diff --git a/src_frescan/frescan_data.h b/src_frescan/frescan_data.h
new file mode 100644 (file)
index 0000000..0e78bda
--- /dev/null
@@ -0,0 +1,188 @@
+/*!
+ * @file frescan_data.h
+ *
+ * @brief global data used from different modules in frescan
+ *
+ * @version 0.01
+ *
+ * @date 12-Mar-2008
+ *
+ * @author
+ *      Daniel Sangorrin
+ *
+ * @comments
+ *
+ * In order to simplify we have a single module, frescan_data, to store the
+ * main internal structures and global data of the FRESCAN protocol.
+ *
+ * @license
+ *
+ * See MaRTE OS license
+ *
+ */
+
+#ifndef _MARTE_FRESCAN_DATA_H_
+#define _MARTE_FRESCAN_DATA_H_
+
+#include <stdint.h>    // uint32_t
+#include <semaphore.h> // sem_t
+#include <time.h>      // struct timespec, timer_t
+#include <pthread.h>   // pthread_t
+
+#include <misc/linux_list.h> // struct list_head
+#include <misc/freelist.h>   // freelist_t
+
+#include <drivers/frescan.h> // frescan_node_t, _prio_t, _budget_t
+#include "frescan_config.h"  // FRESCAN_MLOCK_T, FRESCAN_MX_XXX
+#include "frescan_packets.h" // frescan_packet_t
+#include "frescan_servers_replenishments.h" // frescan_repl_op_t
+
+/**
+ * frescan_repl_op_t - a replenishment operation
+ *
+ * @when: when the replenishment operation is programmed at
+ * @amount: number of frames to add to the current_budget
+ * @repl_list: to chain the replenishments for a certain sporadic server
+ * @pool_pos: to know how to free it from the replenishment pool
+ */
+
+typedef struct {
+        struct timespec when;
+        frescan_budget_t amount;
+        struct list_head repl_list;
+        int pool_pos;
+} frescan_repl_op_t;
+
+/**
+ * frescan_server_params_t - server parameters
+ *
+ * @budget: the budget in CAN 8-byte frames
+ * @period: the replenishment period for the server
+ * @prio: the priority for the server TODO: this should be a return value
+ */
+
+typedef struct {
+        frescan_budget_t budget;
+        struct timespec period;
+        frescan_prio_t prio;
+} frescan_server_params_t;
+
+/**
+ * frescan_server_data_t - server data
+ *
+ * @params: the fixed parameters (budget, period and priority)
+ * @current_budget: the current available capacity
+ * @current_priority: the current priority (0=background)
+ * @repl_list: the list of pending replenishment operations
+ * @repl_timer: the timer for the replenishments associated to this server
+ *     NOTE: we could use a single timer for all but for now this is simpler
+ * @packet_list: the packets enqueued on this server
+ */
+
+typedef struct {
+        frescan_server_params_t params;
+        frescan_network_t net;
+        frescan_ss_t      id;
+        frescan_budget_t  current_budget;
+        frescan_prio_t    current_priority;
+        frescan_budget_t  pending_packets;
+        frescan_repl_op_t replenishments;
+        timer_t           repl_timer;
+        frescan_packet_t  packet_list;
+        struct list_head  servers_list;
+} frescan_server_data_t;
+
+/**
+ * the_servers_pool - pool of servers structure
+ */
+
+extern frescan_server_data_t the_servers_pool[FRESCAN_MX_NETWORKS][FRESCAN_MX_IDS];
+extern freelist_t the_servers_pool_freelist[FRESCAN_MX_NETWORKS];
+extern frescan_server_data_t the_active_servers[FRESCAN_MX_NETWORKS];
+
+/**
+ * frescan_prio_queue_t - priority queue
+ *
+ * FRESCAN priority queues are implemented as an array of one 'fifo_queue' for
+ * each priority. Where the 'fifo_queues' are implemented using the
+ * 'struct list_head fifo_list;' field of each packet structure (Linux lists).
+ *
+ * So far mutual exclusion is achieved by disabling interrupts and
+ * synchronization is done using a semaphore. This is because the queues
+ * are accesed concurrently from user threads and the IRQ handler.
+ *
+ * @fifo_queues: an array of packets for each priority where each packet
+ *               is just the head of a fifo_list. The array is allocated
+ *               from the heap, using malloc, at initialization with range
+ *               0..max_prio-1
+ * @max_prio: defines the number of priorities as (0 .. max_prio - 1)
+ * @sem: semaphore used for synchronization
+ */
+
+typedef struct {
+        frescan_packet_t *fifo_queues;
+        uint32_t max_prio;
+        sem_t sem;
+} frescan_prio_queue_t;
+
+/**
+ * frescan_queues_t - the set of FRESCAN queues for each instance of a protocol
+ *
+ * @tx_fp_queue: priority queue for the fixed priority packets
+ * @rx_channel_queues: a priority queue for each receiving channel
+ *
+ * TODO: add here the sporadic server queues...
+ */
+
+typedef struct {
+        frescan_prio_queue_t *tx_fp_queue;
+        frescan_prio_queue_t **rx_channel_queues;
+        uint32_t num_rx_channels;
+} frescan_queues_t;
+
+/**
+ * frescan_network_data_t - data for each network instance
+ *
+ * @local_node: the local node id for that network. The implementation does not
+ * support several interfaces for the same network.
+ * @fd: file descriptor associated to /dev/canXX
+ * @queues: the queues of this network instance
+ * @last_packet: pointer to the last packet from which a frame was inserted
+ *               in the chip and its transmission is not complete.
+ * @last_packet_prio: prio of the packet in the buffer
+ * @id_queues: queues to store received packets while the whole message is
+ *             not complete (fragmentation). (id = 0 .. FRESCAN_MX_IDS - 1)
+ * @id_fp_queues: the same as id_queues but for fp messages, which have
+ *                id=FRESCAN_MX_IDS and are distinguised through their
+ *                priorities.
+ *
+ * the implementation can handle several FRESCAN networks at the same time
+ * in the same node, so we need a place to store its internal data. The data
+ * is allocated as an array where the index is the MINOR number (which also
+ * identifies the /dev/canx device for that network)
+ */
+
+typedef struct {
+        FRESCAN_MLOCK_T lock;
+        frescan_node_t local_node;
+        int fd;
+        pthread_t repl_thread_id;
+        frescan_queues_t queues;
+        frescan_packet_t *last_packet;
+        frescan_prio_t last_packet_prio;
+        frescan_packet_t *id_queues[FRESCAN_MX_IDS];      // TODO: alloc at init
+        frescan_packet_t *id_fp_queues[FRESCAN_MX_PRIOS]; // TODO: alloc at init
+} frescan_network_data_t;
+
+extern frescan_network_data_t the_networks[FRESCAN_MX_NETWORKS];
+
+/**
+ * frescan_data_init() - init the data global variables
+ *
+ */
+
+extern int frescan_data_init(int fd, frescan_init_params_t *params);
+
+
+
+#endif // _MARTE_FRESCAN_DATA_H_
diff --git a/src_frescan/frescan_debug.h b/src_frescan/frescan_debug.h
new file mode 100644 (file)
index 0000000..7048c89
--- /dev/null
@@ -0,0 +1,56 @@
+/*!
+ * @file frecan_debug.h
+ *
+ * @brief debuggin macros and flags for the frescan protocol
+ *
+ * @version 0.01
+ *
+ * @date 21-Feb-2008
+ *
+ * @author
+ *      Daniel Sangorrin
+ *
+ * @comments
+ *
+ * This module contains macros and flags to enable debugging in the
+ * frescan protocol for MaRTE OS
+ *
+ * @license
+ *
+ * See MaRTE OS license
+ *
+ */
+
+#ifndef _MARTE_FRESCAN_DEBUG_H_
+#define _MARTE_FRESCAN_DEBUG_H_
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+/**
+ * DEBUG macros
+ **/
+
+#define DEBUG(enable,x,args...) if(enable) printc("DEBUG (%s): " x, __func__ , ##args)
+#define ERROR(x,args...) {printe("ERROR (%s:%u): " x, __func__ , __LINE__ , ##args); exit(-1);}
+#define WARNING(x,args...) printe("WARNING (%s): " x, __func__ , ##args)
+
+/**
+ * DEBUGGING FLAGS to enable/disable debugging messages
+ **/
+
+#define FRESCAN_SERVERS_ENABLE_DEBUG false
+#define FRESCAN_PACKETPOOL_ENABLE_DEBUG false
+#define FRESCAN_FRAG_ENABLE_DEBUG false
+#define FRESCAN_INIT_ENABLE_DEBUG false
+#define FRESCAN_SEND_ENABLE_DEBUG false
+#define FRESCAN_RECV_ENABLE_DEBUG false
+#define FRESCAN_RX_HOOK_ENABLE_DEBUG false
+#define FRESCAN_SENT_HOOK_ENABLE_DEBUG false
+#define FRESCAN_QUEUES_ENABLE_DEBUG false
+#define FRESCAN_HW_BUFFER_ENABLE_DEBUG false
+#define FRESCAN_REPL_ENABLE_DEBUG false
+#define FRESCAN_REPLYOBJ_ENABLE_DEBUG true
+
+#endif // _MARTE_FRESCAN_DEBUG_H_
diff --git a/src_frescan/frescan_hw_buffer.c b/src_frescan/frescan_hw_buffer.c
new file mode 100644 (file)
index 0000000..f2996c7
--- /dev/null
@@ -0,0 +1,170 @@
+/*!
+ * @file frescan_hw_buffer.c
+ *
+ * @brief functions to manage the hw transmission buffer
+ *
+ * @version 0.01
+ *
+ * @date 12-Mar-2008
+ *
+ * @author
+ *      Daniel Sangorrin
+ *
+ * @comments
+ *
+ * This file contains the functions needed to manage the hw transmission buffer.
+ * This is needed to update the transmission buffer of the CAN chip with the
+ * message with highest priority. This could involve having to abort the
+ * frame that is currently in the buffer.
+ *
+ * @license
+ *
+ * See MaRTE OS license
+ *
+ */
+
+#include "frescan_hw_buffer.h"
+
+#include <string.h> // memcpy
+
+#include "frescan_data.h"    // the_networks
+#include "frescan_debug.h"   // DEBUG, ERROR
+#include "frescan_servers.h" // frescan_servers_get_highest_prio
+#include "frescan_queues.h"  // frescan_pqueue_xxx, frescan_servers_dequeue
+#include "frescan_id.h"      // frescan_id_set_field
+
+/**
+ * frescan_hw_buffer_abort - abort the packet in the hw tx buffer
+ *
+ * This function aborts the packet that is currently in the hw transmission
+ * buffer of the chip. It is useful to prevent priority inversion when there
+ * is another packet with highest priority waiting in the frescan queues.
+ *
+ * TODO: implement it
+ */
+
+int frescan_hw_buffer_abort(frescan_network_t net)
+{
+//         int ret;
+//
+//         ret = ioctl(the_networks[net].fd,
+//                     CAN_IOCTL_ABORT_FRAME, NULL);
+//         if (ret == -1) {
+//                 ERROR ("could not abort the frame\n");
+//                 return -1;
+//         }
+        ERROR ("NOT IMPLEMENTED\n");
+        return -1;
+}
+
+/**
+ * frescan_hw_buffer_update - update the hw tx buffer
+ *
+ * This function updates the hw tx buffer with the packet with highest
+ * priority (including fp packets and server packets).
+ *
+ * TODO: use copy of pointer
+ */
+
+int frescan_hw_buffer_update(frescan_network_t net)
+{
+        int ret;
+        bool is_frame_in_chip, is_fp_highest_prio;
+        uint32_t frag_flag;
+        frescan_packet_t *packet;
+        frescan_prio_queue_t *pqueue;
+        frescan_prio_t fprio, sprio, prio;
+        frescan_ss_t id;
+
+        ret = frescan_servers_get_highest_prio(net, &id, &sprio);
+        if (ret != 0) return ret;
+
+        pqueue = the_networks[net].queues.tx_fp_queue;
+
+        ret = frescan_pqueue_get_highest_prio(pqueue, &packet, &fprio);
+        if (ret != 0) return ret;
+
+        if ((id == FRESCAN_MX_IDS) && (packet == NULL)) {
+                DEBUG(FRESCAN_HW_BUFFER_ENABLE_DEBUG, "(ss:0 fp:0)\n");
+                return 0;
+        }
+
+        if ((id != FRESCAN_MX_IDS) && (packet == NULL)) {
+                DEBUG(FRESCAN_HW_BUFFER_ENABLE_DEBUG, "(ss:1 fp:0)\n");
+                is_fp_highest_prio = false;
+        }
+
+        if ((id == FRESCAN_MX_IDS) && (packet != NULL)) {
+                DEBUG(FRESCAN_HW_BUFFER_ENABLE_DEBUG, "(ss:0 fp:1)\n");
+                is_fp_highest_prio = true;
+        }
+
+        if ((id != FRESCAN_MX_IDS) && (packet != NULL)) {
+                DEBUG(FRESCAN_HW_BUFFER_ENABLE_DEBUG, "(ss:1 fp:1)\n");
+                is_fp_highest_prio = (fprio > sprio);
+        }
+
+        prio = (is_fp_highest_prio) ? fprio : sprio;
+        is_frame_in_chip = (the_networks[net].last_packet != NULL);
+
+        if (is_frame_in_chip &&
+           (prio > the_networks[net].last_packet_prio)) {
+                DEBUG(FRESCAN_HW_BUFFER_ENABLE_DEBUG,"abort frame\n");
+                ret = frescan_hw_buffer_abort(net);
+                if (ret != 0) {
+                        ERROR ("could not abort frame\n");
+                        return ret;
+                }
+                return 0;
+        }
+
+        if (is_fp_highest_prio) {
+                ret = frescan_pqueue_dequeue(pqueue, &packet, &prio, 0);
+                if (ret != 0) return ret;
+        } else {
+                ret = frescan_servers_dequeue(net, id, &packet, &prio);
+                if (ret != 0) return ret;
+
+                frescan_id_set_field(&packet->frame->id,
+                                      FRESCAN_FIELD_PRIO,
+                                      (uint32_t)prio);
+        }
+
+        if (packet->buffer_pending_bytes > 8) {
+                packet->frame->dlc = 8;
+        } else {
+                packet->frame->dlc = packet->buffer_pending_bytes;
+        }
+
+        memcpy(packet->frame->data,
+               packet->buffer_read_pointer,
+               packet->frame->dlc);
+
+        packet->buffer_pending_bytes -= packet->frame->dlc;
+        packet->buffer_read_pointer  += packet->frame->dlc;
+
+        frag_flag = (packet->buffer_pending_bytes > 0) ? 1 : 0;
+        frescan_id_set_field
+                        (&packet->frame->id, FRESCAN_FIELD_FRAG_FLAG, frag_flag);
+
+        the_networks[net].last_packet = packet;
+        the_networks[net].last_packet_prio = prio;
+
+        DEBUG(FRESCAN_HW_BUFFER_ENABLE_DEBUG,
+              "frame->id:0x%X pend_bytes:%u dlc:%u fflag:%u\n",
+              packet->frame->id,
+              packet->buffer_pending_bytes,
+              packet->frame->dlc,
+              frag_flag);
+
+        ret = write(the_networks[net].fd,
+                    (void *)packet->frame,
+                    sizeof(struct can_frame_t));
+
+        if (ret != sizeof(struct can_frame_t)) {
+                ERROR ("could not send frame\n");
+                return ret;
+        }
+
+        return 0;
+}
diff --git a/src_frescan/frescan_hw_buffer.h b/src_frescan/frescan_hw_buffer.h
new file mode 100644 (file)
index 0000000..f1b1b4f
--- /dev/null
@@ -0,0 +1,33 @@
+/*!
+ * @file frescan_hw_buffer.h
+ *
+ * @brief functions to manage the hw transmission buffer
+ *
+ * @version 0.01
+ *
+ * @date 12-Mar-2008
+ *
+ * @author
+ *      Daniel Sangorrin
+ *
+ * @comments
+ *
+ * This file contains the functions needed to manage the hw transmission buffer.
+ * This is needed to update the transmission buffer of the CAN chip with the
+ * message with highest priority. This could involve having to abort the
+ * frame that is currently in the buffer.
+ *
+ * @license
+ *
+ * See MaRTE OS license
+ *
+ */
+
+#ifndef _MARTE_FRESCAN_HW_BUFFER_H_
+#define _MARTE_FRESCAN_HW_BUFFER_H_
+
+#include <drivers/frescan.h>
+
+extern int frescan_hw_buffer_update(frescan_network_t net);
+
+#endif // _MARTE_FRESCAN_HW_BUFFER_H_
diff --git a/src_frescan/frescan_id.c b/src_frescan/frescan_id.c
new file mode 100644 (file)
index 0000000..5613b6f
--- /dev/null
@@ -0,0 +1,55 @@
+/*!
+ * @file frescan_id.c
+ *
+ * @brief functions to manage the fields of the FRESCAN Identifier
+ *
+ * @version 0.01
+ *
+ * @date 27-Feb-2008
+ *
+ * @author
+ *      Daniel Sangorrin
+ *
+ * @comments
+ *
+ * This file contains the functions needed to manage the fields of a
+ * FRESCAN identifier. That is, how the 29 CAN ID bits of each frame are
+ * allocated in the FRESCAN protocol. If this configuration was to
+ * be changed (for example, the bits per field or the position  of the
+ * fields inside the ID), then only these functions need to be modified
+ *
+ * @license
+ *
+ * See MaRTE OS license
+ *
+ */
+
+#include "frescan_id.h"
+
+typedef struct {
+        uint32_t bit_offset; // offset of the field in the CAN id
+        uint32_t bit_mask;   // the number of bits of the field in a mask
+} frescan_field_t;
+
+static frescan_field_t the_fields[] = {
+        {.bit_offset = 21, .bit_mask = 0xFF},
+        {.bit_offset = 17, .bit_mask = 0x0F},
+        {.bit_offset = 13, .bit_mask = 0x0F},
+        {.bit_offset =  9, .bit_mask = 0x0F},
+        {.bit_offset =  1, .bit_mask = 0xFF},
+        {.bit_offset =  0, .bit_mask = 0x01},
+};
+
+void frescan_id_set_field(uint32_t *id, uint32_t field, uint32_t value)
+{
+        frescan_field_t *f = &the_fields[field];
+
+        *id = *id & ~(f->bit_mask << f->bit_offset);
+        *id = *id | ((value & f->bit_mask) << f->bit_offset);
+}
+
+uint32_t frescan_id_get_field(uint32_t id, uint32_t field)
+{
+        frescan_field_t *f = &the_fields[field];
+        return ((id >> f->bit_offset) & f->bit_mask);
+}
diff --git a/src_frescan/frescan_id.h b/src_frescan/frescan_id.h
new file mode 100644 (file)
index 0000000..3119114
--- /dev/null
@@ -0,0 +1,51 @@
+/*!
+ * @file frescan_id.h
+ *
+ * @brief functions to manage the fields of the FRESCAN Identifier
+ *
+ * @version 0.01
+ *
+ * @date 27-Feb-2008
+ *
+ * @author
+ *      Daniel Sangorrin
+ *
+ * @comments
+ *
+ * This file contains the functions needed to manage the fields of a
+ * FRESCAN identifier. That is, how the 29 CAN ID bits of each frame are
+ * allocated in the FRESCAN protocol. If this configuration was to
+ * be changed (for example, the bits per field or the position  of the
+ * fields inside the ID), then only these functions need to be modified
+ *
+ * @license
+ *
+ * See MaRTE OS license
+ *
+ */
+
+#ifndef _MARTE_FRESCAN_ID_H_
+#define _MARTE_FRESCAN_ID_H_
+
+#include <stdint.h>  // uint32_t
+
+/**
+ *        8          4      4     4          8               1     bytes
+ * +----------------------------------------------------------------+
+ * |     prio     | dest | src | chan |     frag_id     | frag_flag |
+ * +----------------------------------------------------------------+
+ *
+ */
+
+#define FRESCAN_FIELD_PRIO      0
+#define FRESCAN_FIELD_DEST      1
+#define FRESCAN_FIELD_SRC       2
+#define FRESCAN_FIELD_CHAN      3
+#define FRESCAN_FIELD_FRAG_ID   4
+#define FRESCAN_FIELD_FRAG_FLAG 5
+
+extern void frescan_id_set_field(uint32_t *id, uint32_t field, uint32_t value);
+
+extern uint32_t frescan_id_get_field(uint32_t id, uint32_t field);
+
+#endif // _MARTE_FRESCAN_ID_H_
diff --git a/src_frescan/frescan_packets.c b/src_frescan/frescan_packets.c
new file mode 100644 (file)
index 0000000..55744b7
--- /dev/null
@@ -0,0 +1,97 @@
+/*!
+ * @file frescan_packets.h
+ *
+ * @brief FRESCAN packets definition and pool
+ *
+ * @version 0.01
+ *
+ * @date 27-Feb-2008
+ *
+ * @author
+ *      Daniel Sangorrin
+ *
+ * @comments
+ *
+ * This file contains the FRESCAN packets definition and functions to
+ * allocate and free them from a global pool of packets statically
+ * preallocated.
+ *
+ * @license
+ *
+ * See MaRTE OS license
+ *
+ */
+
+#include "frescan_packets.h"
+#include "frescan_debug.h"
+#include <misc/freelist.h>
+
+/**
+ * the_packet_pool - pool of frescan packets
+ *
+ * Like in the CAN driver, in FRESCAN we have a statically preallocated pool
+ * of packets that we will manage through a freelist in O(1) time.
+ */
+
+static frescan_packet_t the_packet_pool[FRESCAN_MX_PACKETS];
+static freelist_t the_packet_pool_freelist;
+
+#ifdef FRESCAN_PACKETPOOL_ENABLE_DEBUG
+        static int allocated_total = 0;
+#endif
+
+/**
+ * frescan_packets_init
+ *
+ * Initializes a pool of packets that will be managed internally
+ * TODO: initalization flag
+ */
+
+int frescan_packets_init() {
+        DEBUG(FRESCAN_PACKETPOOL_ENABLE_DEBUG, "initialize freelist\n");
+        return freelist_init(&the_packet_pool_freelist, FRESCAN_MX_PACKETS);
+}
+
+/**
+ * frescan_packets_alloc
+ *
+ * Allocates a frame from the pool of packets. On error it returns NULL
+ */
+
+frescan_packet_t *frescan_packets_alloc() {
+        int pos;
+
+        pos = freelist_alloc(&the_packet_pool_freelist);
+        if (pos == -1) {
+                ERROR("could not allocate packet\n");
+                return NULL;
+        }
+
+#ifdef FRESCAN_PACKETPOOL_ENABLE_DEBUG
+        allocated_total++;
+#endif
+
+        DEBUG(FRESCAN_PACKETPOOL_ENABLE_DEBUG,
+              "allocating packet, pos:%d, total:%d\n", pos, allocated_total);
+
+        the_packet_pool[pos].pool_pos = pos; // to know how to free it
+        return &the_packet_pool[pos];
+}
+
+/**
+ * frescan_packets_free
+ *
+ * Frees a frame and returns it to the pool of packets.
+ */
+
+int frescan_packets_free(frescan_packet_t *packet)
+{
+#ifdef FRESCAN_PACKETPOOL_ENABLE_DEBUG
+        allocated_total--;
+#endif
+        DEBUG(FRESCAN_PACKETPOOL_ENABLE_DEBUG,
+              "freeing packet, pos:%d, total:%d\n",
+              packet->pool_pos, allocated_total);
+
+        return freelist_free(&the_packet_pool_freelist, packet->pool_pos);
+}
diff --git a/src_frescan/frescan_packets.h b/src_frescan/frescan_packets.h
new file mode 100644 (file)
index 0000000..47a5de4
--- /dev/null
@@ -0,0 +1,110 @@
+/*!
+ * @file frescan_packets.h
+ *
+ * @brief FRESCAN packets definition and pool
+ *
+ * @version 0.01
+ *
+ * @date 27-Feb-2008
+ *
+ * @author
+ *      Daniel Sangorrin
+ *
+ * @comments
+ *
+ * This file contains the FRESCAN packets definition and functions to
+ * allocate and free them from a global pool of packets statically
+ * preallocated.
+ *
+ * @license
+ *
+ * See MaRTE OS license
+ *
+ */
+
+#ifndef _MARTE_FRESCAN_PACKETS_H_
+#define _MARTE_FRESCAN_PACKETS_H_
+
+#include <stdint.h>           // uint8_t ...
+#include <drivers/frescan.h>  // frescan_flags_t
+#include <misc/linux_list.h>  // struct list_head
+#include <drivers/can.h>      // can_frame_t
+
+/**
+ * frescan_packet_t - a frescan packet
+ *
+ * This structure is very important and it is used to store a FRESCAN packet.
+ * As we support fragmentation, a FRESCAN packet can be composed of several
+ * CAN frames. This 'frescan_packet_t' structure is used in two main cases:
+ *
+ * 1.- When we are sending data. In this case, the buffer pointers store the
+ *     real data we want to sent and we use a 'buffer_read_pointer' to know
+ *     how many bytes of the buffer we already sent. In 'frame', we store the
+ *     last sent frame (with the corresponding CAN id fields). We will have
+ *     to update the fragmentation fields as long as we send more packets.
+ *     The 'fifo_list' is used to chained frescan packets of the same priority
+ *     or that belong to the same sporadic server. Finally, 'flags', specify
+ *     if we are sending ASYNC or SYNC. If we are sending SYNC the buffer
+ *     pointers are pointing to the buffer sent by the user (zero copying),
+ *     while if we use ASYNC, a copy of the data is done to the buffer.
+ *
+ * 2.- When we are receiving data, we only use 'frame' and 'fifo_list' fields.
+ *     The IRQ handler of the chip allocates a CAN frame and calls to our hook.
+ *     We store the pointer to that frame in 'frame' and we make a chain with
+ *     frames of the same message (using the fragmentation fields). When we
+ *     have all of them, we move the packet list to the corresponding
+ *     receiving channel to wait for the user to perform a receive operation
+ *     when we will copy the data and free both the packets and the frames.
+ *
+ * @flags: to know if the packet is to be sent SYNC or ASYNC, FP or SERVER...
+ * @frame: pointer to the last sent frame or the received frame
+ * @fifo_list: list to put several packets together
+ * @msg_list: list to put packets of the same message together
+ * @buffer_head: pointer to first byte of the buffer that is going to be sent
+ * @buffer_read_pointer: pointer to the part of the buffer being read
+ * @buffer_pending_bytes: bytes waiting to be sent
+ * @pool_pos: position in the packets pool to know how to free it
+ *
+ * NOTE: the buffers could also be used on the receiving part to support
+ * sequential reads, instead of reading the whole message at once.
+ *
+ */
+
+typedef struct {
+        frescan_flags_t flags;
+        struct can_frame_t *frame;
+        struct list_head fifo_list;
+        struct list_head msg_list;
+        uint8_t *buffer_head;         // only for sending packets
+        uint8_t *buffer_read_pointer; // only for sending packets
+        uint32_t buffer_pending_bytes; // only for sending packets
+        int pool_pos;
+} frescan_packet_t;
+
+#define FRESCAN_MX_PACKETS      100
+
+/**
+ * frescan_packets_init
+ *
+ * Initializes a pool of packets that will be managed internally
+ */
+
+extern int frescan_packets_init();
+
+/**
+ * frescan_packets_alloc
+ *
+ * Allocates a frame from the pool of packets. On error it returns NULL
+ */
+
+extern frescan_packet_t *frescan_packets_alloc();
+
+/**
+ * frescan_packets_free
+ *
+ * Frees a frame and returns it to the pool of packets.
+ */
+
+extern int frescan_packets_free(frescan_packet_t *packet);
+
+#endif // _MARTE_FRESCAN_PACKETS_H_
diff --git a/src_frescan/frescan_queues.c b/src_frescan/frescan_queues.c
new file mode 100644 (file)
index 0000000..c3e2957
--- /dev/null
@@ -0,0 +1,368 @@
+/*!
+ * @file frescan_queues.c
+ *
+ * @brief FRESCAN queues to manage the packets by prio and servers
+ *
+ * @version 0.01
+ *
+ * @date 27-Feb-2008
+ *
+ * @author
+ *      Daniel Sangorrin
+ *
+ * @comments
+ *
+ * This file contains the FRESCAN queues where frescan packets are stored and
+ * managed.
+ *
+ * TODO: disable interrupts for mutual exclusion!!!
+ *
+ * @license
+ *
+ * See MaRTE OS license
+ *
+ */
+
+#include <stdlib.h>
+
+#include "frescan_queues.h"
+#include "frescan_packets.h"
+#include "frescan_debug.h"
+#include "frescan_id.h"
+
+/**
+ * frescan_pqueue_create() - creates a priority queue
+ */
+
+static inline frescan_prio_queue_t *frescan_pqueue_create(uint32_t max_prio)
+{
+        int ret, prio;
+        frescan_prio_queue_t *pq; // priority queue
+
+        pq = (frescan_prio_queue_t *)malloc(sizeof(frescan_prio_queue_t));
+        if (pq == NULL) {
+                ERROR("could not allocate memory for prio queue\n");
+                return NULL;
+        }
+
+        pq->max_prio = max_prio;
+
+        ret = sem_init (&pq->sem, 0, 0);
+        if (ret != 0) {
+                ERROR("could not init the semaphore\n");
+                free(pq);
+                return NULL;
+        }
+
+        pq->fifo_queues = (frescan_packet_t *)
+                        malloc(max_prio * sizeof(frescan_packet_t));
+
+        for(prio=0; prio<max_prio; prio++) {
+                INIT_LIST_HEAD(&(pq->fifo_queues[prio].fifo_list));
+        }
+
+        return pq;
+}
+
+/**
+ * frescan_queues_init() - initialize the queues
+ *
+ * 1.- create the transmission fixed priority queue
+ * 2.- create the rx channels and its associated priority queues
+ *
+ * TODO: when error free memory
+ */
+
+int frescan_queues_init(frescan_queues_t *queues,
+                        frescan_init_params_t *params)
+{
+        int i;
+        uint32_t max_prio;
+
+        // create transmission fixed priority queue
+        queues->tx_fp_queue = frescan_pqueue_create(params->tx_fp_max_prio);
+
+        if (queues->tx_fp_queue == NULL)  {
+                ERROR("could not allocate memory for tx fp queue\n");
+                return -1;
+        }
+
+        // create receiving channels
+        queues->rx_channel_queues = (frescan_prio_queue_t **)
+                malloc(params->rx_num_of_channels *
+                       sizeof(frescan_prio_queue_t *));
+
+        if (queues->rx_channel_queues == NULL) {
+                ERROR("could not allocate memory for receiving channels\n");
+                return -1;
+        }
+
+        queues->num_rx_channels = params->rx_num_of_channels;
+
+        // create a priority queue for each channel
+        for(i=0; i<params->rx_num_of_channels; i++) {
+
+                if (params->rx_channel_max_prio == NULL) {
+                        max_prio = params->tx_fp_max_prio;
+                } else {
+                        max_prio = params->rx_channel_max_prio[i];
+                }
+
+                queues->rx_channel_queues[i] = frescan_pqueue_create(max_prio);
+
+                if (queues->rx_channel_queues[i] == NULL)  {
+                        ERROR("could not allocate memory for rx pq %d\n", i);
+                        return -1;
+                }
+        }
+
+        return 0;
+}
+
+/**
+ * frescan_pqueue_enqueue() - enqueue a packet
+ *
+ * check the packet flags and enqueue the packet in the appropiate queue
+ */
+
+int frescan_pqueue_enqueue(frescan_prio_queue_t *pqueue,
+                           frescan_packet_t *packet,
+                           frescan_prio_t prio)
+{
+        int ret;
+
+        if (prio >= pqueue->max_prio) {
+                ERROR("priority of the packet is too high\n");
+                return -1;
+        }
+
+        DEBUG(FRESCAN_QUEUES_ENABLE_DEBUG,
+              "enqueue packet with prio %u, pending %u\n",
+              prio, packet->buffer_pending_bytes);
+
+        list_add_tail(&(packet->fifo_list),
+                      &(pqueue->fifo_queues[prio].fifo_list));
+
+        ret = sem_post(&pqueue->sem);
+        if (ret != 0) return ret;
+
+        return 0;
+}
+
+/**
+ * frescan_pqueue_requeue() - requeue a packet
+ */
+
+int frescan_pqueue_requeue(frescan_prio_queue_t *pqueue,
+                           frescan_packet_t *packet,
+                           frescan_prio_t prio)
+{
+        int ret;
+
+        if (prio >= pqueue->max_prio) {
+                ERROR("priority of the packet is too high\n");
+                return -1;
+        }
+
+        list_add(&packet->fifo_list, &(pqueue->fifo_queues[prio].fifo_list));
+
+        ret = sem_post(&pqueue->sem);
+        if (ret != 0) return ret;
+
+        return 0;
+}
+
+/**
+ * frescan_pqueue_dequeue() - dequeue the packet with highest priority
+ */
+
+int frescan_pqueue_dequeue(frescan_prio_queue_t *pqueue,
+                           frescan_packet_t **packet,
+                           frescan_prio_t *packet_prio,
+                           bool blocking)
+{
+        int prio;
+        int ret;
+        frescan_packet_t *tmp;
+        struct list_head *pos;
+
+        *packet = NULL;
+
+        if (blocking) {
+                DEBUG(FRESCAN_QUEUES_ENABLE_DEBUG, "calling sem_wait\n");
+                sem_wait(&pqueue->sem);
+        } else {
+                ret = sem_trywait (&pqueue->sem);
+                if (ret != 0) {
+                        DEBUG(FRESCAN_QUEUES_ENABLE_DEBUG,
+                              "sem_trywait was locked (no packets)\n");
+                        return 0;
+                }
+        }
+
+        DEBUG(FRESCAN_QUEUES_ENABLE_DEBUG,
+              "check priority fifo queues (max_prio=%u)\n", pqueue->max_prio);
+
+        for(prio=pqueue->max_prio-1; prio >= 0; prio--) {
+                if (!list_empty(&pqueue->fifo_queues[prio].fifo_list)) {
+                        list_for_each(pos,
+                                      &pqueue->fifo_queues[prio].fifo_list) {
+                                tmp = list_entry(pos, frescan_packet_t,
+                                                 fifo_list);
+                                break;
+                        }
+                        *packet = tmp;
+                        list_del(&tmp->fifo_list);
+                        break;
+                }
+        }
+
+        DEBUG(FRESCAN_QUEUES_ENABLE_DEBUG, "dequeued prio %u\n", prio);
+        *packet_prio = prio;
+
+        return 0;
+}
+
+/**
+ * frescan_pqueue_get_highest_prio() - returns the packet with highest prio
+ * but not extracting it from the queue.
+ */
+
+int frescan_pqueue_get_highest_prio(frescan_prio_queue_t *pqueue,
+                                    frescan_packet_t **packet,
+                                    frescan_prio_t *packet_prio)
+{
+        int prio;
+        frescan_packet_t *tmp;
+        struct list_head *pos;
+
+        *packet = NULL;
+
+        for(prio=pqueue->max_prio-1; prio >= 0; prio--) {
+                if (!list_empty(&pqueue->fifo_queues[prio].fifo_list)) {
+                        list_for_each(pos,
+                                      &pqueue->fifo_queues[prio].fifo_list) {
+                                tmp = list_entry(pos, frescan_packet_t,
+                                                 fifo_list);
+                                break;
+                        }
+                        *packet = tmp;
+                        break;
+                }
+        }
+
+        DEBUG(FRESCAN_QUEUES_ENABLE_DEBUG, "highest prio %u\n", prio);
+        *packet_prio = prio;
+
+        return 0;
+}
+
+
+/**
+ * frescan_servers_enqueue() - enqueue a packet through a server
+ *
+ * @net: the network instance
+ * @id: the identificator for the server
+ * @packet: the packet being enqueued
+ *
+ */
+
+int frescan_servers_enqueue(frescan_network_t net,
+                            frescan_ss_t id,
+                            frescan_packet_t *packet)
+{
+        DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG, "enqueue packet for id:%u\n", id);
+
+        // add the packet to the server fifo list
+        list_add_tail(&packet->fifo_list,
+                       &the_servers_pool[net][id].packet_list.fifo_list);
+
+        // if the server was inactive (no packets to send) put it active
+        // (in the active list)
+        if (the_servers_pool[net][id].pending_packets == 0) {
+                DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
+                      "server was inactive, put in the active list\n");
+                list_add_tail(&the_servers_pool[net][id].servers_list,
+                               &the_active_servers[net].servers_list);
+        }
+
+        the_servers_pool[net][id].pending_packets++;
+        return 0;
+}
+
+/**
+ * frescan_servers_requeue() - requeue a packet through a server
+ *
+ * @net: the network instance
+ * @id: the identificator for the server
+ * @packet: the packet being requeued
+ *
+ */
+
+int frescan_servers_requeue(frescan_network_t net,
+                            frescan_ss_t id,
+                            frescan_packet_t *packet)
+{
+        DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
+              "requeue packet for id:%u\n", id);
+
+        // add the packet to the server fifo list
+        list_add(&packet->fifo_list,
+                  &the_servers_pool[net][id].packet_list.fifo_list);
+
+        // if the server was inactive (no packets to send) put it active
+        // (in the active list)
+        if (the_servers_pool[net][id].pending_packets == 0) {
+                DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
+                      "server was inactive, put in the active list\n");
+                list_add(&the_servers_pool[net][id].servers_list,
+                          &the_active_servers[net].servers_list);
+        }
+
+        the_servers_pool[net][id].pending_packets++;
+        return 0;
+}
+
+/**
+ * frescan_servers_dequeue() - dequeue a packet from a server
+ *
+ * @net: the network instance
+ * @id: the identificator for the server
+ * @packet: the packet dequeued
+ * @packet_prio: the priority current of the server
+ *
+ */
+
+int frescan_servers_dequeue(frescan_network_t net,
+                            frescan_ss_t id,
+                            frescan_packet_t **packet,
+                            frescan_prio_t *packet_prio)
+{
+        struct list_head *pos;
+
+        if (list_empty(&the_servers_pool[net][id].packet_list.fifo_list)) {
+                ERROR("no packet in server %d fifo list\n", id);
+                return -1;
+        }
+
+        list_for_each(pos, &the_servers_pool[net][id].packet_list.fifo_list) {
+                *packet = list_entry(pos, frescan_packet_t, fifo_list);
+                break;
+        }
+
+        list_del(&((*packet)->fifo_list));
+        *packet_prio = the_servers_pool[net][id].current_priority;
+        the_servers_pool[net][id].pending_packets--;
+
+        if (the_servers_pool[net][id].pending_packets == 0) {
+                DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
+                      "no more packets, delete from active list\n");
+                list_del(&the_servers_pool[net][id].servers_list);
+        }
+
+        DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
+              "dequeued packet server:%u cur_prio:%u pending:%u\n",
+              id, *packet_prio, the_servers_pool[net][id].pending_packets);
+
+        return 0;
+}
diff --git a/src_frescan/frescan_queues.h b/src_frescan/frescan_queues.h
new file mode 100644 (file)
index 0000000..4227173
--- /dev/null
@@ -0,0 +1,159 @@
+/*!
+ * @file frescan_queues.h
+ *
+ * @brief FRESCAN queues to manage the packets by prio and servers
+ *
+ * @version 0.01
+ *
+ * @date 27-Feb-2008
+ *
+ * @author
+ *      Daniel Sangorrin
+ *
+ * @comments
+ *
+ * This file contains the FRESCAN queues where frescan packets are stored and
+ * managed.
+ *
+ * @license
+ *
+ * See MaRTE OS license
+ *
+ */
+
+#ifndef _MARTE_FRESCAN_QUEUES_H_
+#define _MARTE_FRESCAN_QUEUES_H_
+
+#include <stdint.h>           // uint8_t
+#include <stdbool.h>          // bool
+
+#include <drivers/frescan.h>  // frescan_prio_t
+#include "frescan_packets.h"  // frescan_packet_t
+#include "frescan_data.h"
+
+/**
+ * frescan_queues_init() - initialize the queues
+ *
+ * This function initializes the queue structures for an instance of frescan
+ * protocol. We provide different sizes and constants so, at initialization
+ * time, the structures are allocated from the heap. Note, that this approach
+ * is not conflicting with real-time systems where typically static allocation
+ * is used because we only do it at the initialization and also because we
+ * are using a real-time memory allocator. The advantage is that we have the
+ * flexibility of using different values for different instances of the
+ * protocol and that we can also supply the protocol compiled as a library.
+ *
+ * @queues: the queues structures
+ * @frescan_init_params_t: some init parameters for the queues
+ *
+ * TODO: add maximum number of packets per queue?? so far they are taken from
+ *       the same pool.
+ * TODO: add policy for overwritting
+ */
+
+int frescan_queues_init(frescan_queues_t *queues,
+                        frescan_init_params_t *params);
+
+/**
+ * frescan_pqueue_enqueue() - enqueue a packet
+ *
+ * this function enqueues a frescan_packet into the a priority queue. For the
+ * case of same priority packets they are stored at the tail, following a FIFO
+ * enqueuing policy.
+ *
+ * @pqueue: the priority queue
+ * @packet: the packet that we want to store
+ *
+ */
+
+int frescan_pqueue_enqueue(frescan_prio_queue_t *pqueue,
+                           frescan_packet_t *packet,
+                           frescan_prio_t prio);
+
+/**
+ * frescan_pqueue_requeue() - requeue a packet
+ *
+ * this function requeues a previously extracted frescan_packet. It puts
+ * the packet at the head of the fifo queue. This is useful when you abort
+ * the transmission of the packet beacuse another one with highest priority
+ * has arrived, and you still want to preserve the order in which the packets
+ * where enqueued
+ *
+ * @pqueue: the priority queue
+ * @packet: the packet that we want to store
+ *
+ */
+
+int frescan_pqueue_requeue(frescan_prio_queue_t *pqueue,
+                           frescan_packet_t *packet,
+                           frescan_prio_t prio);
+
+/**
+ * frescan_pqueue_dequeue() - dequeue the packet with highest priority
+ *
+ * @pqueue: the priority queue
+ * @packet: the packet extracted
+ * @blocking: if there are no packets we can choose to block or not. In
+ * a non-blocking mode, if there are no packets 'packet' will be NULL
+ *
+ */
+
+int frescan_pqueue_dequeue(frescan_prio_queue_t *pqueue,
+                           frescan_packet_t **packet,
+                           frescan_prio_t *packet_prio,
+                           bool blocking);
+
+/**
+ * frescan_pqueue_get_highest_prio() - returns the packet with highest prio
+ * but not extracting it from the queue.
+ *
+ * @pqueue: the priority queue
+ * @packet: the packet with highest prio (not extracted from the pqueue)
+ *
+ */
+
+int frescan_pqueue_get_highest_prio(frescan_prio_queue_t *pqueue,
+                                    frescan_packet_t **packet,
+                                    frescan_prio_t *packet_prio);
+
+/**
+ * frescan_servers_enqueue() - enqueue a packet through a server
+ *
+ * @net: the network instance
+ * @id: the identificator for the server
+ * @packet: the packet being enqueued
+ *
+ */
+
+int frescan_servers_enqueue(frescan_network_t net,
+                            frescan_ss_t id,
+                            frescan_packet_t *packet);
+
+/**
+ * frescan_servers_requeue() - requeue a packet through a server
+ *
+ * @net: the network instance
+ * @id: the identificator for the server
+ * @packet: the packet being requeued
+ *
+ */
+
+int frescan_servers_requeue(frescan_network_t net,
+                            frescan_ss_t id,
+                            frescan_packet_t *packet);
+
+/**
+ * frescan_servers_dequeue() - dequeue a packet from a server
+ *
+ * @net: the network instance
+ * @id: the identificator for the server
+ * @packet: the packet dequeued
+ *
+ */
+
+int frescan_servers_dequeue(frescan_network_t net,
+                            frescan_ss_t id,
+                            frescan_packet_t **packet,
+                            frescan_prio_t *packet_prio);
+
+#endif // _MARTE_FRESCAN_QUEUES_H_
diff --git a/src_frescan/frescan_servers.c b/src_frescan/frescan_servers.c
new file mode 100644 (file)
index 0000000..278f794
--- /dev/null
@@ -0,0 +1,271 @@
+/*!
+ * @file frescan_servers.c
+ *
+ * @brief FRESCAN sporadic servers
+ *
+ * @version 0.01
+ *
+ * @date 27-Feb-2008
+ *
+ * @author
+ *      Daniel Sangorrin
+ *
+ * @comments
+ *
+ * This file contains the FRESCAN sporadic servers that allow to isolate
+ * different streams of data by assigning them a budget and replenishment
+ * period.
+ *
+ * @license
+ *
+ * See MaRTE OS license
+ *
+ */
+
+#include "frescan_servers.h"
+#include "frescan_debug.h"
+#include "frescan_data.h"
+#include <misc/linux_list.h>
+#include <signal.h>
+
+/**
+ * frescan_servers_init() - initialize server structures
+ *
+ * @net: the network instance
+ */
+
+int frescan_servers_init(frescan_network_t net)
+{
+        int ret, i;
+
+        DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG, "initializing servers\n");
+
+        ret = freelist_init(&the_servers_pool_freelist[net], FRESCAN_MX_IDS);
+        if (ret != 0) return ret;
+
+        for (i=0; i<FRESCAN_MX_NETWORKS; i++) {
+                INIT_LIST_HEAD(&the_active_servers[net].servers_list);
+        }
+
+        return 0;
+}
+
+/**
+ * frescan_servers_create() - create a sporadic server
+ *
+ * @net: the network instance
+ * @params: the parameters for the server
+ * @id: the identificator for the server as a return value
+ *
+ */
+
+int frescan_servers_create(frescan_network_t net,
+                           const frescan_server_params_t *params,
+                           frescan_ss_t *id)
+{
+        int ret, pos;
+        struct sigevent evp;
+
+        pos = freelist_alloc(&the_servers_pool_freelist[net]);
+        if (pos == -1) {
+                ERROR("could not allocate servers\n");
+                return -1;
+        }
+
+        *id = (frescan_ss_t)pos;
+
+        the_servers_pool[net][*id].net = net;
+        the_servers_pool[net][*id].id  = *id;
+        the_servers_pool[net][*id].params = *params;
+        the_servers_pool[net][*id].current_budget = params->budget;
+        the_servers_pool[net][*id].current_priority = params->prio;
+        the_servers_pool[net][*id].pending_packets = 0;
+
+        INIT_LIST_HEAD(&the_servers_pool[net][*id].replenishments.repl_list);
+        INIT_LIST_HEAD(&the_servers_pool[net][*id].packet_list.fifo_list);
+
+        // the repl timer sends a signal when it expires with the server id
+        evp.sigev_notify = SIGEV_SIGNAL;
+        evp.sigev_signo  = FRESCAN_REPL_SIGNAL_NUM;
+        evp.sigev_value.sival_int  = (int)*id;
+
+        ret = timer_create (CLOCK_MONOTONIC,
+                            &evp, &the_servers_pool[net][*id].repl_timer);
+        if (ret != 0) {
+                ERROR("could not create timer\n");
+                return ret;
+        }
+
+        DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
+              "server created, id:%u budget:%u prio:%u\n",
+              *id,
+              the_servers_pool[net][*id].params.budget,
+              the_servers_pool[net][*id].params.prio);
+
+        return 0;
+}
+
+/**
+ * frescan_servers_update() - update a sporadic server data
+ *
+ * @net: the network instance
+ * @params: the parameters for the server
+ * @id: the identificator for the server
+ *
+ */
+
+int frescan_servers_update(frescan_network_t net,
+                           const frescan_server_params_t *params,
+                           frescan_ss_t id)
+{
+        the_servers_pool[net][id].params = *params;
+        return 0;
+}
+
+/**
+ * frescan_servers_destroy() - delete a sporadic server
+ *
+ * @net: the network instance
+ * @id: the identificator for the server
+ *
+ */
+
+int frescan_servers_destroy(frescan_network_t net, frescan_ss_t id)
+{
+        int ret;
+
+        // TODO: free the replenishment operations and the packets for the
+        // server.
+
+        ret = timer_delete (the_servers_pool[net][id].repl_timer);
+        if (ret != 0) {
+                ERROR("could not delete timer\n");
+                return ret;
+        }
+
+        list_del(&the_servers_pool[net][id].servers_list);
+
+        ret = freelist_free(&the_servers_pool_freelist[net], id);
+        if (ret != 0) {
+                ERROR("could not free server data from pool\n");
+                return ret;
+        }
+
+        return 0;
+}
+
+/**
+ * frescan_servers_get_data() - get a sporadic server data
+ *
+ * @net: the network instance
+ * @params: the parameters of the server
+ * @id: the identificator for the server
+ *
+ */
+
+int frescan_servers_get_data(frescan_network_t net,
+                             frescan_server_params_t *params,
+                             frescan_ss_t id)
+{
+        *params = the_servers_pool[net][id].params;
+        return 0;
+}
+
+/**
+ * frescan_servers_get_current_budget() - get the current sporadic server budget
+ *
+ * @net: the network instance
+ * @id: the identificator for the server
+ * @current_budget: the current budget of the server
+ *
+ */
+
+int frescan_servers_get_current_budget(frescan_network_t net,
+                                       frescan_ss_t id,
+                                       frescan_budget_t *current_budget)
+{
+        *current_budget = the_servers_pool[net][id].current_budget;
+        return 0;
+}
+
+/**
+ * frescan_servers_get_highest_prio() - get the server with highest priority
+ *
+ * @net: the network instance
+ * @id: the identificator for the server
+ * @prio: the priority of that server
+ *
+ * For each active server, check the priority.
+ * If "id" is returned with a value of FRESCAN_MX_IDS,
+ * there are no active servers.
+ * NOTE: id=FRESCAN_MX_IDS is the identifier for fixed priority messages
+ * TODO: use a priority queue of active servers
+ *
+ */
+
+int frescan_servers_get_highest_prio(frescan_network_t net,
+                                     frescan_ss_t *id,
+                                     frescan_prio_t *prio)
+{
+        frescan_server_data_t *server;
+
+        if (list_empty(&the_active_servers->servers_list)) {
+                DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG, "server list is empty\n");
+                *id = FRESCAN_MX_IDS;
+                return 0;
+        }
+
+        *prio = 0;
+        list_for_each_entry(server, &the_active_servers[net].servers_list,
+                            servers_list) {
+                if (server->current_priority >= *prio) {
+                        *id = server->id;
+                        *prio = server->current_priority;
+                }
+        }
+
+        DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
+              "highest prio:%u id:%u\n", *prio, *id);
+
+        return 0;
+}
+
+/**
+ * frescan_servers_frame_sent() - hook to control the server budget and prio
+ *
+ * @net: the network instance
+ * @id: the identificator for the server
+ *
+ * This function is called when a frame has been effectively sent through the
+ * CAN bus and that frame is associated to a certain server. The function
+ * decreases the capacity of the server and sets the priority to background
+ * in case the budget is exhausted.
+ *
+ * NOTE: the replenishment operation is programmed using the corresponding
+ * function at frescan_servers_replenishments module
+ */
+
+int frescan_servers_frame_sent(frescan_network_t net, frescan_ss_t id)
+{
+        DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
+              "id:%u, current_budget:%u, current_priority:%u\n",
+              id,
+              the_servers_pool[net][id].current_budget,
+              the_servers_pool[net][id].current_priority);
+
+        if (the_servers_pool[net][id].current_budget > 0) {
+                the_servers_pool[net][id].current_budget--;
+                if (the_servers_pool[net][id].current_budget == 0) {
+                        the_servers_pool[net][id].current_priority =
+                                        FRESCAN_BACKGROUND_PRIO;
+                }
+        }
+
+        DEBUG(FRESCAN_SERVERS_ENABLE_DEBUG,
+              "now... id:%u, current_budget:%u, current_priority:%u\n",
+              id,
+              the_servers_pool[net][id].current_budget,
+              the_servers_pool[net][id].current_priority);
+
+        return 0;
+}
diff --git a/src_frescan/frescan_servers.h b/src_frescan/frescan_servers.h
new file mode 100644 (file)
index 0000000..e38622c
--- /dev/null
@@ -0,0 +1,137 @@
+/*!
+ * @file frescan_servers.h
+ *
+ * @brief FRESCAN sporadic servers
+ *
+ * @version 0.01
+ *
+ * @date 27-Feb-2008
+ *
+ * @author
+ *      Daniel Sangorrin
+ *
+ * @comments
+ *
+ * This file contains the FRESCAN sporadic servers that allow to isolate
+ * different streams of data by assigning them a budget and replenishment
+ * period.
+ *
+ * @license
+ *
+ * See MaRTE OS license
+ *
+ */
+
+#ifndef _MARTE_FRESCAN_SERVERS_H_
+#define _MARTE_FRESCAN_SERVERS_H_
+
+#include <drivers/frescan.h> // frescan_prio_t, frescan_ss_t
+#include "frescan_packets.h" // frescan_packet_t
+#include <time.h>            // struct timespec
+#include "frescan_data.h"
+
+/**
+ * frescan_servers_init() - initialize server structures
+ *
+ * @net: the network instance
+ */
+
+extern int frescan_servers_init(frescan_network_t net);
+
+/**
+ * frescan_servers_create() - create a sporadic server
+ *
+ * @net: the network instance
+ * @params: the parameters for the server
+ * @id: the identificator for the server as a return value
+ *
+ */
+
+extern int frescan_servers_create(frescan_network_t net,
+                                  const frescan_server_params_t *params,
+                                  frescan_ss_t *id);
+
+/**
+ * frescan_servers_update() - update a sporadic server data
+ *
+ * @net: the network instance
+ * @params: the parameters for the server
+ * @id: the identificator for the server
+ *
+ */
+
+extern int frescan_servers_update(frescan_network_t net,
+                                  const frescan_server_params_t *params,
+                                  frescan_ss_t id);
+
+/**
+ * frescan_servers_destroy() - delete a sporadic server
+ *
+ * @net: the network instance
+ * @id: the identificator for the server
+ *
+ */
+
+extern int frescan_servers_destroy(frescan_network_t net, frescan_ss_t id);
+
+/**
+ * frescan_servers_get_data() - get a sporadic server data
+ *
+ * @net: the network instance
+ * @params: the parameters of the server
+ * @id: the identificator for the server
+ *
+ */
+
+extern  int frescan_servers_get_data(frescan_network_t net,
+                                     frescan_server_params_t *params,
+                                     frescan_ss_t id);
+
+/**
+ * frescan_servers_get_current_budget() - get the current sporadic server budget
+ *
+ * @net: the network instance
+ * @id: the identificator for the server
+ * @current_budget: the current budget of the server
+ *
+ */
+
+extern int frescan_servers_get_current_budget(frescan_network_t net,
+                                              frescan_ss_t id,
+                                              frescan_budget_t *current_budget);
+
+/**
+ * frescan_servers_get_highest_prio() - get the server with highest priority
+ *
+ * @net: the network instance
+ * @id: the identificator for the server
+ * @prio: the priority of that server
+ *
+ * If "id" is returned with a value of FRESCAN_MX_IDS,
+ * there are no active servers.
+ * NOTE: id=FRESCAN_MX_IDS is the identifier for fixed priority messages
+ *
+ */
+
+extern int frescan_servers_get_highest_prio(frescan_network_t net,
+                                            frescan_ss_t *id,
+                                            frescan_prio_t *prio);
+
+/**
+ * frescan_servers_frame_sent() - hook to control the server budget and prio
+ *
+ * @net: the network instance
+ * @id: the identificator for the server
+ *
+ * This function is called when a frame has been effectively sent through the
+ * CAN bus and that frame is associated to a certain server. The function
+ * decreases the capacity of the server and sets the priority to background
+ * in case the budget is exhausted.
+ *
+ * NOTE: the replenishment operation is programmed using the corresponding
+ * function at frescan_servers_replenishments module
+ */
+
+extern int frescan_servers_frame_sent(frescan_network_t net, frescan_ss_t id);
+
+#endif // _MARTE_FRESCAN_SERVERS_H_
diff --git a/src_frescan/frescan_servers_replenishments.c b/src_frescan/frescan_servers_replenishments.c
new file mode 100644 (file)
index 0000000..383f17e
--- /dev/null
@@ -0,0 +1,285 @@
+/*!
+ * @file frescan_servers_replenishments.c
+ *
+ * @brief the replenishment data and thread for the servers
+ *
+ * @version 0.01
+ *
+ * @date 12-Mar-2008
+ *
+ * @author
+ *      Daniel Sangorrin
+ *
+ * @comments
+ *
+ * This module contains the thread that waits for server's replenishment
+ * timer signals and perform the necessary replenishments.
+ *
+ * @license
+ *
+ * See MaRTE OS license
+ *
+ */
+
+#include <time.h>            // clock_gettime
+
+#include <misc/freelist.h>   // freelist_t
+#include <misc/linux_list.h> // list_add_tail
+#include <misc/timespec_operations.h>
+
+#include "frescan_servers_replenishments.h"
+#include "frescan_config.h"  // FRESCAN_MX_REPL_OPS
+#include "frescan_debug.h"   // ERROR
+#include "frescan_data.h"    // frescan_repl_op_t
+
+/**
+ * the_repl_op_pool - pool of replenishment operations
+ *
+ * We have a pool of replenishment operation structures and an associated
+ * freelist where we can get/put replenishment operations in O(1) time
+ *
+ * @the_repl_op_pool: array with the replenishment operations allocated
+ * @the_repl_op_pool_freelist: freelist for the_repl_op_pool
+ * @frescan_repl_op_init: initializes the freelist
+ * @frescan_repl_op_alloc: get a free replenishment operation structure
+ * @frescan_repl_op_free: free a replenishment operation structure
+ *
+ */
+
+static frescan_repl_op_t the_repl_op_pool[FRESCAN_MX_REPL_OPS];
+static freelist_t the_repl_op_pool_freelist;
+
+static int frescan_repl_op_init()
+{
+        return freelist_init(&the_repl_op_pool_freelist, FRESCAN_MX_REPL_OPS);
+}
+
+static frescan_repl_op_t *frescan_repl_op_alloc()
+{
+        int pos;
+
+        pos = freelist_alloc(&the_repl_op_pool_freelist);
+        if (pos == -1) {
+                ERROR("could not allocate repl op\n");
+                return NULL;
+        }
+        the_repl_op_pool[pos].pool_pos = pos; // to know how to free it
+        return &the_repl_op_pool[pos];
+}
+
+static int frescan_repl_op_free(frescan_repl_op_t *repl_op)
+{
+        return freelist_free(&the_repl_op_pool_freelist, repl_op->pool_pos);
+}
+
+/**
+ * frescan_repl_thread - the thread that executes the replenishments
+ */
+
+static void *frescan_repl_thread(void *arg)
+{
+        int ret;
+        sigset_t set;
+        siginfo_t siginfo;
+        frescan_ss_t id;
+        frescan_network_t net;
+        struct list_head *pos;
+        frescan_repl_op_t *repl;
+        frescan_server_data_t *server;
+        struct itimerspec timerdata;
+
+        net = (frescan_network_t)(uint32_t)arg;
+        timerdata.it_interval.tv_sec  = 0;
+        timerdata.it_interval.tv_nsec = 0;
+
+        sigemptyset(&set);
+        sigaddset(&set, FRESCAN_REPL_SIGNAL_NUM);
+
+        while (1) {
+                ret = sigwaitinfo(&set, &siginfo);
+                if (ret == -1) {
+                        ERROR("sigwaitinfo failed\n");
+                        return NULL;
+                }
+
+                if (siginfo.si_signo != FRESCAN_REPL_SIGNAL_NUM) continue;
+
+                DEBUG(FRESCAN_REPL_ENABLE_DEBUG,
+                      "net:%u signal:%d code:%d value(server_id):%d\n",
+                      net,
+                      siginfo.si_signo,            // FRESCAN_REPL_SIGNAL_NUM
+                      siginfo.si_code,             // SI_TIMER
+                      siginfo.si_value.sival_int); // the server id
+
+                id = siginfo.si_value.sival_int;
+                server = &the_servers_pool[net][id];
+
+                DEBUG(FRESCAN_REPL_ENABLE_DEBUG,
+                      "id:%u, current_budget:%u, budget:%u, current_prio:%u\n",
+                      id,
+                      server->current_budget,
+                      server->params.budget,
+                      server->current_priority);
+
+                server->current_budget++;
+
+                if (server->current_priority == FRESCAN_BACKGROUND_PRIO) {
+                        server->current_priority = server->params.prio;
+                }
+
+                DEBUG(FRESCAN_REPL_ENABLE_DEBUG,
+                      "now... current_budget:%u, current_prio:%u\n",
+                      server->current_budget,
+                      server->current_priority);
+
+                // delete the replenishment of this call
+                list_for_each(pos, &server->replenishments.repl_list) {
+                        repl = list_entry(pos, frescan_repl_op_t, repl_list);
+                        break;
+                }
+
+                list_del(&repl->repl_list);
+
+                ret = frescan_repl_op_free(repl);
+                if (ret != 0) {
+                        ERROR("could not free replenishment op\n");
+                        return NULL;
+                }
+
+                // check if there are pending replenishments
+                if (list_empty(&server->replenishments.repl_list)) continue;
+
+                list_for_each(pos, &server->replenishments.repl_list) {
+                        repl = list_entry(pos, frescan_repl_op_t, repl_list);
+                        break;
+                }
+
+                timerdata.it_value = repl->when;
+
+                DEBUG(FRESCAN_REPL_ENABLE_DEBUG,
+                      "set timer to %d sec, %d nsec\n",
+                      repl->when.tv_sec, repl->when.tv_nsec);
+
+                ret = timer_settime(server->repl_timer,
+                                    TIMER_ABSTIME, &timerdata, NULL);
+                if (ret != 0) {
+                        ERROR("could not set replenishment timer\n");
+                        return NULL;
+                }
+        }
+
+        return NULL;
+}
+
+/**
+ * frescan_replenishments_init - init the replenishment structures and thread
+ *
+ * @net: the network instance
+ *
+ * Initialize the repl_op pool, set the mask for the timer signals and create
+ * the thread that will await for those signals and replenish the appropiate
+ * sporadic server.
+ */
+
+int frescan_replenishments_init(frescan_network_t net)
+{
+        int ret;
+        sigset_t set;
+        struct sigaction action;
+
+        ret = frescan_repl_op_init();
+        if (ret != 0) {
+                ERROR("could not init repl_op pool\n");
+                return ret;
+        }
+
+        sigemptyset(&set);
+        sigaddset(&set, FRESCAN_REPL_SIGNAL_NUM);
+
+        ret = pthread_sigmask(SIG_BLOCK, &set, NULL);
+        if (ret != 0) {
+                ERROR("could not put the signal mask for replenishments\n");
+                return ret;
+        }
+
+        // the following is unnecesary in MaRTE OS because all signals are RT
+        action.sa_handler = SIG_DFL;
+        sigemptyset(&action.sa_mask);
+        action.sa_flags = SA_SIGINFO;
+        ret = sigaction (FRESCAN_REPL_SIGNAL_NUM, &action, NULL);
+        if (ret != 0) {
+                ERROR("could not set action for the repl signal\n");
+                return ret;
+        }
+
+        // TODO: set the pthread attributes
+        ret = pthread_create(&the_networks[net].repl_thread_id,
+                              NULL,
+                              frescan_repl_thread,
+                              (void *)(uint32_t)net);
+        if (ret != 0) {
+                ERROR("could not create the replenishment thread\n");
+                return ret;
+        }
+
+        return 0;
+}
+
+/**
+ * frescan_replenishment_program - set a replenishment operation
+ *
+ * @net: the network instance
+ * @ss: the server
+ */
+
+int frescan_replenishment_program(frescan_network_t net,
+                                  frescan_ss_t ss)
+{
+        int ret;
+        frescan_repl_op_t *repl;
+        bool empty;
+        struct itimerspec timerdata;
+        frescan_server_data_t *server;
+
+        server = &the_servers_pool[net][ss];
+
+        if (server->current_priority == FRESCAN_BACKGROUND_PRIO) {
+                DEBUG(FRESCAN_REPL_ENABLE_DEBUG, "ss in background\n");
+                return 0;
+        }
+
+        repl = frescan_repl_op_alloc();
+        if (repl == NULL) {
+                ERROR("could not allocate a repl operation\n");
+                return -1;
+        }
+
+        clock_gettime (CLOCK_MONOTONIC, &repl->when);
+        incr_timespec (&repl->when, &server->params.period);
+        repl->amount = 1;
+
+        empty = list_empty(&server->replenishments.repl_list);
+        DEBUG(FRESCAN_REPL_ENABLE_DEBUG, "ss:%u, empty:%u\n", ss, empty);
+
+        list_add_tail(&repl->repl_list,
+                      &server->replenishments.repl_list);
+
+        if (empty) {
+                timerdata.it_interval.tv_sec  = 0;
+                timerdata.it_interval.tv_nsec = 0;
+                timerdata.it_value = repl->when;
+
+                DEBUG(FRESCAN_REPL_ENABLE_DEBUG,
+                      "set timer to %d sec, %d nsec\n",
+                      repl->when.tv_sec, repl->when.tv_nsec);
+
+                ret = timer_settime(server->repl_timer,
+                                    TIMER_ABSTIME, &timerdata, NULL);
+                if (ret != 0) {
+                        ERROR("could not set the replenishment timer\n");
+                        return ret;
+                }
+        }
+
+        return 0;
+}
diff --git a/src_frescan/frescan_servers_replenishments.h b/src_frescan/frescan_servers_replenishments.h
new file mode 100644 (file)
index 0000000..c723a09
--- /dev/null
@@ -0,0 +1,53 @@
+/*!
+ * @file frescan_servers_replenishments.h
+ *
+ * @brief the replenishment data and thread for the servers
+ *
+ * @version 0.01
+ *
+ * @date 12-Mar-2008
+ *
+ * @author
+ *      Daniel Sangorrin
+ *
+ * @comments
+ *
+ * This module contains the thread that waits for server's replenishment
+ * timer signals and perform the necessary replenishments.
+ *
+ * @license
+ *
+ * See MaRTE OS license
+ *
+ */
+
+#ifndef _MARTE_FRESCAN_SERVERS_REPLENISHMENTS_H_
+#define _MARTE_FRESCAN_SERVERS_REPLENISHMENTS_H_
+
+#include <drivers/frescan.h> // frescan_network_t
+
+/**
+ * frescan_replenishments_init - init the replenishment structures and thread
+ *
+ * @net: the network instance
+ *
+ * Initialize the repl_op pool, set the mask for the timer signals and create
+ * the thread that will await for those signals and replenish the appropiate
+ * sporadic server.
+ *
+ * NOTE: it must be called from the MAIN because it sets the signal mask
+ */
+
+extern int frescan_replenishments_init(frescan_network_t net);
+
+/**
+ * frescan_replenishment_program - set a replenishment operation
+ *
+ * @net: the network instance
+ * @ss: the server
+ */
+
+extern int frescan_replenishment_program(frescan_network_t net,
+                                         frescan_ss_t ss);
+
+#endif // _MARTE_FRESCAN_SERVERS_REPLENISHMENTS_H_
diff --git a/src_frescan/test_frescan_init.c b/src_frescan/test_frescan_init.c
new file mode 100644 (file)
index 0000000..b98045a
--- /dev/null
@@ -0,0 +1,35 @@
+#include <stdio.h>  // perror
+#include <stdlib.h> // exit
+#include <unistd.h>   // sleep
+
+#include <drivers/frescan.h>
+
+#define ERROR(s) {perror (s); exit (-1);}
+
+#define NETWORK 0
+#define LOCAL_NODE 1
+
+int main ()
+{
+        int ret;
+        frescan_init_params_t init_params;
+
+        init_params.net = NETWORK;
+        init_params.node = LOCAL_NODE;
+        init_params.tx_fp_max_prio = 10;
+        init_params.rx_num_of_channels = 5;
+        init_params.rx_channel_max_prio = NULL;
+
+        ret = frescan_init(&init_params);
+        if (ret != 0) ERROR ("could not init FRESCAN");
+
+        printf("FRESCAN initialized\n");
+
+        while (1) {
+                sleep(1);
+        }
+
+        return 0;
+}
+
+
diff --git a/src_frescan/test_frescan_queues.c b/src_frescan/test_frescan_queues.c
new file mode 100644 (file)
index 0000000..a556601
--- /dev/null
@@ -0,0 +1,123 @@
+#include <stdio.h>  // perror
+#include <stdlib.h> // exit
+#include <unistd.h> // sleep
+#include <stdint.h> // uint32_t
+
+#include "frescan_queues.h"
+#include <drivers/can.h>
+#include <misc/linux_list.h>
+
+#define ERROR(s) {perror (s); exit (-1);}
+#define DEBUG(enable,x,args...) if(enable) {printf("\t>> %s: " x, __func__ , ##args);} // pause();}
+
+#define DEBUG_ENABLE 1
+
+// static void pause(){
+//         char key;
+//         printf(" press Enter...");
+//         key = getchar();
+// }
+
+int main ()
+{
+        int i, ret;
+        frescan_queues_t queues;
+        frescan_packet_t *packet, *head;
+        struct can_frame_t *frame;
+        frescan_prio_queue_t *pqueue;
+        frescan_prio_t prio;
+        bool blocking;
+        frescan_init_params_t init_params;
+
+        DEBUG(DEBUG_ENABLE, "init frames and packets pool\n");
+
+        // ret = can_framespool_init();
+        // if (ret != 0) ERROR ("could not init frames pool\n");
+
+        ret = frescan_packets_init();
+        if (ret != 0) ERROR ("could not init packet pool\n");
+
+        DEBUG(DEBUG_ENABLE, "init queues\n");
+
+        init_params.tx_fp_max_prio = 10;
+        init_params.rx_num_of_channels = 5;
+        init_params.rx_channel_max_prio = NULL;
+
+        ret = frescan_queues_init(&queues, &init_params);
+        if (ret != 0) ERROR("could not initialize the queues\n");
+
+        head = NULL;
+
+        DEBUG(DEBUG_ENABLE, "create queue of 5 packets\n");
+
+        for (i=0; i<5; i++) {
+                frame = can_framespool_alloc();
+                if (frame == NULL) ERROR ("frames pool is exhausted\n");
+
+                frame->is_extended_format = 1;
+                frame->is_rtr = 0;
+                frame->id = 0x696969;
+                frame->dlc = 8;
+                frame->data[0] = 69;
+                frame->data[7] = 69;
+
+                packet = frescan_packets_alloc();
+                if (packet == NULL) ERROR ("could not alloc packet\n");
+
+                packet->frame = frame;
+
+                if (head == NULL) {
+                        DEBUG(DEBUG_ENABLE, "head was null\n");
+                        head = frescan_packets_alloc();
+                        if (head == NULL) ERROR ("could not alloc packet\n");
+                        INIT_LIST_HEAD(&head->msg_list);
+                }
+
+                list_add_tail(&packet->msg_list, &head->msg_list);
+        }
+
+        DEBUG(DEBUG_ENABLE, "enqueue head in priority queue\n");
+
+        pqueue = queues.rx_channel_queues[0];
+        ret = frescan_pqueue_enqueue(pqueue, head, 7);
+        if (ret != 0) ERROR ("could not enqueue packet\n");
+
+        blocking = true;
+
+        DEBUG(DEBUG_ENABLE, "dequeue head from priority queue\n");
+
+        ret = frescan_pqueue_dequeue(pqueue, &head, &prio, blocking);
+        if (ret != 0) ERROR ("could not dequeue packet\n");
+
+        if (head == NULL) {
+                if (blocking == false) {
+                        ERROR ("blocking false packet null\n");
+                } else {
+                        ERROR ("blocking true, and packet = null\n");
+                }
+        }
+
+        DEBUG(DEBUG_ENABLE, "traverse the list of packets\n");
+
+        list_for_each_entry(packet, &head->msg_list, msg_list) {
+                DEBUG(DEBUG_ENABLE,
+                      "ID Packet, dlc: %u, frame pool pos: %u\n",
+                       packet->frame->dlc, packet->frame->pool_pos);
+
+                ret = can_framespool_free(packet->frame);
+                if (ret != 0) ERROR("could not free frame\n");
+
+                ret = frescan_packets_free(packet);
+                if (ret != 0) ERROR("could not free packet\n");
+        }
+
+        DEBUG(DEBUG_ENABLE, "free head\n");
+
+        ret = frescan_packets_free(head);
+        if (ret != 0) {
+                ERROR("could not free head packet\n");
+                return -1;
+        }
+
+        return 0;
+}
diff --git a/src_frescan/test_frescan_send_basic.c b/src_frescan/test_frescan_send_basic.c
new file mode 100644 (file)
index 0000000..af69133
--- /dev/null
@@ -0,0 +1,133 @@
+// mgcc test_frescan_send_basic.c -L. -lfrescan -o mprogram_wifi2
+// mgcc test_frescan_send_basic.c -DSENDER -L. -lfrescan -o mprogram_wifi1
+
+#include <stdio.h>  // perror
+#include <stdlib.h> // exit
+#include <unistd.h>   // sleep
+
+#include <drivers/frescan.h>
+
+#define ERROR(s) {perror (s); exit (-1);}
+
+#define NETWORK 0
+
+// #define SENDER
+// #define ENABLE_LOGGING
+
+#ifdef SENDER
+
+#define LOCAL_NODE 0
+
+#ifdef ENABLE_LOGGING
+
+#include <drivers/console_switcher.h>
+#include <misc/logger.h>
+#include <assert.h>
+#define LOG_DEVICE LOG_ETHERNET
+
+#endif
+
+static void pause(){
+        char key;
+        printf(" press Enter...");
+        key = getchar();
+}
+
+int main ()
+{
+        int i, ret;
+        frescan_send_params_t params;
+        char msg[200];
+        int written;
+        frescan_init_params_t init_params;
+
+        init_params.net = NETWORK;
+        init_params.node = LOCAL_NODE;
+        init_params.tx_fp_max_prio = 10;
+        init_params.rx_num_of_channels = 5;
+        init_params.rx_channel_max_prio = NULL;
+
+#ifdef ENABLE_LOGGING
+
+        ret = logger_init(LOG_DEVICE);
+        assert(ret == 0);
+
+        printf("Changing to membuffer console\n");
+        MEMBUFFER_CONSOLE_INIT();
+
+#endif
+
+        ret = frescan_init(&init_params);
+        if (ret != 0) ERROR ("could not init FRESCAN");
+
+        printf("FRESCAN initialized\n");
+
+        params.net      = NETWORK;
+        params.to       = 1;
+        params.channel  = 0;
+        params.flags    = FRESCAN_FP | FRESCAN_ASYNC;
+        params.prio     = 7;
+
+        while(1) {
+                pause();
+                for (i=0; i<=3; i++) {
+                        written = snprintf(msg, sizeof(msg), "his number is... %d", i);
+                        ret = frescan_send(&params, (uint8_t *)msg, written);
+                        if (ret != 0) ERROR ("could not send message\n");
+                        printf("SENT: %d\n", i);
+                }
+#ifdef ENABLE_LOGGING
+                while (logger_manual_call() > 0);
+#endif
+        }
+
+        return 0;
+}
+
+#else
+
+#define LOCAL_NODE 1
+
+int main ()
+{
+        int ret;
+        frescan_recv_params_t params;
+        uint8_t msg[3000];
+        size_t recv_bytes;
+        frescan_node_t from;
+        frescan_init_params_t init_params;
+        frescan_prio_t prio;
+
+        init_params.net = NETWORK;
+        init_params.node = LOCAL_NODE;
+        init_params.tx_fp_max_prio = 10;
+        init_params.rx_num_of_channels = 5;
+        init_params.rx_channel_max_prio = NULL;
+
+        ret = frescan_init(&init_params);
+        if (ret != 0) ERROR ("could not init FRESCAN");
+
+        printf("FRESCAN initialized\n");
+
+        params.net      = NETWORK;
+        params.channel  = 0;
+        params.flags    = FRESCAN_SYNC;
+
+        while (1) {
+                printf("RECEIVING...\n");
+                ret = frescan_recv(&params, (uint8_t *)msg, sizeof(msg),
+                                    &recv_bytes, &from, &prio);
+                if (ret != 0) ERROR ("could not send message");
+
+                msg[recv_bytes] = '\0';
+                printf("RECEIVED: %s with prio:%u\n", msg, prio);
+
+//                 for (i=0; i<recv_bytes; i++) {
+//                         printf("msg[%d] = 0x%X;\n", i, msg[i]);
+//                 }
+        }
+
+        return 0;
+}
+
+#endif
diff --git a/src_frescan/test_frescan_servers_send_basic.c b/src_frescan/test_frescan_servers_send_basic.c
new file mode 100644 (file)
index 0000000..65f2af2
--- /dev/null
@@ -0,0 +1,150 @@
+// mgcc test_frescan_servers_send_basic.c -L. -lfrescan -o mprogram_wifi2
+// mgcc test_frescan_servers_send_basic.c -DSENDER -L. -lfrescan -o mprogram_wifi1
+
+#include <stdio.h>  // perror
+#include <stdlib.h> // exit
+#include <unistd.h>   // sleep
+
+#include <drivers/frescan.h>
+#include "frescan_servers.h"
+
+#define ERROR(s) {perror (s); exit (-1);}
+
+#define NETWORK 0
+
+// #define SENDER
+// #define ENABLE_LOGGING
+
+#ifdef SENDER
+
+#define LOCAL_NODE 0
+
+#ifdef ENABLE_LOGGING
+
+#include <drivers/console_switcher.h>
+#include <misc/logger.h>
+#include <assert.h>
+#define LOG_DEVICE LOG_ETHERNET
+
+#endif
+
+static void pause(){
+        char key;
+        printf(" press Enter...");
+        key = getchar();
+}
+
+int main ()
+{
+        int i, ret;
+        frescan_send_params_t params;
+        char msg[200];
+        int written;
+        frescan_init_params_t init_params;
+        frescan_server_params_t server_params;
+
+
+
+#ifdef ENABLE_LOGGING
+
+        ret = logger_init(LOG_DEVICE);
+        assert(ret == 0);
+
+        printf("Changing to membuffer console\n");
+        MEMBUFFER_CONSOLE_INIT();
+
+#endif
+
+        printf(">> Initializing FRESCAN\n");
+
+        init_params.net = NETWORK;
+        init_params.node = LOCAL_NODE;
+        init_params.tx_fp_max_prio = 10;
+        init_params.rx_num_of_channels = 5;
+        init_params.rx_channel_max_prio = NULL;
+
+        ret = frescan_init(&init_params);
+        if (ret != 0) ERROR ("could not init FRESCAN");
+
+        printf(">> Creating a Server\n");
+
+        server_params.budget = 3;
+        server_params.period.tv_sec  = 3;
+        server_params.period.tv_nsec = 0;
+        server_params.prio = 4;
+
+        ret = frescan_servers_create(NETWORK,
+                                     &server_params,
+                                     &params.ss);
+        if (ret != 0) ERROR ("could not create server");
+
+        printf(">> Enter in loop for sending packets\n");
+
+        params.net      = NETWORK;
+        params.to       = 1;
+        params.channel  = 0;
+        params.flags    = FRESCAN_SS | FRESCAN_ASYNC;
+
+        while(1) {
+                pause();
+                for (i=0; i<=2; i++) {
+                        written = snprintf(msg, sizeof(msg), "his %d", i);
+                        ret = frescan_send(&params, (uint8_t *)msg, written);
+                        if (ret != 0) ERROR ("could not send message\n");
+                        printf("SENT: %d\n", i);
+}
+#ifdef ENABLE_LOGGING
+                while (logger_manual_call() > 0);
+#endif
+}
+
+        return 0;
+}
+
+#else
+
+#define LOCAL_NODE 1
+
+int main ()
+{
+        int ret;
+        frescan_recv_params_t params;
+        uint8_t msg[3000];
+        size_t recv_bytes;
+        frescan_node_t from;
+        frescan_init_params_t init_params;
+        frescan_prio_t prio;
+
+        init_params.net = NETWORK;
+        init_params.node = LOCAL_NODE;
+        init_params.tx_fp_max_prio = 10;
+        init_params.rx_num_of_channels = 5;
+        init_params.rx_channel_max_prio = NULL;
+
+        ret = frescan_init(&init_params);
+        if (ret != 0) ERROR ("could not init FRESCAN");
+
+        printf("FRESCAN initialized\n");
+
+        params.net      = NETWORK;
+        params.channel  = 0;
+        params.flags    = FRESCAN_SYNC;
+
+        while (1) {
+                printf("RECEIVING...\n");
+                ret = frescan_recv(&params, (uint8_t *)msg, sizeof(msg),
+                                   &recv_bytes, &from, &prio);
+                if (ret != 0) ERROR ("could not send message");
+
+                msg[recv_bytes] = '\0';
+                printf("RECEIVED: %s with prio:%u\n", msg, prio);
+
+//                 for (i=0; i<recv_bytes; i++) {
+//                         printf("msg[%d] = 0x%X;\n", i, msg[i]);
+//                 }
+        }
+
+        return 0;
+}
+
+#endif