diff --git a/Makefile.dep b/Makefile.dep index d919119e4ece2..2f668d4c6027c 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -76,9 +76,8 @@ ifneq (,$(filter cc2420,$(USEMODULE))) endif ifneq (,$(filter at86rf231,$(USEMODULE))) - USEMODULE += transceiver + USEMODULE += netdev_802154 USEMODULE += ieee802154 - USEMODULE += vtimer endif ifneq (,$(filter vtimer,$(USEMODULE))) @@ -95,6 +94,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/iot-lab_M3/Makefile.dep b/boards/iot-lab_M3/Makefile.dep index cbe5dc58c4b58..ab5c150ef0981 100644 --- a/boards/iot-lab_M3/Makefile.dep +++ b/boards/iot-lab_M3/Makefile.dep @@ -1,4 +1,6 @@ ifneq (,$(filter defaulttransceiver,$(USEMODULE))) USEMODULE += at86rf231 - USEMODULE += transceiver + ifeq (,$(filter netdev_base,$(USEMODULE))) + USEMODULE += transceiver + endif endif diff --git a/core/include/config.h b/core/include/config.h index 59ef1f4296f8d..005df365f4418 100644 --- a/core/include/config.h +++ b/core/include/config.h @@ -40,6 +40,7 @@ typedef struct { uint16_t id; /**< unique node identifier */ uint8_t radio_address; /**< address for radio communication */ uint8_t radio_channel; /**< current frequency */ + uint16_t radio_pan_id; /**< PAN id for radio communication */ char name[CONFIG_NAME_LEN]; /**< name of the node */ } config_t; diff --git a/drivers/Makefile b/drivers/Makefile index bb0312148d02d..9c0b5ef25e131 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -49,5 +49,8 @@ endif ifneq (,$(filter mq3,$(USEMODULE))) DIRS += mq3 endif +ifneq (,$(filter netdev_802154,$(USEMODULE))) + DIRS += netdev/802154 +endif include $(RIOTBASE)/Makefile.base diff --git a/drivers/at86rf231/at86rf231.c b/drivers/at86rf231/at86rf231.c index d94eed7e4105d..82427c3e7b302 100644 --- a/drivers/at86rf231/at86rf231.c +++ b/drivers/at86rf231/at86rf231.c @@ -31,32 +31,48 @@ #define ENABLE_DEBUG (0) #include "debug.h" +#define _MAX_RETRIES (100) + static uint16_t radio_pan; static uint8_t radio_channel; static uint16_t radio_address; static uint64_t radio_address_long; +netdev_802154_raw_packet_cb_t at86rf231_raw_packet_cb; +netdev_rcv_data_cb_t at86rf231_data_packet_cb; + +/* default source address length for sending in number of byte */ +static size_t _default_src_addr_len = 2; + uint8_t driver_state; -uint8_t at86rf231_get_status(void); void at86rf231_gpio_spi_interrupts_init(void); void at86rf231_reset(void); - +#ifdef MODULE_TRANSCEIVER void at86rf231_init(kernel_pid_t tpid) { transceiver_pid = tpid; + at86rf231_initialize(NULL); +} +#endif +int at86rf231_initialize(netdev_t *dev) +{ at86rf231_gpio_spi_interrupts_init(); at86rf231_reset(); - // TODO : Enable addr decode, auto ack, auto crc - // and configure security, power, channel, pan + at86rf231_on(); - radio_pan = 0; - radio_pan = 0x00FF & (uint16_t)at86rf231_reg_read(AT86RF231_REG__PAN_ID_0); - radio_pan |= (uint16_t)at86rf231_reg_read(AT86RF231_REG__PAN_ID_1) << 8; + /* TODO : + * and configure security, power + */ +#ifdef MODULE_CONFIG + at86rf231_set_pan(sysconfig.radio_pan_id); +#else + at86rf231_set_pan(0x0001); +#endif radio_channel = at86rf231_reg_read(AT86RF231_REG__PHY_CC_CCA) & AT86RF231_PHY_CC_CCA_MASK__CHANNEL; @@ -72,49 +88,104 @@ void at86rf231_init(kernel_pid_t tpid) radio_address_long |= ((uint64_t)at86rf231_reg_read(AT86RF231_REG__IEEE_ADDR_1)) << 48; radio_address_long |= ((uint64_t)at86rf231_reg_read(AT86RF231_REG__IEEE_ADDR_1)) << 56; + return 0; +} + +int at86rf231_on(void) +{ + /* Send a FORCE TRX OFF command */ + at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__FORCE_TRX_OFF); + + /* busy wait for TRX_OFF state */ + do { + int delay = _MAX_RETRIES; + if (!--delay) { + DEBUG("at86rf231 : ERROR : could not enter TRX_OFF mode\n"); + return 0; + } + } while (at86rf231_get_status() != AT86RF231_TRX_STATUS__TRX_OFF); + + at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__RX_ON); + + /* change into basic reception mode to initialise CSMA seed by RNG */ + do { + int delay = _MAX_RETRIES; + if (!--delay) { + DEBUG("at86rf231 : ERROR : could not enter RX_ON mode\n"); + return 0; + } + } while (at86rf231_get_status() != AT86RF231_TRX_STATUS__RX_ON); + + /* read RNG values into CSMA_SEED_0 */ + for (int i=0; i<7; i+=2) { + uint8_t tmp = at86rf231_reg_read(AT86RF231_REG__PHY_CC_CCA); + tmp = ((tmp&0x60)>>5); + at86rf231_reg_write(AT86RF231_REG__CSMA_SEED_0, tmp << i); + } + /* read CSMA_SEED_1 and write back with RNG value */ + uint8_t tmp = at86rf231_reg_read(AT86RF231_REG__CSMA_SEED_1); + tmp = ((at86rf231_reg_read(AT86RF231_REG__PHY_CC_CCA)&0x60)>>5); + at86rf231_reg_write(AT86RF231_REG__CSMA_SEED_1, tmp); + + /* change into reception mode */ at86rf231_switch_to_rx(); + + return 1; +} + +void at86rf231_off(void) +{ + /* TODO */ +} + +int at86rf231_is_on(void) +{ + return ((at86rf231_get_status() & 0x1f) != 0); } void at86rf231_switch_to_rx(void) { gpio_irq_disable(AT86RF231_INT); - // Send a FORCE TRX OFF command - at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__FORCE_TRX_OFF); + /* now change to PLL_ON state for extended operating mode */ + at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__PLL_ON); + + do { + int max_wait = _MAX_RETRIES; + if (!--max_wait) { + DEBUG("at86rf231 : ERROR : could not enter PLL_ON mode\n"); + break; + } + } while (at86rf231_get_status() != AT86RF231_TRX_STATUS__PLL_ON); - // Reset IRQ to TRX END only + /* Reset IRQ to TRX END only */ at86rf231_reg_write(AT86RF231_REG__IRQ_MASK, AT86RF231_IRQ_STATUS_MASK__TRX_END); - // Read IRQ to clear it + /* Read IRQ to clear it */ at86rf231_reg_read(AT86RF231_REG__IRQ_STATUS); - // Enable IRQ interrupt + /* Enable IRQ interrupt */ gpio_irq_enable(AT86RF231_INT); - // Start RX - at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__RX_ON); - - // wait until it is on RX_ON state - uint8_t status; - uint8_t max_wait = 100; // TODO : move elsewhere, this is in 10us + /* Enter RX_AACK_ON state */ + at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__RX_AACK_ON); do { - status = at86rf231_get_status(); - - hwtimer_wait(HWTIMER_TICKS(10)); - + int max_wait = _MAX_RETRIES; if (!--max_wait) { - printf("at86rf231 : ERROR : could not enter RX_ON mode\n"); + DEBUG("at86rf231 : ERROR : could not enter RX_AACK_ON mode\n"); break; } - } - while ((status & AT86RF231_TRX_STATUS_MASK__TRX_STATUS) != AT86RF231_TRX_STATUS__RX_ON); + } while (at86rf231_get_status() != AT86RF231_TRX_STATUS__RX_AACK_ON); } -void at86rf231_rx_irq(void *arg) +void at86rf231_rxoverflow_irq(void) { - (void)arg; + /* TODO */ +} +void at86rf231_rx_irq(void) +{ /* check if we are in sending state */ if (driver_state == AT_DRIVER_STATE_SENDING) { /* Read IRQ to clear it */ @@ -123,7 +194,6 @@ void at86rf231_rx_irq(void *arg) at86rf231_switch_to_rx(); /* clear internal state */ driver_state = AT_DRIVER_STATE_DEFAULT; - return; } else { /* handle receive */ @@ -131,6 +201,51 @@ void at86rf231_rx_irq(void *arg) } } +int at86rf231_add_raw_recv_callback(netdev_t *dev, + netdev_802154_raw_packet_cb_t recv_cb) +{ + (void)dev; + + if (at86rf231_raw_packet_cb == NULL){ + at86rf231_raw_packet_cb = recv_cb; + return 0; + } + + return -ENOBUFS; + +} + +int at86rf231_rem_raw_recv_callback(netdev_t *dev, + netdev_802154_raw_packet_cb_t recv_cb) +{ + (void)dev; + + at86rf231_raw_packet_cb = NULL; + return 0; +} + +int at86rf231_add_data_recv_callback(netdev_t *dev, + netdev_rcv_data_cb_t recv_cb) +{ + (void)dev; + + if (at86rf231_data_packet_cb == NULL){ + at86rf231_data_packet_cb = recv_cb; + return 0; + } + + return -ENOBUFS; +} + +int at86rf231_rem_data_recv_callback(netdev_t *dev, + netdev_rcv_data_cb_t recv_cb) +{ + (void)dev; + + at86rf231_data_packet_cb = NULL; + return 0; +} + radio_address_t at86rf231_set_address(radio_address_t address) { radio_address = address; @@ -182,34 +297,44 @@ uint16_t at86rf231_get_pan(void) return radio_pan; } -int8_t at86rf231_set_channel(uint8_t channel) +int at86rf231_set_channel(unsigned int channel) { - uint8_t cca_state; radio_channel = channel; - if (channel < RF86RF231_MIN_CHANNEL || - channel > RF86RF231_MAX_CHANNEL) { + if (channel < AT86RF231_MIN_CHANNEL || + channel > AT86RF231_MAX_CHANNEL) { #if DEVELHELP puts("[at86rf231] channel out of range!"); #endif return -1; } - cca_state = at86rf231_reg_read(AT86RF231_REG__PHY_CC_CCA) & ~AT86RF231_PHY_CC_CCA_MASK__CHANNEL; - at86rf231_reg_write(AT86RF231_REG__PHY_CC_CCA, cca_state | (radio_channel & AT86RF231_PHY_CC_CCA_MASK__CHANNEL)); + at86rf231_reg_write(AT86RF231_REG__PHY_CC_CCA, (radio_channel & AT86RF231_PHY_CC_CCA_MASK__CHANNEL)); return radio_channel; } -uint8_t at86rf231_get_channel(void) +unsigned int at86rf231_get_channel(void) { return radio_channel; } -void at86rf231_set_monitor(uint8_t mode) +void at86rf231_set_monitor(int mode) { - (void) mode; - // TODO + /* read register */ + uint8_t tmp = at86rf231_reg_read(AT86RF231_REG__XAH_CTRL_1); + /* set promicuous mode depending on *mode* */ + if (mode) { + at86rf231_reg_write(AT86RF231_REG__XAH_CTRL_1, (tmp|AT86RF231_XAH_CTRL_1__AACK_PROM_MODE)); + } + else { + at86rf231_reg_write(AT86RF231_REG__XAH_CTRL_1, (tmp&(~AT86RF231_XAH_CTRL_1__AACK_PROM_MODE))); + } +} + +int at86rf231_get_monitor(void) +{ + return (at86rf231_reg_read(AT86RF231_REG__XAH_CTRL_1) & AT86RF231_XAH_CTRL_1__AACK_PROM_MODE); } void at86rf231_gpio_spi_interrupts_init(void) @@ -217,7 +342,7 @@ void at86rf231_gpio_spi_interrupts_init(void) /* SPI init */ spi_init_master(AT86RF231_SPI, SPI_CONF_FIRST_RISING, SPI_SPEED_5MHZ); /* IRQ0 */ - gpio_init_int(AT86RF231_INT, GPIO_NOPULL, GPIO_RISING, at86rf231_rx_irq, NULL); + gpio_init_int(AT86RF231_INT, GPIO_NOPULL, GPIO_RISING, (gpio_cb_t)at86rf231_rx_irq, NULL); /* CS */ gpio_init_out(AT86RF231_CS, GPIO_NOPULL); /* SLEEP */ @@ -240,21 +365,320 @@ void at86rf231_reset(void) while (delay--){} gpio_set(AT86RF231_RESET); +} - /* Send a FORCE TRX OFF command */ - at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__FORCE_TRX_OFF); +int at86rf231_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 at86rf231_init) remove when adapter for transceiver exists */ + if (dev != &at86rf231_netdev) { + return -ENODEV; + } - /* busy wait for TRX_OFF state */ - uint8_t status; - uint8_t max_wait = 100; + 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) = at86rf231_get_channel(); + break; - do { - status = at86rf231_get_status(); + 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) = at86rf231_get_address(); + break; - if (!--max_wait) { - printf("at86rf231 : ERROR : could not enter TRX_OFF mode\n"); + 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) = at86rf231_get_pan(); break; - } - } while ((status & AT86RF231_TRX_STATUS_MASK__TRX_STATUS) - != AT86RF231_TRX_STATUS__TRX_OFF); + + 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) = at86rf231_get_address_long(); + 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) = AT86RF231_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; + + case NETDEV_OPT_SRC_LEN: + if (*value_len < sizeof(size_t)) { + return -EOVERFLOW; + } + if (*value_len > sizeof(size_t)) { + *value_len = sizeof(size_t); + } + *((size_t *)value) = _default_src_addr_len; + + 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; + } +} + +int at86rf231_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 at86rf231_init) remove when adapter for transceiver exists */ + if (dev != &at86rf231_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; + } + at86rf231_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; + } + at86rf231_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; + } + at86rf231_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? */ + at86rf231_set_address_long(*v); + } + break; + + case NETDEV_OPT_SRC_LEN: + if ((res = _type_pun_up_unsigned(set_value, sizeof(size_t), + value, value_len)) == 0) { + size_t *v = (size_t *)set_value; + + if (*v != 2 || *v != 8) { + return -EINVAL; + } + _default_src_addr_len = *v; + } + break; + + default: + return -ENOTSUP; + } + + return res; } + +int at86rf231_get_state(netdev_t *dev, netdev_state_t *state) +{ + /* XXX: first check only for backwards compatibility with transceiver + * (see at86rf231_init) remove when adapter for transceiver exists */ + if (dev != &at86rf231_netdev) { + return -ENODEV; + } + + if (!at86rf231_is_on()) { + *state = NETDEV_STATE_POWER_OFF; + } + else if (at86rf231_get_monitor()) { + *state = NETDEV_STATE_PROMISCUOUS_MODE; + } + else { + *state = NETDEV_STATE_RX_MODE; + } + + return 0; +} + +int at86rf231_set_state(netdev_t *dev, netdev_state_t state) +{ + /* XXX: first check only for backwards compatibility with transceiver + * (see at86rf231_init) remove when adapter for transceiver exists */ + if (dev != &at86rf231_netdev) { + return -ENODEV; + } + + if (state != NETDEV_STATE_PROMISCUOUS_MODE && at86rf231_get_monitor()) { + at86rf231_set_monitor(0); + } + + switch (state) { + case NETDEV_STATE_POWER_OFF: + at86rf231_off(); + break; + + case NETDEV_STATE_RX_MODE: + at86rf231_switch_to_rx(); + break; + + case NETDEV_STATE_PROMISCUOUS_MODE: + at86rf231_set_monitor(1); + break; + + default: + return -ENOTSUP; + } + + return 0; +} + +int at86rf231_channel_is_clear(netdev_t *dev) +{ + (void)dev; + /* channel is checked by hardware automatically before transmission */ + return 1; +} + +void at86rf231_event(netdev_t *dev, uint32_t event_type) +{ + (void)dev; + (void)event_type; +} + +const netdev_802154_driver_t at86rf231_driver = { + .init = at86rf231_initialize, + .send_data = netdev_802154_send_data, + .add_receive_data_callback = at86rf231_add_data_recv_callback, + .rem_receive_data_callback = at86rf231_rem_data_recv_callback, + .get_option = at86rf231_get_option, + .set_option = at86rf231_set_option, + .get_state = at86rf231_get_state, + .set_state = at86rf231_set_state, + .event = at86rf231_event, + .load_tx = at86rf231_load_tx_buf, + .transmit = at86rf231_transmit_tx_buf, + .send = netdev_802154_send, + .add_receive_raw_callback = at86rf231_add_raw_recv_callback, + .rem_receive_raw_callback = at86rf231_rem_raw_recv_callback, + .channel_is_clear = at86rf231_channel_is_clear, +}; + +netdev_t at86rf231_netdev = { NETDEV_TYPE_802154, (netdev_driver_t *) &at86rf231_driver, NULL }; diff --git a/drivers/at86rf231/at86rf231_rx.c b/drivers/at86rf231/at86rf231_rx.c index 628d989069e66..11559cd8864ef 100644 --- a/drivers/at86rf231/at86rf231_rx.c +++ b/drivers/at86rf231/at86rf231_rx.c @@ -35,28 +35,29 @@ at86rf231_packet_t at86rf231_rx_buffer[AT86RF231_RX_BUF_SIZE]; uint8_t buffer[AT86RF231_RX_BUF_SIZE][AT86RF231_MAX_PKT_LENGTH]; volatile uint8_t rx_buffer_next; +extern netdev_802154_raw_packet_cb_t at86rf231_raw_packet_cb; void at86rf231_rx_handler(void) { uint8_t lqi, fcs_rssi; - // read packet length + /* read packet length */ at86rf231_read_fifo(&at86rf231_rx_buffer[rx_buffer_next].length, 1); - // read psdu, read packet with length as first byte and lqi as last byte. + /* read psdu, read packet with length as first byte and lqi as last byte. */ uint8_t *buf = buffer[rx_buffer_next]; at86rf231_read_fifo(buf, at86rf231_rx_buffer[rx_buffer_next].length); - // read lqi which is appended after the psdu + /* read lqi which is appended after the psdu */ lqi = buf[at86rf231_rx_buffer[rx_buffer_next].length - 1]; - // read fcs and rssi, from a register + /* read fcs and rssi, from a register */ fcs_rssi = at86rf231_reg_read(AT86RF231_REG__PHY_RSSI); - // build package + /* build package */ at86rf231_rx_buffer[rx_buffer_next].lqi = lqi; - // RSSI has no meaning here, it should be read during packet reception. + /* RSSI has no meaning here, it should be read during packet reception. */ at86rf231_rx_buffer[rx_buffer_next].rssi = fcs_rssi & 0x0F; // bit[4:0] - // bit7, boolean, 1 FCS valid, 0 FCS not valid + /* bit7, boolean, 1 FCS valid, 0 FCS not valid */ at86rf231_rx_buffer[rx_buffer_next].crc = (fcs_rssi >> 7) & 0x01; if (at86rf231_rx_buffer[rx_buffer_next].crc == 0) { @@ -64,14 +65,21 @@ void at86rf231_rx_handler(void) return; } + /* read buffer into ieee802154_frame */ ieee802154_frame_read(&buf[1], &at86rf231_rx_buffer[rx_buffer_next].frame, at86rf231_rx_buffer[rx_buffer_next].length); + /* if packet is no ACK */ if (at86rf231_rx_buffer[rx_buffer_next].frame.fcf.frame_type != 2) { #ifdef DEBUG_ENABLED ieee802154_frame_print_fcf_frame(&at86rf231_rx_buffer[rx_buffer_next].frame); #endif - + if (at86rf231_raw_packet_cb != NULL) { + at86rf231_raw_packet_cb(&at86rf231_netdev, (void*)buf, + at86rf231_rx_buffer[rx_buffer_next].length, + fcs_rssi, lqi, (fcs_rssi >> 7)); + } +#ifdef MODULE_TRANSCEIVER /* notify transceiver thread if any */ if (transceiver_pid != KERNEL_PID_UNDEF) { msg_t m; @@ -79,19 +87,21 @@ void at86rf231_rx_handler(void) m.content.value = rx_buffer_next; msg_send_int(&m, transceiver_pid); } +#endif } else { + /* This should not happen, ACKs are consumed by hardware */ #ifdef DEBUG_ENABLED DEBUG("GOT ACK for SEQ %u\n", at86rf231_rx_buffer[rx_buffer_next].frame.seq_nr); ieee802154_frame_print_fcf_frame(&at86rf231_rx_buffer[rx_buffer_next].frame); #endif } - // shift to next buffer element + /* shift to next buffer element */ if (++rx_buffer_next == AT86RF231_RX_BUF_SIZE) { rx_buffer_next = 0; } - // Read IRQ to clear it + /* Read IRQ to clear it */ at86rf231_reg_read(AT86RF231_REG__IRQ_STATUS); } diff --git a/drivers/at86rf231/at86rf231_spi.c b/drivers/at86rf231/at86rf231_spi.c index 73c25bb028426..72fb0ff98798c 100644 --- a/drivers/at86rf231/at86rf231_spi.c +++ b/drivers/at86rf231/at86rf231_spi.c @@ -72,6 +72,6 @@ void at86rf231_write_fifo(const uint8_t *data, radio_packet_length_t length) uint8_t at86rf231_get_status(void) { - return at86rf231_reg_read(AT86RF231_REG__TRX_STATUS) - & AT86RF231_TRX_STATUS_MASK__TRX_STATUS; + return (at86rf231_reg_read(AT86RF231_REG__TRX_STATUS) + & AT86RF231_TRX_STATUS_MASK__TRX_STATUS); } diff --git a/drivers/at86rf231/at86rf231_tx.c b/drivers/at86rf231/at86rf231_tx.c index e9666af53f111..af9a931a44e2f 100644 --- a/drivers/at86rf231/at86rf231_tx.c +++ b/drivers/at86rf231/at86rf231_tx.c @@ -11,7 +11,7 @@ * @{ * * @file - * @brief RX related functionality for the AT86RF231 device driver + * @brief TX related functionality for the AT86RF231 device driver * * @author Alaeddine Weslati * @author Thomas Eichinger @@ -26,16 +26,182 @@ #define ENABLE_DEBUG (0) #include "debug.h" -static void at86rf231_xmit(uint8_t *data, radio_packet_length_t length); +#define _MAX_RETRIES (100) +static int16_t at86rf231_load(at86rf231_packet_t *packet); static void at86rf231_gen_pkt(uint8_t *buf, at86rf231_packet_t *packet); static uint8_t sequence_nr; +static uint8_t wait_for_ack; int16_t at86rf231_send(at86rf231_packet_t *packet) +{ + int16_t result; + result = at86rf231_load(packet); + if (result < 0) { + return result; + } + at86rf231_transmit_tx_buf(NULL); + return result; +} + +netdev_802154_tx_status_t at86rf231_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; + + uint8_t mhr[24]; + uint8_t index = 3; + + /* frame type */ + switch (kind) { + case NETDEV_802154_PKT_KIND_BEACON: + mhr[0] = 0x00; + break; + case NETDEV_802154_PKT_KIND_DATA: + mhr[0] = 0x01; + break; + case NETDEV_802154_PKT_KIND_ACK: + mhr[0] = 0x02; + break; + default: + return NETDEV_802154_TX_STATUS_INVALID_PARAM; + } + + if (wants_ack) { + mhr[0] |= 0x20; + } + + wait_for_ack = wants_ack; + + uint16_t src_pan = at86rf231_get_pan(); + uint8_t compress_pan = 0; + + if (use_long_addr) { + mhr[1] = 0xcc; + } + else { + mhr[1] = 0x88; + if (dest->pan.id == src_pan) { + compress_pan = 1; + mhr[0] |= 0x40; + } + } + + mhr[2] = sequence_nr++; + + /* First 3 bytes are fixed with FCS and SEQ, resume with index=3 */ + if (use_long_addr) { + mhr[index++] = (uint8_t)(dest->long_addr & 0xFF); + mhr[index++] = (uint8_t)(dest->long_addr >> 8); + mhr[index++] = (uint8_t)(dest->long_addr >> 16); + mhr[index++] = (uint8_t)(dest->long_addr >> 24); + mhr[index++] = (uint8_t)(dest->long_addr >> 32); + mhr[index++] = (uint8_t)(dest->long_addr >> 40); + mhr[index++] = (uint8_t)(dest->long_addr >> 48); + mhr[index++] = (uint8_t)(dest->long_addr >> 56); + + uint64_t src_long_addr = at86rf231_get_address_long(); + mhr[index++] = (uint8_t)(src_long_addr & 0xFF); + mhr[index++] = (uint8_t)(src_long_addr >> 8); + mhr[index++] = (uint8_t)(src_long_addr >> 16); + mhr[index++] = (uint8_t)(src_long_addr >> 24); + mhr[index++] = (uint8_t)(src_long_addr >> 32); + mhr[index++] = (uint8_t)(src_long_addr >> 40); + mhr[index++] = (uint8_t)(src_long_addr >> 48); + mhr[index++] = (uint8_t)(src_long_addr >> 56); + } + else { + mhr[index++] = (uint8_t)(dest->pan.id & 0xFF); + mhr[index++] = (uint8_t)(dest->pan.id >> 8); + + mhr[index++] = (uint8_t)(dest->pan.addr & 0xFF); + mhr[index++] = (uint8_t)(dest->pan.addr >> 8); + + if (!compress_pan) { + mhr[index++] = (uint8_t)(src_pan & 0xFF); + mhr[index++] = (uint8_t)(src_pan >> 8); + } + + uint16_t src_addr = at86rf231_get_address(); + mhr[index++] = (uint8_t)(src_addr & 0xFF); + mhr[index++] = (uint8_t)(src_addr >> 8); + } + + /* total frame size: + * index -> MAC header + * len -> payload length + * 2 -> CRC bytes + * + lengths of upper layers' headers */ + size_t size = index + len + 2 + netdev_get_hlist_len(upper_layer_hdrs); + + if (size > AT86RF231_MAX_PKT_LENGTH) { + return NETDEV_802154_TX_STATUS_PACKET_TOO_LONG; + } + + uint8_t size_byte = (uint8_t)size; + netdev_hlist_t *ptr = upper_layer_hdrs; + + at86rf231_write_fifo(&size_byte, 1); + at86rf231_write_fifo(mhr, (radio_packet_length_t)index); + if (upper_layer_hdrs) { + do { + at86rf231_write_fifo(ptr->header, + (radio_packet_length_t)(ptr->header_len)); + netdev_hlist_advance(&ptr); + } while (ptr != upper_layer_hdrs); + } + at86rf231_write_fifo((uint8_t*)buf, len); + return NETDEV_802154_TX_STATUS_OK; +} + +netdev_802154_tx_status_t at86rf231_transmit_tx_buf(netdev_t *dev) +{ + (void)dev; + /* radio driver state: sending */ + /* will be freed in at86rf231_rx_irq when TRX_END interrupt occurs */ + driver_state = AT_DRIVER_STATE_SENDING; + + /* Start TX */ + at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__TX_START); + DEBUG("Started TX\n"); + + if (!wait_for_ack) { + return NETDEV_802154_TX_STATUS_OK; + } + + uint8_t trac_status; + do { + trac_status = at86rf231_reg_read(AT86RF231_REG__TRX_STATE); + trac_status &= AT86RF231_TRX_STATE_MASK__TRAC; + } + while (trac_status == AT86RF231_TRX_STATE__TRAC_INVALID); + + switch (trac_status) { + case AT86RF231_TRX_STATE__TRAC_CHANNEL_ACCESS_FAILURE: + return NETDEV_802154_TX_STATUS_MEDIUM_BUSY; + + case AT86RF231_TRX_STATE__TRAC_NO_ACK: + return NETDEV_802154_TX_STATUS_NOACK; + + default: + return NETDEV_802154_TX_STATUS_OK; + } +} + +int16_t at86rf231_load(at86rf231_packet_t *packet) { // Set missing frame information packet->frame.fcf.frame_ver = 0; + packet->frame.fcf.frame_type = 0x1; + + packet->frame.src_pan_id = at86rf231_get_pan(); if (packet->frame.src_pan_id == packet->frame.dest_pan_id) { packet->frame.fcf.panid_comp = 1; @@ -59,12 +225,9 @@ int16_t at86rf231_send(at86rf231_packet_t *packet) packet->frame.src_addr[7] = (uint8_t)(at86rf231_get_address_long() & 0xFF); } - packet->frame.src_pan_id = at86rf231_get_pan(); - packet->frame.seq_nr = sequence_nr; + packet->frame.seq_nr = sequence_nr++; - sequence_nr += 1; - - // calculate size of the frame (payload + FCS) */ + /* calculate size of the frame (payload + FCS) */ packet->length = ieee802154_frame_get_hdr_len(&packet->frame) + packet->frame.payload_len + 1; @@ -72,54 +235,45 @@ int16_t at86rf231_send(at86rf231_packet_t *packet) return -1; } - // FCS is added in hardware + /* FCS is added in hardware */ uint8_t pkt[packet->length]; /* generate pkt */ at86rf231_gen_pkt(pkt, packet); - // transmit packet - at86rf231_xmit(pkt, packet->length); - return packet->length; -} - -static void at86rf231_xmit(uint8_t *data, radio_packet_length_t length) -{ - // Go to state PLL_ON + /* Go to state PLL_ON */ at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__PLL_ON); - // wait until it is on PLL_ON state - uint8_t status; - uint8_t max_wait = 100; // TODO : move elsewhere, this is in 10us - + /* wait until it is on PLL_ON state */ do { - status = at86rf231_get_status(); + int max_wait = _MAX_RETRIES; + if (!--max_wait) { + DEBUG("at86rf231 : ERROR : could not enter PLL_ON mode\n"); + break; + } + } while ((at86rf231_get_status() & AT86RF231_TRX_STATUS_MASK__TRX_STATUS) + != AT86RF231_TRX_STATUS__PLL_ON); - hwtimer_wait(HWTIMER_TICKS(10)); + /* change into TX_ARET_ON state */ + at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__TX_ARET_ON); + do { + int max_wait = _MAX_RETRIES; if (!--max_wait) { - printf("at86rf231 : ERROR : could not enter PLL_ON mode"); + DEBUG("at86rf231 : ERROR : could not enter TX_ARET_ON mode\n"); break; } - } - while ((status & AT86RF231_TRX_STATUS_MASK__TRX_STATUS) != AT86RF231_TRX_STATUS__PLL_ON); - - /* radio driver state: sending */ - /* will be freed in at86rf231_rx_irq when TRX_END interrupt occurs */ - driver_state = AT_DRIVER_STATE_SENDING; + } while (at86rf231_get_status() != AT86RF231_TRX_STATUS__TX_ARET_ON); - // copy the packet to the radio FIFO - at86rf231_write_fifo(data, length); + /* load packet into fifo */ + at86rf231_write_fifo(pkt, packet->length); DEBUG("Wrote to FIFO\n"); - // Start TX - at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__TX_START); - DEBUG("Started TX\n"); + return packet->length; } /** * @brief Static function to generate byte array from at86rf231 packet. - * */ static void at86rf231_gen_pkt(uint8_t *buf, at86rf231_packet_t *packet) { diff --git a/drivers/include/at86rf231.h b/drivers/include/at86rf231.h index ceca8ab778228..80e25bced35c0 100644 --- a/drivers/include/at86rf231.h +++ b/drivers/include/at86rf231.h @@ -7,7 +7,7 @@ */ /** - * @defgroup drivers_at86rf231 + * @defgroup drivers_at86rf231 at86rf231 * @ingroup drivers * @brief Device driver for the Atmel AT86RF231 radio * @{ @@ -31,34 +31,66 @@ #include "ieee802154_frame.h" #include "at86rf231/at86rf231_settings.h" #include "periph/gpio.h" +#include "netdev/802154.h" #ifdef __cplusplus extern "C" { #endif -#define AT86RF231_MAX_PKT_LENGTH 127 -#define AT86RF231_MAX_DATA_LENGTH 118 +/** + * @brief Maximum length of a frame on at86rf231 + */ +#define AT86RF231_MAX_PKT_LENGTH (127) + +/** + * @brief Maximum payload length + * @details Assuming intra PAN short address mode + * results in 2 bytes FCF + * + 1 bytes SEQNr + * + 2 bytes PAN Id + * + 2 bytes destination address + * + 2 bytes source address + */ +#define AT86RF231_MAX_DATA_LENGTH (118) + +/** + * @brief Broadcast address + */ +#define AT86RF231_BROADCAST_ADDRESS (0xFFFF) + +/** + * @brief at86rf231's lowest supported channel + */ +#define AT86RF231_MIN_CHANNEL (11) /** - * Structure to represent a at86rf231 packet. + * @brief at86rf231's highest supported channel */ -typedef struct __attribute__((packed)) /* TODO: do we need the packed here? it leads to an - unaligned pointer -> trouble for M0 systems... */ +#define AT86RF231_MAX_CHANNEL (26) + +/** + * @brief Structure to represent a at86rf231 packet. + */ +typedef struct __attribute__((packed)) { - /* @{ */ - uint8_t length; /** < the length of the frame of the frame including fcs*/ - ieee802154_frame_t frame; /** < the ieee802154 frame */ - int8_t rssi; /** < the rssi value */ - uint8_t crc; /** < 1 if crc was successfull, 0 otherwise */ - uint8_t lqi; /** < the link quality indicator */ - /* @} */ -} -at86rf231_packet_t; + /** @{ */ + uint8_t length; /**< the length of the frame of the frame including fcs*/ + ieee802154_frame_t frame; /**< the ieee802154 frame */ + int8_t rssi; /**< the rssi value */ + uint8_t crc; /**< 1 if crc was successfull, 0 otherwise */ + uint8_t lqi; /**< the link quality indicator */ + /** @} */ +} at86rf231_packet_t; -extern volatile kernel_pid_t transceiver_pid; +extern netdev_t at86rf231_netdev; /**< netdev representation of this driver */ +/** + * @brief States to be assigned to `driver_state` + * @{ + */ #define AT_DRIVER_STATE_DEFAULT (0) #define AT_DRIVER_STATE_SENDING (1) +/** @} */ /** * @brief To keep state inside of at86rf231 driver @@ -68,38 +100,300 @@ extern volatile kernel_pid_t transceiver_pid; */ extern uint8_t driver_state; +/** + * @brief Initialize the at86rf231 transceiver + */ +int at86rf231_initialize(netdev_t *dev); + +#ifdef MODULE_TRANSCEIVER +/** + * @brief Init the at86rf231 for use with RIOT's transceiver module. + * + * @param[in] tpid The PID of the transceiver thread. + */ + void at86rf231_init(kernel_pid_t tpid); -/* void at86rf231_reset(void); */ -void at86rf231_rx(void); -void at86rf231_rx_handler(void); -void at86rf231_rx_irq(void *arg); +#endif -int16_t at86rf231_send(at86rf231_packet_t *packet); +/** + * @brief Turn at86rf231 on. + * + * @return 1 if the radio was correctly turned on; 0 otherwise. + */ +int at86rf231_on(void); + +/** + * @brief Turn at86rf231 off. + */ +void at86rf231_off(void); + +/** + * @brief Indicate if the at86rf231 is on. + * + * @return 1 if the radio transceiver is on (active); 0 otherwise. + */ +int at86rf231_is_on(void); + +/** + * @brief Switches the at86rf231 into receive mode. + */ +void at86rf231_switch_to_rx(void); + +/** + * @brief Turns monitor (promiscuous) mode on or off. + * + * @param[in] mode The desired mode: + * 1 for monitor (promiscuous) mode; + * 0 for normal (auto address-decoding) mode. + */ +void at86rf231_set_monitor(int mode); + +/** + * @brief Indicate if the at86rf231 is in monitor (promiscuous) mode. + * + * @return 1 if the transceiver is in monitor (promiscuous) mode; + * 0 if it is in normal (auto address-decoding) mode. + */ +int at86rf231_get_monitor(void); + +/** + * @brief Set the channel of the at86rf231. + * + * @param[in] chan The desired channel, valid channels are from 11 to 26. + * + * @return The tuned channel after calling, or -1 on error. + */ +int at86rf231_set_channel(unsigned int chan); + +/** + * @brief Get the channel of the at86rf231. + * + * @return The tuned channel. + */ +unsigned int at86rf231_get_channel(void); -int8_t at86rf231_set_channel(uint8_t channel); -uint8_t at86rf231_get_channel(void); +/** + * @brief Sets the short address of the at86rf231. + * + * @param[in] addr The desired address. + * + * @return The set address after calling. + */ +uint16_t at86rf231_set_address(uint16_t addr); + +/** + * @brief Gets the current short address of the at86rf231. + * + * @return The current short address. + */ +uint16_t at86rf231_get_address(void); + +/** + * @brief Sets the IEEE long address of the at86rf231. + * + * @param[in] addr The desired address. + * + * @return The set address after calling. + */ +uint64_t at86rf231_set_address_long(uint64_t addr); + +/** + * @brief Gets the current IEEE long address of the at86rf231. + * + * @return The current IEEE long address. + */ +uint64_t at86rf231_get_address_long(void); +/** + * @brief Sets the pan ID of the at86rf231. + * + * @param[in] pan The desired pan ID. + * + * @return The set pan ID after calling. + */ uint16_t at86rf231_set_pan(uint16_t pan); + +/** + * @brief Gets the current IEEE long address of the at86rf231. + * + * @return The current IEEE long address. + */ uint16_t at86rf231_get_pan(void); -radio_address_t at86rf231_set_address(radio_address_t address); -radio_address_t at86rf231_get_address(void); -uint64_t at86rf231_get_address_long(void); -uint64_t at86rf231_set_address_long(uint64_t address); +/** + * @brief Sets the output (TX) power of the at86rf231. + * + * @param[in] pow The desired TX (output) power in dBm, + * valid values are -25 to 0; other values + * will be "saturated" into this range. + * + * @return The set TX (output) power after calling. + */ +int at86rf231_set_tx_power(int pow); -void at86rf231_switch_to_rx(void); +/** + * @brief Gets the current output (TX) power of the at86rf231. + * + * @return The current TX (output) power. + */ +int at86rf231_get_tx_power(void); + +/** + * @brief Checks if the radio medium is available/clear to send + * ("Clear Channel Assessment" a.k.a. CCA). + * + * @return a 1 value if radio medium is clear (available), + * a 0 value otherwise. + * + */ +int at86rf231_channel_is_clear(netdev_t *dev); -void at86rf231_set_monitor(uint8_t mode); +/** + * @brief Interrupt handler, gets fired when a RX overflow happens. + * + */ +void at86rf231_rxoverflow_irq(void); + +/** + * @brief Interrupt handler, gets fired when bytes in the RX FIFO are present. + * + */ +void at86rf231_rx_irq(void); + +/** + * @brief Sets the function called back when a packet is received. + * (Low-level mechanism, parallel to the `transceiver` module). + * + * @param[in] dev The network device to operate on. (Currently not used) + * @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 + */ +int at86rf231_add_raw_recv_callback(netdev_t *dev, + netdev_802154_raw_packet_cb_t recv_cb); -enum { - RF86RF231_MAX_TX_LENGTH = 125, - RF86RF231_MAX_RX_LENGTH = 127, - RF86RF231_MIN_CHANNEL = 11, - RF86RF231_MAX_CHANNEL = 26 -}; +/** + * @brief Unsets the function called back when a packet is received. + * (Low-level mechanism, parallel to the `transceiver` module). + * + * @param[in] dev The network device to operate on. (Currently not used) + * @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 at86rf231_rem_raw_recv_callback(netdev_t *dev, + netdev_802154_raw_packet_cb_t recv_cb); +/** + * @brief Sets a function called back when a data packet is received. + * + * @param[in] dev The network device to operate on. (Currently not used) + * @param[in] recv_cb callback function for 802.15.4 data packet arrival + * + * @return 0 on success + * @return -ENODEV if *dev* is not recognized + * @return -ENOBUFS, if maximum number of registable callbacks is exceeded + */ +int at86rf231_add_data_recv_callback(netdev_t *dev, + netdev_rcv_data_cb_t recv_cb); + +/** + * @brief Unsets a function called back when a data packet is received. + * + * @param[in] dev The network device to operate on. (Currently not used) + * @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 at86rf231_rem_data_recv_callback(netdev_t *dev, + netdev_rcv_data_cb_t recv_cb); + +/** + * @brief RX handler, process data from the RX FIFO. + * + */ +void at86rf231_rx_handler(void); + +/** + * @brief Prepare the at86rf231 TX buffer to send with the given packet. + * + * @param[in] dev The network device to operate on. (Currently not used) + * @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 at86rf231_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 at86rf231 TX buffer. + * + * @param[in] dev The network device to operate on. (Currently not used) + * + * @return @ref netdev_802154_tx_status_t + */ +netdev_802154_tx_status_t at86rf231_transmit_tx_buf(netdev_t *dev); + +/** + * @brief Send function, sends a at86rf231_packet_t over the air. + * + * @param[in] *packet The Packet which will be send. + * + * @return The count of bytes which are send or -1 on error + * + */ +int16_t at86rf231_send(at86rf231_packet_t *packet); + +/** + * RX Packet Buffer, read from the transceiver, filled by the at86rf231_rx_handler. + */ extern at86rf231_packet_t at86rf231_rx_buffer[AT86RF231_RX_BUF_SIZE]; +/** + * Get at86rf231's status byte + */ +uint8_t at86rf231_get_status(void); + +/** + * Get at86rf231's TRAC status byte + */ +uint8_t at86rf231_get_trac_status(void); + +/** + * at86rf231 low-level radio driver definition. + */ +extern const netdev_802154_driver_t at86rf231_driver; + #ifdef __cplusplus } #endif diff --git a/drivers/include/at86rf231/at86rf231_settings.h b/drivers/include/at86rf231/at86rf231_settings.h index c1bf82e043dfc..274202e82a2e8 100644 --- a/drivers/include/at86rf231/at86rf231_settings.h +++ b/drivers/include/at86rf231/at86rf231_settings.h @@ -158,6 +158,8 @@ enum at86rf231_trx_status { }; enum at86rf231_trx_state { + AT86RF231_TRX_STATE_MASK__TRAC = 0xe0, + AT86RF231_TRX_STATE__NOP = 0x00, AT86RF231_TRX_STATE__TX_START = 0x02, AT86RF231_TRX_STATE__FORCE_TRX_OFF = 0x03, @@ -167,6 +169,13 @@ enum at86rf231_trx_state { AT86RF231_TRX_STATE__PLL_ON = 0x09, AT86RF231_TRX_STATE__RX_AACK_ON = 0x16, AT86RF231_TRX_STATE__TX_ARET_ON = 0x19, + + AT86RF231_TRX_STATE__TRAC_SUCCESS = 0x00, + AT86RF231_TRX_STATE__TRAC_SUCCESS_DATA_PENDING = 0x20, + AT86RF231_TRX_STATE__TRAC_SUCCESS_WAIT_FOR_ACK = 0x40, + AT86RF231_TRX_STATE__TRAC_CHANNEL_ACCESS_FAILURE = 0x60, + AT86RF231_TRX_STATE__TRAC_NO_ACK = 0xa0, + AT86RF231_TRX_STATE__TRAC_INVALID = 0xe0, }; enum at86rf231_phy_cc_cca { @@ -216,7 +225,7 @@ enum at86rf231_xosc_ctrl { AT86RF231_XOSC_CTRL__XTAL_MODE_EXTERNAL = 0xF0, }; -enum { +enum at86rf231_timing { AT86RF231_TIMING__VCC_TO_P_ON = 330, AT86RF231_TIMING__SLEEP_TO_TRX_OFF = 380, AT86RF231_TIMING__TRX_OFF_TO_PLL_ON = 110, @@ -227,8 +236,20 @@ enum { AT86RF231_TIMING__RESET_TO_TRX_OFF = 37, }; +enum at86rf231_xah_ctrl_1 { + AT86RF231_XAH_CTRL_1__AACK_FLTR_RES_FT = 0x20, + AT86RF231_XAH_CTRL_1__AACK_UPLD_RES_FT = 0x10, + AT86RF231_XAH_CTRL_1__AACK_ACK_TIME = 0x04, + AT86RF231_XAH_CTRL_1__AACK_PROM_MODE = 0x02, +}; + +enum at86rf231_csma_seed_1 { + AT86RF231_CSMA_SEED_1__AACK_SET_PD = 0x20, + AT86RF231_CSMA_SEED_1__AACK_DIS_ACK = 0x10, + AT86RF231_CSMA_SEED_1__AACK_I_AM_COORD = 0x08, +}; + #ifdef __cplusplus } #endif - -#endif +#endif /* AT86AT86RF231_SETTINGS_H */ diff --git a/drivers/include/netdev/802154.h b/drivers/include/netdev/802154.h new file mode 100644 index 0000000000000..e949fe60693c5 --- /dev/null +++ b/drivers/include/netdev/802154.h @@ -0,0 +1,429 @@ +/* + * 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" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @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_802154_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 + * + * @details 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 + * + * @details 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] dev the network device + * @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. + * + * @param[in] dev the network device + * + * @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] dev the network device + * @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. + * + * @details 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] dev the network device + * @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_802154_raw_packet_cb_t recv_func); + + /** + * @brief Remove a callback set by netdev_802154_driver_t::add_receive_raw_callback() + * + * @param[in] dev the network device + * @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_802154_raw_packet_cb_t recv_func); + + /** + * @brief Indicates if the radio medium is available for transmission + * ("Clear Channel Assessment"). + * + * @param[in] dev the network device + * + * @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] dev the network device + * @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 */ + +#ifdef __cplusplus +} +#endif + +#endif /* __NETDEV_802154_H_ */ + +/** + * @} + */ diff --git a/drivers/include/netdev/base.h b/drivers/include/netdev/base.h index 94fa1947fb457..f8fde140a9cc5 100644 --- a/drivers/include/netdev/base.h +++ b/drivers/include/netdev/base.h @@ -41,6 +41,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; /** @@ -105,6 +107,10 @@ typedef enum { signed value in host byte order */ NETDEV_OPT_MAX_PACKET_SIZE, /**< Maximum packet size the device supports unsigned value in host byte order */ + NETDEV_OPT_SRC_LEN, /**< Default mode the source address is + set to as value of `size_t`. (e.g. + either PAN-centric 16-bit address or + EUI-64 in IEEE 802.15.4) */ /** * @brief Last value for @netdev_opt_t defined here diff --git a/drivers/include/netdev/default.h b/drivers/include/netdev/default.h index 4446bb62ceb88..0d525af9ba3c9 100644 --- a/drivers/include/netdev/default.h +++ b/drivers/include/netdev/default.h @@ -27,6 +27,13 @@ * * @brief Default device as a pointer of netdev_t. */ +#ifdef MODULE_AT86RF231 +#include "at86rf231.h" + +#ifndef NETDEV_DEFAULT +#define NETDEV_DEFAULT ((netdev_t *)(&at86rf231_netdev)) +#endif /* NETDEV_DEFAULT */ +#endif /* MODULE_AT86RF231 */ #ifdef MODULE_NATIVENET diff --git a/drivers/netdev/802154/802154.c b/drivers/netdev/802154/802154.c new file mode 100644 index 0000000000000..f2cf538aabbee --- /dev/null +++ b/drivers/netdev/802154/802154.c @@ -0,0 +1,119 @@ +/* + * 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 +static size_t _get_src_len(netdev_t *dev) +{ + size_t src_len, src_len_len = sizeof(size_t); + + if (_get_driver(dev)->get_option(dev, NETDEV_OPT_SRC_LEN, &src_len, &src_len_len) < 0) { + return 2; + } + + return src_len; +} + +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) +{ + int use_long_addr; + + if (dev == NULL || dev->type != NETDEV_TYPE_802154) { + return -ENODEV; + } + + use_long_addr = _get_src_len(dev) == 8; + + 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, + use_long_addr, 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; diff --git a/sys/config/config.c b/sys/config/config.c index 560e41d1dce88..e0c9eea893af5 100644 --- a/sys/config/config.c +++ b/sys/config/config.c @@ -19,8 +19,9 @@ #include config_t sysconfig = { - 0, ///< default ID - 0, ///< default radio address - 0, ///< default radio channel - "foobar", ///< default name + 0, /**< default ID */ + 0, /**< default radio address */ + 0, /**< default radio channel */ + 1, /**< default radio PAN id */ + "foobar", /**< default name */ }; diff --git a/sys/shell/commands/sc_transceiver.c b/sys/shell/commands/sc_transceiver.c index f4b8a7fe46427..16b1b264ebd71 100644 --- a/sys/shell/commands/sc_transceiver.c +++ b/sys/shell/commands/sc_transceiver.c @@ -218,8 +218,8 @@ void _transceiver_send_handler(int argc, char **argv) puts("Transceiver not initialized"); return; } - if (argc != 3) { - printf("Usage:\t%s \n", argv[0]); + if (argc < 3) { + printf("Usage:\t%s [PAN]\n", argv[0]); return; } @@ -243,8 +243,13 @@ void _transceiver_send_handler(int argc, char **argv) p.frame.payload_len = strlen(text_msg) + 1; p.frame.fcf.dest_addr_m = IEEE_802154_SHORT_ADDR_M; p.frame.fcf.src_addr_m = IEEE_802154_SHORT_ADDR_M; - p.frame.dest_pan_id = 1; p.frame.dest_addr[1] = atoi(argv[1]); + if (argc == 4) { + p.frame.dest_pan_id = atoi(argv[3]); + } + else { + p.frame.dest_pan_id = 1; + } #else p.data = (uint8_t *) text_msg; p.length = strlen(text_msg) + 1;