nuttx/drivers/wireless/ieee802154/xbee/xbee_mac.c

603 lines
18 KiB
C
Raw Normal View History

Merged in merlin17/nuttx/xbee (pull request #484) drivers/wireless: Adds XBee S2C (802.15.4 firmware) support. XBee driver emulates mac802154 interface * drivers/wireless/xbee: Adds xbee_netdev. Very similar to mac802154_netdev * configs/same70-xplained: Starts adding support for XBee radio * drivers/wireless/ieee802154/xbee: More structuring of XBee driver * drivers/wireless/ieee802154/xbee: More Xbee work. Starts adding support on Clicker2 * drivers/wireless/ieee802154/xbee: More XBee MAC code * configs/clicker2-stm32: More work to add XBee radio support * drivers/wireless/ieee802154/xbee: Most of driver is now structured. No build errors * configs/clicker2-stm32: Adjustments to XBee click module support * drivers/xbee: Changes md_ prefix to xd_ prefix for xbeenet_driver_s fields * drivers/xbee: XBee network device now passes MAC events via IOCTL * drivers/xbee: Support querying device for parameters, setting parameters, and structures association/startpan logic * configs/clicker2-stm32: Fixes Xbee lower half ATTN poll logic * drivers/xbee: Removes dependce on CONFIG_IEEE802154_NETDEV * drivers/xbee: Supports MAC RESET.request primitive * drivers/xbee: Exposes generic AT query to the rest of driver * drivers/xbee: Sets local values when writing setting change to Xbee device * drivers/xbee: Finish association logic * drivers/xbee: Adds xbee_get_mhrlen( ) allocating enough space for API frame header to frame * drivers/xbee: Finishes transmit/receive logic * drivers/xbee: Fixes xbee_netdev to match logic in mac802154_netdev.c * drivers/xbee: Rearranges logic to prevent a loop condition where recursion could potentially occur to the point of deadlocking the system Approved-by: Gregory Nutt <gnutt@nuttx.org>
2017-09-15 16:37:55 +02:00
/****************************************************************************
* drivers/wireless/xbee/drivers/xbee_mac.c
*
* Copyright (C) 2017 Verge Inc. All rights reserved.
* Author: Anthony Merlino <anthony@vergeaero.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <errno.h>
#include <nuttx/mm/iob.h>
#include "xbee.h"
#include "xbee_mac.h"
#include <nuttx/wireless/ieee802154/ieee802154_mac.h>
#include <nuttx/wireless/ieee802154/xbee.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define XBEE_ASSOC_POLLDELAY 100
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static void xbee_assoctimer(int argc, uint32_t arg, ...);
static void xbee_assocworker(FAR void *arg);
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: xbee_assoctimer
*
* Description:
* This function is used to schedule * an associatioin indication poll. When
* association first gets triggered, a watchdog timer is started. This function
* is called when it expires. The watchdog timer is scheduled again until
* the association is either successful or fails.
*
* Parameters:
* argc - The number of available arguments
* arg - The first argument
*
* Returned Value:
* None
*
* Assumptions:
*
****************************************************************************/
static void xbee_assoctimer(int argc, uint32_t arg, ...)
{
FAR struct xbee_priv_s *priv = (FAR struct xbee_priv_s *)arg;
int ret;
/* In complex environments, we cannot do SPI transfers from the timout
* handler because semaphores are probably used to lock the SPI bus. In
* this case, we will defer processing to the worker thread. This is also
* much kinder in the use of system resources and is, therefore, probably
* a good thing to do in any event.
*/
DEBUGASSERT(priv && work_available(&priv->assocwork));
/* Notice that poll watchdog is not active so further poll timeouts can
* occur until we restart the poll timeout watchdog.
*/
ret = work_queue(HPWORK, &priv->assocwork, xbee_assocworker, (FAR void *)priv, 0);
(void)ret;
DEBUGASSERT(ret == OK);
}
/****************************************************************************
* Name: xbee_assocworker
*
* Description:
* Poll the device for the assosciation status. This function is indirectly
* scheduled rom xbee_req_associate in order to poll the device for association
* progress.
*
* Parameters:
* arg - The reference to the driver structure (cast to void*)
*
* Returned Value:
* None
*
* Assumptions:
*
****************************************************************************/
static void xbee_assocworker(FAR void *arg)
{
FAR struct xbee_priv_s *priv = (FAR struct xbee_priv_s *)arg;
xbee_at_query(priv, "AI");
(void)wd_start(priv->assocwd, XBEE_ASSOC_POLLDELAY, xbee_assoctimer, 1, (wdparm_t)arg);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: xbee_bind
*
* Description:
* Bind the MAC callback table to the XBee driver.
*
* Parameters:
* xbee - Reference to the XBee driver structure
* cb - MAC callback operations
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int xbee_bind(XBEEHANDLE xbee, FAR struct xbee_maccb_s *cb)
{
FAR struct xbee_priv_s *priv = (FAR struct xbee_priv_s *)xbee;
FAR struct xbee_maccb_s *next;
FAR struct xbee_maccb_s *prev;
/* Add the MAC client callback structure to the list of MAC callbacks in
* priority order.
*
* Search the list to find the location to insert the new instance.
* The list is maintained in descending priority order.
*/
for (prev = NULL, next = priv->cb;
(next != NULL && cb->prio <= next->prio);
prev = next, next = next->flink);
/* Add the instance to the spot found in the list. Check if the instance
* goes at the head of the list.
*/
if (prev == NULL)
{
cb->flink = priv->cb; /* May be NULL */
priv->cb = cb;
}
/* No.. the instance goes between prev and next */
else
{
cb->flink = next; /* May be NULL */
prev->flink = cb;
}
/* Keep track of the number of clients requesting notification */
if (cb->notify != NULL)
{
priv->nclients++;
}
return OK;
}
/****************************************************************************
* Name: xbee_get_mhrlen
*
* Description:
* Calculate the MAC header length given the frame meta-data. For the XBee,
* we use the header to store the entire API frame for the TX request. The
* size we need is fixed based on the address mode we are using as it changes
* which API frame we need to issue.
*
****************************************************************************/
int xbee_get_mhrlen(XBEEHANDLE xbee, FAR const struct ieee802154_frame_meta_s *meta)
{
int ret = 9; /* Smallest possible header size */
/* We assume that the XBee is configured with application header on but
* encryption not on.
*/
ret += 2;
if (meta->srcmode == IEEE802154_ADDRMODE_EXTENDED)
{
ret += 6;
}
if (meta->destaddr.mode == IEEE802154_ADDRMODE_EXTENDED)
{
ret += 6;
}
return ret;
}
/****************************************************************************
* Name: xbee_req_data
*
* Description:
* 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.
*
****************************************************************************/
int xbee_req_data(XBEEHANDLE xbee,
FAR const struct ieee802154_frame_meta_s *meta,
FAR struct iob_s *frame)
{
FAR struct xbee_priv_s *priv = (FAR struct xbee_priv_s *)xbee;
int index;
uint16_t apiframelen;
uint8_t frametype;
#ifdef CONFIG_DEBUG_ASSERTIONS
Merged in merlin17/nuttx/xbee (pull request #484) drivers/wireless: Adds XBee S2C (802.15.4 firmware) support. XBee driver emulates mac802154 interface * drivers/wireless/xbee: Adds xbee_netdev. Very similar to mac802154_netdev * configs/same70-xplained: Starts adding support for XBee radio * drivers/wireless/ieee802154/xbee: More structuring of XBee driver * drivers/wireless/ieee802154/xbee: More Xbee work. Starts adding support on Clicker2 * drivers/wireless/ieee802154/xbee: More XBee MAC code * configs/clicker2-stm32: More work to add XBee radio support * drivers/wireless/ieee802154/xbee: Most of driver is now structured. No build errors * configs/clicker2-stm32: Adjustments to XBee click module support * drivers/xbee: Changes md_ prefix to xd_ prefix for xbeenet_driver_s fields * drivers/xbee: XBee network device now passes MAC events via IOCTL * drivers/xbee: Support querying device for parameters, setting parameters, and structures association/startpan logic * configs/clicker2-stm32: Fixes Xbee lower half ATTN poll logic * drivers/xbee: Removes dependce on CONFIG_IEEE802154_NETDEV * drivers/xbee: Supports MAC RESET.request primitive * drivers/xbee: Exposes generic AT query to the rest of driver * drivers/xbee: Sets local values when writing setting change to Xbee device * drivers/xbee: Finish association logic * drivers/xbee: Adds xbee_get_mhrlen( ) allocating enough space for API frame header to frame * drivers/xbee: Finishes transmit/receive logic * drivers/xbee: Fixes xbee_netdev to match logic in mac802154_netdev.c * drivers/xbee: Rearranges logic to prevent a loop condition where recursion could potentially occur to the point of deadlocking the system Approved-by: Gregory Nutt <gnutt@nuttx.org>
2017-09-15 16:37:55 +02:00
int prevoffs = frame->io_offset;
#endif
Merged in merlin17/nuttx/xbee (pull request #484) drivers/wireless: Adds XBee S2C (802.15.4 firmware) support. XBee driver emulates mac802154 interface * drivers/wireless/xbee: Adds xbee_netdev. Very similar to mac802154_netdev * configs/same70-xplained: Starts adding support for XBee radio * drivers/wireless/ieee802154/xbee: More structuring of XBee driver * drivers/wireless/ieee802154/xbee: More Xbee work. Starts adding support on Clicker2 * drivers/wireless/ieee802154/xbee: More XBee MAC code * configs/clicker2-stm32: More work to add XBee radio support * drivers/wireless/ieee802154/xbee: Most of driver is now structured. No build errors * configs/clicker2-stm32: Adjustments to XBee click module support * drivers/xbee: Changes md_ prefix to xd_ prefix for xbeenet_driver_s fields * drivers/xbee: XBee network device now passes MAC events via IOCTL * drivers/xbee: Support querying device for parameters, setting parameters, and structures association/startpan logic * configs/clicker2-stm32: Fixes Xbee lower half ATTN poll logic * drivers/xbee: Removes dependce on CONFIG_IEEE802154_NETDEV * drivers/xbee: Supports MAC RESET.request primitive * drivers/xbee: Exposes generic AT query to the rest of driver * drivers/xbee: Sets local values when writing setting change to Xbee device * drivers/xbee: Finish association logic * drivers/xbee: Adds xbee_get_mhrlen( ) allocating enough space for API frame header to frame * drivers/xbee: Finishes transmit/receive logic * drivers/xbee: Fixes xbee_netdev to match logic in mac802154_netdev.c * drivers/xbee: Rearranges logic to prevent a loop condition where recursion could potentially occur to the point of deadlocking the system Approved-by: Gregory Nutt <gnutt@nuttx.org>
2017-09-15 16:37:55 +02:00
/* Figure out how much room we need to place the API frame header */
if (meta->destaddr.mode == IEEE802154_ADDRMODE_EXTENDED)
{
DEBUGASSERT(frame->io_offset >= 14);
frame->io_offset -= 14;
frametype = XBEE_APIFRAME_TXREQ_EADDR;
}
else if (meta->destaddr.mode == IEEE802154_ADDRMODE_SHORT)
{
DEBUGASSERT(frame->io_offset >= 8);
frame->io_offset -= 8;
frametype = XBEE_APIFRAME_TXREQ_SADDR;
}
else
{
return -EINVAL;
}
index = frame->io_offset;
apiframelen = (frame->io_len - frame->io_offset - 3);
frame->io_data[index++] = XBEE_STARTBYTE;
frame->io_data[index++] = ((apiframelen >> 8) & 0xFF);
frame->io_data[index++] = (apiframelen & 0xFF);
frame->io_data[index++] = frametype;
frame->io_data[index++] = xbee_next_frameid(priv);
if (meta->destaddr.mode == IEEE802154_ADDRMODE_EXTENDED)
{
frame->io_data[index++] = meta->destaddr.eaddr[7];
frame->io_data[index++] = meta->destaddr.eaddr[6];
frame->io_data[index++] = meta->destaddr.eaddr[5];
frame->io_data[index++] = meta->destaddr.eaddr[4];
frame->io_data[index++] = meta->destaddr.eaddr[3];
frame->io_data[index++] = meta->destaddr.eaddr[2];
frame->io_data[index++] = meta->destaddr.eaddr[1];
frame->io_data[index++] = meta->destaddr.eaddr[0];
}
else
{
frame->io_data[index++] = meta->destaddr.saddr[1];
frame->io_data[index++] = meta->destaddr.saddr[0];
}
frame->io_data[index++] = 0; /* Options byte. Currently we do not support anything here */
DEBUGASSERT(index == prevoffs);
/* Increment io_len by 1 to account for checksum */
frame->io_len++;
xbee_insert_checksum(&frame->io_data[frame->io_offset],
(frame->io_len - frame->io_offset));
xbee_send_apiframe(priv, &frame->io_data[frame->io_offset],
(frame->io_len - frame->io_offset));
iob_free(frame);
return OK;
}
/****************************************************************************
* Name: xbee_req_get
*
* Description:
* The MLME-GET.request primitive requests information about a given PIB
* attribute.
*
* NOTE: The standard specifies that the attribute value should be returned
* via the asynchronous MLME-GET.confirm primitve. However, in our
* implementation, we synchronously return the value immediately.Therefore, we
* merge the functionality of the MLME-GET.request and MLME-GET.confirm
* primitives together.
*
****************************************************************************/
int xbee_req_get(XBEEHANDLE xbee, enum ieee802154_attr_e attr,
FAR union ieee802154_attr_u *attrval)
{
FAR struct xbee_priv_s *priv = (FAR struct xbee_priv_s *)xbee;
int ret = IEEE802154_STATUS_SUCCESS;
switch (attr)
{
case IEEE802154_ATTR_MAC_PANID:
{
xbee_query_panid(priv);
IEEE802154_PANIDCOPY(attrval->mac.panid, priv->addr.panid);
}
break;
case IEEE802154_ATTR_MAC_SADDR:
{
xbee_query_saddr(priv);
IEEE802154_SADDRCOPY(attrval->mac.saddr, priv->addr.saddr);
}
break;
case IEEE802154_ATTR_MAC_EADDR:
{
xbee_query_eaddr(priv);
IEEE802154_EADDRCOPY(attrval->mac.eaddr, priv->addr.eaddr);
}
break;
case IEEE802154_ATTR_MAC_COORD_SADDR:
{
IEEE802154_SADDRCOPY(attrval->mac.coordsaddr, priv->pandesc.coordaddr.saddr);
}
break;
case IEEE802154_ATTR_MAC_COORD_EADDR:
{
IEEE802154_EADDRCOPY(attrval->mac.coordeaddr, priv->pandesc.coordaddr.eaddr);
}
break;
case IEEE802154_ATTR_MAC_DEVMODE:
{
attrval->mac.devmode = priv->devmode;
}
break;
case IEEE802154_ATTR_PHY_CHAN:
{
xbee_query_chan(priv);
attrval->phy.chan = priv->chan;
}
break;
case IEEE802154_ATTR_RADIO_REGDUMP:
{
xbee_regdump(priv);
}
break;
default:
{
wlwarn("Unsupported attribute\n");
ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE;
}
break;
}
return ret;
}
/****************************************************************************
* Name: xbee_req_set
*
* Description:
* The MLME-SET.request primitive attempts to write the given value to the
* indicated MAC PIB attribute.
*
* NOTE: The standard specifies that confirmation should be indicated via
* the asynchronous MLME-SET.confirm primitve. However, in our implementation
* we synchronously return the status from the request. Therefore, we do merge
* the functionality of the MLME-SET.request and MLME-SET.confirm primitives
* together.
*
****************************************************************************/
int xbee_req_set(XBEEHANDLE xbee, enum ieee802154_attr_e attr,
FAR const union ieee802154_attr_u *attrval)
{
FAR struct xbee_priv_s *priv = (FAR struct xbee_priv_s *)xbee;
int ret = IEEE802154_STATUS_SUCCESS;
switch (attr)
{
case IEEE802154_ATTR_MAC_PANID:
{
xbee_set_panid(priv, attrval->mac.panid);
}
break;
case IEEE802154_ATTR_MAC_EADDR:
{
ret = IEEE802154_STATUS_DENIED;
}
break;
case IEEE802154_ATTR_MAC_SADDR:
{
xbee_set_saddr(priv, attrval->mac.saddr);
}
break;
case IEEE802154_ATTR_PHY_CHAN:
{
xbee_set_chan(priv, attrval->phy.chan);
}
break;
case IEEE802154_ATTR_MAC_ASSOCIATION_PERMIT:
{
if (attrval->mac.assocpermit)
{
xbee_set_coordassocflags(priv, XBEE_COORDASSOCFLAGS_ALLOWASSOC);
}
else
{
xbee_set_coordassocflags(priv, 0);
}
}
break;
#if 0
case IEEE802154_ATTR_MAC_COORD_SADDR:
{
xbee_set_coordsaddr(priv, attrval->mac.coordsaddr);
}
break;
case IEEE802154_ATTR_MAC_COORD_EADDR:
{
xbee_set_coordeaddr(priv, attrval->mac.coordeaddr);
}
break;
case IEEE802154_ATTR_MAC_RESPONSE_WAIT_TIME:
{
priv->resp_waittime = attrval->mac.resp_waittime;
}
case IEEE802154_ATTR_MAC_RX_ON_WHEN_IDLE:
{
xbee_setrxonidle(priv, attrval->mac.rxonidle);
}
#endif
default:
{
wlwarn("Unsupported attribute\n");
ret = IEEE802154_STATUS_UNSUPPORTED_ATTRIBUTE;
}
break;
}
return ret;
}
/****************************************************************************
* Name: xbee_req_start
*
* Description:
* The MLME-START.request primitive makes a request for the device to start
* acting as a coordinator. The XBee modules do not support beacon-enabled
* networking!
*
****************************************************************************/
int xbee_req_start(XBEEHANDLE xbee, FAR struct ieee802154_start_req_s *req)
{
FAR struct xbee_priv_s *priv = (FAR struct xbee_priv_s *)xbee;
if (req->beaconorder != 15)
{
wlwarn("xbee: beacon-enabled networks not supported\n");
return -EINVAL;
}
xbee_set_panid(priv, req->panid);
xbee_set_chan(priv, req->chan);
xbee_enable_coord(priv, true);
xbee_set_sleepperiod(priv, 0);
return OK;
}
/****************************************************************************
* Name: xbee_req_associate
*
* Description:
* The MLME-ASSOCIATE.request primitive allows a device to request an
* association with a coordinator.
*
* 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
*
****************************************************************************/
int xbee_req_associate(XBEEHANDLE xbee, FAR struct ieee802154_assoc_req_s *req)
{
FAR struct xbee_priv_s *priv = (FAR struct xbee_priv_s *)xbee;
if (req->coordaddr.mode == IEEE802154_ADDRMODE_NONE)
{
return -EINVAL;
}
xbee_enable_coord(priv, false);
xbee_set_panid(priv, req->coordaddr.panid);
xbee_set_chan(priv, req->chan);
xbee_set_epassocflags(priv, XBEE_EPASSOCFLAGS_AUTOASSOC);
/* In order to track the association status, we must poll the device for
* an update.
*/
return wd_start(priv->assocwd, XBEE_ASSOC_POLLDELAY, xbee_assoctimer, 1, (wdparm_t)priv);
}
/****************************************************************************
* Name: xbee_req_reset
*
* Description:
* The MLME-RESET.request primitive allows the next higher layer to request
* that the MLME performs a reset operation.
*
* Input Parameters:
* xbee - Handle to the XBee instance
* resetattr - Whether or not to reset the MAC PIB attributes to defaults
*
****************************************************************************/
int xbee_req_reset(XBEEHANDLE xbee, bool resetattr)
{
FAR struct xbee_priv_s *priv = (FAR struct xbee_priv_s *)xbee;
/* Reset the XBee radio */
priv->lower->reset(priv->lower);
if (resetattr)
{
xbee_set_panid(priv, IEEE802154_PANID_UNSPEC);
xbee_set_saddr(priv, IEEE802154_SADDR_UNSPEC);
xbee_enable_coord(priv, false);
xbee_set_epassocflags(priv, 0);
xbee_set_coordassocflags(priv, 0);
}
return OK;
}