From 06634afbe08766929b26ee35f7514aa6d836ee4b Mon Sep 17 00:00:00 2001 From: Anthony Merlino Date: Mon, 15 May 2017 21:44:51 -0400 Subject: [PATCH] wireless/ieee802154: Restructuring of MAC notifications. Simplifes some interfaces --- drivers/wireless/ieee802154/mrf24j40.c | 44 +- .../wireless/ieee802154/ieee802154_ioctl.h | 5 +- .../wireless/ieee802154/ieee802154_mac.h | 236 +++--- .../wireless/ieee802154/ieee802154_radio.h | 24 +- wireless/ieee802154/mac802154.c | 795 +++++++++++++----- wireless/ieee802154/mac802154.h | 56 +- wireless/ieee802154/mac802154_device.c | 504 +++++------ wireless/ieee802154/mac802154_netdev.c | 102 +-- 8 files changed, 1061 insertions(+), 705 deletions(-) diff --git a/drivers/wireless/ieee802154/mrf24j40.c b/drivers/wireless/ieee802154/mrf24j40.c index fe022d5114..903b843c9c 100644 --- a/drivers/wireless/ieee802154/mrf24j40.c +++ b/drivers/wireless/ieee802154/mrf24j40.c @@ -107,13 +107,6 @@ * Private Types ****************************************************************************/ -struct mrf24j40_txdesc_s -{ - struct ieee802154_txdesc_s pub; - - uint8_t busy : 1; /* Is this txdesc being used */ -}; - /* A MRF24J40 device instance */ struct mrf24j40_radio_s @@ -145,11 +138,13 @@ struct mrf24j40_radio_s /* Buffer Allocations */ - struct mrf24j40_txdesc_s csma_desc; + struct ieee802154_txdesc_s *csma_desc; FAR struct iob_s *csma_frame; + bool csma_busy; - struct mrf24j40_txdesc_s gts_desc[MRF24J40_GTS_SLOTS]; + struct ieee802154_txdesc_s *gts_desc[MRF24J40_GTS_SLOTS]; FAR struct iob_s *gts_frame[MRF24J40_GTS_SLOTS]; + bool gts_busy[MRF24J40_GTS_SLOTS]; }; /**************************************************************************** @@ -189,7 +184,6 @@ static int mrf24j40_gts_setup(FAR struct mrf24j40_radio_s *dev, uint8_t gts, 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 *dev, uint8_t chan); static int mrf24j40_getchannel(FAR struct mrf24j40_radio_s *dev, @@ -206,10 +200,6 @@ static int mrf24j40_seteaddr(FAR struct mrf24j40_radio_s *dev, FAR const uint8_t *eaddr); static int mrf24j40_geteaddr(FAR struct mrf24j40_radio_s *dev, FAR uint8_t *eaddr); -static int mrf24j40_setpromisc(FAR struct mrf24j40_radio_s *dev, - bool promisc); -static int mrf24j40_getpromisc(FAR struct mrf24j40_radio_s *dev, - FAR bool *promisc); static int mrf24j40_setdevmode(FAR struct mrf24j40_radio_s *dev, uint8_t mode); static int mrf24j40_getdevmode(FAR struct mrf24j40_radio_s *dev, @@ -446,17 +436,17 @@ static void mrf24j40_dopoll_csma(FAR void *arg) /* If this a CSMA transaction and we have room in the CSMA fifo */ - if (!dev->csma_desc.busy) + if (!dev->csma_busy) { /* need to somehow allow for a handle to be passed */ - len = dev->radiocb->poll_csma(dev->radiocb, &dev->csma_desc.pub, + len = dev->radiocb->poll_csma(dev->radiocb, &dev->csma_desc, &dev->csma_frame); if (len > 0) { /* Now the txdesc is in use */ - dev->csma_desc.busy = 1; + dev->csma_busy = 1; /* Setup the transaction on the device in the CSMA FIFO */ @@ -501,15 +491,15 @@ static void mrf24j40_dopoll_gts(FAR void *arg) for (gts = 0; gts < MRF24J40_GTS_SLOTS; gts++) { - if (!dev->gts_desc[gts].busy) + if (!dev->gts_busy[gts]) { - len = dev->radiocb->poll_gts(dev->radiocb, &dev->gts_desc[gts].pub, + len = dev->radiocb->poll_gts(dev->radiocb, &dev->gts_desc[gts], &dev->gts_frame[0]); if (len > 0) { /* Now the txdesc is in use */ - dev->gts_desc[gts].busy = 1; + dev->gts_busy[gts]= 1; /* Setup the transaction on the device in the open GTS FIFO */ @@ -1406,15 +1396,15 @@ static void mrf24j40_irqwork_txnorm(FAR struct mrf24j40_radio_s *dev) */ txstat = mrf24j40_getreg(dev->spi, MRF24J40_TXSTAT); - dev->csma_desc.pub.status = txstat & MRF24J40_TXSTAT_TXNSTAT; + dev->csma_desc->conf->status = txstat & MRF24J40_TXSTAT_TXNSTAT; /* Inform the next layer of the transmission success/failure */ - dev->radiocb->txdone(dev->radiocb, &dev->csma_desc.pub); + dev->radiocb->txdone(dev->radiocb, dev->csma_desc); /* We are now done with the transaction */ - dev->csma_desc.busy = 0; + dev->csma_busy = 0; /* Free the IOB */ @@ -1451,20 +1441,20 @@ static void mrf24j40_irqwork_txgts(FAR struct mrf24j40_radio_s *dev, if (gts == 0) { - dev->csma_desc.pub.status = txstat & MRF24J40_TXSTAT_TXG1STAT; + dev->csma_desc->conf->status = txstat & MRF24J40_TXSTAT_TXG1STAT; } else if (gts == 1) { - dev->csma_desc.pub.status = txstat & MRF24J40_TXSTAT_TXG2STAT; + dev->csma_desc->conf->status = txstat & MRF24J40_TXSTAT_TXG2STAT; } /* Inform the next layer of the transmission success/failure */ - dev->radiocb->txdone(dev->radiocb, &dev->gts_desc[gts].pub); + dev->radiocb->txdone(dev->radiocb, dev->gts_desc[gts]); /* We are now done with the transaction */ - dev->gts_desc[gts].busy = 0; + dev->gts_busy[gts]= 0; /* Free the IOB */ diff --git a/include/nuttx/wireless/ieee802154/ieee802154_ioctl.h b/include/nuttx/wireless/ieee802154/ieee802154_ioctl.h index 5f14f2e2c6..318289b4db 100644 --- a/include/nuttx/wireless/ieee802154/ieee802154_ioctl.h +++ b/include/nuttx/wireless/ieee802154/ieee802154_ioctl.h @@ -62,8 +62,9 @@ /* IEEE 802.15.4 MAC Character Driver IOCTL commands ********************************/ -#define MAC802154IOC_MCPS_REGISTER _WLCIOC(IEEE802154_FIRST) -#define MAC802154IOC_MLME_REGISTER _WLCIOC(IEEE802154_FIRST+1) +#define MAC802154IOC_NOTIFY_REGISTER _WLCIOC(IEEE802154_FIRST) +#define MAC802154IOC_GET_EVENT _WLCIOC(IEEE802154_FIRST+1) +#define MAC802154IOC_ENABLE_EVENTS _WLCIOC(IEEE802154_FIRST+2) /************************************************************************************ * Public Types diff --git a/include/nuttx/wireless/ieee802154/ieee802154_mac.h b/include/nuttx/wireless/ieee802154/ieee802154_mac.h index 15963b46e1..5f28cfa0c7 100644 --- a/include/nuttx/wireless/ieee802154/ieee802154_mac.h +++ b/include/nuttx/wireless/ieee802154/ieee802154_mac.h @@ -102,31 +102,12 @@ /* IEEE 802.15.4 MAC Interface **********************************************/ -/* Frame Type */ - -#define IEEE802154_FRAME_BEACON 0x00 -#define IEEE802154_FRAME_DATA 0x01 -#define IEEE802154_FRAME_ACK 0x02 -#define IEEE802154_FRAME_COMMAND 0x03 - -/* MAC commands */ - -#define IEEE802154_CMD_ASSOC_REQ 0x01 -#define IEEE802154_CMD_ASSOC_RESP 0x02 -#define IEEE802154_CMD_DISASSOC_NOT 0x03 -#define IEEE802154_CMD_DATA_REQ 0x04 -#define IEEE802154_CMD_PANID_CONF_NOT 0x05 -#define IEEE802154_CMD_ORPHAN_NOT 0x06 -#define IEEE802154_CMD_BEACON_REQ 0x07 -#define IEEE802154_CMD_COORD_REALIGN 0x08 -#define IEEE802154_CMD_GTS_REQ 0x09 - /* Some addresses */ #define IEEE802154_PAN_UNSPEC (uint16_t)0xFFFF #define IEEE802154_SADDR_UNSPEC (uint16_t)0xFFFF #define IEEE802154_SADDR_BCAST (uint16_t)0xFFFE -#define IEEE802154_EADDR_UNSPEC (uint8_t*)"\xff\xff\xff\xff\xff\xff\xff\xff" +#define IEEE802154_EADDR_UNSPEC (uint8_t[]){0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF} /* Frame control field masks, 2 bytes * Seee IEEE 802.15.4/2011 5.2.1.1 page 57 @@ -150,6 +131,22 @@ #define IEEE802154_FRAMECTRL_SHIFT_VERSION 12 /* Source addressing mode, bits 12-13 */ #define IEEE802154_FRAMECTRL_SHIFT_SADDR 14 /* Source addressing mode, bits 14-15 */ +/* Capability Information Bitfield + * + */ + +#define IEEE802154_CAPABILITY_DEVTYPE 0x02 +#define IEEE802154_CAPABILITY_PWRSRC 0x04 +#define IEEE802154_CAPABILITY_RXONIDLE 0x08 +#define IEEE802154_CAPABILITY_SECURITY 0x40 +#define IEEE802154_CAPABILITY_ALLOCADDR 0x80 + +#define IEEE802154_CAPABILITY_SHIFT_DEVTYPE 1 +#define IEEE802154_CAPABILITY_SHIFT_PWRSRC 2 +#define IEEE802154_CAPABILITY_SHIFT_RXONIDLE 3 +#define IEEE802154_CAPABILITY_SHIFT_SECURITY 6 +#define IEEE802154_CAPABILITY_SHIFT_ALLOCADDR 7 + /* IEEE 802.15.4 PHY constants */ #define IEEE802154_MAX_PHY_PACKET_SIZE 127 @@ -194,7 +191,6 @@ #define MAX_ORPHAN_ADDR 32 /* REVISIT */ -// TODO: Add macros /**************************************************************************** * Public Types @@ -329,6 +325,31 @@ enum ieee802154_pib_attr_e IEEE802154_PIB_MAC_PANCOORD_SHORT_ADDR, }; +/* Frame Type */ + +enum ieee802154_frametype_e +{ + IEEE802154_FRAME_BEACON = 0, + IEEE802154_FRAME_DATA, + IEEE802154_FRAME_ACK, + IEEE802154_FRAME_COMMAND +}; + +/* MAC command IDs */ + +enum ieee802154_cmdid_e +{ + IEEE802154_CMD_ASSOC_REQ = 1, + IEEE802154_CMD_ASSOC_RESP, + IEEE802154_CMD_DISASSOC_NOT, + IEEE802154_CMD_DATA_REQ, + IEEE802154_CMD_PANID_CONF_NOT, + IEEE802154_CMD_ORPHAN_NOT, + IEEE802154_CMD_BEACON_REQ, + IEEE802154_CMD_COORD_REALIGN, + IEEE802154_CMD_GTS_REQ, +}; + enum ieee802154_devmode_e { IEEE802154_DEVMODE_ENDPOINT, @@ -405,13 +426,13 @@ enum ieee802154_ranging_e struct ieee802154_capability_info_s { uint8_t reserved_0 : 1; /* Reserved */ - uint8_t device_type : 1; /* 0=RFD, 1=FFD */ - uint8_t power_source : 1; /* 1=AC, 0=Other */ - uint8_t rx_on_idle : 1; /* 0=Receiver off when idle + uint8_t devtype : 1; /* 0=RFD, 1=FFD */ + uint8_t powersource : 1; /* 1=AC, 0=Other */ + uint8_t rxonidle : 1; /* 0=Receiver off when idle * 1=Receiver on when idle */ uint8_t reserved_45 : 2; /* Reserved */ uint8_t security : 1; /* 0=disabled, 1=enabled */ - uint8_t allocate_addr : 1; /* 1=Coordinator allocates short address + uint8_t allocaddr : 1; /* 1=Coordinator allocates short address * 0=otherwise */ }; @@ -462,31 +483,6 @@ struct ieee802154_pend_addr_s struct ieee802154_addr_s addr[7]; /* Array of at most 7 addresses */ }; -#ifdef CONFIG_IEEE802154_RANGING -#define IEEE802154_TXDESC_FIELDS \ - uint8_t handle; \ - uint32_t timestamp; \ - uint8_t status; -#else -#define IEEE802154_TXDESC_FIELDS \ - uint8_t handle; \ - uint32_t timestamp; \ - uint8_t status; - bool rng_rcvd; \ - uint32_t rng_counter_start; \ - uint32_t rng_counter_stop; \ - uint32_t rng_tracking_interval; \ - uint32_t rng_offset;\ - uint8_t rng_fom; -#endif - -struct ieee802154_txdesc_s -{ - IEEE802154_TXDESC_FIELDS - - /* TODO: Add slotting information for GTS transactions */ -}; - struct ieee802154_cca_s { uint8_t use_ed : 1; /* CCA using ED */ @@ -631,7 +627,44 @@ struct ieee802154_frame_meta_s struct ieee802154_data_conf_s { - IEEE802154_TXDESC_FIELDS + uint8_t handle; /* Handle assoc. with MSDU */ + + /* The time, in symbols, at which the data were transmitted */ + + uint32_t timestamp; + enum ieee802154_status_e status; /* The status of the MSDU transmission */ + +#ifdef CONFIG_IEEE802154_RANGING + bool rng_rcvd; /* Ranging indicated by MSDU */ + + /* A count of the time units corresponding to an RMARKER at the antenna at + * the beginning of the ranging exchange + */ + + uint32_t rng_counter_start; + + /* A count of the time units corresponding to an RMARKER at the antenna at + * end of the ranging exchange + */ + + uint32_t rng_counter_stop; + + /* A count of the time units in a message exchange over which the tracking + * offset was measured + */ + + uint32_t rng_tracking_interval; + + /* A count of the time units slipped or advanced by the radio tracking + * system over the course of the entire tracking interval + */ + + uint32_t rng_offset; + + /* The Figure of Merit (FoM) characterizing the ranging measurement */ + + uint8_t rng_fom; +#endif }; /***************************************************************************** @@ -734,12 +767,12 @@ struct ieee802154_purge_req_s struct ieee802154_assoc_req_s { - uint8_t channel; /* Channel number to attempt association */ - uint8_t channel_page; /* Channel page to attempt association */ + uint8_t chnum; /* Channel number to attempt association */ + uint8_t chpage; /* Channel page to attempt association */ /* Coordinator Address with which to associate */ - struct ieee802154_addr_s coord_addr; + struct ieee802154_addr_s coordaddr; /* Capabilities of associating device */ @@ -1307,8 +1340,42 @@ struct ieee802154_poll_conf_s enum ieee802154_status_e status; }; -union ieee802154_mlme_notify_u +/* MAC Service Notifications */ + +enum ieee802154_notify_e { + /* MCPS Notifications */ + + IEEE802154_NOTIFY_CONF_DATA = 0x00, + + /* MLME Notifications */ + + IEEE802154_NOTIFY_CONF_ASSOC, + IEEE802154_NOTIFY_CONF_DISASSOC, + IEEE802154_NOTIFY_CONF_GTS, + IEEE802154_NOTIFY_CONF_RESET, + IEEE802154_NOTIFY_CONF_RXENABLE, + IEEE802154_NOTIFY_CONF_SCAN, + IEEE802154_NOTIFY_CONF_START, + IEEE802154_NOTIFY_CONF_POLL, + + IEEE802154_NOTIFY_IND_ASSOC, + IEEE802154_NOTIFY_IND_DISASSOC, + IEEE802154_NOTIFY_IND_BEACONNOTIFY, + IEEE802154_NOTIFY_IND_GTS, + IEEE802154_NOTIFY_IND_ORPHAN, + IEEE802154_NOTIFY_IND_COMMSTATUS, + IEEE802154_NOTIFY_IND_SYNCLOSS +}; + +union ieee802154_notif_u +{ + /* MCPS Notifications */ + + struct ieee802154_data_conf_s dataconf; + + /* MLME Notifications */ + struct ieee802154_assoc_conf_s assocconf; struct ieee802154_disassoc_conf_s disassocconf; struct ieee802154_gts_conf_s gtsconf; @@ -1326,10 +1393,18 @@ union ieee802154_mlme_notify_u struct ieee802154_syncloss_ind_s synclossind; }; -union ieee802154_mcps_notify_u +struct ieee802154_notif_s { - struct ieee802154_data_conf_s dataconf; - struct ieee802154_data_ind_s *dataind; + /* Must be first member so that we can interchange between the actual + *notification and this extended struct. + */ + + union ieee802154_notif_u u; + enum ieee802154_notify_e notiftype; + + /* Support a singly linked list */ + + FAR struct ieee802154_notif_s *flink; }; /* A pointer to this structure is passed as the argument of each IOCTL @@ -1376,51 +1451,6 @@ struct ieee802154_netmac_s typedef FAR void *MACHANDLE; -/* MAC Service Notifications */ - -enum ieee802154_macnotify_e -{ - /* MCPS Notifications */ - - IEEE802154_NOTIFY_CONF_DATA = 0x00, - IEEE802154_NOTIFY_IND_DATA, - - /* MLME Notifications */ - - IEEE802154_NOTIFY_CONF_ASSOC, - IEEE802154_NOTIFY_CONF_DISASSOC, - IEEE802154_NOTIFY_CONF_GTS, - IEEE802154_NOTIFY_CONF_RESET, - IEEE802154_NOTIFY_CONF_RXENABLE, - IEEE802154_NOTIFY_CONF_SCAN, - IEEE802154_NOTIFY_CONF_START, - IEEE802154_NOTIFY_CONF_POLL, - - IEEE802154_NOTIFY_IND_ASSOC, - IEEE802154_NOTIFY_IND_DISASSOC, - IEEE802154_NOTIFY_IND_BEACONNOTIFY, - IEEE802154_NOTIFY_IND_GTS, - IEEE802154_NOTIFY_IND_ORPHAN, - IEEE802154_NOTIFY_IND_COMMSTATUS, - IEEE802154_NOTIFY_IND_SYNCLOSS -}; - -/* Callback operations to notify the next highest layer of various asynchronous - * events, usually triggered by some previous request or response invoked by the - * upper layer. - */ - -struct ieee802154_maccb_s -{ - CODE void (*mlme_notify)(FAR const struct ieee802154_maccb_s *maccb, - enum ieee802154_macnotify_e notif, - FAR const union ieee802154_mlme_notify_u *arg); - - CODE void (*mcps_notify)(FAR const struct ieee802154_maccb_s *maccb, - enum ieee802154_macnotify_e notif, - FAR const union ieee802154_mcps_notify_u *arg); -}; - #ifdef __cplusplus #define EXTERN extern "C" extern "C" diff --git a/include/nuttx/wireless/ieee802154/ieee802154_radio.h b/include/nuttx/wireless/ieee802154/ieee802154_radio.h index d3fcb5db74..e0ff8b664f 100644 --- a/include/nuttx/wireless/ieee802154/ieee802154_radio.h +++ b/include/nuttx/wireless/ieee802154/ieee802154_radio.h @@ -58,15 +58,35 @@ * Public Types ****************************************************************************/ +/* Data only used between radio and MAC layer */ + +struct ieee802154_txdesc_s +{ + /* Support a singly linked list of tx descriptors */ + + FAR struct ieee802154_txdesc_s *flink; + + /* Pointer to the data confirmation structure to be populated upon + * success/failure of the transmission. + */ + + FAR struct ieee802154_data_conf_s *conf; + + enum ieee802154_frametype_e frametype; /* Frame type. Used by MAC layer to + * control how tx done is handled */ + + /* TODO: Add slotting information for GTS transactions */ +}; + /* IEEE802.15.4 Radio Interface Operations **********************************/ struct ieee802154_radiocb_s { CODE int (*poll_csma) (FAR const struct ieee802154_radiocb_s *radiocb, - FAR struct ieee802154_txdesc_s *tx_desc, + FAR struct ieee802154_txdesc_s **tx_desc, FAR struct iob_s **frame); CODE int (*poll_gts) (FAR const struct ieee802154_radiocb_s *radiocb, - FAR struct ieee802154_txdesc_s *tx_desc, + FAR struct ieee802154_txdesc_s **tx_desc, FAR struct iob_s **frame); CODE void (*txdone) (FAR const struct ieee802154_radiocb_s *radiocb, FAR const struct ieee802154_txdesc_s *tx_desc); diff --git a/wireless/ieee802154/mac802154.c b/wireless/ieee802154/mac802154.c index 8b7b545699..c57891f83c 100644 --- a/wireless/ieee802154/mac802154.c +++ b/wireless/ieee802154/mac802154.c @@ -52,11 +52,11 @@ #include +#include "mac802154.h" + #include #include -#include "mac802154.h" - /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -80,17 +80,32 @@ # endif #endif +#if !defined(CONFIG_MAC802154_NNOTIF) || CONFIG_MAC802154_NNOTIF <= 0 +# undef CONFIG_MAC802154_NNOTIF +# define CONFIG_MAC802154_NNOTIF 6 +#endif + +#if !defined(CONFIG_MAC802154_NTXDESC) || CONFIG_MAC802154_NTXDESC <= 0 +# undef CONFIG_MAC802154_NTXDESC +# define CONFIG_MAC802154_NTXDESC 3 +#endif + +#if CONFIG_MAC802154_NTXDESC > CONFIG_MAC802154_NNOTIF +#error CONFIG_MAC802154_NNOTIF must be greater than CONFIG_MAC802154_NTXDESC +#endif + /**************************************************************************** * Private Types ****************************************************************************/ -struct mac802154_txframe_s +struct mac802154_txtrans_s { /* Supports a singly linked list */ - FAR struct mac802154_txframe_s *flink; + FAR struct mac802154_txtrans_s *flink; FAR struct iob_s *frame; - uint8_t msdu_handle; + uint8_t handle; + enum ieee802154_frametype_e frametype; sem_t sem; }; @@ -118,11 +133,46 @@ struct mac802154_radiocb_s struct ieee802154_privmac_s { FAR struct ieee802154_radio_s *radio; /* Contained IEEE802.15.4 radio dev */ - FAR const struct ieee802154_maccb_s *cb; /* Contained MAC callbacks */ + FAR const struct mac802154_maccb_s *cb; /* Contained MAC callbacks */ FAR struct mac802154_radiocb_s radiocb; /* Interface to bind to radio */ sem_t exclsem; /* Support exclusive access */ + /* Support a single transaction dedicated to commands. As of now I see no + * condition where you need to have more than one command frame simultaneously + */ + + struct + { + sem_t sem; /* Exclusive use of the cmdtrans */ + enum ieee802154_cmdid_e type; /* Type of cmd in the cmdtrans */ + struct mac802154_txtrans_s trans; /* Dedicated txframe for cmds */ + + /* Has the command been successfully sent. This is to help protect + * against an odd edge case that may or may not ever happen. The condition + * occurs when you receive a seemingly appropriate response to the command + * yet the command was never actually sent. + */ + + bool txdone; + } cmd; + + /* Pre-allocated notifications to be passed to the registered callback. These + * need to be freed by the application using mac802154_xxxxnotif_free when + * the callee layer is finished with it's use. + */ + + FAR struct ieee802154_notif_s *notif_free; + struct ieee802154_notif_s notif_alloc[CONFIG_MAC802154_NNOTIF]; + sq_queue_t notif_queue; + + FAR struct ieee802154_txdesc_s *txdesc_free; + struct ieee802154_txdesc_s txdesc_alloc[CONFIG_IEEE802154_NTXDESC]; + sq_queue_t txdesc_queue; + sq_queue_t txdone_queue; + + /* Work structures for offloading aynchronous work */ + struct work_s tx_work; struct work_s rx_work; @@ -132,8 +182,7 @@ struct ieee802154_privmac_s * during the CAP of the Coordinator's superframe. */ - FAR struct mac802154_txframe_s *csma_head; - FAR struct mac802154_txframe_s *csma_tail; + sq_queue_t csma_queue; /* Support a singly linked list of transactions that will be sent indirectly. * This list should only be used by a MAC acting as a coordinator. These @@ -142,16 +191,12 @@ struct ieee802154_privmac_s * list should also be used to populate the address list of the outgoing * beacon frame. */ - - FAR struct mac802154_txframe_s *indirect_head; - FAR struct mac802154_txframe_s *indirect_tail; - - uint8_t txdesc_count; - struct ieee802154_txdesc_s txdesc[CONFIG_IEEE802154_NTXDESC]; + + sq_queue_t indirect_queue; /* Support a singly linked list of frames received */ - FAR struct ieee802154_data_ind_s *dataind_head; - FAR struct ieee802154_data_ind_s *dataind_tail; + + sq_queue_t dataind_queue; /* MAC PIB attributes, grouped to save memory */ @@ -264,7 +309,10 @@ struct ieee802154_privmac_s enum ieee802154_devmode_e devmode : 2; - /* 11-bits remaining */ + bool csma_tryagain : 1; + bool gts_tryagain : 1; + + /* 10-bits remaining */ /* End of 32-bit bitfield. */ @@ -275,25 +323,33 @@ struct ieee802154_privmac_s * Private Function Prototypes ****************************************************************************/ +/* Internal Functions */ + static inline int mac802154_takesem(sem_t *sem); #define mac802154_givesem(s) sem_post(s); -static void mac802154_txdone_worker(FAR void *arg); -static void mac802154_rxframe_worker(FAR void *arg); - -/* Internal Functions */ +static void mac802154_resetqueues(FAR struct ieee802154_privmac_s *priv); +static void mac802154_notifpool_init(FAR struct ieee802154_privmac_s *priv); +static FAR struct ieee802154_notif_s * + mac802154_notif_alloc(FAR struct ieee802154_privmac_s *priv); static int mac802154_defaultmib(FAR struct ieee802154_privmac_s *priv); static int mac802154_applymib(FAR struct ieee802154_privmac_s *priv); +static void mac802154_txdone_worker(FAR void *arg); +static void mac802154_rxframe_worker(FAR void *arg); + +static void mac802154_cmd_txdone(FAR struct ieee802154_privmac_s *priv, + FAR struct ieee802154_txdesc_s *txdesc); + /* IEEE 802.15.4 PHY Interface OPs */ static int mac802154_poll_csma(FAR const struct ieee802154_radiocb_s *radiocb, - FAR struct ieee802154_txdesc_s *tx_desc, + FAR struct ieee802154_txdesc_s **tx_desc, FAR struct iob_s **frame); static int mac802154_poll_gts(FAR const struct ieee802154_radiocb_s *radiocb, - FAR struct ieee802154_txdesc_s *tx_desc, + FAR struct ieee802154_txdesc_s **tx_desc, FAR struct iob_s **frame); static void mac802154_txdone(FAR const struct ieee802154_radiocb_s *radiocb, @@ -339,149 +395,100 @@ static inline int mac802154_takesem(sem_t *sem) } /**************************************************************************** - * Name: mac802154_push_csma + * Name: mac802154_resetqueues * * Description: - * Push a CSMA transaction onto the list + * Initializes the various queues used in the MAC layer. Called on creation + * of MAC. * ****************************************************************************/ -static void mac802154_push_csma(FAR struct ieee802154_privmac_s *priv, - FAR struct mac802154_txframe_s *trans) +static void mac802154_resetqueues(FAR struct ieee802154_privmac_s *priv) { - /* Ensure the transactions forward link is NULL */ + int i; - trans->flink = NULL; + sq_init(&priv->txdone_queue); + sq_init(&priv->csma_queue); + sq_init(&priv->indirect_queue); + sq_init(&priv->dataind_queue); - /* If the tail is not empty, make the transaction pointed to by the tail, - * point to the new transaction */ + sq_init(&priv->notif_queue); + sq_init(&priv->txdesc_queue); - if (priv->csma_tail != NULL) + for (i = 0; i < CONFIG_MAC802154_NNOTIF; i++) { - priv->csma_tail->flink = trans; + sq_addlast((FAR sq_entry_t *)&priv->notif_alloc[i], &priv->notif_queue); } - /* Point the tail at the new transaction */ - - priv->csma_tail = trans; - - /* If the head is NULL, we need to point it at the transaction since there - * is only one transaction in the list at this point */ - - if (priv->csma_head == NULL) + for (i = 0; i < CONFIG_MAC802154_NTXDESC; i++) { - priv->csma_head = trans; + sq_addlast((FAR sq_entry_t *)&priv->txdesc_alloc[i], &priv->txdesc_queue); + } + + mac802154_notifpool_init(priv); +} + +/**************************************************************************** + * Name: mac802154_notifpool_init + * + * Description: + * This function initializes the notification structure pool. It allows the + * MAC to pass notifications and for the callee to free them when they are + * done using them, saving copying the data when passing. + * + ****************************************************************************/ + +static void mac802154_notifpool_init(FAR struct ieee802154_privmac_s *priv) +{ + FAR struct ieee802154_notif_s *pool = priv->notif_alloc; + int remaining = CONFIG_MAC802154_NNOTIF; + + priv->notif_free = NULL; + while (remaining > 0) + { + FAR struct ieee802154_notif_s *notif = pool; + + /* Add the next meta data structure from the pool to the list of + * general structures. + */ + + notif->flink = priv->notif_free; + priv->notif_free = notif; + + /* Set up for the next structure from the pool */ + + pool++; + remaining--; } } /**************************************************************************** - * Name: mac802154_pop_csma + * Name: mac802154_notif_alloc * * Description: - * Pop a CSMA transaction from the list + * This function allocates a free notification structure from the free list + * to be used for passing to the registered notify callback. The callee software + * is responsible for freeing the notification structure after it is done using + * it via mac802154_notif_free. + * + * Assumptions: + * priv MAC struct is locked when calling. * ****************************************************************************/ - -static FAR struct mac802154_txframe_s * - mac802154_pop_csma(FAR struct ieee802154_privmac_s *priv) +static FAR struct ieee802154_notif_s * + mac802154_notif_alloc(FAR struct ieee802154_privmac_s *priv) { - FAR struct mac802154_txframe_s *trans; + FAR struct ieee802154_notif_s *notif; - if (priv->csma_head == NULL) + if (priv->notif_free == NULL) { return NULL; } - /* Get the transaction from the head of the list */ + notif = priv->notif_free; + priv->notif_free = notif->flink; - trans = priv->csma_head; - trans->flink = NULL; - - /* Move the head pointer to the next transaction */ - - priv->csma_head = trans->flink; - - /* If the head is now NULL, the list is empty, so clear the tail too */ - - if (priv->csma_head == NULL) - { - priv->csma_tail = NULL; - } - - return trans; -} - -/**************************************************************************** - * Name: mac802154_push_dataind - * - * Description: - * Push a data indication onto the list to be processed - * - ****************************************************************************/ - -static void mac802154_push_dataind(FAR struct ieee802154_privmac_s *priv, - 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 (priv->dataind_tail != NULL) - { - priv->dataind_tail->flink = ind; - } - - /* Point the tail at the new frame */ - - priv->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 (priv->dataind_head == NULL) - { - priv->dataind_head = ind; - } -} - -/**************************************************************************** - * Name: mac802154_pop_dataind - * - * Description: - * Pop a data indication from the list - * - ****************************************************************************/ - -static FAR struct ieee802154_data_ind_s * - mac802154_pop_dataind(FAR struct ieee802154_privmac_s *priv) -{ - FAR struct ieee802154_data_ind_s *ind; - - if (priv->dataind_head == NULL) - { - return NULL; - } - - /* Get the data indication from the head of the list */ - - ind = priv->dataind_head; - ind->flink = NULL; - - /* Move the head pointer to the next data indication */ - - priv->dataind_head = ind->flink; - - /* If the head is now NULL, the list is empty, so clear the tail too */ - - if (priv->dataind_head == NULL) - { - priv->dataind_tail = NULL; - } - - return ind; + return notif; } /**************************************************************************** @@ -518,7 +525,6 @@ static int mac802154_defaultmib(FAR struct ieee802154_privmac_s *priv) priv->trans_persisttime = 0x01F4; - /* Reset the Coordinator address */ priv->coordaddr.mode = IEEE802154_ADDRMODE_NONE; @@ -580,13 +586,15 @@ static int mac802154_applymib(FAR struct ieee802154_privmac_s *priv) ****************************************************************************/ static int mac802154_poll_csma(FAR const struct ieee802154_radiocb_s *radiocb, - FAR struct ieee802154_txdesc_s *tx_desc, + FAR struct ieee802154_txdesc_s **txdesc, FAR struct iob_s **frame) { FAR struct mac802154_radiocb_s *cb = (FAR struct mac802154_radiocb_s *)radiocb; FAR struct ieee802154_privmac_s *priv; - FAR struct mac802154_txframe_s *trans; + FAR struct mac802154_txtrans_s *trans; + FAR struct ieee802154_txdesc_s *desc; + FAR struct ieee802154_notif_s *notif; DEBUGASSERT(cb != NULL && cb->priv != NULL); priv = cb->priv; @@ -599,16 +607,41 @@ static int mac802154_poll_csma(FAR const struct ieee802154_radiocb_s *radiocb, /* Check to see if there are any CSMA transactions waiting */ - trans = mac802154_pop_csma(priv); + trans = (FAR struct mac802154_txtrans_s *)sq_remfirst(&priv->csma_queue); mac802154_givesem(&priv->exclsem); if (trans != NULL) { - /* Setup the transmit descriptor */ + /* Allocate a Tx descriptor to pass */ - tx_desc->handle = trans->msdu_handle; + desc = (FAR struct ieee802154_txdesc_s *)sq_remfirst(&priv->txdesc_queue); + if (desc == NULL) + { + wlerr("ERROR: Failed to allocate ieee802154_txdesc_s"); + goto errout; + } + + /* Allocate a notif struct (ie data confirmation struct) to pass with + * the tx descriptor. + */ + + notif = mac802154_notif_alloc(priv); + if (notif == NULL) + { + wlerr("ERROR: Failed to allocate ieee802154_notif_s"); + + /* Free the tx descriptor */ + + sq_addlast((FAR sq_entry_t *)desc, &priv->txdesc_queue); + goto errout; + } + + desc->conf = (FAR struct ieee802154_data_conf_s *)notif; + desc->conf->handle = trans->handle; + desc->frametype = trans->frametype; *frame = trans->frame; + *txdesc = desc; /* Now that we've passed off the data, notify the waiting thread. * NOTE: The transaction was allocated on the waiting thread's stack so @@ -619,6 +652,13 @@ static int mac802154_poll_csma(FAR const struct ieee802154_radiocb_s *radiocb, return (trans->frame->io_len); } +errout: + /* Need to set flag to tell MAC to retry notifying radio layer about transmit + * since we couldn't allocate the required data structures at this time. + */ + + priv->csma_tryagain = true; + mac802154_givesem(&priv->exclsem); return 0; } @@ -634,13 +674,14 @@ static int mac802154_poll_csma(FAR const struct ieee802154_radiocb_s *radiocb, ****************************************************************************/ static int mac802154_poll_gts(FAR const struct ieee802154_radiocb_s *radiocb, - FAR struct ieee802154_txdesc_s *tx_desc, + FAR struct ieee802154_txdesc_s **tx_desc, FAR struct iob_s **frame) { FAR struct mac802154_radiocb_s *cb = (FAR struct mac802154_radiocb_s *)radiocb; FAR struct ieee802154_privmac_s *priv; - FAR struct mac802154_txframe_s *trans; + FAR struct mac802154_txtrans_s *trans; + FAR struct ieee802154_txdesc_s *desc; int ret = 0; DEBUGASSERT(cb != NULL && cb->priv != NULL); @@ -657,6 +698,15 @@ static int mac802154_poll_gts(FAR const struct ieee802154_radiocb_s *radiocb, mac802154_givesem(&priv->exclsem); return 0; + +errout: + /* Need to set flag to tell MAC to retry notifying radio layer about transmit + * since we couldn't allocate the required data structures at this time. + */ + + priv->gts_tryagain = true; + mac802154_givesem(&priv->exclsem); + return 0; } /**************************************************************************** @@ -673,7 +723,7 @@ static int mac802154_poll_gts(FAR const struct ieee802154_radiocb_s *radiocb, ****************************************************************************/ static void mac802154_txdone(FAR const struct ieee802154_radiocb_s *radiocb, - FAR const struct ieee802154_txdesc_s *tx_desc) + FAR const struct ieee802154_txdesc_s *txdesc) { FAR struct mac802154_radiocb_s *cb = (FAR struct mac802154_radiocb_s *)radiocb; @@ -688,20 +738,7 @@ static void mac802154_txdone(FAR const struct ieee802154_radiocb_s *radiocb, while (mac802154_takesem(&priv->exclsem) != 0); - /* Check to see if there is an available tx descriptor slot. If there is - * not we simply drop the notification */ - - if (priv->txdesc_count < CONFIG_IEEE802154_NTXDESC) - { - /* Copy the txdesc over and link it into our list */ - - memcpy(&priv->txdesc[priv->txdesc_count++], tx_desc, - sizeof(struct ieee802154_txdesc_s)); - } - else - { - wlinfo("MAC802154: No room for TX Desc.\n"); - } + sq_addlast((FAR sq_entry_t *)txdesc, &priv->txdone_queue); mac802154_givesem(&priv->exclsem); @@ -728,7 +765,11 @@ static void mac802154_txdone_worker(FAR void *arg) { FAR struct ieee802154_privmac_s *priv = (FAR struct ieee802154_privmac_s *)arg; - int i = 0; + FAR struct ieee802154_txdesc_s *txdesc; + FAR struct ieee802154_data_conf_s *conf; + FAR struct ieee802154_notif_s *notif; + enum ieee802154_frametype_e frametype; + int count; /* 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. @@ -736,20 +777,121 @@ static void mac802154_txdone_worker(FAR void *arg) while (mac802154_takesem(&priv->exclsem) != 0); - /* For each pending TX descriptor, send an application callback */ - - for (i = 0; i < priv->txdesc_count; i++) + while (1) { - priv->cb->mcps_notify(priv->cb, IEEE802154_NOTIFY_CONF_DATA, - (FAR const union ieee802154_mcps_notify_u *) &priv->txdesc[i]); + txdesc = (FAR struct ieee802154_txdesc_s *)sq_remfirst(&priv->txdone_queue); + + if (txdesc == NULL) + { + break; + } + + count++; + + /* Once we get the frametype and data confirmation struct, we can free + * the tx descriptor. + */ + + conf = txdesc->conf; + frametype = txdesc->frametype; + sq_addlast((FAR sq_entry_t *)txdesc, &priv->txdesc_queue); + + /* Cast the data_conf to a notification */ + + notif = (FAR struct ieee802154_notif_s *)conf; + + switch(frametype) + { + case IEEE802154_FRAME_DATA: + { + notif->notiftype = IEEE802154_NOTIFY_CONF_DATA; + + /* Release the MAC then call the callback */ + + mac802154_givesem(&priv->exclsem); + priv->cb->notify(priv->cb, notif); + } + break; + + case IEEE802154_FRAME_COMMAND: + { + mac802154_cmd_txdone(priv, txdesc); + + /* We can deallocate the data conf notification as it is no longer + * needed. We don't use the public function here since we already + * have the MAC locked. Additionally, we are already handling the + * tx_tryagain here, so we wouldn't want to handle it twice. + */ + + notif->flink = priv->notif_free; + priv->notif_free = notif; + mac802154_givesem(&priv->exclsem); + } + break; + + default: + { + mac802154_givesem(&priv->exclsem); + } + break; + + } } - /* We've handled all the descriptors and no further desc could have been added - * since we have the struct locked */ + /* If we've freed a tx descriptor or notification structure and a previous + * attempt at passing data to the radio layer failed due to insufficient + * available structures, try again now that we've freed some resources */ - priv->txdesc_count = 0; + if (count > 0 && priv->csma_tryagain) + { + priv->csma_tryagain = false; + priv->radio->ops->txnotify_csma(priv->radio); + } + + if (count > 0 && priv->gts_tryagain) + { + priv->gts_tryagain = false; + priv->radio->ops->txnotify_gts(priv->radio); + } +} - mac802154_givesem(&priv->exclsem); +/**************************************************************************** + * Name: mac802154_cmd_txdone + * + * Description: + * Called from mac802154_txdone_worker, this is a helper function for + * handling command frames that have either successfully sent or failed. + * + ****************************************************************************/ + +static void mac802154_cmd_txdone(FAR struct ieee802154_privmac_s *priv, + FAR struct ieee802154_txdesc_s *txdesc) +{ + + /* Check to see what type of command it was. All information about the command + * will still be valid because it is protected by a semaphore. + */ + + switch (priv->cmd.type) + { + case IEEE802154_CMD_ASSOC_REQ: + if(txdesc->conf->status != IEEE802154_STATUS_SUCCESS) + { + /* if the association request command cannot be sent due to a + * channel access failure, the MAC sublayer shall notify the next + * higher layer. [1] pg. 33 + */ + + + } + else + { + priv->cmd.txdone = true; + } + break; + default: + break; + } } /**************************************************************************** @@ -784,7 +926,7 @@ static void mac802154_rxframe(FAR const struct ieee802154_radiocb_s *radiocb, /* Push the iob onto the tail of the frame list for processing */ - mac802154_push_dataind(priv, ind); + sq_addlast((FAR sq_entry_t *)ind, &priv->dataind_queue); mac802154_givesem(&priv->exclsem); @@ -813,7 +955,6 @@ static void mac802154_rxframe_worker(FAR void *arg) FAR struct ieee802154_privmac_s *priv = (FAR struct ieee802154_privmac_s *)arg; FAR struct ieee802154_data_ind_s *ind; - union ieee802154_mcps_notify_u mcps_notify; FAR struct iob_s *frame; uint16_t *frame_ctrl; bool panid_comp; @@ -829,7 +970,7 @@ static void mac802154_rxframe_worker(FAR void *arg) /* Push the iob onto the tail of the frame list for processing */ - ind = mac802154_pop_dataind(priv); + ind = (FAR struct ieee802154_data_ind_s *)sq_remfirst(&priv->dataind_queue); if (ind == NULL) { @@ -932,11 +1073,9 @@ static void mac802154_rxframe_worker(FAR void *arg) * the frame, otherwise, throw it out. */ - if (priv->cb->mcps_notify != NULL) + if (priv->cb->rxframe != NULL) { - mcps_notify.dataind = ind; - priv->cb->mcps_notify(priv->cb, IEEE802154_NOTIFY_IND_DATA, - &mcps_notify); + priv->cb->rxframe(priv->cb, ind); } else { @@ -1009,6 +1148,15 @@ MACHANDLE mac802154_create(FAR struct ieee802154_radio_s *radiodev) sem_init(&mac->exclsem, 0, 1); + /* Allow exlusive access to the dedicated command transaction */ + + sem_init(&mac->cmd.sem, 0, 1); + + /* Setup the signaling semaphore for the dedicated command transaction */ + + sem_init(&mac->cmd.trans.sem, 0, 0); + sem_setprotocol(&mac->cmd.trans.sem, SEM_PRIO_NONE); + /* Initialize fields */ mac->radio = radiodev; @@ -1030,10 +1178,11 @@ MACHANDLE mac802154_create(FAR struct ieee802154_radio_s *radiodev) radiodev->ops->bind(radiodev, &mac->radiocb.cb); - /* Initialize our data indication pool */ + /* Initialize our various data pools */ ieee802154_indpool_initialize(); - + mac802154_resetqueues(mac); + return (MACHANDLE)mac; } @@ -1052,7 +1201,7 @@ MACHANDLE mac802154_create(FAR struct ieee802154_radio_s *radiodev) * ****************************************************************************/ -int mac802154_bind(MACHANDLE mac, FAR const struct ieee802154_maccb_s *cb) +int mac802154_bind(MACHANDLE mac, FAR const struct mac802154_maccb_s *cb) { FAR struct ieee802154_privmac_s *priv = (FAR struct ieee802154_privmac_s *)mac; @@ -1260,7 +1409,7 @@ int mac802154_get_mhrlen(MACHANDLE mac, * The MCPS-DATA.request primitive requests the transfer of a data SPDU * (i.e., MSDU) from a local SSCS entity to a single peer SSCS entity. * Confirmation is returned via the - * struct ieee802154_maccb_s->conf_data callback. + * struct mac802154_maccb_s->conf_data callback. * ****************************************************************************/ @@ -1270,7 +1419,7 @@ int mac802154_req_data(MACHANDLE mac, { FAR struct ieee802154_privmac_s *priv = (FAR struct ieee802154_privmac_s *)mac; - FAR struct mac802154_txframe_s trans; + FAR struct mac802154_txtrans_s trans; uint16_t *frame_ctrl; uint8_t mhr_len = 3; /* Start assuming frame control and seq. num */ int ret; @@ -1284,7 +1433,7 @@ int mac802154_req_data(MACHANDLE mac, /* Cast the first two bytes of the IOB to a uint16_t frame control field */ - frame_ctrl = (uint16_t *)&frame->io_data[0]; + frame_ctrl = (FAR uint16_t *)&frame->io_data[0]; /* Ensure we start with a clear frame control field */ @@ -1415,9 +1564,11 @@ int mac802154_req_data(MACHANDLE mac, /* Setup our transaction */ - trans.msdu_handle = meta->msdu_handle; + trans.handle = meta->msdu_handle; + trans.frametype = IEEE802154_FRAME_DATA; trans.frame = frame; - sem_init(&trans.sem, 0, 1); + sem_init(&trans.sem, 0, 0); + sem_setprotocol(&trans.sem, SEM_PRIO_NONE); /* If the TxOptions parameter specifies that a GTS transmission is required, * the MAC sublayer will determine whether it has a valid GTS as described @@ -1477,7 +1628,7 @@ int mac802154_req_data(MACHANDLE mac, { /* Link the transaction into the CSMA transaction list */ - mac802154_push_csma(priv, &trans); + sq_addlast((FAR sq_entry_t *)&trans, &priv->csma_queue); /* We no longer need to have the MAC layer locked. */ @@ -1505,7 +1656,7 @@ int mac802154_req_data(MACHANDLE mac, * Description: * The MCPS-PURGE.request primitive allows the next higher layer to purge * an MSDU from the transaction queue. Confirmation is returned via - * the struct ieee802154_maccb_s->conf_purge callback. + * the struct mac802154_maccb_s->conf_purge callback. * * NOTE: The standard specifies that confirmation should be indicated via * the asynchronous MLME-PURGE.confirm primitve. However, in our @@ -1528,7 +1679,7 @@ int mac802154_req_purge(MACHANDLE mac, uint8_t msdu_handle) * Description: * The MLME-ASSOCIATE.request primitive allows a device to request an * association with a coordinator. Confirmation is returned via the - * struct ieee802154_maccb_s->conf_associate callback. + * struct mac802154_maccb_s->conf_associate callback. * ****************************************************************************/ @@ -1537,31 +1688,213 @@ int mac802154_req_associate(MACHANDLE mac, { FAR struct ieee802154_privmac_s *priv = (FAR struct ieee802154_privmac_s *)mac; + FAR struct mac802154_txtrans_s trans; + FAR struct iob_s *iob; + FAR uint16_t *u16; + bool rxonidle; + int ret; - /* Set the channel of the PHY layer */ - - /* Set the channel page of the PHY layer */ - - /* Set the macPANId */ - - /* Set either the macCoordExtendedAddress and macCoordShortAddress - * depending on the CoordAddrMode in the primitive. + /* On receipt of the MLME-ASSOCIATE.request primitive, the MLME of an + * unassociated device first updates the appropriate PHY and MAC PIB + * attributes, as described in 5.1.3.1, and then generates an association + * request command, as defined in 5.3.1 [1] pg.80 */ - if (req->coord_addr.mode == IEEE802154_ADDRMODE_EXTENDED) - { + /* Get exlusive access to the shared command transaction. This must happen + * before getting exclusive access to the MAC struct or else there could be + * a lockup condition. This would occur if another thread is using the cmdtrans + * but needs access to the MAC in order to unlock it. + */ + if (sem_wait(&priv->cmd.sem) < 0) + { + /* EINTR is the only error that we expect */ + + int errcode = get_errno(); + DEBUGASSERT(errcode == EINTR); + return -errcode; } - else if (req->coord_addr.mode == IEEE802154_ADDRMODE_EXTENDED) - { + /* Get exclusive access to the MAC */ + + ret = mac802154_takesem(&priv->exclsem); + if (ret < 0) + { + wlerr("ERROR: mac802154_takesem failed: %d\n", ret); + return ret; + } + + /* Set the channel and channel page of the PHY layer */ + + priv->radio->ops->set_attr(priv->radio, IEEE802154_PIB_PHY_CURRENT_CHANNEL, + (FAR const union ieee802154_attr_u *)&req->chnum); + + priv->radio->ops->set_attr(priv->radio, IEEE802154_PIB_PHY_CURRENT_PAGE, + (FAR const union ieee802154_attr_u *)&req->chpage); + + /* Set the PANID attribute */ + + priv->addr.panid = req->coordaddr.panid; + priv->coordaddr.panid = req->coordaddr.panid; + priv->radio->ops->set_attr(priv->radio, IEEE802154_PIB_MAC_PANID, + (FAR const union ieee802154_attr_u *)&req->coordaddr.panid); + + /* Set the coordinator address attributes */ + + priv->coordaddr.mode = req->coordaddr.mode; + + if (priv->coordaddr.mode == IEEE802154_ADDRMODE_SHORT) + { + priv->coordaddr.saddr = req->coordaddr.saddr; + memcpy(&priv->coordaddr.eaddr[0], IEEE802154_EADDR_UNSPEC, + IEEE802154_EADDR_LEN); + } + else if (priv->coordaddr.mode == IEEE802154_ADDRMODE_EXTENDED) + { + priv->coordaddr.saddr = IEEE802154_SADDR_UNSPEC; + memcpy(&priv->coordaddr.eaddr[0], &req->coordaddr.eaddr[0], + IEEE802154_EADDR_LEN); } else + { + ret = -EINVAL; + goto errout; + } + + /* Copy in the capabilities information bitfield */ + + priv->devmode = (req->capabilities.devtype) ? + IEEE802154_DEVMODE_COORD : IEEE802154_DEVMODE_ENDPOINT; + + /* Unlike other attributes, we can't simply cast this one since it is a bit + * in a bitfield. Casting it will give us unpredicatble results. Instead + * of creating a ieee802154_attr_u, we use a local bool. Allocating the + * ieee802154_attr_u value would take up more room on the stack since it is + * as large as the largest attribute type. + */ + + rxonidle = req->capabilities.rxonidle; + priv->radio->ops->set_attr(priv->radio, IEEE802154_PIB_MAC_RX_ON_WHEN_IDLE, + (FAR const union ieee802154_attr_u *)&rxonidle); + + /* Allocate an IOB to put the frame in */ + + iob = iob_alloc(false); + DEBUGASSERT(iob != NULL); + + iob->io_flink = NULL; + iob->io_len = 0; + iob->io_offset = 0; + iob->io_pktlen = 0; + + /* Get a uin16_t reference to the first two bytes. ie frame control field */ + + u16 = (FAR uint16_t *)&iob->io_data[0]; + + *u16 = (IEEE802154_FRAME_COMMAND << IEEE802154_FRAMECTRL_SHIFT_FTYPE); + *u16 |= IEEE802154_FRAMECTRL_ACKREQ; + *u16 |= (priv->coordaddr.mode << IEEE802154_FRAMECTRL_SHIFT_DADDR); + *u16 |= (IEEE802154_ADDRMODE_EXTENDED << IEEE802154_FRAMECTRL_SHIFT_SADDR); + + iob->io_len = 2; + + /* Each time a data or a MAC command frame is generated, the MAC sublayer + * shall copy the value of macDSN into the Sequence Number field of the MHR + * of the outgoing frame and then increment it by one. [1] pg. 40. + */ + + iob->io_data[iob->io_len++] = priv->dsn++; + + /* The Destination PAN Identifier field shall contain the identifier of the + * PAN to which to associate. [1] pg. 68 + */ + + memcpy(&iob->io_data[iob->io_len], &priv->coordaddr.panid, 2); + + /* The Destination Address field shall contain the address from the beacon + * frame that was transmitted by the coordinator to which the association + * request command is being sent. [1] pg. 68 + */ + + if (priv->coordaddr.mode == IEEE802154_ADDRMODE_SHORT) { - return -EINVAL; + memcpy(&iob->io_data[iob->io_len], &priv->coordaddr.saddr, 2); + iob->io_len += 2; + } + else if (priv->coordaddr.mode == IEEE802154_ADDRMODE_EXTENDED) + { + memcpy(&iob->io_data[iob->io_len], &priv->coordaddr.eaddr[0], + IEEE802154_EADDR_LEN); + iob->io_len += IEEE802154_EADDR_LEN; + } + + /* The Source PAN Identifier field shall contain the broadcast PAN identifier.*/ + + u16 = (uint16_t *)&iob->io_data[iob->io_len]; + *u16 = IEEE802154_SADDR_BCAST; + iob->io_len += 2; + + /* The Source Address field shall contain the value of macExtendedAddress. */ + + memcpy(&iob->io_data[iob->io_len], &priv->addr.eaddr[0], + IEEE802154_EADDR_LEN); + iob->io_len += IEEE802154_EADDR_LEN; + + /* Copy in the Command Frame Identifier */ + + iob->io_data[iob->io_len++] = IEEE802154_CMD_ASSOC_REQ; + + /* Copy in the capability information bits */ + + iob->io_data[iob->io_len] = 0; + iob->io_data[iob->io_len] |= (req->capabilities.devtype << + IEEE802154_CAPABILITY_SHIFT_DEVTYPE); + iob->io_data[iob->io_len] |= (req->capabilities.powersource << + IEEE802154_CAPABILITY_SHIFT_PWRSRC); + iob->io_data[iob->io_len] |= (req->capabilities.rxonidle << + IEEE802154_CAPABILITY_SHIFT_RXONIDLE); + iob->io_data[iob->io_len] |= (req->capabilities.security << + IEEE802154_CAPABILITY_SHIFT_SECURITY); + iob->io_data[iob->io_len] |= (req->capabilities.allocaddr << + IEEE802154_CAPABILITY_SHIFT_ALLOCADDR); + + iob->io_len++; + + /* Copy reference to the frame into the shared command transaction */ + + priv->cmd.trans.frame = iob; + priv->cmd.trans.frametype = IEEE802154_FRAME_COMMAND; + priv->cmd.type = IEEE802154_CMD_ASSOC_REQ; + + /* Link the transaction into the CSMA transaction list */ + + sq_addlast((FAR sq_entry_t *)&trans, &priv->csma_queue); + + /* We no longer need to have the MAC layer locked. */ + + mac802154_givesem(&priv->exclsem); + + /* TODO: Need to setup a timeout here so that we can return an error to the + * user if the device never receives a response. + */ + + /* Notify the radio driver that there is data available */ + + priv->radio->ops->txnotify_csma(priv->radio); + + /* Wait for the transaction to be passed to the radio layer */ + + ret = sem_wait(&priv->cmd.trans.sem); + if (ret < 0) + { + return -EINTR; } - return -ENOTTY; + return OK; + +errout: + mac802154_givesem(&priv->exclsem); + return ret; } /**************************************************************************** @@ -1572,7 +1905,7 @@ int mac802154_req_associate(MACHANDLE mac, * notify the coordinator of its intent to leave the PAN. It is also used by * the coordinator to instruct an associated device to leave the PAN. * Confirmation is returned via the - * struct ieee802154_maccb_s->conf_disassociate callback. + * struct mac802154_maccb_s->conf_disassociate callback. * ****************************************************************************/ @@ -1584,7 +1917,6 @@ int mac802154_req_disassociate(MACHANDLE mac, return -ENOTTY; } - /**************************************************************************** * Name: mac802154_req_gts * @@ -1592,7 +1924,7 @@ int mac802154_req_disassociate(MACHANDLE mac, * The MLME-GTS.request primitive allows a device to send a request to the PAN * coordinator to allocate a new GTS or to deallocate an existing GTS. * Confirmation is returned via the - * struct ieee802154_maccb_s->conf_gts callback. + * struct mac802154_maccb_s->conf_gts callback. * ****************************************************************************/ @@ -1636,7 +1968,7 @@ int mac802154_req_reset(MACHANDLE mac, bool rst_pibattr) * The MLME-RX-ENABLE.request primitive allows the next higher layer to * request that the receiver is enable for a finite period of time. * Confirmation is returned via the - * struct ieee802154_maccb_s->conf_rxenable callback. + * struct mac802154_maccb_s->conf_rxenable callback. * ****************************************************************************/ @@ -1657,7 +1989,7 @@ int mac802154_req_rxenable(MACHANDLE mac, * energy on the channel, search for the coordinator with which it associated, * or search for all coordinators transmitting beacon frames within the POS of * the scanning device. Scan results are returned - * via MULTIPLE calls to the struct ieee802154_maccb_s->conf_scan callback. + * via MULTIPLE calls to the struct mac802154_maccb_s->conf_scan callback. * This is a difference with the official 802.15.4 specification, implemented * here to save memory. * @@ -1750,7 +2082,7 @@ int mac802154_req_set(MACHANDLE mac, enum ieee802154_pib_attr_e pib_attr, * Description: * The MLME-START.request primitive makes a request for the device to start * using a new superframe configuration. Confirmation is returned - * via the struct ieee802154_maccb_s->conf_start callback. + * via the struct mac802154_maccb_s->conf_start callback. * ****************************************************************************/ @@ -1858,7 +2190,7 @@ errout: * The MLME-SYNC.request primitive requests to synchronize with the * coordinator by acquiring and, if specified, tracking its beacons. * Confirmation is returned via the - * struct ieee802154_maccb_s->int_commstatus callback. TOCHECK. + * struct mac802154_maccb_s->int_commstatus callback. TOCHECK. * ****************************************************************************/ @@ -1875,8 +2207,8 @@ int mac802154_req_sync(MACHANDLE mac, FAR struct ieee802154_sync_req_s *req) * Description: * The MLME-POLL.request primitive prompts the device to request data from * the coordinator. Confirmation is returned via the - * struct ieee802154_maccb_s->conf_poll callback, followed by a - * struct ieee802154_maccb_s->ind_data callback. + * struct mac802154_maccb_s->conf_poll callback, followed by a + * struct mac802154_maccb_s->ind_data callback. * ****************************************************************************/ @@ -1921,3 +2253,42 @@ int mac802154_resp_orphan(MACHANDLE mac, return -ENOTTY; } +/**************************************************************************** + * Name: mac802154_notif_free + * + * Description: + * When the MAC calls the registered callback, it passes a reference + * to a mac802154_notify_s structure. This structure needs to be freed + * after the callback handler is done using it. + * + ****************************************************************************/ + +int mac802154_notif_free(MACHANDLE mac, + FAR struct ieee802154_notif_s *notif) +{ + FAR struct ieee802154_privmac_s *priv = + (FAR struct ieee802154_privmac_s *)mac; + + /* Get exclusive access to the MAC */ + + while(mac802154_takesem(&priv->exclsem) < 0); + + notif->flink = priv->notif_free; + priv->notif_free = notif; + + mac802154_givesem(&priv->exclsem); + + if (priv->csma_tryagain) + { + priv->csma_tryagain = false; + priv->radio->ops->txnotify_csma(priv->radio); + } + + if (priv->gts_tryagain) + { + priv->gts_tryagain = false; + priv->radio->ops->txnotify_gts(priv->radio); + } + + return -ENOTTY; +} diff --git a/wireless/ieee802154/mac802154.h b/wireless/ieee802154/mac802154.h index 168bc33cf2..2e8110f755 100644 --- a/wireless/ieee802154/mac802154.h +++ b/wireless/ieee802154/mac802154.h @@ -54,6 +54,26 @@ #include +/**************************************************************************** + * Public Data Types + ****************************************************************************/ + + + +/* Callback operations to notify the next highest layer of various asynchronous + * events, usually triggered by some previous request or response invoked by the + * upper layer. + */ + +struct mac802154_maccb_s +{ + CODE void (*notify)(FAR const struct mac802154_maccb_s *maccb, + FAR struct ieee802154_notif_s *notif); + + CODE void (*rxframe)(FAR const struct mac802154_maccb_s *maccb, + FAR struct ieee802154_data_ind_s *ind); +}; + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ @@ -75,7 +95,7 @@ struct iob_s; /* Forward reference */ * ****************************************************************************/ -int mac802154_bind(MACHANDLE mac, FAR const struct ieee802154_maccb_s *cb); +int mac802154_bind(MACHANDLE mac, FAR const struct mac802154_maccb_s *cb); /**************************************************************************** * Name: mac802154_ioctl @@ -117,7 +137,7 @@ int mac802154_get_mhrlen(MACHANDLE mac, * The MCPS-DATA.request primitive requests the transfer of a data SPDU * (i.e., MSDU) from a local SSCS entity to a single peer SSCS entity. * Confirmation is returned via the - * struct ieee802154_maccb_s->conf_data callback. + * struct mac802154_maccb_s->conf_data callback. * ****************************************************************************/ @@ -131,7 +151,7 @@ int mac802154_req_data(MACHANDLE mac, * Description: * The MCPS-PURGE.request primitive allows the next higher layer to purge * an MSDU from the transaction queue. Confirmation is returned via - * the struct ieee802154_maccb_s->conf_purge callback. + * the struct mac802154_maccb_s->conf_purge callback. * * NOTE: The standard specifies that confirmation should be indicated via * the asynchronous MLME-PURGE.confirm primitve. However, in our @@ -149,7 +169,7 @@ int mac802154_req_purge(MACHANDLE mac, uint8_t msdu_handle); * Description: * The MLME-ASSOCIATE.request primitive allows a device to request an * association with a coordinator. Confirmation is returned via the - * struct ieee802154_maccb_s->conf_associate callback. + * struct mac802154_maccb_s->conf_associate callback. * ****************************************************************************/ @@ -166,7 +186,7 @@ int mac802154_req_associate(MACHANDLE mac, * PAN. * * Confirmation is returned via the - * struct ieee802154_maccb_s->conf_disassociate callback. + * struct mac802154_maccb_s->conf_disassociate callback. * ****************************************************************************/ @@ -180,7 +200,7 @@ int mac802154_req_disassociate(MACHANDLE mac, * The MLME-GTS.request primitive allows a device to send a request to the * PAN coordinator to allocate a new GTS or to deallocate an existing GTS. * Confirmation is returned via the - * struct ieee802154_maccb_s->conf_gts callback. + * struct mac802154_maccb_s->conf_gts callback. * ****************************************************************************/ @@ -214,7 +234,7 @@ int mac802154_req_reset(MACHANDLE mac, bool rst_pibattr); * The MLME-RX-ENABLE.request primitive allows the next higher layer to * request that the receiver is enable for a finite period of time. * Confirmation is returned via the - * struct ieee802154_maccb_s->conf_rxenable callback. + * struct mac802154_maccb_s->conf_rxenable callback. * ****************************************************************************/ @@ -230,7 +250,7 @@ int mac802154_req_rxenable(MACHANDLE mac, * the energy on the channel, search for the coordinator with which it * associated, or search for all coordinators transmitting beacon frames * within the POS of the scanning device. Scan results are returned - * via MULTIPLE calls to the struct ieee802154_maccb_s->conf_scan + * via MULTIPLE calls to the struct mac802154_maccb_s->conf_scan * callback. This is a difference with the official 802.15.4 * specification, implemented here to save memory. * @@ -280,7 +300,7 @@ int mac802154_req_set(MACHANDLE mac, enum ieee802154_pib_attr_e pib_attr, * Description: * The MLME-START.request primitive makes a request for the device to * start using a new superframe configuration. Confirmation is returned - * via the struct ieee802154_maccb_s->conf_start callback. + * via the struct mac802154_maccb_s->conf_start callback. * ****************************************************************************/ @@ -293,7 +313,7 @@ int mac802154_req_start(MACHANDLE mac, FAR struct ieee802154_start_req_s *req); * The MLME-SYNC.request primitive requests to synchronize with the * coordinator by acquiring and, if specified, tracking its beacons. * Confirmation is returned via the - * struct ieee802154_maccb_s->int_commstatus callback. TOCHECK. + * struct mac802154_maccb_s->int_commstatus callback. TOCHECK. * ****************************************************************************/ @@ -305,8 +325,8 @@ int mac802154_req_sync(MACHANDLE mac, FAR struct ieee802154_sync_req_s *req); * Description: * The MLME-POLL.request primitive prompts the device to request data from * the coordinator. Confirmation is returned via the - * struct ieee802154_maccb_s->conf_poll callback, followed by a - * struct ieee802154_maccb_s->ind_data callback. + * struct mac802154_maccb_s->conf_poll callback, followed by a + * struct mac802154_maccb_s->ind_data callback. * ****************************************************************************/ @@ -336,6 +356,18 @@ int mac802154_resp_associate(MACHANDLE mac, int mac802154_resp_orphan(MACHANDLE mac, FAR struct ieee802154_orphan_resp_s *resp); +/**************************************************************************** + * Name: mac802154_notif_free + * + * Description: + * When the MAC calls the registered callback, it passes a reference + * to a mac802154_notify_s structure. This structure needs to be freed + * after the callback handler is done using it. + * + ****************************************************************************/ + +int mac802154_notif_free(MACHANDLE mac, + FAR struct ieee802154_notif_s *notif); #undef EXTERN #ifdef __cplusplus diff --git a/wireless/ieee802154/mac802154_device.c b/wireless/ieee802154/mac802154_device.c index 309ca2c99c..a41ff240bf 100644 --- a/wireless/ieee802154/mac802154_device.c +++ b/wireless/ieee802154/mac802154_device.c @@ -83,22 +83,11 @@ struct mac802154dev_open_s volatile bool md_closing; }; -struct mac802154dev_dwait_s -{ - uint8_t mw_handle; /* The msdu handle identifying the frame */ - sem_t mw_sem; /* The semaphore used to signal the completion */ - int mw_status; /* The success/error of the transaction */ - - /* Supports a singly linked list */ - - FAR struct mac802154dev_dwait_s *mw_flink; -}; - struct mac802154dev_callback_s { /* This holds the information visible to the MAC layer */ - struct ieee802154_maccb_s mc_cb; /* Interface understood by the MAC layer */ + struct mac802154_maccb_s mc_cb; /* Interface understood by the MAC layer */ FAR struct mac802154_chardevice_s *mc_priv; /* Our priv data */ }; @@ -108,31 +97,33 @@ 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 */ + /* Hold a list of events */ + + bool enableevents : 1; /* Are events enabled? */ + bool geteventpending : 1; /* Is there a get event using the semaphore? */ + sem_t geteventsem; /* Signaling semaphore for waiting get event */ + FAR struct ieee802154_notif_s *event_head; + FAR struct ieee802154_notif_s *event_tail; /* The following is a singly linked list of open references to the * MAC device. */ 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; + bool readpending; /* Is there a read using the semaphore? */ + sem_t readsem; /* Signaling semaphore for waiting read */ + sq_queue_t dataind_queue; #ifndef CONFIG_DISABLE_SIGNALS - /* MCPS Service notification information */ + /* MAC Service notification information */ - struct mac802154dev_notify_s md_mcps_notify; - pid_t md_mcps_pid; + bool notify_registered; + struct mac802154dev_notify_s md_notify; + pid_t md_notify_pid; - /* MLME Service notification information */ - - struct mac802154dev_notify_s md_mlme_notify; - pid_t md_mlme_pid; #endif }; @@ -145,19 +136,16 @@ 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 inline void mac802154dev_pushevent(FAR struct mac802154_chardevice_s *dev, + FAR struct ieee802154_notif_s *notif); +static inline FAR struct ieee802154_notif_s * + mac802154dev_popevent(FAR struct mac802154_chardevice_s *dev); +static void mac802154dev_notify(FAR const struct mac802154_maccb_s *maccb, + FAR struct ieee802154_notif_s *notif); -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); - -static void mac802154dev_mcps_notify(FAR const struct ieee802154_maccb_s *maccb, - enum ieee802154_macnotify_e notif, - FAR const union ieee802154_mcps_notify_u *arg); +static void mac802154dev_rxframe(FAR const struct mac802154_maccb_s *maccb, + FAR struct ieee802154_data_ind_s *ind); static int mac802154dev_open(FAR struct file *filep); static int mac802154dev_close(FAR struct file *filep); @@ -168,13 +156,6 @@ static ssize_t mac802154dev_write(FAR struct file *filep, static int mac802154dev_ioctl(FAR struct file *filep, int cmd, unsigned long arg); -/* MAC callback helpers */ - -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 ****************************************************************************/ @@ -224,76 +205,60 @@ static inline int mac802154dev_takesem(sem_t *sem) } /**************************************************************************** - * Name: mac802154dev_push_dataind + * Name: mac802154dev_pushevent * * Description: - * Push a data indication onto the list to be processed + * Push event onto the event queue + * + * Assumptions: + * Called with the char device struct locked. * ****************************************************************************/ -static void mac802154dev_push_dataind(FAR struct mac802154_chardevice_s *dev, - FAR struct ieee802154_data_ind_s *ind) +static inline void mac802154dev_pushevent(FAR struct mac802154_chardevice_s *dev, + FAR struct ieee802154_notif_s *notif) { - /* 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) + notif->flink = NULL; + if (!dev->event_head) { - dev->dataind_tail->flink = ind; + dev->event_head = notif; + dev->event_tail = notif; } - - /* 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) + else { - dev->dataind_head = ind; + dev->event_tail->flink = notif; + dev->event_tail = notif; } } /**************************************************************************** - * Name: mac802154dev_pop_dataind + * Name: mac802154dev_popevent * * Description: - * Pop a data indication from the list + * Pop an event off of the event queue + * + * Assumptions: + * Called with the char device struct locked. * ****************************************************************************/ -static FAR struct ieee802154_data_ind_s * - mac802154dev_pop_dataind(FAR struct mac802154_chardevice_s *dev) +static inline FAR struct ieee802154_notif_s * + mac802154dev_popevent(FAR struct mac802154_chardevice_s *dev) { - FAR struct ieee802154_data_ind_s *ind; + FAR struct ieee802154_notif_s *notif = dev->event_head; - if (dev->dataind_head == NULL) + if (notif) { - return NULL; + dev->event_head = notif->flink; + if (!dev->event_head) + { + dev->event_head = NULL; + } + + notif->flink = 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; + return notif; } /**************************************************************************** @@ -383,7 +348,7 @@ static int mac802154dev_close(FAR struct file *filep) * * This is actually a pretty feeble attempt to handle this. The * improbable race condition occurs if two different threads try to - * close the joystick driver at the same time. The rule: don't do + * close the driver at the same time. The rule: don't do * that! It is feeble because we do not really enforce stale pointer * detection anyway. */ @@ -437,6 +402,23 @@ static int mac802154dev_close(FAR struct file *filep) /* And free the open structure */ kmm_free(opriv); + + /* If there are now no open instances of the driver and a signal handler is + * not registered, purge the list of events. + */ + + if (dev->md_open) + { + FAR struct ieee802154_notif_s *notif; + + while (dev->event_head != NULL) + { + notif = mac802154dev_popevent(dev); + DEBUGASSERT(notif != NULL); + mac802154_notif_free(dev->md_mac, notif); + } + } + ret = OK; errout_with_exclsem: @@ -491,7 +473,7 @@ static ssize_t mac802154dev_read(FAR struct file *filep, FAR char *buffer, /* Try popping a data indication off the list */ - ind = mac802154dev_pop_dataind(dev); + ind = (FAR struct ieee802154_data_ind_s *)sq_remfirst(&dev->dataind_queue); /* If the indication is not null, we can exit the loop and copy the data */ @@ -522,11 +504,7 @@ static ssize_t mac802154dev_read(FAR struct file *filep, FAR char *buffer, 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; } @@ -571,7 +549,6 @@ static ssize_t mac802154dev_write(FAR struct file *filep, FAR struct mac802154_chardevice_s *dev; FAR struct mac802154dev_txframe_s *tx; FAR struct iob_s *iob; - struct mac802154dev_dwait_s dwait; int ret; DEBUGASSERT(filep && filep->f_inode); @@ -579,7 +556,7 @@ static ssize_t mac802154dev_write(FAR struct file *filep, DEBUGASSERT(inode->i_private); dev = (FAR struct mac802154_chardevice_s *)inode->i_private; - /* Check if the struct is write */ + /* Check if the struct is the correct size */ if (len != sizeof(struct mac802154dev_txframe_s)) { @@ -618,38 +595,6 @@ static ssize_t mac802154dev_write(FAR struct file *filep, iob->io_len += tx->length; - /* If this is a blocking operation, we need to setup a wait struct so we - * can unblock when the packet transmission has finished. If this is a - * non-blocking write, we pass off the data and then move along. Technically - * we stil have to wait for the transaction to get put into the buffer, but we - * won't wait for the transaction to actually finish. */ - - if (!(filep->f_oflags & O_NONBLOCK)) - { - /* 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; - } - - /* Setup the wait struct */ - - dwait.mw_handle = tx->meta.msdu_handle; - - /* Link the wait struct */ - - dwait.mw_flink = dev->md_dwait; - dev->md_dwait = &dwait; - - sem_init(&dwait.mw_sem, 0, 0); - sem_setprotocol(&dwait.mw_sem, SEM_PRIO_NONE); - - mac802154dev_givesem(&dev->md_exclsem); - } - /* Pass the request to the MAC layer */ ret = mac802154_req_data(dev->md_mac, &tx->meta, iob); @@ -659,28 +604,6 @@ static ssize_t mac802154dev_write(FAR struct file *filep, return ret; } - if (!(filep->f_oflags & O_NONBLOCK)) - { - /* Wait for the DATA.confirm callback to be called for our handle */ - - if (sem_wait(&dwait.mw_sem) < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - sem_destroy(&dwait.mw_sem); - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* The unlinking of the wait struct happens inside the callback. This - * is more efficient since it will already have to find the struct in - * the list in order to perform the sem_post. - */ - - sem_destroy(&dwait.mw_sem); - return dwait.mw_status; - } - return OK; } @@ -688,7 +611,7 @@ static ssize_t mac802154dev_write(FAR struct file *filep, * Name: mac802154dev_ioctl * * Description: - * Control the MAC layer via MLME IOCTL commands. + * Control the MAC layer via IOCTL commands. * ****************************************************************************/ @@ -728,7 +651,7 @@ static int mac802154dev_ioctl(FAR struct file *filep, int cmd, * failure with the errno value set appropriately. */ - case MAC802154IOC_MLME_REGISTER: + case MAC802154IOC_NOTIFY_REGISTER: { FAR struct mac802154dev_notify_s *notify = (FAR struct mac802154dev_notify_s *)((uintptr_t)arg); @@ -737,38 +660,101 @@ static int mac802154dev_ioctl(FAR struct file *filep, int cmd, { /* Save the notification events */ - dev->md_mlme_notify.mn_signo = notify->mn_signo; - dev->md_mlme_pid = getpid(); + dev->md_notify.mn_signo = notify->mn_signo; + dev->md_notify_pid = getpid(); + dev->notify_registered = true; - return OK; + ret = OK; } - } - break; - - case MAC802154IOC_MCPS_REGISTER: - { - FAR struct mac802154dev_notify_s *notify = - (FAR struct mac802154dev_notify_s *)((uintptr_t)arg); - - if (notify) + else { - /* Save the notification events */ - - dev->md_mcps_notify.mn_signo = notify->mn_signo; - dev->md_mcps_pid = getpid(); - - return OK; + ret = -EINVAL; } } break; #endif + + case MAC802154IOC_GET_EVENT: + { + FAR struct ieee802154_notif_s *usr_notif = + (FAR struct ieee802154_notif_s *)((uintptr_t)arg); + FAR struct ieee802154_notif_s *notif; + + while (1) + { + /* Try popping an event off the queue */ + + notif = mac802154dev_popevent(dev); + + /* If there was an event to pop off, copy it into the user data and + * free it from the MAC layer's memory. + */ + + if (notif != NULL) + { + memcpy(usr_notif, notif, sizeof(struct ieee802154_notif_s)); + + /* Free the notification */ + + mac802154_notif_free(dev->md_mac, notif); + + ret = OK; + break; + } + + /* If this is a non-blocking call, or if there is another getevent + * operation already pending, don't block. This driver returns + * EAGAIN even when configured as non-blocking if another getevent + * operation is already pending This situation should be rare. + * It will only occur when there are 2 calls from separate threads + * and there was no events in the queue. + */ + + if ((filep->f_oflags & O_NONBLOCK) || dev->geteventpending) + { + ret = -EAGAIN; + break; + } + + dev->geteventpending = true; + mac802154dev_givesem(&dev->md_exclsem); + + /* Wait to be signaled when an event is queued */ + + if (sem_wait(&dev->geteventsem) < 0) + { + DEBUGASSERT(errno == EINTR); + dev->geteventpending = false; + return -EINTR; + } + + /* Get exclusive access again, then loop back around and try and + * pop an event off the queue + */ + + ret = mac802154dev_takesem(&dev->md_exclsem); + if (ret < 0) + { + wlerr("ERROR: mac802154dev_takesem failed: %d\n", ret); + return ret; + } + } + } + break; + + case MAC802154IOC_ENABLE_EVENTS: + { + dev->enableevents = (bool)arg; + ret = OK; + } + break; + default: { /* Forward any unrecognized commands to the MAC layer */ - mac802154_ioctl(dev->md_mac, cmd, arg); + ret = mac802154_ioctl(dev->md_mac, cmd, arg); } - break; } @@ -776,9 +762,8 @@ static int mac802154dev_ioctl(FAR struct file *filep, int cmd, return ret; } -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) +static void mac802154dev_notify(FAR const struct mac802154_maccb_s *maccb, + FAR struct ieee802154_notif_s *notif) { FAR struct mac802154dev_callback_s *cb = (FAR struct mac802154dev_callback_s *)maccb; @@ -787,108 +772,70 @@ static void mac802154dev_mlme_notify(FAR const struct ieee802154_maccb_s *maccb, DEBUGASSERT(cb != NULL && cb->mc_priv != NULL); dev = cb->mc_priv; - switch (notif) - { -#warning Handle MLME notifications - default: - break; - } -} - -static void mac802154dev_mcps_notify(FAR const struct ieee802154_maccb_s *maccb, - enum ieee802154_macnotify_e notif, - FAR const union ieee802154_mcps_notify_u *arg) -{ - FAR struct mac802154dev_callback_s *cb = - (FAR struct mac802154dev_callback_s *)maccb; - FAR struct mac802154_chardevice_s *dev; - - DEBUGASSERT(cb != NULL && cb->mc_priv != NULL); - dev = cb->mc_priv; - - switch (notif) - { - case IEEE802154_NOTIFY_CONF_DATA: - { - mac802154dev_conf_data(dev, &arg->dataconf); - } - break; - case IEEE802154_NOTIFY_IND_DATA: - { - mac802154dev_ind_data(dev, arg->dataind); - } - break; - default: - break; - } -} - -static void mac802154dev_conf_data(FAR struct mac802154_chardevice_s *dev, - FAR const struct ieee802154_data_conf_s *conf) -{ - FAR struct mac802154dev_dwait_s *curr; - FAR struct mac802154dev_dwait_s *prev; - /* 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); - /* Search to see if there is a dwait pending for this transaction */ + /* If there is a registered notification receiver, queue the event and signal + * the receiver. Events should be popped from the queue from the application + * at a reasonable rate in order for the MAC layer to be able to allocate new + * notifications. + */ - for (prev = NULL, curr = dev->md_dwait; - curr && curr->mw_handle != conf->handle; - prev = curr, curr = curr->mw_flink); + if (dev->enableevents && (dev->md_open != NULL || dev->notify_registered)) + { + mac802154dev_pushevent(dev, notif); - /* If a dwait is found */ + /* Check if there is a read waiting for data */ - if (curr) - { - /* Unlink the structure from the list. The struct should be allocated on - * the calling write's stack, so we don't need to worry about deallocating - * here */ - - if (prev) + if (dev->geteventpending) { - prev->mw_flink = curr->mw_flink; - } - else - { - dev->md_dwait = curr->mw_flink; + /* Wake the thread waiting for the data transmission */ + + dev->geteventpending = false; + sem_post(&dev->geteventsem); } - /* Copy the transmission status into the dwait struct */ - - curr->mw_status = conf->status; - - /* Wake the thread waiting for the data transmission */ - - sem_post(&curr->mw_sem); - - /* Release the driver */ - - mac802154dev_givesem(&dev->md_exclsem); - } - -#ifndef CONFIG_DISABLE_SIGNALS - /* Send a signal to the registered application */ +#ifndef CONFIG_DISABLE_SIGNALS + if (dev->notify_registered) + { #ifdef CONFIG_CAN_PASS_STRUCTS - /* Copy the status as the signal data to be optionally used by app */ - - union sigval value; - value.sival_int = (int)conf->status; - (void)sigqueue(dev->md_mcps_pid, dev->md_mcps_notify.mn_signo, value); + union sigval value; + value.sival_int = (int)notif->notiftype; + (void)sigqueue(dev->md_notify_pid, dev->md_notify.mn_signo, value); #else - (void)sigqueue(dev->md_mcps_pid, dev->md_mcps_notify.mn_signo, - value.sival_ptr); -#endif + (void)sigqueue(dev->md_notify_pid, dev->md_notify.mn_signo, + (FAR void *)notif->notiftype); #endif + } +#endif + } + else + { + /* Just free the event if the driver is closed and there isn't a registered + * signal number. + */ + + mac802154_notif_free(dev->md_mac, notif); + } + + /* Release the driver */ + + mac802154dev_givesem(&dev->md_exclsem); } -static void mac802154dev_ind_data(FAR struct mac802154_chardevice_s *dev, - FAR struct ieee802154_data_ind_s *ind) +static void mac802154dev_rxframe(FAR const struct mac802154_maccb_s *maccb, + FAR struct ieee802154_data_ind_s *ind) { + FAR struct mac802154dev_callback_s *cb = + (FAR struct mac802154dev_callback_s *)maccb; + FAR struct mac802154_chardevice_s *dev; + + DEBUGASSERT(cb != NULL && cb->mc_priv != NULL); + dev = cb->mc_priv; + /* 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 */ @@ -896,7 +843,7 @@ static void mac802154dev_ind_data(FAR struct mac802154_chardevice_s *dev, /* Push the indication onto the list */ - mac802154dev_push_dataind(dev, ind); + sq_addlast((FAR sq_entry_t *)ind, &dev->dataind_queue); /* Check if there is a read waiting for data */ @@ -911,21 +858,6 @@ static void mac802154dev_ind_data(FAR struct mac802154_chardevice_s *dev, /* 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 } /**************************************************************************** @@ -953,7 +885,7 @@ static void mac802154dev_ind_data(FAR struct mac802154_chardevice_s *dev, int mac802154dev_register(MACHANDLE mac, int minor) { FAR struct mac802154_chardevice_s *dev; - FAR struct ieee802154_maccb_s *maccb; + FAR struct mac802154_maccb_s *maccb; char devname[DEVNAME_FMTLEN]; int ret; @@ -974,13 +906,25 @@ int mac802154dev_register(MACHANDLE mac, int minor) sem_setprotocol(&dev->readsem, SEM_PRIO_NONE); dev->readpending = false; + sq_init(&dev->dataind_queue); + + dev->geteventpending = false; + sem_init(&dev->geteventsem, 0, 0); + sem_setprotocol(&dev->geteventsem, SEM_PRIO_NONE); + + dev->event_head = NULL; + dev->event_tail = NULL; + + dev->enableevents = true; + dev->notify_registered = false; + /* Initialize the MAC callbacks */ dev->md_cb.mc_priv = dev; - maccb = &dev->md_cb.mc_cb; - maccb->mlme_notify = mac802154dev_mlme_notify; - maccb->mcps_notify = mac802154dev_mcps_notify; + maccb = &dev->md_cb.mc_cb; + maccb->notify = mac802154dev_notify; + maccb->rxframe = mac802154dev_rxframe; /* Bind the callback structure */ diff --git a/wireless/ieee802154/mac802154_netdev.c b/wireless/ieee802154/mac802154_netdev.c index b09ea4493c..7fcd25e3af 100644 --- a/wireless/ieee802154/mac802154_netdev.c +++ b/wireless/ieee802154/mac802154_netdev.c @@ -109,7 +109,7 @@ struct macnet_callback_s { /* This holds the information visible to the MAC layer */ - struct ieee802154_maccb_s mc_cb; /* Interface understood by the MAC layer */ + struct mac802154_maccb_s mc_cb; /* Interface understood by the MAC layer */ FAR struct macnet_driver_s *mc_priv; /* Our priv data */ }; @@ -138,12 +138,10 @@ struct macnet_driver_s /* IEE802.15.4 MAC callback functions ***************************************/ -static void macnet_mlme_notify(FAR const struct ieee802154_maccb_s *maccb, - enum ieee802154_macnotify_e notif, - FAR const union ieee802154_mlme_notify_u *arg); -static void macnet_mcps_notify(FAR const struct ieee802154_maccb_s *maccb, - enum ieee802154_macnotify_e notif, - FAR const union ieee802154_mcps_notify_u *arg); +static void macnet_notify(FAR const struct mac802154_maccb_s *maccb, + FAR struct ieee802154_notif_s *notif); +static void macnet_rxframe(FAR const struct mac802154_maccb_s *maccb, + FAR struct ieee802154_data_ind_s *ind); /* Asynchronous confirmations to requests */ @@ -166,8 +164,6 @@ static void macnet_conf_poll(FAR struct macnet_driver_s *priv, /* Asynchronous event indications, replied to synchronously with responses */ -static void macnet_ind_data(FAR struct macnet_driver_s *priv, - FAR struct ieee802154_data_ind_s *conf); static void macnet_ind_associate(FAR struct macnet_driver_s *priv, FAR struct ieee802154_assoc_ind_s *conf); static void macnet_ind_disassociate(FAR struct macnet_driver_s *priv, @@ -221,15 +217,14 @@ static int macnet_req_data(FAR struct ieee802154_driver_s *netdev, ****************************************************************************/ /**************************************************************************** - * Name: macnet_mlme_notify + * Name: macnet_notify * * Description: * ****************************************************************************/ -static void macnet_mlme_notify(FAR const struct ieee802154_maccb_s *maccb, - enum ieee802154_macnotify_e notif, - FAR const union ieee802154_mlme_notify_u *arg) +static void macnet_notify(FAR const struct mac802154_maccb_s *maccb, + FAR struct ieee802154_notif_s *notif) { FAR struct macnet_callback_s *cb = (FAR struct macnet_callback_s *)maccb; @@ -238,8 +233,13 @@ static void macnet_mlme_notify(FAR const struct ieee802154_maccb_s *maccb, DEBUGASSERT(cb != NULL && cb->mc_priv != NULL); priv = cb->mc_priv; - switch (notif) + switch (notif->notiftype) { + case IEEE802154_NOTIFY_CONF_DATA: + { + macnet_conf_data(priv, ¬if->u.dataconf); + } + break; default: break; @@ -247,40 +247,38 @@ static void macnet_mlme_notify(FAR const struct ieee802154_maccb_s *maccb, } /**************************************************************************** - * Name: macnet_mcps_notify + * Name: macnet_rxframe * * Description: * ****************************************************************************/ -static void macnet_mcps_notify(FAR const struct ieee802154_maccb_s *maccb, - enum ieee802154_macnotify_e notif, - FAR const union ieee802154_mcps_notify_u *arg) +static void macnet_rxframe(FAR const struct mac802154_maccb_s *maccb, + FAR struct ieee802154_data_ind_s *ind) { FAR struct macnet_callback_s *cb = (FAR struct macnet_callback_s *)maccb; FAR struct macnet_driver_s *priv; + FAR struct iob_s *iob; DEBUGASSERT(cb != NULL && cb->mc_priv != NULL); priv = cb->mc_priv; - switch (notif) - { - case IEEE802154_NOTIFY_CONF_DATA: - { - macnet_conf_data(priv, &arg->dataconf); - } - break; + /* Extract the IOB containing the frame from the struct ieee802154_data_ind_s */ - case IEEE802154_NOTIFY_IND_DATA: - { - macnet_ind_data(priv, arg->dataind); - } - break; + DEBUGASSERT(priv != NULL && ind != NULL && ind->frame != NULL); + iob = ind->frame; + ind->frame = NULL; - default: - break; - } + /* Transfer the frame to the network logic */ + + sixlowpan_input(&priv->md_dev, iob, ind); + + /* sixlowpan_input() will free the IOB, but we must free the struct + * ieee802154_data_ind_s container here. + */ + + ieee802154_ind_free(ind); } /**************************************************************************** @@ -391,36 +389,6 @@ static void macnet_conf_poll(FAR struct macnet_driver_s *priv, } -/**************************************************************************** - * Name: macnet_ind_data - * - * Description: - * Data frame received - * - ****************************************************************************/ - -static void macnet_ind_data(FAR struct macnet_driver_s *priv, - FAR struct ieee802154_data_ind_s *ind) -{ - FAR struct iob_s *iob; - - /* Extract the IOB containing the frame from the struct ieee802154_data_ind_s */ - - DEBUGASSERT(priv != NULL && ind != NULL && ind->frame != NULL); - iob = ind->frame; - ind->frame = NULL; - - /* Transfer the frame to the network logic */ - - sixlowpan_input(&priv->md_dev, iob, ind); - - /* sixlowpan_input() will free the IOB, but we must free the struct - * ieee802154_data_ind_s container here. - */ - - ieee802154_ind_free(ind); -} - /**************************************************************************** * Name: macnet_ind_associate * @@ -1041,7 +1009,7 @@ int mac802154netdev_register(MACHANDLE mac) FAR struct macnet_driver_s *priv; FAR struct ieee802154_driver_s *ieee; FAR struct net_driver_s *dev; - FAR struct ieee802154_maccb_s *maccb; + FAR struct mac802154_maccb_s *maccb; FAR uint8_t *pktbuf; int ret; @@ -1103,9 +1071,9 @@ int mac802154netdev_register(MACHANDLE mac) priv->md_cb.mc_priv = priv; - maccb = &priv->md_cb.mc_cb; - maccb->mlme_notify = macnet_mlme_notify; - maccb->mcps_notify = macnet_mcps_notify; + maccb = &priv->md_cb.mc_cb; + maccb->notify = macnet_notify; + maccb->rxframe = macnet_rxframe; /* Bind the callback structure */