diff --git a/Makefile.dep b/Makefile.dep index 706fe6f05813f..2852b0287ec7a 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -72,7 +72,7 @@ ifneq (,$(filter cc110x_ng,$(USEMODULE))) endif ifneq (,$(filter cc2420,$(USEMODULE))) - USEMODULE += transceiver + USEMODULE += netdev_802154 USEMODULE += ieee802154 endif @@ -96,6 +96,10 @@ ifneq (,$(filter ccn_lite,$(USEMODULE))) USEMODULE += crypto endif +ifneq (,$(filter netdev_802154,$(USEMODULE))) + USEMODULE += netdev_base +endif + ifneq (,$(filter rgbled,$(USEMODULE))) USEMODULE += color endif diff --git a/boards/telosb/Makefile.include b/boards/telosb/Makefile.include index 0ec71cd2fbf39..1f3142b37a81c 100644 --- a/boards/telosb/Makefile.include +++ b/boards/telosb/Makefile.include @@ -26,8 +26,10 @@ export INCLUDES += -I$(RIOTCPU)/msp430-common/include -I$(RIOTBOARD)/$(BOARD)/in export OFLAGS = -O ihex ifneq (,$(filter defaulttransceiver,$(USEMODULE))) - USEMODULE += cc2420 - USEMODULE += transceiver + USEMODULE += cc2420 + ifeq (,$(filter netdev_base,$(USEMODULE))) + USEMODULE += transceiver + endif endif export UNDEF += $(BINDIR)msp430_common/startup.o diff --git a/boards/wsn430-v1_4/Makefile.dep b/boards/wsn430-v1_4/Makefile.dep index e9314092db391..842bd39b8b201 100644 --- a/boards/wsn430-v1_4/Makefile.dep +++ b/boards/wsn430-v1_4/Makefile.dep @@ -1,6 +1,8 @@ USEMODULE += msp430_common ifneq (,$(filter defaulttransceiver,$(USEMODULE))) - USEMODULE += cc2420 - USEMODULE += transceiver + USEMODULE += cc2420 + ifeq (,$(filter netdev_base,$(USEMODULE))) + USEMODULE += transceiver + endif endif diff --git a/boards/z1/Makefile.include b/boards/z1/Makefile.include index e40c829634312..7de8abcc89424 100644 --- a/boards/z1/Makefile.include +++ b/boards/z1/Makefile.include @@ -26,12 +26,10 @@ export TERMFLAGS += -p "$(PORT)" export INCLUDES += -I $(RIOTCPU)/msp430-common/include -I$(RIOTBOARD)/$(BOARD)/include -I$(RIOTBASE)/drivers/cc2420/include -I$(RIOTBASE)/sys/net/include ifneq (,$(filter defaulttransceiver,$(USEMODULE))) - ifeq (,$(filter cc2240,$(USEMODULE))) - USEMODULE += cc2420 - endif - ifeq (,$(filter transceiver,$(USEMODULE))) - USEMODULE += transceiver - endif + USEMODULE += cc2420 + ifeq (,$(filter netdev_base,$(USEMODULE))) + USEMODULE += transceiver + endif endif export UNDEF += $(BINDIR)msp430_common/startup.o diff --git a/drivers/Makefile b/drivers/Makefile index c88c956ddc89b..4f6718d42af83 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -43,5 +43,8 @@ endif ifneq (,$(filter netdev_base,$(USEMODULE))) DIRS += netdev/base endif +ifneq (,$(filter netdev_802154,$(USEMODULE))) + DIRS += netdev/802154 +endif include $(RIOTBASE)/Makefile.base diff --git a/drivers/cc2420/cc2420.c b/drivers/cc2420/cc2420.c index 9adf0b18a54fa..057665ad45799 100644 --- a/drivers/cc2420/cc2420.c +++ b/drivers/cc2420/cc2420.c @@ -14,6 +14,8 @@ #include "cc2420_settings.h" #include "cc2420_arch.h" #include "hwtimer.h" +#include "netdev/802154.h" +#include "netdev/base.h" #include "transceiver.h" #define ENABLE_DEBUG (0) @@ -26,20 +28,24 @@ /* startup timeout (2 ms) in 16MHz-clock cycles */ #define CC2420_STARTUP_TIMEOUT 32000U - /* implementation of driver's functions */ -void cc2420_initialize(void) +int cc2420_initialize(netdev_t *dev) { cc2420_spi_init(); hwtimer_wait(CC2420_WAIT_TIME); cc2420_reset(); - bool ok = false; + int ok = 0; + for (int i = 0; i < CC2420_STARTUP_ATTEMPTS; i++) { ok = cc2420_on(); - if (ok) break; + + if (ok) { + break; + } } + if (!ok) { core_panic(0x2420, "Could not start CC2420 radio transceiver"); } @@ -73,34 +79,41 @@ void cc2420_initialize(void) DEBUG("CC2420 initialized and set to channel %i and pan 0x1111\n", CC2420_DEFAULT_CHANNR); cc2420_init_interrupts(); cc2420_switch_to_rx(); + + return 0; } +#ifdef MODULE_TRANSCEIVER void cc2420_init(kernel_pid_t tpid) { transceiver_pid = tpid; - cc2420_initialize(); + cc2420_initialize(NULL); /* TODO */ } +#endif -bool cc2420_on(void) +int cc2420_on(void) { /* enable transceiver's crystal oscillator */ cc2420_strobe(CC2420_STROBE_XOSCON); /* wait for the oscillator to be stable */ unsigned int delay_on = 0; + do { delay_on++; + if (delay_on >= CC2420_STARTUP_TIMEOUT) { - /* could not start up radio transceiver! */ - return false; + /* could not start up radio transceiver!*/ + return 0; } } while ((cc2420_status_byte() & CC2420_STATUS_XOSC16M_STABLE) == 0); + hwtimer_wait(CC2420_WAIT_TIME); /* discard any potential garbage in TX buffer */ cc2420_strobe(CC2420_STROBE_FLUSHTX); /* switch to RX mode */ cc2420_switch_to_rx(); /* OK, radio is on */ - return true; + return 1; } void cc2420_off(void) @@ -111,7 +124,7 @@ void cc2420_off(void) cc2420_strobe(CC2420_STROBE_XOSCOFF); } -bool cc2420_is_on(void) +int cc2420_is_on(void) { return ((cc2420_status_byte() & CC2420_STATUS_XOSC16M_STABLE) != 0); } @@ -136,18 +149,27 @@ void cc2420_rx_irq(void) cc2420_rx_handler(); } -void cc2420_set_monitor(bool mode) +void cc2420_event(netdev_t *dev, uint32_t event_type) +{ + (void)dev; + (void)event_type; +} + +void cc2420_set_monitor(int mode) { uint16_t reg = cc2420_read_reg(CC2420_REG_MDMCTRL0); + if (mode) { reg &= ~CC2420_ADR_DECODE; - } else { + } + else { reg |= CC2420_ADR_DECODE; } + cc2420_write_reg(CC2420_REG_MDMCTRL0, reg); } -bool cc2420_get_monitor(void) +int cc2420_get_monitor(void) { uint16_t reg = cc2420_read_reg(CC2420_REG_MDMCTRL0); return ((reg & CC2420_ADR_DECODE) == 0); @@ -159,6 +181,7 @@ int cc2420_set_channel(unsigned int chan) DEBUG("Invalid channel %i set. Valid channels are 11 through 26\n", chan); return -1; } + /* * calculation from http://www.ti.com/lit/ds/symlink/cc2420.pdf p.50 */ @@ -238,9 +261,16 @@ int cc2420_set_tx_power(int pow) uint16_t txctrl_reg = cc2420_read_reg(CC2420_REG_TXCTRL); /* reset PA_LEVEL bits */ txctrl_reg &= 0xFFE0; + /* constrain power in transceiver's acceptable set of values */ - if (pow > 0) pow = 0; - if (pow < -25) pow = -25; + if (pow > 0) { + pow = 0; + } + + if (pow < -25) { + pow = -25; + } + /* determine TX level from power in dBm */ uint8_t level = DBM_TO_LEVEL[-pow]; /* put wanted value in PA_LEVEL bits, and write back register */ @@ -264,33 +294,436 @@ int cc2420_get_tx_power(void) return pow; } -inline bool cc2420_channel_clear(void) +int cc2420_channel_clear(netdev_t *dev) { - return (cc2420_get_cca() != 0); + /* XXX: first check only for backwards compatibility with transceiver + * (see cc2420_init) remove when adapter for transceiver exists */ + if (dev != &cc2420_netdev) { + return -ENODEV; + } + + return (cc2420_get_cca() != 0) ? 1 : 0; } -/* CC2420 low-level radio driver definition */ -const ieee802154_radio_driver_t cc2420_radio_driver = { - .init = cc2420_initialize, - .on = cc2420_on, - .off = cc2420_off, - .is_on = cc2420_is_on, - .load_tx = cc2420_load_tx_buf, - .transmit = cc2420_transmit_tx_buf, - .send = cc2420_do_send, - .set_receive_callback = cc2420_set_recv_callback, - .switch_to_rx = cc2420_switch_to_rx, - .set_channel = do_set_channel, - .get_channel = cc2420_get_channel, - .set_address = do_set_address, - .get_address = cc2420_get_address, - .set_long_address = do_set_long_address, - .get_long_address = cc2420_get_address_long, - .set_pan_id = do_set_pan_id, - .get_pan_id = cc2420_get_pan, - .set_tx_power = do_set_tx_power, - .get_tx_power = cc2420_get_tx_power, - .channel_is_clear = cc2420_channel_clear, - .set_promiscuous_mode = cc2420_set_monitor, - .in_promiscuous_mode = cc2420_get_monitor +int cc2420_get_option(netdev_t *dev, netdev_opt_t opt, void *value, + size_t *value_len) +{ + /* XXX: first check only for backwards compatibility with transceiver + * (see cc2420_init) remove when adapter for transceiver exists */ + if (dev != &cc2420_netdev) { + return -ENODEV; + } + + switch (opt) { + case NETDEV_OPT_CHANNEL: + if (*value_len < sizeof(unsigned int)) { + return -EOVERFLOW; + } + + if (*value_len > sizeof(unsigned int)) { + *value_len = sizeof(unsigned int); + } + + *((unsigned int *)value) = cc2420_get_channel(); + + break; + + case NETDEV_OPT_ADDRESS: + if (*value_len < sizeof(uint16_t)) { + return -EOVERFLOW; + } + + if (*value_len > sizeof(uint16_t)) { + *value_len = sizeof(uint16_t); + } + + *((uint16_t *)value) = cc2420_get_address(); + + break; + + case NETDEV_OPT_NID: + if (*value_len < sizeof(uint16_t)) { + return -EOVERFLOW; + } + + if (*value_len > sizeof(uint16_t)) { + *value_len = sizeof(uint16_t); + } + + *((uint16_t *)value) = cc2420_get_pan(); + + break; + + case NETDEV_OPT_ADDRESS_LONG: + if (*value_len < sizeof(uint64_t)) { + return -EOVERFLOW; + } + + if (*value_len > sizeof(uint64_t)) { + *value_len = sizeof(uint64_t); + } + + *((uint64_t *)value) = cc2420_get_address_long(); + + break; + + case NETDEV_OPT_TX_POWER: + if (*value_len < sizeof(int)) { + return -EOVERFLOW; + } + + if (*value_len > sizeof(int)) { + *value_len = sizeof(int); + } + + *((uint64_t *)value) = cc2420_get_tx_power(); + + break; + + case NETDEV_OPT_MAX_PACKET_SIZE: + if (*value_len == 0) { + return -EOVERFLOW; + } + + if (*value_len > sizeof(uint8_t)) { + *value_len = sizeof(uint8_t); + } + + *((uint8_t *)value) = CC2420_MAX_PKT_LENGTH; + + break; + + case NETDEV_OPT_PROTO: + if (*value_len < sizeof(netdev_proto_t)) { + return -EOVERFLOW; + } + + if (*value_len > sizeof(netdev_proto_t)) { + *value_len = sizeof(netdev_proto_t); + } + + *((netdev_type_t *)value) = NETDEV_PROTO_802154; + + break; + + default: + return -ENOTSUP; + } + + return 0; +} + +static int _type_pun_up_unsigned(void *value_out, size_t desired_len, + void *value_in, size_t given_len) +{ + if (given_len > desired_len) { + return -EOVERFLOW; + } + + /* XXX this is ugly, but bear with me */ + switch (given_len) { + case 8: + switch (desired_len) { + case 8: + *((uint64_t *)value_out) = (*((uint64_t *)value_in)); + return 0; + + default: + return -EINVAL; + } + + case 4: + switch (desired_len) { + case 8: + *((uint64_t *)value_out) = (uint64_t)(*((uint32_t *)value_in)); + return 0; + + case 4: + *((uint32_t *)value_out) = (*((uint32_t *)value_in)); + return 0; + + default: + return -EINVAL; + } + + case 2: + switch (desired_len) { + case 8: + *((uint64_t *)value_out) = (uint64_t)(*((uint16_t *)value_in)); + return 0; + + case 4: + *((uint32_t *)value_out) = (uint32_t)(*((uint16_t *)value_in)); + return 0; + + case 2: + *((uint16_t *)value_out) = (*((uint16_t *)value_in)); + return 0; + + default: + return -EINVAL; + } + + case 1: + switch (desired_len) { + case 8: + *((uint64_t *)value_out) = (uint64_t)(*((uint8_t *)value_in)); + return 0; + + case 4: + *((uint32_t *)value_out) = (uint32_t)(*((uint8_t *)value_in)); + return 0; + + case 2: + *((uint16_t *)value_out) = (uint16_t)(*((uint8_t *)value_in)); + return 0; + + case 1: + *((uint8_t *)value_out) = (*((uint8_t *)value_in)); + return 0; + + default: + return -EINVAL; + } + + default: + return -EINVAL; + } +} + +static int _type_pun_up_signed(void *value_out, size_t desired_len, + void *value_in, size_t given_len) +{ + if (given_len > desired_len) { + return -EOVERFLOW; + } + + /* XXX this is ugly, but bear with me */ + switch (given_len) { + case 8: + switch (desired_len) { + case 8: + *((int64_t *)value_out) = (*((int64_t *)value_in)); + return 0; + + default: + return -EINVAL; + } + + case 4: + switch (desired_len) { + case 8: + *((int64_t *)value_out) = (int64_t)(*((int32_t *)value_in)); + return 0; + + case 4: + *((int32_t *)value_out) = (*((int32_t *)value_in)); + return 0; + + default: + return -EINVAL; + } + + case 2: + switch (desired_len) { + case 8: + *((int64_t *)value_out) = (int64_t)(*((int16_t *)value_in)); + return 0; + + case 4: + *((int32_t *)value_out) = (int32_t)(*((int16_t *)value_in)); + return 0; + + case 2: + *((int16_t *)value_out) = (*((int16_t *)value_in)); + return 0; + + default: + return -EINVAL; + } + + case 1: + switch (desired_len) { + case 8: + *((int64_t *)value_out) = (int64_t)(*((int8_t *)value_in)); + return 0; + + case 4: + *((int32_t *)value_out) = (int32_t)(*((int8_t *)value_in)); + return 0; + + case 2: + *((int16_t *)value_out) = (int16_t)(*((int8_t *)value_in)); + return 0; + + case 1: + *((int8_t *)value_out) = (*((int8_t *)value_in)); + return 0; + + default: + return -EINVAL; + } + + default: + return -EINVAL; + } +} + +int cc2420_set_option(netdev_t *dev, netdev_opt_t opt, void *value, + size_t value_len) +{ + uint8_t set_value[sizeof(uint64_t)]; + int res = 0; + + /* XXX: first check only for backwards compatibility with transceiver + * (see cc2420_init) remove when adapter for transceiver exists */ + if (dev != &cc2420_netdev) { + return -ENODEV; + } + + switch (opt) { + case NETDEV_OPT_CHANNEL: + if ((res = _type_pun_up_unsigned(set_value, sizeof(unsigned int), + value, value_len)) == 0) { + unsigned int *v = (unsigned int *)set_value; + + if (*v > 26) { + return -EINVAL; + } + + cc2420_set_channel(*v); + } + + break; + + case NETDEV_OPT_ADDRESS: + if ((res = _type_pun_up_unsigned(set_value, sizeof(uint16_t), + value, value_len)) == 0) { + uint16_t *v = (uint16_t *)set_value; + + if (*v == 0xffff) { + /* Do not allow setting to broadcast */ + return -EINVAL; + } + + cc2420_set_address(*v); + } + + break; + + case NETDEV_OPT_NID: + if ((res = _type_pun_up_unsigned(set_value, sizeof(uint16_t), + value, value_len)) == 0) { + uint16_t *v = (uint16_t *)set_value; + + if (*v == 0xffff) { + /* Do not allow setting to broadcast */ + return -EINVAL; + } + + cc2420_set_pan(*v); + } + + break; + + case NETDEV_OPT_ADDRESS_LONG: + if ((res = _type_pun_up_unsigned(set_value, sizeof(uint64_t), + value, value_len)) == 0) { + uint64_t *v = (uint64_t *)set_value; + /* TODO: error checking? */ + cc2420_set_address_long(*v); + } + + break; + + case NETDEV_OPT_TX_POWER: + if ((res = _type_pun_up_signed(set_value, sizeof(int), + value, value_len)) == 0) { + int *v = (int *)set_value; + /* TODO: error checking? */ + cc2420_set_tx_power(*v); + } + + break; + + default: + return -ENOTSUP; + } + + return res; +} + + +int cc2420_get_state(netdev_t *dev, netdev_state_t *state) +{ + /* XXX: first check only for backwards compatibility with transceiver + * (see cc2420_init) remove when adapter for transceiver exists */ + if (dev != &cc2420_netdev) { + return -ENODEV; + } + + if (!cc2420_is_on()) { + *state = NETDEV_STATE_POWER_OFF; + } + else if (cc2420_get_monitor()) { + *state = NETDEV_STATE_PROMISCUOUS_MODE; + } + else { + *state = NETDEV_STATE_RX_MODE; + } + + return 0; +} + +int cc2420_set_state(netdev_t *dev, netdev_state_t state) +{ + /* XXX: first check only for backwards compatibility with transceiver + * (see cc2420_init) remove when adapter for transceiver exists */ + if (dev != &cc2420_netdev) { + return -ENODEV; + } + + if (state != NETDEV_STATE_PROMISCUOUS_MODE && cc2420_get_monitor()) { + cc2420_set_monitor(0); + } + + switch (state) { + case NETDEV_STATE_POWER_OFF: + cc2420_off(); + break; + + case NETDEV_STATE_RX_MODE: + cc2420_switch_to_rx(); + break; + + case NETDEV_STATE_PROMISCUOUS_MODE: + cc2420_set_monitor(1); + break; + + default: + return -ENOTSUP; + } + + return 0; +} + +/* CC2420 netdev radio driver definition */ +const netdev_802154_driver_t cc2420_driver = { + cc2420_initialize, + netdev_802154_send_data, + cc2420_add_data_recv_callback, + cc2420_rem_data_recv_callback, + cc2420_get_option, + cc2420_set_option, + cc2420_get_state, + cc2420_set_state, + cc2420_event, + cc2420_load_tx_buf, + cc2420_transmit_tx_buf, + netdev_802154_send, + cc2420_add_raw_recv_callback, + cc2420_rem_raw_recv_callback, + cc2420_channel_clear, }; + +netdev_t cc2420_netdev = { NETDEV_TYPE_802154, (netdev_driver_t *) &cc2420_driver, NULL }; diff --git a/drivers/cc2420/cc2420_rx.c b/drivers/cc2420/cc2420_rx.c index 4c509e8c96f48..9cd6a865fedda 100644 --- a/drivers/cc2420/cc2420_rx.c +++ b/drivers/cc2420/cc2420_rx.c @@ -26,12 +26,81 @@ cc2420_packet_t cc2420_rx_buffer[CC2420_RX_BUF_SIZE]; volatile uint8_t rx_buffer_next; /* index of next free cell in RX buffer */ /* pointer to the callback low-level function for packet reception */ -static receive_802154_packet_callback_t recv_func = NULL; +typedef struct { + enum { CC2420_CB_TYPE_NONE = 0, CC2420_CB_TYPE_RAW, CC2420_CB_TYPE_DATA } type; + union { + netdev_802153_raw_packet_cb_t raw; + netdev_rcv_data_cb_t data; + } cb; +} cc2420_callback_t; +static cc2420_callback_t recv_func = {0, {NULL}}; -void cc2420_set_recv_callback(receive_802154_packet_callback_t recv_cb) +int cc2420_add_raw_recv_callback(netdev_t *dev, netdev_802153_raw_packet_cb_t recv_cb) { - recv_func = recv_cb; + /* XXX: first check only for backwards compatibility with transceiver + * (see cc2420_init) remove when adapter for transceiver exists */ + if (dev != &cc2420_netdev) { + return -ENODEV; + } + + if (recv_func.cb.raw != NULL) { + return -ENOBUFS; + } + + recv_func.type = CC2420_CB_TYPE_RAW; + recv_func.cb.raw = recv_cb; + + return 0; +} + +int cc2420_rem_raw_recv_callback(netdev_t *dev, netdev_802153_raw_packet_cb_t recv_cb) +{ + /* XXX: first check only for backwards compatibility with transceiver + * (see cc2420_init) remove when adapter for transceiver exists */ + if (dev != &cc2420_netdev) { + return -ENODEV; + } + + if (recv_func.cb.raw == recv_cb) { + recv_func.cb.raw = NULL; + } + + return 0; +} + +int cc2420_add_data_recv_callback(netdev_t *dev, netdev_rcv_data_cb_t recv_cb) +{ + /* XXX: first check only for backwards compatibility with transceiver + * (see cc2420_init) remove when adapter for transceiver exists */ + if (dev != &cc2420_netdev) { + return -ENODEV; + } + + if (recv_func.cb.data != NULL) { + return -ENOBUFS; + } + + recv_func.type = CC2420_CB_TYPE_DATA; + recv_func.cb.data = recv_cb; + + return 0; +} + +int cc2420_rem_data_recv_callback(netdev_t *dev, netdev_rcv_data_cb_t recv_cb) +{ + /* XXX: first check only for backwards compatibility with transceiver + * (see cc2420_init) remove when adapter for transceiver exists */ + if (dev != &cc2420_netdev) { + return -ENODEV; + } + + + if (recv_func.cb.data == recv_cb) { + recv_func.cb.data = NULL; + } + + return 0; } void cc2420_rx_handler(void) @@ -52,14 +121,15 @@ void cc2420_rx_handler(void) cc2420_read_fifo(&pkt_lqi, 1); crc_ok = ((pkt_lqi & 0x80) != 0); pkt_lqi &= 0x7F; + if (!crc_ok) { DEBUG("Got packet with invalid crc.\n"); return; } /* low-level reception mechanism (for MAC layer, among others) */ - if (recv_func != NULL) { - recv_func(buf, pkt_len - 2, pkt_rssi, pkt_lqi, crc_ok); + if (recv_func.type == CC2420_CB_TYPE_RAW && recv_func.cb.raw != NULL) { + recv_func.cb.raw(NULL, buf, pkt_len - 2, pkt_rssi, pkt_lqi, crc_ok); } /* decode received packet */ @@ -71,12 +141,25 @@ void cc2420_rx_handler(void) &cc2420_rx_buffer[rx_buffer_next].frame, cc2420_rx_buffer[rx_buffer_next].length); + /* low-level data reception mechanism */ + if (recv_func.type == CC2420_CB_TYPE_DATA && recv_func.cb.data != NULL && + cc2420_rx_buffer[rx_buffer_next].frame.fcf.frame_type == 1) { + recv_func.cb.data(NULL, cc2420_rx_buffer[rx_buffer_next].frame.src_addr, + (cc2420_rx_buffer[rx_buffer_next].frame.fcf.src_addr_m == 2) ? 2 : 8, + cc2420_rx_buffer[rx_buffer_next].frame.dest_addr, + (cc2420_rx_buffer[rx_buffer_next].frame.fcf.dest_addr_m == 2) ? 2 : 8, + cc2420_rx_buffer[rx_buffer_next].frame.payload, + cc2420_rx_buffer[rx_buffer_next].frame.payload_len); + } + /* follow-up to transceiver module if adequate */ if (cc2420_rx_buffer[rx_buffer_next].frame.fcf.frame_type != 2) { #ifdef DEBUG ieee802154_frame_print_fcf_frame(&cc2420_rx_buffer[rx_buffer_next].frame); #endif +#ifdef MODULE_TRANSCEIVER + /* notify transceiver thread if any */ if (transceiver_pid != KERNEL_PID_UNDEF) { msg_t m; @@ -84,6 +167,8 @@ void cc2420_rx_handler(void) m.content.value = rx_buffer_next; msg_send_int(&m, transceiver_pid); } + +#endif } #ifdef DEBUG diff --git a/drivers/cc2420/cc2420_tx.c b/drivers/cc2420/cc2420_tx.c index e55cb3a1cc4ec..442b5b0fdd5f0 100644 --- a/drivers/cc2420/cc2420_tx.c +++ b/drivers/cc2420/cc2420_tx.c @@ -23,49 +23,59 @@ static void cc2420_gen_pkt(uint8_t *buf, cc2420_packet_t *packet); static uint8_t sequence_nr; -static bool wait_for_ack; - -radio_tx_status_t cc2420_load_tx_buf(ieee802154_packet_kind_t kind, - ieee802154_node_addr_t dest, - bool use_long_addr, - bool wants_ack, - void *buf, - unsigned int len) +static int wait_for_ack; + +netdev_802154_tx_status_t cc2420_load_tx_buf(netdev_t *dev, + netdev_802154_pkt_kind_t kind, + netdev_802154_node_addr_t *dest, + int use_long_addr, + int wants_ack, + netdev_hlist_t *upper_layer_hdrs, + void *buf, + unsigned int len) { + (void)dev; /* TODO: see cc2420_initialize() in cc2420.c */ + uint8_t hdr[24]; /* FCS : frame version 0, we don't manage security, nor batchs of packets */ switch (kind) { - case PACKET_KIND_BEACON: - hdr[0] = 0x00; - break; - case PACKET_KIND_DATA: - hdr[0] = 0x01; - break; - case PACKET_KIND_ACK: - hdr[0] = 0x02; - break; - default: - return RADIO_TX_INVALID_PARAM; + case NETDEV_802154_PKT_KIND_BEACON: + hdr[0] = 0x00; + break; + + case NETDEV_802154_PKT_KIND_DATA: + hdr[0] = 0x01; + break; + + case NETDEV_802154_PKT_KIND_ACK: + hdr[0] = 0x02; + break; + + default: + return NETDEV_802154_TX_STATUS_INVALID_PARAM; } if (wants_ack) { hdr[0] |= 0x20; } + wait_for_ack = wants_ack; uint16_t src_pan = cc2420_get_pan(); - bool compress_pan = false; + int compress_pan = 0; if (use_long_addr) { hdr[1] = 0xcc; - } else { + } + else { hdr[1] = 0x88; + /* short address mode, use PAN ID compression for intra-PAN communication */ - if (dest.pan.id == src_pan) { - compress_pan = true; + if (dest->pan.id == src_pan) { + compress_pan = 1; hdr[0] |= 0x40; } } @@ -78,14 +88,14 @@ radio_tx_status_t cc2420_load_tx_buf(ieee802154_packet_kind_t kind, if (use_long_addr) { /* dest long addr */ - hdr[idx++] = (uint8_t)(dest.long_addr & 0xFF); - hdr[idx++] = (uint8_t)(dest.long_addr >> 8); - hdr[idx++] = (uint8_t)(dest.long_addr >> 16); - hdr[idx++] = (uint8_t)(dest.long_addr >> 24); - hdr[idx++] = (uint8_t)(dest.long_addr >> 32); - hdr[idx++] = (uint8_t)(dest.long_addr >> 40); - hdr[idx++] = (uint8_t)(dest.long_addr >> 48); - hdr[idx++] = (uint8_t)(dest.long_addr >> 56); + hdr[idx++] = (uint8_t)(dest->long_addr & 0xFF); + hdr[idx++] = (uint8_t)(dest->long_addr >> 8); + hdr[idx++] = (uint8_t)(dest->long_addr >> 16); + hdr[idx++] = (uint8_t)(dest->long_addr >> 24); + hdr[idx++] = (uint8_t)(dest->long_addr >> 32); + hdr[idx++] = (uint8_t)(dest->long_addr >> 40); + hdr[idx++] = (uint8_t)(dest->long_addr >> 48); + hdr[idx++] = (uint8_t)(dest->long_addr >> 56); /* src long addr */ uint64_t src_long_addr = cc2420_get_address_long(); hdr[idx++] = (uint8_t)(src_long_addr & 0xFF); @@ -96,19 +106,22 @@ radio_tx_status_t cc2420_load_tx_buf(ieee802154_packet_kind_t kind, hdr[idx++] = (uint8_t)(src_long_addr >> 40); hdr[idx++] = (uint8_t)(src_long_addr >> 48); hdr[idx++] = (uint8_t)(src_long_addr >> 56); - } else { + } + else { /* dest PAN ID */ - hdr[idx++] = (uint8_t)(dest.pan.id & 0xFF); - hdr[idx++] = (uint8_t)(dest.pan.id >> 8); + hdr[idx++] = (uint8_t)(dest->pan.id & 0xFF); + hdr[idx++] = (uint8_t)(dest->pan.id >> 8); /* dest short addr */ - hdr[idx++] = (uint8_t)(dest.pan.addr & 0xFF); - hdr[idx++] = (uint8_t)(dest.pan.addr >> 8); + hdr[idx++] = (uint8_t)(dest->pan.addr & 0xFF); + hdr[idx++] = (uint8_t)(dest->pan.addr >> 8); + /* src PAN ID */ if (!compress_pan) { uint16_t src_pan = cc2420_get_pan(); hdr[idx++] = (uint8_t)(src_pan & 0xFF); hdr[idx++] = (uint8_t)(src_pan >> 8); } + /* src short addr */ uint16_t src_addr = cc2420_get_address(); hdr[idx++] = (uint8_t)(src_addr & 0xFF); @@ -116,30 +129,41 @@ radio_tx_status_t cc2420_load_tx_buf(ieee802154_packet_kind_t kind, } /* total frame size */ - uint8_t size = idx + len + 2; + size_t size = idx + len + 2 + netdev_get_hlist_len(upper_layer_hdrs); + if (size > CC2420_MAX_PKT_LENGTH) { - return RADIO_TX_PACKET_TOO_LONG; + return NETDEV_802154_TX_STATUS_PACKET_TOO_LONG; } + uint8_t size_byte = (uint8_t)size; + netdev_hlist_t *ptr = upper_layer_hdrs; + /* flush TX buffer */ cc2420_strobe(CC2420_STROBE_FLUSHTX); /* write length, header and payload to TX FIFO */ - cc2420_write_fifo(&size, 1); + cc2420_write_fifo(&size_byte, 1); + if (upper_layer_hdrs) { + do { + cc2420_write_fifo(ptr->header, + (radio_packet_length_t)(ptr->header_len)); + netdev_hlist_advance(&ptr); + } while (ptr != upper_layer_hdrs); + } cc2420_write_fifo(hdr, idx); cc2420_write_fifo(buf, len); - return RADIO_TX_OK; + return NETDEV_802154_TX_STATUS_OK; } #define CC2420_ACK_WAIT_DELAY_uS 1000 #define ACK_LENGTH 5 -radio_tx_status_t cc2420_transmit_tx_buf(void) +netdev_802154_tx_status_t cc2420_transmit_tx_buf(netdev_t *dev) { /* check if channel clear */ - if (!cc2420_channel_clear()) { - return RADIO_TX_MEDIUM_BUSY; + if (!cc2420_channel_clear(dev)) { + return NETDEV_802154_TX_STATUS_MEDIUM_BUSY; } /* put tranceiver in idle mode */ @@ -150,6 +174,7 @@ radio_tx_status_t cc2420_transmit_tx_buf(void) cc2420_strobe(CC2420_STROBE_TXON); int abort_count = 0; + while (cc2420_get_sfd() == 0) { /* Wait for SFD signal to be set -> sync word transmitted */ abort_count++; @@ -158,7 +183,7 @@ radio_tx_status_t cc2420_transmit_tx_buf(void) /* Abort waiting. CC2420 maybe in wrong mode e.g. sending preambles for always */ puts("[CC2420 TX] fatal error: could not send packet\n"); - return RADIO_TX_ERROR; + return NETDEV_802154_TX_STATUS_ERROR; } } @@ -166,6 +191,7 @@ radio_tx_status_t cc2420_transmit_tx_buf(void) /* wait for packet to be sent, i.e.: SFD to go down */ uint8_t st; + do { st = cc2420_status_byte(); } while (cc2420_get_sfd() != 0); @@ -173,44 +199,30 @@ radio_tx_status_t cc2420_transmit_tx_buf(void) /* check for underflow error flag */ if (st & CC2420_STATUS_TX_UNDERFLOW) { - return RADIO_TX_UNDERFLOW; + return NETDEV_802154_TX_STATUS_UNDERFLOW; } /* wait for ACK only if needed */ if (!wait_for_ack) { - return RADIO_TX_OK; + return NETDEV_802154_TX_STATUS_OK; } /* delay for the peer to answer our packet */ //TODO design a more robust method? hwtimer_wait(HWTIMER_TICKS(CC2420_ACK_WAIT_DELAY_uS)); + /* try to read a returning ACK packet */ if (cc2420_get_fifop()) { uint8_t ackbuf[ACK_LENGTH]; /* a packet has arrived, read the arrived data */ cc2420_read_fifo(ackbuf, ACK_LENGTH); + if (ackbuf[0] == 0x02 /* ack packet in buffer */ && (ackbuf[2] == sequence_nr - 1)) /* correct sequence number */ - return RADIO_TX_OK; + return NETDEV_802154_TX_STATUS_OK; } - return RADIO_TX_NOACK; -} -radio_tx_status_t cc2420_do_send(ieee802154_packet_kind_t kind, - ieee802154_node_addr_t dest, - bool use_long_addr, - bool wants_ack, - void *buf, - unsigned int len) -{ - radio_tx_status_t st = cc2420_load_tx_buf(kind, dest, - use_long_addr, - wants_ack, - buf, len); - if (st != RADIO_TX_OK) { - return st; - } - return cc2420_transmit_tx_buf(); + return NETDEV_802154_TX_STATUS_NOACK; } int16_t cc2420_send(cc2420_packet_t *packet) diff --git a/drivers/include/cc2420.h b/drivers/include/cc2420.h index e4242856dba00..1f07db1770b86 100644 --- a/drivers/include/cc2420.h +++ b/drivers/include/cc2420.h @@ -78,13 +78,11 @@ Frame type value: #ifndef CC2420_H #define CC2420_H -#include - #include "kernel_types.h" #include "ieee802154_frame.h" #include "cc2420_settings.h" -#include "radio_driver.h" +#include "netdev/802154.h" #define CC2420_MAX_PKT_LENGTH 127 #define CC2420_MAX_DATA_LENGTH (118) @@ -103,15 +101,18 @@ typedef struct __attribute__ ((packed)) { ieee802154_frame_t frame; /** < the ieee802154 frame */ int8_t rssi; /** < the rssi value */ uint8_t lqi; /** < the link quality indicator */ - bool crc; /** < 1 if crc was successfull, 0 otherwise */ + int crc; /** < 1 if crc was successfull, 0 otherwise */ /* @} */ } cc2420_packet_t; +extern netdev_t cc2420_netdev; /**< netdev representation of this driver */ + /** * @brief Initialize the CC2420 transceiver. */ -void cc2420_initialize(void); +int cc2420_initialize(netdev_t *dev); +#ifdef MODULE_TRANSCEIVER /** * @brief Init the CC2420 for use with RIOT's transceiver module. * @@ -119,13 +120,14 @@ void cc2420_initialize(void); */ void cc2420_init(kernel_pid_t tpid); +#endif /** * @brief Turn CC2420 on. * - * @return true if the radio was correctly turned on; false otherwise. + * @return 1 if the radio was correctly turned on; 0 otherwise. */ -bool cc2420_on(void); +int cc2420_on(void); /** * @brief Turn CC2420 off. @@ -135,9 +137,9 @@ void cc2420_off(void); /** * @brief Indicate if the CC2420 is on. * - * @return true if the radio transceiver is on (active); false otherwise. + * @return 1 if the radio transceiver is on (active); 0 otherwise. */ -bool cc2420_is_on(void); +int cc2420_is_on(void); /** * @brief Switches the CC2420 into receive mode. @@ -148,18 +150,18 @@ void cc2420_switch_to_rx(void); * @brief Turns monitor (promiscuous) mode on or off. * * @param[in] mode The desired mode: - * true for monitor (promiscuous) mode; - * false for normal (auto address-decoding) mode. + * 1 for monitor (promiscuous) mode; + * 0 for normal (auto address-decoding) mode. */ -void cc2420_set_monitor(bool mode); +void cc2420_set_monitor(int mode); /** * @brief Indicate if the CC2420 is in monitor (promiscuous) mode. * - * @return true if the transceiver is in monitor (promiscuous) mode; - * false if it is in normal (auto address-decoding) mode. + * @return 1 if the transceiver is in monitor (promiscuous) mode; + * 0 if it is in normal (auto address-decoding) mode. */ -bool cc2420_get_monitor(void); +int cc2420_get_monitor(void); /** * @brief Set the channel of the CC2420. @@ -247,11 +249,11 @@ int cc2420_get_tx_power(void); * @brief Checks if the radio medium is available/clear to send * ("Clear Channel Assessment" a.k.a. CCA). * - * @return a `true` value if radio medium is clear (available), - * a `false` value otherwise. + * @return a 1 value if radio medium is clear (available), + * a 0 value otherwise. * */ -bool cc2420_channel_clear(void); +int cc2420_channel_clear(netdev_t *dev); /** * @brief Interrupt handler, gets fired when a RX overflow happens. @@ -269,84 +271,98 @@ void cc2420_rx_irq(void); * @brief Sets the function called back when a packet is received. * (Low-level mechanism, parallel to the `transceiver` module). * - * @param[in] recv_cb callback function for 802.15.4 packet arrival; - * pass `NULL` to deactivate packet reception. + * @param[in] recv_cb callback function for 802.15.4 packet arrival + * + * @return 0 on success + * @return -ENODEV if *dev* is not recognized + * @return -ENOBUFS, if maximum number of registable callbacks is exceeded */ -void cc2420_set_recv_callback(receive_802154_packet_callback_t recv_cb); +int cc2420_add_raw_recv_callback(netdev_t *dev, + netdev_802153_raw_packet_cb_t recv_cb); /** - * @brief RX handler, process data from the RX FIFO. + * @brief Unsets the function called back when a packet is received. + * (Low-level mechanism, parallel to the `transceiver` module). + * + * @param[in] recv_cb callback function to unset * + * @return 0 on success + * @return -ENODEV if *dev* is not recognized + * @return -ENOBUFS, if maximum number of registable callbacks is exceeded */ -void cc2420_rx_handler(void); +int cc2420_rem_raw_recv_callback(netdev_t *dev, + netdev_802153_raw_packet_cb_t recv_cb); /** - * @brief Prepare the CC2420 TX buffer to send with the given packet. + * @brief Sets a function called back when a data packet is received. * - * @param[in] kind Kind of packet to transmit. - * @param[in] dest Address of the node to which the packet is sent. - * @param[in] use_long_addr `true` to use the 64-bit address mode - * with `dest` param; `false` to use - * "short" PAN-centric mode. - * @param[in] wants_ack `true` to request an acknowledgement - * from the receiving node for this packet; - * `false` otherwise. - * @param[in] buf Pointer to the buffer containing the payload - * of the 802.15.4 packet to transmit. - * The frame header (i.e.: FCS, sequence number, - * src and dest PAN and addresses) is inserted - * using values in accord with `kind` parameter - * and transceiver configuration. - * @param[in] len Length (in bytes) of the outgoing packet payload. + * @param[in] recv_cb callback function for 802.15.4 data packet arrival * - * @return `true` if the transceiver TX buffer was loaded correctly; - * `false` otherwise (transceiver error). + * @return 0 on success + * @return -ENODEV if *dev* is not recognized + * @return -ENOBUFS, if maximum number of registable callbacks is exceeded */ -radio_tx_status_t cc2420_load_tx_buf(ieee802154_packet_kind_t kind, - ieee802154_node_addr_t dest, - bool use_long_addr, - bool wants_ack, - void *buf, - unsigned int len); +int cc2420_add_data_recv_callback(netdev_t *dev, + netdev_rcv_data_cb_t recv_cb); /** - * @brief Transmit the data loaded into the CC2420 TX buffer. + * @brief Unsets a function called back when a data packet is received. + * + * @param[in] recv_cb callback function to unset + * + * @return 0 on success + * @return -ENODEV if *dev* is not recognized + * @return -ENOBUFS, if maximum number of registable callbacks is exceeded + */ +int cc2420_rem_data_recv_callback(netdev_t *dev, + netdev_rcv_data_cb_t recv_cb); + +/** + * @brief RX handler, process data from the RX FIFO. * - * @return The outcome of this packet's transmission. - * @see radio_tx_status_t */ -radio_tx_status_t cc2420_transmit_tx_buf(void); +void cc2420_rx_handler(void); /** - * @brief Transmit the given IEEE 802.15.4 packet, - * by calling successively functions`load_tx()` - * and `transmit()`. + * @brief Prepare the CC2420 TX buffer to send with the given packet. * * @param[in] kind Kind of packet to transmit. * @param[in] dest Address of the node to which the packet is sent. - * @param[in] use_long_addr `true` to use the 64-bit address mode - * with `dest` param; `false` to use + * @param[in] use_long_addr 1 to use the 64-bit address mode + * with *dest* param; 0 to use * "short" PAN-centric mode. - * @param[in] wants_ack `true` to request an acknowledgement + * @param[in] wants_ack 1 to request an acknowledgement * from the receiving node for this packet; - * `false` otherwise. + * 0 otherwise. + * @param[in] upper_layer_hdrs header data from higher network layers from + * highest to lowest layer. Must be prepended to + * the data stream by the network device. May be + * NULL if there are none. * @param[in] buf Pointer to the buffer containing the payload * of the 802.15.4 packet to transmit. * The frame header (i.e.: FCS, sequence number, * src and dest PAN and addresses) is inserted - * using values in accord with `kind` parameter + * using values in accord with *kind* parameter * and transceiver configuration. * @param[in] len Length (in bytes) of the outgoing packet payload. * - * @return The outcome of this packet's transmission. - * @see radio_tx_status_t + * @return @ref netdev_802154_tx_status_t + */ +netdev_802154_tx_status_t cc2420_load_tx_buf(netdev_t *dev, + netdev_802154_pkt_kind_t kind, + netdev_802154_node_addr_t *dest, + int use_long_addr, + int wants_ack, + netdev_hlist_t *upper_layer_hdrs, + void *buf, + unsigned int len); + +/** + * @brief Transmit the data loaded into the CC2420 TX buffer. + * + * @return @ref netdev_802154_tx_status_t */ -radio_tx_status_t cc2420_do_send(ieee802154_packet_kind_t kind, - ieee802154_node_addr_t dest, - bool use_long_addr, - bool wants_ack, - void *buf, - unsigned int len); +netdev_802154_tx_status_t cc2420_transmit_tx_buf(netdev_t *dev); /** * @brief Send function, sends a cc2420_packet_t over the air. @@ -367,34 +383,10 @@ extern cc2420_packet_t cc2420_rx_buffer[CC2420_RX_BUF_SIZE]; /** Utility macro: get CC2420's status byte */ #define cc2420_status_byte() cc2420_strobe(NOBYTE) - -/* setter functions wrappers, to maintain compatibility with both - ieee802154_radio_driver_t and transceiver module */ - -static inline void do_set_channel(unsigned int chan) { - cc2420_set_channel(chan); -} - -static inline void do_set_address(uint16_t addr) { - cc2420_set_address(addr); -} - -static inline void do_set_long_address(uint64_t addr) { - cc2420_set_address_long(addr); -} - -static inline void do_set_pan_id(uint16_t pan) { - cc2420_set_pan(pan); -} - -static inline void do_set_tx_power(int pow) { - cc2420_set_tx_power(pow); -} - /** * CC2420 low-level radio driver definition. */ -extern const ieee802154_radio_driver_t cc2420_radio_driver; +extern const netdev_802154_driver_t cc2420_driver; #endif diff --git a/drivers/include/netdev/802154.h b/drivers/include/netdev/802154.h new file mode 100644 index 0000000000000..23d1d5d4737e8 --- /dev/null +++ b/drivers/include/netdev/802154.h @@ -0,0 +1,412 @@ +/* + * Copyright (C) 2014 INRIA + * + * 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 netdev_802154 IEEE 802.15.4 interface + * @addtogroup netdev + * @{ + * @file netdev/802154.h + * @brief API definitions for 802.15.4 radio transceivers' drivers + * @author Kévin Roussel + * @author Martine Lenders + * + */ + +#ifndef __NETDEV_802154_H_ +#define __NETDEV_802154_H_ + +#include + +#include "netdev/base.h" + +/** + * @brief Callback function type for receiving incoming packets + * from 802.15.4 radio transceiver. + * + * @param[in] buf Pointer to the buffer containing the incoming + * 802.15.4 packet's raw data. + * @param[in] len Length (in bytes) of the incoming packet's raw data. + * @param[in] rssi Value of the Receive Signal Strength Indicator (RSSI) + * for the incoming packet. + * @param[in] lqi Value of the Link Quality Indicator (LQI) + * for the incoming packet. + * @param[in] crc_ok 1 if incoming packet's checksum (CRC) is valid; + * 0 otherwise (corrupted packet). + */ +typedef void (* netdev_802153_raw_packet_cb_t)(netdev_t *dev, + void *buf, + size_t len, + int8_t rssi, + uint8_t lqi, + int crc_ok); + +/** + * @brief Kind of packet to prepare/configure for transmission. + * + */ +typedef enum { + /** Beacon packet */ + NETDEV_802154_PKT_KIND_BEACON, + + /** Standard data packet */ + NETDEV_802154_PKT_KIND_DATA, + + /** Acknowledgement packet */ + NETDEV_802154_PKT_KIND_ACK, + + /** MAC command */ + NETDEV_802154_PKT_KIND_MAC_CMD, + + /** invalid packet kind */ + NETDEV_802154_PKT_KIND_INVALID = -1 + +} netdev_802154_pkt_kind_t; + +/** + * @brief Return values for packet emission function of 802.15.4 radio driver. + * + */ +typedef enum { + /** Transmission completed successfully */ + NETDEV_802154_TX_STATUS_OK, + + /** Device not found or not an IEEE 802.15.4 device */ + NETDEV_802154_TX_STATUS_NO_DEV, + + /** Transmission buffer underflow (forgot to call netdev_802154_driver_t::load_tx() + before netdev_802154_driver_t::transmit() ) */ + NETDEV_802154_TX_STATUS_UNDERFLOW, + + /** Transmission cannot start because radio medium is already busy */ + NETDEV_802154_TX_STATUS_MEDIUM_BUSY, + + /** Transmission failed because of collision on radio medium */ + NETDEV_802154_TX_STATUS_COLLISION, + + /** Wrong parameter given to TX-related functions */ + NETDEV_802154_TX_STATUS_INVALID_PARAM, + + /** Too much given data to be included in a single packet */ + NETDEV_802154_TX_STATUS_PACKET_TOO_LONG, + + /** Transmission supposedly failed since no ACK packet + has been received as response */ + NETDEV_802154_TX_STATUS_NOACK, + + /** Transmission failed because of an unexpected (fatal?) error */ + NETDEV_802154_TX_STATUS_ERROR, + +} netdev_802154_tx_status_t; + +/** + * @brief Definition of an IEEE 802.15.4 node address. + * + * @details The `union` allows to choose between PAN-centric addressing + * ("volatile" 16-bit address and 16-bit PAN ID), or canonical + * IEEE 64-bit ("long") addressing. + * + */ +typedef union { + /** @brief PAN-centric ("short") addressing mode */ + struct { + /** @brief Address assigned to the node within its current PAN */ + uint16_t addr; + /** @brief ID of the PAN to which the node is currently associated */ + uint16_t id; + } pan; + /** @brief 64-bit ("long") addressing mode */ + uint64_t long_addr; +} netdev_802154_node_addr_t; + +/** + * @brief IEEE 802.15.4 radio driver API definition. + * + * @details This is the set of functions that must be implemented + * by any driver for a 802.15.4 radio transceiver. + * + * @extends netdev_driver_t + */ +typedef struct { + /** + * @see netdev_driver_t::init + */ + int (*init)(netdev_t *dev); + + /** + * @details wraps netdev_802154_driver_t::send with + * + * @see netdev_driver_t::send_data + */ + int (*send_data)(netdev_t *dev, void *dest, size_t dest_len, + netdev_hlist_t *upper_layer_hdrs, void *data, + size_t data_len); + + /** + * @see netdev_driver_t::add_receive_data_callback + */ + int (*add_receive_data_callback)(netdev_t *dev, netdev_rcv_data_cb_t cb); + + /** + * @see netdev_driver_t::rem_receive_data_callback + */ + int (*rem_receive_data_callback)(netdev_t *dev, netdev_rcv_data_cb_t cb); + + /** + * @see netdev_driver_t::get_option + * + * @detail The options are constrained as follows: + * + * *opt* | type | *value_len* + * --------------------------- | ----------- | ----------- + * NETDEV_OPT_CHANNEL | uint8_t | >= 1 + * NETDEV_OPT_ADDRESS | uint16_t | >= 2 + * NETDEV_OPT_NID | uint16_t | >= 2 + * NETDEV_OPT_ADDRESS_LONG | uint64_t | >= 8 + * NETDEV_OPT_TX_POWER | int | >= 4 + * NETDEV_OPT_MAX_PACKET_SIZE | uint8_t | >= 1 + */ + int (*get_option)(netdev_t *dev, netdev_opt_t opt, void *value, + size_t *value_len); + + /** + * @see netdev_driver_t::set_option + * + * @detail The options are constrained as follows: + * + * *opt* | type | *value_len* | *value* + * --------------------------- | ----------- | ----------- | -------- + * NETDEV_OPT_CHANNEL | uint8_t | >= 1 | <= 26 + * NETDEV_OPT_ADDRESS | uint16_t | >= 2 | + * NETDEV_OPT_NID | uint16_t | >= 2 | + * NETDEV_OPT_ADDRESS_LONG | uint64_t | >= 8 | + * NETDEV_OPT_TX_POWER | int | >= 4 | + * + * NETDEV_OPT_MAX_PACKET_SIZE can not be set. + */ + int (*set_option)(netdev_t *dev, netdev_opt_t opt, void *value, + size_t value_len); + + /** + * @see netdev_driver_t::get_state + */ + int (*get_state)(netdev_t *dev, netdev_state_t *state); + + /** + * @see netdev_driver_t::set_state + */ + int (*set_state)(netdev_t *dev, netdev_state_t state); + + /** + * @see netdev_driver_t::event + */ + void (*event)(netdev_t *dev, uint32_t event_type); + + /** + * @brief Load the transceiver TX buffer with the given + * IEEE 802.15.4 packet. + * + * @param[in] kind Kind of packet to transmit. + * @param[in] dest Address of the node to which the packet is sent. + * @param[in] use_long_addr 1 to use the 64-bit address mode + * with *dest* param; 0 to use + * "short" PAN-centric mode. + * @param[in] wants_ack 1 to request an acknowledgement + * from the receiving node for this packet; + * 0 otherwise. + * @param[in] upper_layer_hdrs header data from higher network layers from + * highest to lowest layer. Must be prepended to + * the data stream by the network device. May be + * NULL if there are none. + * @param[in] buf Pointer to the buffer containing the payload + * of the 802.15.4 packet to transmit. + * The frame header (i.e.: FCS, sequence number, + * src and dest PAN and addresses) is inserted + * using values in accord with *kind* parameter + * and transceiver configuration. + * @param[in] len Length (in bytes) of the outgoing packet payload. + * + * @return The outcome of this packet's transmission. + * @see netdev_802154_tx_status_t + */ + netdev_802154_tx_status_t (* load_tx)(netdev_t *dev, + netdev_802154_pkt_kind_t kind, + netdev_802154_node_addr_t *dest, + int use_long_addr, + int wants_ack, + netdev_hlist_t *upper_layer_hdrs, + void *buf, + unsigned int len); + + /** + * @brief Transmit the data loaded into the transceiver TX buffer. + * + * @return The outcome of this packet's transmission. + * @see netdev_802154_tx_status_t + */ + netdev_802154_tx_status_t (* transmit)(netdev_t *dev); + + /** + * @brief Transmit the given IEEE 802.15.4 packet, + * by calling successively functions netdev_802154_driver_t::load_tx() + * and netdev_802154_driver_t::transmit(). + * + * @param[in] kind Kind of packet to transmit. + * @param[in] dest Address of the node to which the packet is sent. + * @param[in] use_long_addr 1 to use the 64-bit address mode + * with *dest* param; 0 to use + * "short" PAN-centric mode. + * @param[in] wants_ack 1 to request an acknowledgement + * from the receiving node for this packet; + * 0 otherwise. + * @param[in] upper_layer_hdrs header data from higher network layers from + * highest to lowest layer. Must be prepended to + * the data stream by the network device. May be + * NULL if there are none. + * @param[in] buf Pointer to the buffer containing the payload + * of the 802.15.4 packet to transmit. + * The frame header (i.e.: FCS, sequence number, + * src and dest PAN and addresses) is inserted + * using values in accord with *kind* parameter + * and transceiver configuration. + * @param[in] len Length (in bytes) of the outgoing packet payload. + * + * @return The outcome of this packet's transmission. + * @see netdev_802154_tx_status_t + */ + netdev_802154_tx_status_t (* send)(netdev_t *dev, + netdev_802154_pkt_kind_t kind, + netdev_802154_node_addr_t *dest, + int use_long_addr, + int wants_ack, + netdev_hlist_t *upper_layer_hdrs, + void *buf, + unsigned int len); + + /** + * @brief Add a function to be called back when the radio transceiver + * has received a incoming packet. + * + * @detail This function differentiates from + * netdev_driver_t::add_receive_data_callback() as it expects + * a callback that excepts the raw frame format of IEEE 802.15.4, + * rather than just the source and destination addresses and the + * payload. + * + * @param[in] recv_func the callback function to invoke for each + * packet received by the radio transceiver. + * @see netdev_802153_raw_packet_cb_t + * + * @return 0, on success + * @return -ENOBUFS, if maximum number of registrable callbacks is exceeded + * @return -ENODEV, if *dev* is not recognized + */ + int (* add_receive_raw_callback)(netdev_t *dev, netdev_802153_raw_packet_cb_t recv_func); + + /** + * @brief Remove a callback set by netdev_802154_driver_t::add_receive_raw_callback() + * + * @param[in] recv_func the callback function to invoke for each + * packet received by the radio transceiver. + * @see netdev_802153_raw_packet_cb_t + * + * @return 0, on success + * @return -ENODEV, if *dev* is not recognized + */ + int (* rem_receive_raw_callback)(netdev_t *dev, netdev_802153_raw_packet_cb_t recv_func); + + /** + * @brief Indicates if the radio medium is available for transmission + * ("Clear Channel Assessment"). + * + * @return 1 if radio medium is "clear" (available); + * @return 0 if another transmission is already running. + * @return -ENODEV, if *dev* is not recognized + */ + int (* channel_is_clear)(netdev_t *dev); +} netdev_802154_driver_t; + +/* define to implement yourself and omit compilation of this function */ +#ifndef NETDEV_802154_SEND_DATA_OVERLOAD +/** + * @brief wraps netdev_802154_driver_t::send(), default value for + * netdev_802154_driver_t::send_data(). + * + * @param[in] dev the network device + * @param[in] dest the (hardware) destination address for the data + * in host byte order. + * @param[in] dest_len the length of *dest* in byte + * @param[in] upper_layer_hdrs header data from higher network layers from + * highest to lowest layer. Must be prepended to + * the data stream by the network device. May be + * NULL if there are none. + * @param[in] data the data to send + * @param[in] data_len the length of *data* in byte + * + * @return the number of byte actually (data_len + total length of upper layer + * headers) send on success + * @return -EAFNOSUPPORT if address of length dest_len is not supported + * by the device *dev* + * @return -EBUSY if transmission cannot start because radio medium is already + * busy or collision on radio medium occured. + * @return -EINVAL if wrong parameter was given + * @return -ENODEV if *dev* is not recognized as IEEE 802.15.4 device + * @return -EMSGSIZE if the total frame size is too long to fit in a frame + * of the device *dev* + * @return -EIO if any other occured (netdev_802154_driver_t::send() returned + * NETDEV_802154_TX_STATUS_ERROR) + */ +int netdev_802154_send_data(netdev_t *dev, void *dest, size_t dest_len, + netdev_hlist_t *upper_layer_hdrs, void *data, + size_t data_len); +#endif /* NETDEV_802154_SEND_DATA_OVERLOAD */ + +/* define to implement yourself and omit compilation of this function */ +#ifndef NETDEV_802154_SEND_OVERLOAD +/** + * @brief Transmit the given IEEE 802.15.4 packet, by calling + * functions netdev_802154_driver_t::load_tx() and + * netdev_802154_driver_t::transmit() successfully. Default value for + * netdev_802154_driver_t::send() + * + * @param[in] kind Kind of packet to transmit. + * @param[in] dest Address of the node to which the packet is sent. + * @param[in] use_long_addr 1 to use the 64-bit address mode + * with *dest* param; 0 to use + * "short" PAN-centric mode. + * @param[in] wants_ack 1 to request an acknowledgement + * from the receiving node for this packet; + * 0 otherwise. + * @param[in] upper_layer_hdrs header data from higher network layers from + * highest to lowest layer. Must be prepended to + * the data stream by the network device. May be + * NULL if there are none. + * @param[in] buf Pointer to the buffer containing the payload + * of the 802.15.4 packet to transmit. + * The frame header (i.e.: FCS, sequence number, + * src and dest PAN and addresses) is inserted + * using values in accord with *kind* parameter + * and transceiver configuration. + * @param[in] len Length (in bytes) of the outgoing packet payload. + * + * @return @ref netdev_802154_tx_status_t + */ +netdev_802154_tx_status_t netdev_802154_send(netdev_t *dev, + netdev_802154_pkt_kind_t kind, + netdev_802154_node_addr_t *dest, + int use_long_addr, + int wants_ack, + netdev_hlist_t *upper_layer_hdrs, + void *buf, + unsigned int len); +#endif /* NETDEV_802154_SEND_OVERLOAD */ + +#endif /* __NETDEV_802154_H_ */ + +/** + * @} + */ diff --git a/drivers/include/netdev/base.h b/drivers/include/netdev/base.h index 2e67cc51d4327..3f31b40d1a824 100644 --- a/drivers/include/netdev/base.h +++ b/drivers/include/netdev/base.h @@ -37,6 +37,8 @@ typedef enum { NETDEV_TYPE_UNKNOWN = 0, /**< Type was not specified and may not understand this API */ NETDEV_TYPE_BASE, /**< Device understands this API */ + NETDEV_TYPE_802154, /**< Device understands this API and the API + defined in @ref netdev_802154 */ } netdev_type_t; /** @@ -170,6 +172,12 @@ typedef struct { /** * @brief Initialize a given network device. * + * @detail This is typically not to set netdev_t::type or netdev_t::more. + * This has to be done externally (e.g. given by the board's + * configuration), but init() might check it. netdev_t::driver + * could be set in init() but for consistancie's sake it is + * ill-adviced. + * * @param[in] dev the device to initialize * * @return 0 on success diff --git a/drivers/include/netdev/default.h b/drivers/include/netdev/default.h index c3cc45c625052..fd60ca34d8a44 100644 --- a/drivers/include/netdev/default.h +++ b/drivers/include/netdev/default.h @@ -27,4 +27,13 @@ * * @brief Default device as a pointer of netdev_t. */ + +#ifdef MODULE_CC2420 +#include "cc2420.h" + +#ifndef NETDEV_DEFAULT +#define NETDEV_DEFAULT ((netdev_t *)(&cc2420_netdev)) +#endif /* NETDEV_DEFAULT */ +#endif /* MODULE_CC2420 */ + #endif /* __NETDEV_DEFAULT_H_ */ diff --git a/drivers/include/radio_driver.h b/drivers/include/radio_driver.h deleted file mode 100644 index fb6b9dac045a0..0000000000000 --- a/drivers/include/radio_driver.h +++ /dev/null @@ -1,353 +0,0 @@ -/** - * Copyright (C) 2014 INRIA - * - * 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. - */ - -/** - * @ingroup drivers - * @{ - * @file radio_driver.h - * @brief API definitions for 802.15.4 radio transceivers' drivers - * @author Kévin Roussel - * - */ - -#ifndef IEEE802154_RADIO_DRIVER_API_ -#define IEEE802154_RADIO_DRIVER_API_ - -#include -#include - - -/** - * @brief Callback function type for receiving incoming packets - * from 802.15.4 radio transceiver. - * - * @param[in] buf Pointer to the buffer containing the incoming - * 802.15.4 packet's raw data. - * @param[in] len Length (in bytes) of the incoming packet's raw data. - * @param[in] rssi Value of the Receive Signal Strength Indicator (RSSI) - * for the incoming packet. - * @param[in] lqi Value of the Link Quality Indicator (LQI) - * for the incoming packet. - * @param[in] crc_ok @c true if incoming packet's checksum (CRC) is valid; - * @c false otherwise (corrupted packet). - */ -typedef void (* receive_802154_packet_callback_t)(void *buf, - unsigned int len, - int8_t rssi, - uint8_t lqi, - bool crc_ok); - -/** - * @brief Kind of packet to prepare/configure for transmission. - * - */ -typedef enum { - /** Beacon packet */ - PACKET_KIND_BEACON, - - /** Standard data packet */ - PACKET_KIND_DATA, - - /** Acknowledgement packet */ - PACKET_KIND_ACK, - - /** MAC command */ - PACKET_KIND_MAC_CMD, - - /** invalid packet kind */ - PACKET_KIND_INVALID = -1 - -} ieee802154_packet_kind_t; - -/** - * @brief Return values for packet emission function of 802.15.4 radio driver. - * - */ -typedef enum { - /** Transmission completed successfully */ - RADIO_TX_OK, - - /** Transmission buffer underflow (forgot to call @c load_tx() - before @c transmit() ) */ - RADIO_TX_UNDERFLOW, - - /** Transmission cannot start because radio medium is already busy */ - RADIO_TX_MEDIUM_BUSY, - - /** Transmission failed because of collision on radio medium */ - RADIO_TX_COLLISION, - - /** Wrong parameter given to TX-related functions */ - RADIO_TX_INVALID_PARAM, - - /** Too much given data to be included in a single packet */ - RADIO_TX_PACKET_TOO_LONG, - - /** Transmission supposedly failed since no ACK packet - has been received as response */ - RADIO_TX_NOACK, - - /** Transmission failed because of an unexpected (fatal?) error */ - RADIO_TX_ERROR, - -} radio_tx_status_t; - - -/** - * @brief Definition of an IEEE 802.15.4 node address. - * - * @details The @c union allows to choose between PAN-centric addressing - * ("volatile" 16-bit address and 16-bit PAN ID), or canonical - * IEEE 64-bit ("long") addressing. - * - */ -typedef union { - /** @brief PAN-centric ("short") addressing mode */ - struct { - /** @brief Address assigned to the node within its current PAN */ - uint16_t addr; - /** @brief ID of the PAN to which the node is currently associated */ - uint16_t id; - } pan; - /** @brief 64-bit ("long") addressing mode */ - uint64_t long_addr; -} ieee802154_node_addr_t; - - -/** - * @brief IEEE 802.15.4 radio driver API definition. - * - * @details This is the set of functions that must be implemented - * by any driver for a 802.15.4 radio transceiver. - * - */ -typedef struct { - /** - * @brief Initialize the radio transceiver (call before first use). - */ - void (* init)(void); - - /** - * @brief Turn radio transceiver on. - * - * @return @c true if radio transceiver was actually started; - * @c false if an error prevented transceiver to start. - */ - bool (* on)(void); - - /** - * @brief Turn radio transceiver off. - */ - void (* off)(void); - - /** - * @brief Indicate whether the radio transceiver is up and running. - * - * @return @c true if radio transceiver is on; - * @c false if it is off. - */ - bool (* is_on)(void); - - /** - * @brief Load the tranceiver TX buffer with the given - * IEEE 802.15.4 packet. - * - * @param[in] kind Kind of packet to transmit. - * @param[in] dest Address of the node to which the packet is sent. - * @param[in] use_long_addr @c true to use the 64-bit address mode - * with @c dest param; @c false to use - * "short" PAN-centric mode. - * @param[in] wants_ack @c true to request an acknowledgement - * from the receiving node for this packet; - * @c false otherwise. - * @param[in] buf Pointer to the buffer containing the payload - * of the 802.15.4 packet to transmit. - * The frame header (i.e.: FCS, sequence number, - * src and dest PAN and addresses) is inserted - * using values in accord with @c kind parameter - * and transceiver configuration. - * @param[in] len Length (in bytes) of the outgoing packet payload. - * - * @return The outcome of this packet's transmission. - * @see radio_tx_status_t - */ - radio_tx_status_t (* load_tx)(ieee802154_packet_kind_t kind, - ieee802154_node_addr_t dest, - bool use_long_addr, - bool wants_ack, - void *buf, - unsigned int len); - - /** - * @brief Transmit the data loaded into the transceiver TX buffer. - * - * @return The outcome of this packet's transmission. - * @see radio_tx_status_t - */ - radio_tx_status_t (* transmit)(void); - - /** - * @brief Transmit the given IEEE 802.15.4 packet, - * by calling successively functions @c load_tx() - * and @c transmit(). - * - * @param[in] kind Kind of packet to transmit. - * @param[in] dest Address of the node to which the packet is sent. - * @param[in] use_long_addr @c true to use the 64-bit address mode - * with @c dest param; @c false to use - * "short" PAN-centric mode. - * @param[in] wants_ack @c true to request an acknowledgement - * from the receiving node for this packet; - * @c false otherwise. - * @param[in] buf Pointer to the buffer containing the payload - * of the 802.15.4 packet to transmit. - * The frame header (i.e.: FCS, sequence number, - * src and dest PAN and addresses) is inserted - * using values in accord with @c kind parameter - * and transceiver configuration. - * @param[in] len Length (in bytes) of the outgoing packet payload. - * - * @return The outcome of this packet's transmission. - * @see radio_tx_status_t - */ - radio_tx_status_t (* send)(ieee802154_packet_kind_t kind, - ieee802154_node_addr_t dest, - bool use_long_addr, - bool wants_ack, - void *buf, - unsigned int len); - - /** - * @brief Define the function to be called back the radio transceiver - * has received a incoming packet. - * - * @param[in] recv_func the callback function to invoke for each - * packet received by the radio transceiver. - * @see receive_802154_packet_callback_t - */ - void (* set_receive_callback)(receive_802154_packet_callback_t recv_func); - - /** - * @brief Switch the radio transceiver to receive mode. - */ - void (* switch_to_rx)(void); - - /** - * @brief Set the 802.15.4 channel to be used - * by the radio transceiver as medium. - * - * @param[in] chan Channel to switch to. - * Usual values are 0 (868 MHz band), - * 1 to 10 (915 MHz band), and - * 11 to 26 (2.4 GHz band). - */ - void (* set_channel)(unsigned int chan); - - /** - * @brief Get the 802.15.4 channel currently used - * by the radio transceiver as medium. - */ - unsigned int (* get_channel)(void); - - /** - * @brief Set the 16-bit short address to be used by - * the radio transceiver within the current PAN. - * - * @param[in] addr Address to use. - */ - void (* set_address)(uint16_t addr); - - /** - * @brief Get the 16-bit short address currently used by - * the radio transceiver within the current PAN. - */ - uint16_t (* get_address)(void); - - /** - * @brief Set the 64-bit long ("extended") address - * to be used by the radio transceiver. - * - * @param[in] addr Address to use. - */ - void (* set_long_address)(uint64_t addr); - - /** - * @brief Get the 64-bit long ("extended") address - * currently used by the radio transceiver. - */ - uint64_t (* get_long_address)(void); - - /** - * @brief Set the 16-bit PAN ID within which the radio - * transceiver shall operate. - * - * @param[in] pan PAN ID to use. - */ - void (* set_pan_id)(uint16_t pan); - - /** - * @brief Get the 16-bit PAN ID within which the radio - * transceiver currently operates. - */ - uint16_t (* get_pan_id)(void); - - /** - * @brief Set the transmission power of the radio transceiver. - * - * @param[in] pow Output power to use (in dB). - */ - void (* set_tx_power)(int pow); - - /** - * @brief Get the transmission (output) power currently used - * by the radio transceiver (in dB). - */ - int (* get_tx_power)(void); - - /** - * @brief Indicates if the radio medium is available for transmission - * ("Clear Channel Assessment"). - * - * @return @c true if radio medium is "clear" (available); - * @c false if another transmission is already running. - */ - bool (* channel_is_clear)(void); - - /** - * @brief Set the radio transceiver in or out of "promiscuous mode" - * (i.e. reception of all packets without regard for their - * intended destination). - * - * @param[in] monitor Set to @c true to put the transceiver in - * "promiscuous mode" (a.k.a. monitor mode); - * @c false to only receive packets actually - * destined to the currently used address (i.e.: - * to activate hardware address-decoding). - */ - void (* set_promiscuous_mode)(bool monitor); - - /** - * @brief Indicates if the radio medium is currently in "promiscuous - * mode" (i.e. receiving all packets without regard for their - * intended destination). - * - * @return @c true if the transceiver is in "promiscuous mode"; - * @c false if only packets actually destined to the - * current transceiver are received (i.e. hardware - * address-decoding is active). - */ - bool (* in_promiscuous_mode)(void); - -} ieee802154_radio_driver_t; - - -#endif /* IEEE802154_RADIO_DRIVER_API_ */ - -/** - * @} - */ diff --git a/drivers/netdev/802154/802154.c b/drivers/netdev/802154/802154.c new file mode 100644 index 0000000000000..4ce5ea2843d86 --- /dev/null +++ b/drivers/netdev/802154/802154.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2014 Martin Lenders + * + * 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. + */ + +/** + * @addtogroup netdev + * @{ + * + * @file 802154.c + * @brief Provides wrappers of @ref netdev/base.h functions to + * netdev/802154.h functions. + * + * @author Martine Lenders + */ + +#include +#include +#include + +#include "netdev/802154.h" + +static inline netdev_802154_driver_t *_get_driver(netdev_t *dev) +{ + return (netdev_802154_driver_t *)dev->driver; +} + +/* define to implement yourself and omit compilation of this function */ +#ifndef NETDEV_802154_SEND_DATA_OVERLOAD +int netdev_802154_send_data(netdev_t *dev, void *dest, size_t dest_len, + netdev_hlist_t *upper_layer_hdrs, void *data, + size_t data_len) +{ + if (dev == NULL || dev->type != NETDEV_TYPE_802154) { + return -ENODEV; + } + + if (dest_len != 8 && dest_len != 4) { /* 8 for EUI-64, 4 for short address + PAN ID*/ + return -EAFNOSUPPORT; + } + + switch (_get_driver(dev)->send(dev, NETDEV_802154_PKT_KIND_DATA, + (netdev_802154_node_addr_t *)dest, + (dest_len == 8), 0, upper_layer_hdrs, + data, data_len)) { + case NETDEV_802154_TX_STATUS_OK: + return (int)(data_len + netdev_get_hlist_len(upper_layer_hdrs)); + + case NETDEV_802154_TX_STATUS_MEDIUM_BUSY: + case NETDEV_802154_TX_STATUS_COLLISION: + return -EBUSY; + + case NETDEV_802154_TX_STATUS_INVALID_PARAM: + return -EINVAL; + + case NETDEV_802154_TX_STATUS_PACKET_TOO_LONG: + return -EMSGSIZE; + + case NETDEV_802154_TX_STATUS_ERROR: + default: + return -EIO; + /* NETDEV_802154_TX_STATUS_UNDERFLOW can not happen since + * netdev_802154_driver_t::send always calls + * netdev_802154_driver_t::load_tx */ + /* NETDEV_802154_TX_STATUS_NOACK can not happen since + * wants_ack == 0 */ + } +} +#endif /* NETDEV_802154_SEND_DATA_OVERLOAD */ + +/* define to implement yourself and omit compilation of this function */ +#ifndef NETDEV_802154_SEND_OVERLOAD +netdev_802154_tx_status_t netdev_802154_send(netdev_t *dev, + netdev_802154_pkt_kind_t kind, + netdev_802154_node_addr_t *dest, + int use_long_addr, + int wants_ack, + netdev_hlist_t *upper_layer_hdrs, + void *buf, + unsigned int len) +{ + netdev_802154_tx_status_t status; + + if (dev == NULL || dev->type != NETDEV_TYPE_802154) { + return NETDEV_802154_TX_STATUS_NO_DEV; + } + + status = _get_driver(dev)->load_tx(dev, kind, dest, use_long_addr, wants_ack, + upper_layer_hdrs, buf, len); + + if (status != NETDEV_802154_TX_STATUS_OK) { + return status; + } + + return _get_driver(dev)->transmit(dev); +} +#endif /* NETDEV_802154_SEND_OVERLOAD */ + +/** + * @} + */ diff --git a/drivers/netdev/802154/Makefile b/drivers/netdev/802154/Makefile new file mode 100644 index 0000000000000..18db41909ad13 --- /dev/null +++ b/drivers/netdev/802154/Makefile @@ -0,0 +1,5 @@ +MODULE := netdev_802154 + +INCLUDES += -I$(RIOTBASE)/drivers/include + +include $(RIOTBASE)/Makefile.base diff --git a/drivers/netdev/base/base.c b/drivers/netdev/base/base.c index ff22b679e8a7b..abfd8316b4f9e 100644 --- a/drivers/netdev/base/base.c +++ b/drivers/netdev/base/base.c @@ -31,7 +31,7 @@ size_t netdev_get_hlist_len(const netdev_hlist_t *hlist) do { length += ptr->header_len; - clist_advance((clist_node_t **)&ptr); + netdev_hlist_advance(&ptr); } while (ptr != hlist); return length;