--- /dev/null
+.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 $@";
--- /dev/null
+
+ 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.
--- /dev/null
+/*!
+ * @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;
+};
--- /dev/null
+/*!
+ * @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_
--- /dev/null
+/*!
+ * @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;
+}
--- /dev/null
+/*!
+ * @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_
--- /dev/null
+/*!
+ * @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_
--- /dev/null
+/*!
+ * @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;
+}
--- /dev/null
+/*!
+ * @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_
--- /dev/null
+/*!
+ * @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);
+}
--- /dev/null
+/*!
+ * @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_
--- /dev/null
+/*!
+ * @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);
+}
--- /dev/null
+/*!
+ * @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_
--- /dev/null
+/*!
+ * @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;
+}
--- /dev/null
+/*!
+ * @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_
--- /dev/null
+/*!
+ * @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;
+}
--- /dev/null
+/*!
+ * @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_
--- /dev/null
+/*!
+ * @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;
+}
--- /dev/null
+/*!
+ * @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_
--- /dev/null
+#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;
+}
+
+
--- /dev/null
+#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;
+}
--- /dev/null
+// 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(¶ms, (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(¶ms, (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
--- /dev/null
+// 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,
+ ¶ms.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(¶ms, (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(¶ms, (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