Merged in merlin17/nuttx/ieee802154 (pull request #358)

wireless/ieee802154: Completes basic receive functionality

Approved-by: Gregory Nutt <gnutt@nuttx.org>
This commit is contained in:
Anthony Merlino 2017-05-08 20:29:30 +00:00 committed by Gregory Nutt
commit 933c6c7cda
6 changed files with 356 additions and 110 deletions

View File

@ -121,6 +121,10 @@ struct mrf24j40_radio_s
struct ieee802154_radio_s radio; /* The public device instance */
FAR struct ieee802154_radiocb_s *radiocb; /* Registered callbacks */
/* MAC Attributes */
bool rxonidle : 1;
/* Low-level MCU-specific support */
FAR const struct mrf24j40_lower_s *lower;
@ -186,40 +190,41 @@ static int mrf24j40_setup_fifo(FAR struct mrf24j40_radio_s *dev,
FAR struct iob_s *frame, uint32_t fifo_addr);
static int mrf24j40_setchannel(FAR struct mrf24j40_radio_s *radio,
static int mrf24j40_setchannel(FAR struct mrf24j40_radio_s *dev,
uint8_t chan);
static int mrf24j40_getchannel(FAR struct mrf24j40_radio_s *radio,
static int mrf24j40_getchannel(FAR struct mrf24j40_radio_s *dev,
FAR uint8_t *chan);
static int mrf24j40_setpanid(FAR struct mrf24j40_radio_s *radio,
static int mrf24j40_setpanid(FAR struct mrf24j40_radio_s *dev,
uint16_t panid);
static int mrf24j40_getpanid(FAR struct mrf24j40_radio_s *radio,
static int mrf24j40_getpanid(FAR struct mrf24j40_radio_s *dev,
FAR uint16_t *panid);
static int mrf24j40_setsaddr(FAR struct mrf24j40_radio_s *radio,
static int mrf24j40_setsaddr(FAR struct mrf24j40_radio_s *dev,
uint16_t saddr);
static int mrf24j40_getsaddr(FAR struct mrf24j40_radio_s *radio,
static int mrf24j40_getsaddr(FAR struct mrf24j40_radio_s *dev,
FAR uint16_t *saddr);
static int mrf24j40_seteaddr(FAR struct mrf24j40_radio_s *radio,
static int mrf24j40_seteaddr(FAR struct mrf24j40_radio_s *dev,
FAR const uint8_t *eaddr);
static int mrf24j40_geteaddr(FAR struct mrf24j40_radio_s *radio,
static int mrf24j40_geteaddr(FAR struct mrf24j40_radio_s *dev,
FAR uint8_t *eaddr);
static int mrf24j40_setpromisc(FAR struct mrf24j40_radio_s *radio,
static int mrf24j40_setpromisc(FAR struct mrf24j40_radio_s *dev,
bool promisc);
static int mrf24j40_getpromisc(FAR struct mrf24j40_radio_s *radio,
static int mrf24j40_getpromisc(FAR struct mrf24j40_radio_s *dev,
FAR bool *promisc);
static int mrf24j40_setdevmode(FAR struct mrf24j40_radio_s *radio,
static int mrf24j40_setdevmode(FAR struct mrf24j40_radio_s *dev,
uint8_t mode);
static int mrf24j40_getdevmode(FAR struct mrf24j40_radio_s *radio,
static int mrf24j40_getdevmode(FAR struct mrf24j40_radio_s *dev,
FAR uint8_t *mode);
static int mrf24j40_settxpower(FAR struct mrf24j40_radio_s *radio,
static int mrf24j40_settxpower(FAR struct mrf24j40_radio_s *dev,
int32_t txpwr);
static int mrf24j40_gettxpower(FAR struct mrf24j40_radio_s *radio,
static int mrf24j40_gettxpower(FAR struct mrf24j40_radio_s *dev,
FAR int32_t *txpwr);
static int mrf24j40_setcca(FAR struct mrf24j40_radio_s *radio,
static int mrf24j40_setcca(FAR struct mrf24j40_radio_s *dev,
FAR struct ieee802154_cca_s *cca);
static int mrf24j40_getcca(FAR struct mrf24j40_radio_s *radio,
static int mrf24j40_getcca(FAR struct mrf24j40_radio_s *dev,
FAR struct ieee802154_cca_s *cca);
static int mrf24j40_energydetect(FAR struct mrf24j40_radio_s *radio,
static int mrf24j40_energydetect(FAR struct mrf24j40_radio_s *dev,
FAR uint8_t *energy);
static int mrf24j40_rxenable(FAR struct mrf24j40_radio_s *dev, bool enable);
/* Driver operations */
@ -392,6 +397,12 @@ static int mrf24j40_set_attr(FAR struct ieee802154_radio_s *radio,
ret = IEEE802154_STATUS_SUCCESS;
}
break;
case IEEE802154_PIB_MAC_RX_ON_WHEN_IDLE:
{
dev->rxonidle = attr_value->mac.rxonidle;
mrf24j40_rxenable(dev, dev->rxonidle);
}
break;
default:
ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE;
}
@ -1470,9 +1481,8 @@ static void mrf24j40_irqwork_txgts(FAR struct mrf24j40_radio_s *dev,
*
****************************************************************************/
static int mrf24j40_rxenable(FAR struct ieee802154_radio_s *radio, bool enable)
static int mrf24j40_rxenable(FAR struct mrf24j40_radio_s *dev, bool enable)
{
FAR struct mrf24j40_radio_s *dev = (FAR struct mrf24j40_radio_s *)radio;
uint8_t reg;
if (enable)
@ -1567,11 +1577,14 @@ done:
mrf24j40_setreg(dev->spi, MRF24J40_BBREG1, 0);
/* Enable rx int */
/* Only enable RX interrupt if we are to be listening when IDLE */
reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON);
reg &= ~MRF24J40_INTCON_RXIE;
mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg);
if (dev->rxonidle)
{
reg = mrf24j40_getreg(dev->spi, MRF24J40_INTCON);
reg &= ~MRF24J40_INTCON_RXIE;
mrf24j40_setreg(dev->spi, MRF24J40_INTCON, reg);
}
}
/****************************************************************************

View File

@ -81,5 +81,12 @@ struct mac802154dev_txframe_s
uint16_t length;
};
struct mac802154dev_rxframe_s
{
struct ieee802154_data_ind_s meta;
uint8_t payload[IEEE802154_MAX_MAC_PAYLOAD_SIZE];
uint16_t length;
};
#endif /* CONFIG_WIRELESS_IEEE802154 */
#endif /* __INCLUDE_NUTTX_WIRELESS_IEEE802154_IEEE802154_IOCTL_H */

View File

@ -507,7 +507,7 @@ union ieee802154_macattr_u
bool promisc_mode;
bool rng_support;
bool resp_wait_time;
bool rx_when_idle;
bool rxonidle;
bool sec_enabled;
bool timestamp_support;
@ -1492,6 +1492,72 @@ int mac802154dev_register(MACHANDLE mac, int minor);
int mac802154netdev_register(MACHANDLE mac);
/****************************************************************************
* Name: ieee802154_indpool_initialize
*
* Description:
* This function initializes the meta-data allocator. This function must
* be called early in the initialization sequence before any radios
* begin operation.
*
* Inputs:
* None
*
* Return Value:
* None
*
****************************************************************************/
void ieee802154_indpool_initialize(void);
/****************************************************************************
* Name: ieee802154_ind_allocate
*
* Description:
* The ieee802154_ind_allocate function will get a free meta-data
* structure for use by the IEEE 802.15.4 MAC.
*
* Interrupt handling logic will first attempt to allocate from the
* g_indfree list. If that list is empty, it will attempt to allocate
* from its reserve, g_indfree_irq. If that list is empty, then the
* allocation fails (NULL is returned).
*
* Non-interrupt handler logic will attempt to allocate from g_indfree
* list. If that the list is empty, then the meta-data structure will be
* allocated from the dynamic memory pool.
*
* Inputs:
* None
*
* Return Value:
* A reference to the allocated msg structure. All user fields in this
* structure have been zeroed. On a failure to allocate, NULL is
* returned.
*
****************************************************************************/
FAR struct ieee802154_data_ind_s *ieee802154_ind_allocate(void);
/****************************************************************************
* Name: ieee802154_ind_free
*
* Description:
* The ieee802154_ind_free function will return a meta-data structure to
* the free pool of messages if it was a pre-allocated meta-data
* structure. If the meta-data structure was allocated dynamically it will
* be deallocated.
*
* Inputs:
* ind - meta-data structure to free
*
* Return Value:
* None
*
****************************************************************************/
void ieee802154_ind_free(FAR struct ieee802154_data_ind_s *ind);
#undef EXTERN
#ifdef __cplusplus
}

View File

@ -409,7 +409,7 @@ static FAR struct mac802154_txframe_s *
}
/****************************************************************************
* Name: mac802154_push_rxframe
* Name: mac802154_push_dataind
*
* Description:
* Push a data indication onto the list to be processed
@ -814,6 +814,7 @@ static void mac802154_rxframe_worker(FAR void *arg)
FAR struct iob_s *frame;
uint16_t *frame_ctrl;
bool panid_comp;
uint8_t ftype;
while(1)
{
@ -839,7 +840,7 @@ static void mac802154_rxframe_worker(FAR void *arg)
/* Get a local copy of the frame to make it easier to access */
frame = iob->frame;
frame = ind->frame;
/* Set a local pointer to the frame control then move the offset past
* the frame control field
@ -852,16 +853,16 @@ static void mac802154_rxframe_worker(FAR void *arg)
* this isn't a data frame
*/
ind->src.mode = (frame_ctrl & IEEE802154_FRAMECTRL_SADDR) >>
ind->src.mode = (*frame_ctrl & IEEE802154_FRAMECTRL_SADDR) >>
IEEE802154_FRAMECTRL_SHIFT_SADDR;
ind->dest.mode = (frame_ctrl & IEEE802154_FRAMECTRL_DADDR) >>
ind->dest.mode = (*frame_ctrl & IEEE802154_FRAMECTRL_DADDR) >>
IEEE802154_FRAMECTRL_SHIFT_DADDR;
panid_comp = (frame_ctrl & IEEE802154_FRAMECTRL_PANIDCOMP) >>
panid_comp = (*frame_ctrl & IEEE802154_FRAMECTRL_PANIDCOMP) >>
IEEE802154_FRAMECTRL_SHIFT_PANIDCOMP;
ind->dsn = iob->frame->io_data[frame->io_offset++];
ind->dsn = frame->io_data[frame->io_offset++];
/* If the destination address is included */
@ -879,7 +880,7 @@ static void mac802154_rxframe_worker(FAR void *arg)
}
else if (ind->dest.mode == IEEE802154_ADDRMODE_EXTENDED)
{
memcpy(&ind->dest.eaddr[0], frame->io_data[frame->io_offset],
memcpy(&ind->dest.eaddr[0], &frame->io_data[frame->io_offset],
IEEE802154_EADDR_LEN);
frame->io_offset += 8;
}
@ -913,13 +914,16 @@ static void mac802154_rxframe_worker(FAR void *arg)
}
else if (ind->src.mode == IEEE802154_ADDRMODE_EXTENDED)
{
memcpy(&ind->src.eaddr[0], frame->io_data[frame->io_offset],
memcpy(&ind->src.eaddr[0], &frame->io_data[frame->io_offset],
IEEE802154_EADDR_LEN);
frame->io_offset += 8;
}
}
ftype = (*frame_ctrl & IEEE802154_FRAMECTRL_FTYPE) >>
IEEE802154_FRAMECTRL_SHIFT_FTYPE;
if (frame_ctrl & IEEE802154_FRAMECTRL_FTYPE == IEEE802154_FRAME_DATA)
if (ftype == IEEE802154_FRAME_DATA)
{
/* If there is a registered MCPS callback receiver registered, send
* the frame, otherwise, throw it out.
@ -929,7 +933,7 @@ static void mac802154_rxframe_worker(FAR void *arg)
{
mcps_notify.dataind = ind;
priv->cb->mcps_notify(priv->cb, IEEE802154_NOTIFY_IND_DATA,
mcps_notify);
&mcps_notify);
}
else
{
@ -938,11 +942,11 @@ static void mac802154_rxframe_worker(FAR void *arg)
ieee802154_ind_free(ind);
}
}
else if (frame_ctrl & IEEE802154_FRAMECTRL_FTYPE == IEEE802154_FRAME_COMMAND)
else if (ftype == IEEE802154_FRAME_COMMAND)
{
}
else if (frame_ctrl & IEEE802154_FRAMECTRL_FTYPE == IEEE802154_FRAME_BEACON)
else if (ftype == IEEE802154_FRAME_BEACON)
{
}
@ -1023,6 +1027,10 @@ MACHANDLE mac802154_create(FAR struct ieee802154_radio_s *radiodev)
radiodev->ops->bind(radiodev, &mac->radiocb.cb);
/* Initialize our data indication pool */
ieee802154_indpool_initialize();
return (MACHANDLE)mac;
}
@ -1360,7 +1368,7 @@ int mac802154_req_data(MACHANDLE mac,
*/
if ((meta->dest_addr.mode == IEEE802154_ADDRMODE_NONE) ||
(*frame_ctrl & IEEE802154_FRAMECTRL_PANIDCOMP))
(!(*frame_ctrl & IEEE802154_FRAMECTRL_PANIDCOMP)))
{
memcpy(&frame->io_data[mhr_len], &priv->addr.panid, 2);
mhr_len += 2;

View File

@ -336,70 +336,6 @@ int mac802154_resp_associate(MACHANDLE mac,
int mac802154_resp_orphan(MACHANDLE mac,
FAR struct ieee802154_orphan_resp_s *resp);
/****************************************************************************
* Name: ieee802154_indpool_initialize
*
* Description:
* This function initializes the meta-data allocator. This function must
* be called early in the initialization sequence before any radios
* begin operation.
*
* Inputs:
* None
*
* Return Value:
* None
*
****************************************************************************/
void ieee802154_indpool_initialize(void);
/****************************************************************************
* Name: ieee802154_ind_allocate
*
* Description:
* The ieee802154_ind_allocate function will get a free meta-data
* structure for use by the IEEE 802.15.4 MAC.
*
* Interrupt handling logic will first attempt to allocate from the
* g_indfree list. If that list is empty, it will attempt to allocate
* from its reserve, g_indfree_irq. If that list is empty, then the
* allocation fails (NULL is returned).
*
* Non-interrupt handler logic will attempt to allocate from g_indfree
* list. If that the list is empty, then the meta-data structure will be
* allocated from the dynamic memory pool.
*
* Inputs:
* None
*
* Return Value:
* A reference to the allocated msg structure. All user fields in this
* structure have been zeroed. On a failure to allocate, NULL is
* returned.
*
****************************************************************************/
FAR struct ieee802154_data_ind_s *ieee802154_ind_allocate(void);
/****************************************************************************
* Name: ieee802154_ind_free
*
* Description:
* The ieee802154_ind_free function will return a meta-data structure to
* the free pool of messages if it was a pre-allocated meta-data
* structure. If the meta-data structure was allocated dynamically it will
* be deallocated.
*
* Inputs:
* ind - meta-data structure to free
*
* Return Value:
* None
*
****************************************************************************/
void ieee802154_ind_free(FAR struct ieee802154_data_ind_s *ind);
#undef EXTERN
#ifdef __cplusplus

View File

@ -108,6 +108,9 @@ struct mac802154_chardevice_s
struct mac802154dev_callback_s md_cb; /* Callback information */
sem_t md_exclsem; /* Exclusive device access */
bool readpending; /* Is there a read using the semaphore? */
sem_t readsem; /* Signaling semaphore for waiting read */
/* The following is a singly linked list of open references to the
* MAC device.
*/
@ -115,6 +118,11 @@ struct mac802154_chardevice_s
FAR struct mac802154dev_open_s *md_open;
FAR struct mac802154dev_dwait_s *md_dwait;
/* Hold a list of transactions as a "readahead" buffer */
FAR struct ieee802154_data_ind_s *dataind_head;
FAR struct ieee802154_data_ind_s *dataind_tail;
#ifndef CONFIG_DISABLE_SIGNALS
/* MCPS Service notification information */
@ -137,6 +145,12 @@ struct mac802154_chardevice_s
static inline int mac802154dev_takesem(sem_t *sem);
#define mac802154dev_givesem(s) sem_post(s);
static void mac802154dev_push_dataind(FAR struct mac802154_chardevice_s *dev,
FAR struct ieee802154_data_ind_s *ind);
static FAR struct ieee802154_data_ind_s *
mac802154dev_pop_dataind(FAR struct mac802154_chardevice_s *dev);
static void mac802154dev_mlme_notify(FAR const struct ieee802154_maccb_s *maccb,
enum ieee802154_macnotify_e notif,
FAR const union ieee802154_mlme_notify_u *arg);
@ -158,6 +172,8 @@ static int mac802154dev_ioctl(FAR struct file *filep, int cmd,
static void mac802154dev_conf_data(FAR struct mac802154_chardevice_s *dev,
FAR const struct ieee802154_data_conf_s *conf);
static void mac802154dev_ind_data(FAR struct mac802154_chardevice_s *dev,
FAR struct ieee802154_data_ind_s *ind);
/****************************************************************************
* Private Data
@ -207,6 +223,79 @@ static inline int mac802154dev_takesem(sem_t *sem)
return OK;
}
/****************************************************************************
* Name: mac802154dev_push_dataind
*
* Description:
* Push a data indication onto the list to be processed
*
****************************************************************************/
static void mac802154dev_push_dataind(FAR struct mac802154_chardevice_s *dev,
FAR struct ieee802154_data_ind_s *ind)
{
/* Ensure the forward link is NULL */
ind->flink = NULL;
/* If the tail is not empty, make the frame pointed to by the tail,
* point to the new data indication */
if (dev->dataind_tail != NULL)
{
dev->dataind_tail->flink = ind;
}
/* Point the tail at the new frame */
dev->dataind_tail = ind;
/* If the head is NULL, we need to point it at the data indication since there
* is only one indication in the list at this point */
if (dev->dataind_head == NULL)
{
dev->dataind_head = ind;
}
}
/****************************************************************************
* Name: mac802154dev_pop_dataind
*
* Description:
* Pop a data indication from the list
*
****************************************************************************/
static FAR struct ieee802154_data_ind_s *
mac802154dev_pop_dataind(FAR struct mac802154_chardevice_s *dev)
{
FAR struct ieee802154_data_ind_s *ind;
if (dev->dataind_head == NULL)
{
return NULL;
}
/* Get the data indication from the head of the list */
ind = dev->dataind_head;
ind->flink = NULL;
/* Move the head pointer to the next data indication */
dev->dataind_head = ind->flink;
/* If the head is now NULL, the list is empty, so clear the tail too */
if (dev->dataind_head == NULL)
{
dev->dataind_tail = NULL;
}
return ind;
}
/****************************************************************************
* Name: mac802154dev_open
*
@ -368,6 +457,8 @@ static ssize_t mac802154dev_read(FAR struct file *filep, FAR char *buffer,
{
FAR struct inode *inode;
FAR struct mac802154_chardevice_s *dev;
FAR struct mac802154dev_rxframe_s *rx;
FAR struct ieee802154_data_ind_s *ind;
int ret;
DEBUGASSERT(filep && filep->f_inode);
@ -375,20 +466,94 @@ static ssize_t mac802154dev_read(FAR struct file *filep, FAR char *buffer,
DEBUGASSERT(inode->i_private);
dev = (FAR struct mac802154_chardevice_s *)inode->i_private;
/* Get exclusive access to the driver structure */
/* Check to make sure the buffer is the right size for the struct */
ret = mac802154dev_takesem(&dev->md_exclsem);
if (ret < 0)
if (len != sizeof(struct mac802154dev_rxframe_s))
{
wlerr("ERROR: mac802154dev_takesem failed: %d\n", ret);
return ret;
wlerr("ERROR: buffer isn't a mac802154dev_rxframe_s: %lu\n",
(unsigned long)len);
return -EINVAL;
}
/* TODO: Add code to read a packet and return it */
ret = -ENOTSUP;
DEBUGASSERT(buffer != NULL);
rx = (FAR struct mac802154dev_rxframe_s *)buffer;
mac802154dev_givesem(&dev->md_exclsem);
return ret;
while (1)
{
/* Get exclusive access to the driver structure */
ret = mac802154dev_takesem(&dev->md_exclsem);
if (ret < 0)
{
wlerr("ERROR: mac802154dev_takesem failed: %d\n", ret);
return ret;
}
/* Try popping a data indication off the list */
ind = mac802154dev_pop_dataind(dev);
/* If the indication is not null, we can exit the loop and copy the data */
if (ind != NULL)
{
mac802154dev_givesem(&dev->md_exclsem);
break;
}
/* If this is a non-blocking call, or if there is another read operation
* already pending, don't block. This driver returns EAGAIN even when
* configured as non-blocking if another read operation is already pending
* This situation should be rare. It will only occur when there are 2 calls
* to read from separate threads and there was no data in the rx list.
*/
if ((filep->f_oflags & O_NONBLOCK) || dev->readpending)
{
mac802154dev_givesem(&dev->md_exclsem);
return -EAGAIN;
}
dev->readpending = true;
mac802154dev_givesem(&dev->md_exclsem);
/* Wait to be signaled when a frame is added to the list */
if (sem_wait(&dev->readsem) < 0)
{
DEBUGASSERT(errno == EINTR);
/* Need to get exclusive access again to change the pending bool */
ret = mac802154dev_takesem(&dev->md_exclsem);
dev->readpending = false;
mac802154dev_givesem(&dev->md_exclsem);
return -EINTR;
}
/* Let the loop wrap back around, we will then pop a indication and this
* time, it should have a data indication
*/
}
rx->length = (ind->frame->io_len - ind->frame->io_offset);
/* Copy the data from the IOB to the user supplied struct */
memcpy(&rx->payload[0], &ind->frame->io_data[ind->frame->io_offset],
rx->length);
memcpy(&rx->meta, ind, sizeof(struct ieee802154_data_ind_s));
/* Zero out the forward link and IOB reference */
rx->meta.flink = NULL;
rx->meta.frame = NULL;
/* Deallocate the data indication */
ieee802154_ind_free(ind);
return OK;
}
/****************************************************************************
@ -649,6 +814,11 @@ static void mac802154dev_mcps_notify(FAR const struct ieee802154_maccb_s *maccb,
mac802154dev_conf_data(dev, &arg->dataconf);
}
break;
case IEEE802154_NOTIFY_IND_DATA:
{
mac802154dev_ind_data(dev, arg->dataind);
}
break;
default:
break;
}
@ -717,6 +887,48 @@ static void mac802154dev_conf_data(FAR struct mac802154_chardevice_s *dev,
#endif
}
static void mac802154dev_ind_data(FAR struct mac802154_chardevice_s *dev,
FAR struct ieee802154_data_ind_s *ind)
{
/* Get exclusive access to the driver structure. We don't care about any
* signals so if we see one, just go back to trying to get access again */
while (mac802154dev_takesem(&dev->md_exclsem) != 0);
/* Push the indication onto the list */
mac802154dev_push_dataind(dev, ind);
/* Check if there is a read waiting for data */
if (dev->readpending)
{
/* Wake the thread waiting for the data transmission */
dev->readpending = false;
sem_post(&dev->readsem);
}
/* Release the driver */
mac802154dev_givesem(&dev->md_exclsem);
#ifndef CONFIG_DISABLE_SIGNALS
/* Send a signal to the registered application */
#ifdef CONFIG_CAN_PASS_STRUCTS
/* Copy the status as the signal data to be optionally used by app */
union sigval value;
value.sival_int = IEEE802154_STATUS_SUCCESS;
(void)sigqueue(dev->md_mcps_pid, dev->md_mcps_notify.mn_signo, value);
#else
(void)sigqueue(dev->md_mcps_pid, dev->md_mcps_notify.mn_signo,
value.sival_ptr);
#endif
#endif
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -758,6 +970,10 @@ int mac802154dev_register(MACHANDLE mac, int minor)
dev->md_mac = mac;
sem_init(&dev->md_exclsem, 0, 1); /* Allow the device to be opened once
* before blocking */
sem_init(&dev->readsem, 0, 0);
sem_setprotocol(&dev->readsem, SEM_PRIO_NONE);
dev->readpending = false;
/* Initialize the MAC callbacks */