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:
commit
933c6c7cda
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user