

7 changed files with 421 additions and 0 deletions
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @defgroup nomac Link layer with no medium access |
||||
* @ingroup net |
||||
* @brief Link layer protocol to speak with any transceiver driver |
||||
* directly without any medium access. |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Link layer protocol to speak with any transceiver driver |
||||
* directly without any medium access. |
||||
* |
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de> |
||||
*/ |
||||
|
||||
#ifndef __NOMAC_H_ |
||||
#define __NOMAC_H_ |
||||
|
||||
#include <stdlib.h> |
||||
|
||||
#include "netdev/base.h" |
||||
#include "netapi.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
#ifndef NOMAC_REGISTRY_SIZE |
||||
/**
|
||||
* @brief The size of NOMAC's registry of receiving threads. |
||||
*/ |
||||
#define NOMAC_REGISTRY_SIZE (1) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Recommended stack size for a NOMAC thread |
||||
* TODO: determine real minimal size based on thread_print_all() output |
||||
*/ |
||||
#define NOMAC_CONTROL_STACKSIZE (KERNEL_CONF_STACKSIZE_DEFAULT) |
||||
|
||||
/**
|
||||
* @brief Basic configuration types |
||||
* |
||||
* @extends netapi_conf_type_t |
||||
*/ |
||||
typedef enum { |
||||
NOMAC_PROTO = NETAPI_CONF_PROTO, /**< Set or get protocol */ |
||||
NOMAC_CHANNEL = NETAPI_CONF_CARRIER, /**< Set or get channel */ |
||||
NOMAC_ADDRESS = NETAPI_CONF_ADDRESS, /**< Set or get address */ |
||||
NOMAC_NID = NETAPI_CONF_SUBNETS, /**< Set or get network id
|
||||
* (e.g. PAN ID in 802.15.4)*/ |
||||
NOMAC_MAX_PACKET_SIZE = NETAPI_CONF_MAX_PACKET_SIZE, /**< Set or get maximum
|
||||
* packet size */ |
||||
NOMAC_SRC_LEN = NETAPI_CONF_SRC_LEN, /**< Set or get default source length */ |
||||
NOMAC_REGISTRY = NETAPI_CONF_REGISTRY, /**< get registered threads */ |
||||
NOMAC_ADDRESS2 = NETDEV_OPT_ADDRESS_LONG, /**< Set or get alternative address
|
||||
* format (e.g EUI-64 in 802.15.4) */ |
||||
} nomac_conf_type_t; |
||||
|
||||
/**
|
||||
* @brief Initializes the module |
||||
*/ |
||||
void nomac_init_module(void); |
||||
|
||||
/**
|
||||
* @brief Initialize new NOMAC layer. |
||||
* |
||||
* @param[in] stack Stack for the control thread |
||||
* @param[in] stacksize Size of *stack* |
||||
* @param[in] priority Priority for the control thread |
||||
* @param[in] name Name for the control thread |
||||
* @param[in] dev An *initialized* network device to use with this MAC |
||||
* layer |
||||
* |
||||
* @see @ref thread_create |
||||
* |
||||
* @return PID of NOMAC control thread on success |
||||
* @return -EINVAL if priority is invalid |
||||
* @return -EOVERFLOW if no slot for the new thread is available |
||||
*/ |
||||
kernel_pid_t nomac_init(char *stack, int stacksize, char priority, |
||||
const char *name, netdev_t *dev); |
||||
|
||||
#ifdef MODULE_NETDEV_DUMMY |
||||
/**
|
||||
* @brief Re-updates the receive callback of a network device for testing |
||||
* purposes |
||||
* |
||||
* @param[in] dev A network device |
||||
*/ |
||||
void nomac_update_callback(netdev_t *dev); |
||||
#endif |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* __NOMAC_H_ */ |
||||
|
||||
/** @} */ |
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base |
@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
#include <errno.h> |
||||
#include <string.h> |
||||
|
||||
#include "netapi.h" |
||||
#include "msg.h" |
||||
#include "netdev/base.h" |
||||
#include "thread.h" |
||||
|
||||
#include "nomac.h" |
||||
|
||||
#ifdef MODULE_NETDEV_DUMMY |
||||
#include "netdev_dummy.h" |
||||
#endif |
||||
|
||||
#define ENABLE_DEBUG (0) |
||||
#include "debug.h" |
||||
|
||||
#define NOMAC_MSG_QUEUE_SIZE (16) |
||||
|
||||
static struct { |
||||
kernel_pid_t registrar_pid; /**< Thread recipient is registered to */ |
||||
kernel_pid_t recipient_pid; /**< Registered recipient thread */ |
||||
} _nomac_registry[NOMAC_REGISTRY_SIZE]; |
||||
|
||||
static int _nomac_recv_cb(netdev_t *dev, void *src, size_t src_len, void *dest, |
||||
size_t dest_len, void *payload, size_t payload_len) |
||||
{ |
||||
(void)dev; |
||||
kernel_pid_t current_pid = thread_getpid(); |
||||
size_t offset; |
||||
netapi_rcv_pkt_t packet; |
||||
netapi_ack_t ack_mem; |
||||
msg_t msg_pkt, msg_ack; |
||||
|
||||
packet.type = NETAPI_CMD_RCV; |
||||
packet.ack = &ack_mem; |
||||
packet.src = src; |
||||
packet.src_len = src_len; |
||||
packet.dest = dest; |
||||
packet.dest_len = dest_len; |
||||
msg_pkt.type = NETAPI_MSG_TYPE; |
||||
msg_pkt.content.ptr = (char *)(&packet); |
||||
|
||||
for (unsigned int i = 0; i < NOMAC_REGISTRY_SIZE; i++) { |
||||
if (_nomac_registry[i].registrar_pid == current_pid) { |
||||
offset = 0; |
||||
|
||||
while (offset < payload_len) { |
||||
netapi_ack_t *ack; |
||||
packet.data = (void *)(((char *)payload) + offset); |
||||
packet.data_len = payload_len - offset; |
||||
|
||||
msg_send_receive(&msg_pkt, &msg_ack, |
||||
_nomac_registry[i].recipient_pid); |
||||
ack = (netapi_ack_t *)(msg_ack.content.ptr); |
||||
|
||||
if ((msg_ack.type == NETAPI_MSG_TYPE) && |
||||
(ack->type == NETAPI_CMD_ACK) && |
||||
(ack->orig == NETAPI_CMD_RCV)) { |
||||
if (ack->result > 0) { |
||||
offset += (ack->result); |
||||
} |
||||
else { |
||||
DEBUG("Error code received for registrar %" PRIkernel_pid |
||||
" with recipient %" PRIkernel_pid ": %d", |
||||
_nomac_registry[i].registrar_pid, |
||||
_nomac_registry[i].recipient_pid, |
||||
-(ack->result)); |
||||
|
||||
return ack->result; |
||||
} |
||||
} |
||||
else { |
||||
DEBUG("Unexpected msg instead of ACK. Abort for registrar " |
||||
"\"%s\" with recipient \"%s\": msg.type = %d, " |
||||
"ack->type = %d, ack->orig = %d", |
||||
thread_getname(_nomac_registry[i].registrar_pid), |
||||
thread_getname(_nomac_registry[i].recipient_pid), |
||||
msg_ack.type, ack->type, ack->orig); |
||||
|
||||
return -ENOMSG; |
||||
} |
||||
|
||||
} |
||||
} |
||||
} |
||||
|
||||
return payload_len; |
||||
} |
||||
|
||||
static inline int _nomac_send(netdev_t *dev, netapi_snd_pkt_t *pkt) |
||||
{ |
||||
return dev->driver->send_data(dev, pkt->dest, pkt->dest_len, pkt->ulh, |
||||
pkt->data, pkt->data_len); |
||||
} |
||||
|
||||
static int _nomac_get_registry(netapi_conf_t *conf) |
||||
{ |
||||
kernel_pid_t current_pid = thread_getpid(); |
||||
kernel_pid_t registry[NOMAC_REGISTRY_SIZE]; |
||||
uint8_t size = 0; |
||||
|
||||
for (int i = 0; i < NOMAC_REGISTRY_SIZE; i++) { |
||||
if ((size * sizeof(kernel_pid_t)) > (conf->data_len)) { |
||||
return -EOVERFLOW; |
||||
} |
||||
|
||||
if (_nomac_registry[i].registrar_pid == current_pid) { |
||||
registry[size++] = _nomac_registry[i].recipient_pid; |
||||
} |
||||
} |
||||
|
||||
conf->data_len = size * sizeof(kernel_pid_t); |
||||
memcpy(conf->data, registry, conf->data_len); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int _nomac_get_option(netdev_t *dev, netapi_conf_t *conf) |
||||
{ |
||||
int res; |
||||
|
||||
switch ((nomac_conf_type_t)conf->param) { |
||||
case NOMAC_PROTO: |
||||
case NOMAC_CHANNEL: |
||||
case NOMAC_ADDRESS: |
||||
case NOMAC_NID: |
||||
case NOMAC_MAX_PACKET_SIZE: |
||||
case NOMAC_ADDRESS2: |
||||
if ((res = dev->driver->get_option(dev, (netdev_opt_t)conf->param, |
||||
conf->data, &(conf->data_len)) |
||||
) == 0) { |
||||
return (int)conf->data_len; |
||||
} |
||||
else { |
||||
return res; |
||||
} |
||||
|
||||
case NOMAC_REGISTRY: |
||||
return _nomac_get_registry(conf); |
||||
|
||||
default: |
||||
break; |
||||
} |
||||
|
||||
return -ENOTSUP; |
||||
} |
||||
|
||||
static int _nomac_set_option(netdev_t *dev, netapi_conf_t *conf) |
||||
{ |
||||
switch ((nomac_conf_type_t)(conf->param)) { |
||||
case NOMAC_PROTO: |
||||
case NOMAC_CHANNEL: |
||||
case NOMAC_ADDRESS: |
||||
case NOMAC_NID: |
||||
case NOMAC_ADDRESS2: |
||||
return dev->driver->set_option(dev, (netdev_opt_t)conf->param, |
||||
conf->data, conf->data_len); |
||||
|
||||
default: |
||||
break; |
||||
} |
||||
|
||||
return -ENOTSUP; |
||||
} |
||||
|
||||
static void *_nomac_runner(void *args) |
||||
{ |
||||
netdev_t *dev = (netdev_t *)args; |
||||
msg_t msg_cmd, msg_ack, msg_queue[NOMAC_MSG_QUEUE_SIZE]; |
||||
|
||||
netapi_cmd_t *cmd; |
||||
netapi_ack_t *ack; |
||||
|
||||
msg_ack.type = NETAPI_MSG_TYPE; |
||||
|
||||
msg_init_queue(msg_queue, NOMAC_MSG_QUEUE_SIZE); |
||||
|
||||
dev->driver->init(dev); |
||||
dev->driver->add_receive_data_callback(dev, _nomac_recv_cb); |
||||
|
||||
while (1) { |
||||
msg_receive(&msg_cmd); |
||||
|
||||
if (msg_cmd.type == NETDEV_MSG_EVENT_TYPE) { |
||||
dev->driver->event(dev, msg_cmd.content.value); |
||||
} |
||||
else if (msg_cmd.type == NETAPI_MSG_TYPE) { |
||||
cmd = (netapi_cmd_t *)(msg_cmd.content.ptr); |
||||
ack = cmd->ack; |
||||
msg_ack.content.ptr = (char *)ack; |
||||
|
||||
switch (cmd->type) { |
||||
case NETAPI_CMD_SND: |
||||
ack->result = _nomac_send(dev, (netapi_snd_pkt_t *)cmd); |
||||
break; |
||||
|
||||
case NETAPI_CMD_GET: |
||||
ack->result = _nomac_get_option(dev, (netapi_conf_t *)cmd); |
||||
break; |
||||
|
||||
case NETAPI_CMD_SET: |
||||
ack->result = _nomac_set_option(dev, (netapi_conf_t *)cmd); |
||||
break; |
||||
|
||||
case NETAPI_CMD_REG: |
||||
ack->result = -ENOBUFS; |
||||
|
||||
for (int i = 0; i < NOMAC_REGISTRY_SIZE; i++) { |
||||
if (_nomac_registry[i].registrar_pid == KERNEL_PID_UNDEF) { |
||||
netapi_reg_t *reg = (netapi_reg_t *)cmd; |
||||
|
||||
_nomac_registry[i].registrar_pid = thread_getpid(); |
||||
_nomac_registry[i].recipient_pid = reg->reg_pid; |
||||
ack->result = NETAPI_STATUS_OK; |
||||
|
||||
break; |
||||
} |
||||
} |
||||
|
||||
break; |
||||
|
||||
case NETAPI_CMD_UNREG: |
||||
ack->result = NETAPI_STATUS_OK; |
||||
|
||||
for (int i = 0; i < NOMAC_REGISTRY_SIZE; i++) { |
||||
netapi_reg_t *reg = (netapi_reg_t *)cmd; |
||||
|
||||
if (_nomac_registry[i].registrar_pid == thread_getpid() && |
||||
_nomac_registry[i].recipient_pid == reg->reg_pid) { |
||||
_nomac_registry[i].recipient_pid = KERNEL_PID_UNDEF; |
||||
|
||||
break; |
||||
} |
||||
|
||||
} |
||||
|
||||
break; |
||||
|
||||
#ifdef MODULE_NETDEV_DUMMY |
||||
|
||||
case NETAPI_CMD_FIRE_RCV: |
||||
ack->result = unittest_netdev_dummy_fire_rcv_event(dev, |
||||
((netapi_rcv_pkt_t *)cmd)->src, |
||||
((netapi_rcv_pkt_t *)cmd)->src_len, |
||||
((netapi_rcv_pkt_t *)cmd)->dest, |
||||
((netapi_rcv_pkt_t *)cmd)->dest_len, |
||||
((netapi_rcv_pkt_t *)cmd)->data, |
||||
((netapi_rcv_pkt_t *)cmd)->data_len); |
||||
break; |
||||
#endif |
||||
|
||||
default: |
||||
ack->result = -ENOTSUP; |
||||
break; |
||||
} |
||||
|
||||
ack->type = NETAPI_CMD_ACK; |
||||
ack->orig = cmd->type; |
||||
msg_reply(&msg_cmd, &msg_ack); |
||||
} |
||||
} |
||||
|
||||
/* never reached */ |
||||
return NULL; |
||||
} |
||||
|
||||
void nomac_init_module(void) |
||||
{ |
||||
for (int i = 0; i < NOMAC_REGISTRY_SIZE; i++) { |
||||
_nomac_registry[i].registrar_pid = KERNEL_PID_UNDEF; |
||||
_nomac_registry[i].recipient_pid = KERNEL_PID_UNDEF; |
||||
} |
||||
} |
||||
|
||||
kernel_pid_t nomac_init(char *stack, int stacksize, char priority, |
||||
const char *name, netdev_t *dev) |
||||
{ |
||||
return thread_create(stack, stacksize, priority, CREATE_STACKTEST, |
||||
_nomac_runner, (void *)dev, name); |
||||
} |
||||
|
||||
#ifdef MODULE_NETDEV_DUMMY |
||||
void nomac_update_callback(netdev_t *dev) |
||||
{ |
||||
dev->driver->add_receive_data_callback(dev, _nomac_recv_cb); |
||||
} |
||||
#endif |
Loading…
Reference in new issue