mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-17 05:12:57 +01:00
drivers/at86rf231: refactoring of the at86rf231 radio driver
* deploy extended operation mode * cleanup * implement netdev 802154.h interface
This commit is contained in:
parent
5965220efe
commit
dfb1b56fad
@ -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
|
||||
|
@ -1,4 +1,6 @@
|
||||
ifneq (,$(filter defaulttransceiver,$(USEMODULE)))
|
||||
USEMODULE += at86rf231
|
||||
USEMODULE += transceiver
|
||||
ifeq (,$(filter netdev_base,$(USEMODULE)))
|
||||
USEMODULE += transceiver
|
||||
endif
|
||||
endif
|
||||
|
@ -52,5 +52,8 @@ endif
|
||||
ifneq (,$(filter lps331ap,$(USEMODULE)))
|
||||
DIRS += lps331ap
|
||||
endif
|
||||
ifneq (,$(filter netdev_802154,$(USEMODULE)))
|
||||
DIRS += netdev/802154
|
||||
endif
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
|
@ -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);
|
||||
|
||||
// Reset IRQ to TRX END only
|
||||
at86rf231_reg_write(AT86RF231_REG__IRQ_MASK, AT86RF231_IRQ_STATUS_MASK__TRX_END);
|
||||
|
||||
// Read IRQ to clear it
|
||||
at86rf231_reg_read(AT86RF231_REG__IRQ_STATUS);
|
||||
|
||||
// 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
|
||||
/* now change to PLL_ON state for extended operating mode */
|
||||
at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__PLL_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 PLL_ON mode\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
while ((status & AT86RF231_TRX_STATUS_MASK__TRX_STATUS) != AT86RF231_TRX_STATUS__RX_ON);
|
||||
} while (at86rf231_get_status() != AT86RF231_TRX_STATUS__PLL_ON);
|
||||
|
||||
/* Reset IRQ to TRX END only */
|
||||
at86rf231_reg_write(AT86RF231_REG__IRQ_MASK, AT86RF231_IRQ_STATUS_MASK__TRX_END);
|
||||
|
||||
/* Read IRQ to clear it */
|
||||
at86rf231_reg_read(AT86RF231_REG__IRQ_STATUS);
|
||||
|
||||
/* Enable IRQ interrupt */
|
||||
gpio_irq_enable(AT86RF231_INT);
|
||||
|
||||
/* Enter RX_AACK_ON state */
|
||||
at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__RX_AACK_ON);
|
||||
|
||||
do {
|
||||
int max_wait = _MAX_RETRIES;
|
||||
if (!--max_wait) {
|
||||
DEBUG("at86rf231 : ERROR : could not enter RX_AACK_ON mode\n");
|
||||
break;
|
||||
}
|
||||
} 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);
|
||||
|
||||
/* busy wait for TRX_OFF state */
|
||||
uint8_t status;
|
||||
uint8_t max_wait = 100;
|
||||
|
||||
do {
|
||||
status = at86rf231_get_status();
|
||||
|
||||
if (!--max_wait) {
|
||||
printf("at86rf231 : ERROR : could not enter TRX_OFF mode\n");
|
||||
break;
|
||||
}
|
||||
} while ((status & AT86RF231_TRX_STATUS_MASK__TRX_STATUS)
|
||||
!= AT86RF231_TRX_STATUS__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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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 };
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 <alaeddine.weslati@inria.fr>
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
@ -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();
|
||||
|
||||
hwtimer_wait(HWTIMER_TICKS(10));
|
||||
|
||||
int max_wait = _MAX_RETRIES;
|
||||
if (!--max_wait) {
|
||||
printf("at86rf231 : ERROR : could not enter PLL_ON mode");
|
||||
DEBUG("at86rf231 : ERROR : could not enter PLL_ON mode\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
while ((status & AT86RF231_TRX_STATUS_MASK__TRX_STATUS) != AT86RF231_TRX_STATUS__PLL_ON);
|
||||
} while ((at86rf231_get_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;
|
||||
/* change into TX_ARET_ON state */
|
||||
at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__TX_ARET_ON);
|
||||
|
||||
// copy the packet to the radio FIFO
|
||||
at86rf231_write_fifo(data, length);
|
||||
do {
|
||||
int max_wait = _MAX_RETRIES;
|
||||
if (!--max_wait) {
|
||||
DEBUG("at86rf231 : ERROR : could not enter TX_ARET_ON mode\n");
|
||||
break;
|
||||
}
|
||||
} while (at86rf231_get_status() != AT86RF231_TRX_STATUS__TX_ARET_ON);
|
||||
|
||||
/* 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)
|
||||
{
|
||||
|
@ -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)
|
||||
|
||||
/**
|
||||
* Structure to represent a at86rf231 packet.
|
||||
* @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
|
||||
*/
|
||||
typedef struct __attribute__((packed)) /* TODO: do we need the packed here? it leads to an
|
||||
unaligned pointer -> trouble for M0 systems... */
|
||||
#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)
|
||||
|
||||
/**
|
||||
* @brief at86rf231's highest supported channel
|
||||
*/
|
||||
#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);
|
||||
|
||||
int8_t at86rf231_set_channel(uint8_t channel);
|
||||
uint8_t at86rf231_get_channel(void);
|
||||
/**
|
||||
* @brief Turn at86rf231 off.
|
||||
*/
|
||||
void at86rf231_off(void);
|
||||
|
||||
uint16_t at86rf231_set_pan(uint16_t pan);
|
||||
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 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);
|
||||
|
||||
void at86rf231_set_monitor(uint8_t mode);
|
||||
/**
|
||||
* @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);
|
||||
|
||||
enum {
|
||||
RF86RF231_MAX_TX_LENGTH = 125,
|
||||
RF86RF231_MAX_RX_LENGTH = 127,
|
||||
RF86RF231_MIN_CHANNEL = 11,
|
||||
RF86RF231_MAX_CHANNEL = 26
|
||||
};
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
@ -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 */
|
||||
|
429
drivers/include/netdev/802154.h
Normal file
429
drivers/include/netdev/802154.h
Normal file
@ -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 <Kevin.Roussel@inria.fr>
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __NETDEV_802154_H_
|
||||
#define __NETDEV_802154_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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_ */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
119
drivers/netdev/802154/802154.c
Normal file
119
drivers/netdev/802154/802154.c
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Martin Lenders <mlenders@inf.fu-berlin.de>
|
||||
*
|
||||
* 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 <mlenders@inf.fu-berlin.de>
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#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 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
5
drivers/netdev/802154/Makefile
Normal file
5
drivers/netdev/802154/Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
MODULE := netdev_802154
|
||||
|
||||
INCLUDES += -I$(RIOTBASE)/drivers/include
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
@ -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;
|
||||
|
@ -23,6 +23,7 @@ config_t sysconfig = {
|
||||
#ifdef HAS_RADIO
|
||||
0, /**< default radio address */
|
||||
0, /**< default radio channel */
|
||||
1, /**< default radio PAN id */
|
||||
#endif
|
||||
"foobar", /**< default name */
|
||||
"foobar", /**< default name */
|
||||
};
|
||||
|
@ -45,6 +45,7 @@ typedef struct {
|
||||
#ifdef HAS_RADIO
|
||||
radio_address_t radio_address; /**< address for radio communication */
|
||||
uint8_t radio_channel; /**< current frequency */
|
||||
uint16_t radio_pan_id; /**< PAN id for radio communication */
|
||||
#endif
|
||||
/* cppcheck-suppress unusedStructMember : useful for debug purposes */
|
||||
char name[CONFIG_NAME_LEN]; /**< name of the node */
|
||||
|
@ -218,8 +218,8 @@ void _transceiver_send_handler(int argc, char **argv)
|
||||
puts("Transceiver not initialized");
|
||||
return;
|
||||
}
|
||||
if (argc != 3) {
|
||||
printf("Usage:\t%s <ADDR> <MSG>\n", argv[0]);
|
||||
if (argc < 3) {
|
||||
printf("Usage:\t%s <ADDR> <MSG> [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;
|
||||
|
Loading…
Reference in New Issue
Block a user