/**************************************************************************** * apps/wireless/ieee802154/i8sak/i8sak_events.c * IEEE 802.15.4 Swiss Army Knife * * Copyright (C) 2017 Verge Inc. All rights reserved. * Author: Anthony Merlino * * 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 #include #include #include #include #include #include #include #include #include #include #include "wireless/ieee802154.h" #include "i8sak.h" #include "i8sak_events.h" /**************************************************************************** * Private Function Prototypes ****************************************************************************/ /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name : i8sak_eventthread * * Description : * Listen for events from the MAC layer ****************************************************************************/ static pthread_addr_t i8sak_eventthread(pthread_addr_t arg) { FAR struct i8sak_s *i8sak = (FAR struct i8sak_s *)arg; union ieee802154_macarg_u macarg; #ifdef CONFIG_NET_6LOWPAN struct ieee802154_netmac_s netarg; #endif FAR struct i8sak_eventreceiver_s *receiver; FAR struct ieee802154_primitive_s *primitive = NULL; int ret; if (i8sak->mode == I8SAK_MODE_CHAR) { macarg.enable = true; ioctl(i8sak->fd, MAC802154IOC_ENABLE_EVENTS, (unsigned long)((uintptr_t)&macarg)); } #ifdef CONFIG_NET_6LOWPAN else if (i8sak->mode == I8SAK_MODE_NETIF) { netarg.u.enable = true; strncpy(netarg.ifr_name, i8sak->ifname, IFNAMSIZ); ioctl(i8sak->fd, MAC802154IOC_ENABLE_EVENTS, (unsigned long)((uintptr_t)&netarg)); } #endif while (i8sak->eventlistener_run) { if (i8sak->mode == I8SAK_MODE_CHAR) { ret = ioctl(i8sak->fd, MAC802154IOC_GET_EVENT, (unsigned long)((uintptr_t)&macarg)); primitive = &macarg.primitive; } #ifdef CONFIG_NET_6LOWPAN else if (i8sak->mode == I8SAK_MODE_NETIF) { ret = ioctl(i8sak->fd, MAC802154IOC_GET_EVENT, (unsigned long)((uintptr_t)&netarg)); primitive = &netarg.u.primitive; } #endif if (ret != OK) { return NULL; } ret = sem_wait(&i8sak->eventsem); if (ret != OK) { return NULL; } /* Loop through event receivers and call callbacks for those receivers * listening for this event type. */ receiver = (FAR struct i8sak_eventreceiver_s *)sq_peek( &i8sak->eventreceivers); while (receiver != NULL) { if ((primitive->type == IEEE802154_PRIMITIVE_CONF_DATA && receiver->filter.confevents.data) || (primitive->type == IEEE802154_PRIMITIVE_CONF_ASSOC && receiver->filter.confevents.assoc) || (primitive->type == IEEE802154_PRIMITIVE_CONF_DISASSOC && receiver->filter.confevents.disassoc) || (primitive->type == IEEE802154_PRIMITIVE_CONF_GTS && receiver->filter.confevents.gts) || (primitive->type == IEEE802154_PRIMITIVE_CONF_RESET && receiver->filter.confevents.reset) || (primitive->type == IEEE802154_PRIMITIVE_CONF_RXENABLE && receiver->filter.confevents.rxenable) || (primitive->type == IEEE802154_PRIMITIVE_CONF_SCAN && receiver->filter.confevents.scan) || (primitive->type == IEEE802154_PRIMITIVE_CONF_START && receiver->filter.confevents.start) || (primitive->type == IEEE802154_PRIMITIVE_CONF_POLL && receiver->filter.confevents.poll) || (primitive->type == IEEE802154_PRIMITIVE_IND_ASSOC && receiver->filter.indevents.assoc) || (primitive->type == IEEE802154_PRIMITIVE_IND_DISASSOC && receiver->filter.indevents.disassoc) || (primitive->type == IEEE802154_PRIMITIVE_IND_BEACONNOTIFY && receiver->filter.indevents.beacon) || (primitive->type == IEEE802154_PRIMITIVE_IND_GTS && receiver->filter.indevents.gts) || (primitive->type == IEEE802154_PRIMITIVE_IND_ORPHAN && receiver->filter.indevents.orphan) || (primitive->type == IEEE802154_PRIMITIVE_IND_COMMSTATUS && receiver->filter.indevents.commstatus) || (primitive->type == IEEE802154_PRIMITIVE_IND_SYNCLOSS && receiver->filter.indevents.syncloss)) { receiver->cb(primitive, receiver->arg); if (receiver->oneshot) { /* Unlink the receiver from the list */ sq_rem((FAR sq_entry_t *)receiver, &i8sak->eventreceivers); /* Link the receiver back into the free list */ sq_addlast((FAR sq_entry_t *)receiver, &i8sak->eventreceivers_free); } } receiver = (FAR struct i8sak_eventreceiver_s *)sq_next( (FAR sq_entry_t *)receiver); } sem_post(&i8sak->eventsem); } return NULL; } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: i8sak_eventlistener_start * * Description: * Starts internal threads to listen for events. * * Parameters: * i8sak - handle to the i8sak instance struct * * Returned Value: * OK on success; a negated errno on failure * * Assumptions: * ****************************************************************************/ int i8sak_eventlistener_start(FAR struct i8sak_s *i8sak) { int ret; i8sak->eventlistener_run = true; ret = pthread_create(&i8sak->eventlistener_threadid, NULL, i8sak_eventthread, (void *)i8sak); if (ret != 0) { fprintf(stderr, "failed to start event thread: %d\n", ret); return ret; } return OK; } /**************************************************************************** * Name: i8sak_eventlistener_stop * * Description: * Stops event thread. * * Parameters: * handle - handle to the i8sak instance struct * * Returned Value: * OK on success; a negated errno on failure * * Assumptions: * ****************************************************************************/ int i8sak_eventlistener_stop(FAR struct i8sak_s *i8sak) { return -ENOTTY; } /**************************************************************************** * Name: i8sak_eventlistener_addreceiver * * Description: * Add an event receiver. An event receiver consists of a callback and flags * for which events should be sent to the callback. * * Parameters: * handle - handle to the i8sak instance struct * cb - callback to be called on reception of notification event from * MAC layer that matches one of the masked events * filter - struct containing event mask bits to indicate whether event * type should trigger callback * arg - user specified argument to send to the callback * oneshot - whether the receiver is automatically unregistered after the * first notification * * Returned Value: * OK if successful; a negated errno on failure * * Assumptions: * ****************************************************************************/ int i8sak_eventlistener_addreceiver(FAR struct i8sak_s *i8sak, i8sak_eventcallback_t cb, FAR struct i8sak_eventfilter_s *filter, bool oneshot) { FAR struct i8sak_eventreceiver_s *receiver; int ret; ret = sem_wait(&i8sak->eventsem); if (ret != OK) { fprintf(stderr, "failed to get exclusive access: %d\n", ret); return ret; } /* Allocate a receiver struct from the static pool */ receiver = (FAR struct i8sak_eventreceiver_s *)sq_remfirst( &i8sak->eventreceivers_free); if (receiver == NULL) { fprintf(stderr, "failed to add receiver: %d\n", ENOMEM); sem_post(&i8sak->eventsem); return -ENOMEM; } receiver->cb = cb; memcpy(&receiver->filter, filter, sizeof(struct i8sak_eventfilter_s)); receiver->arg = i8sak; receiver->oneshot = oneshot; /* Link the receiver into the list */ sq_addlast((FAR sq_entry_t *)receiver, &i8sak->eventreceivers); sem_post(&i8sak->eventsem); return OK; } /**************************************************************************** * Name: i8sak_eventlistener_removereceiver * * Description: * Removes a event receiver. Listener will no longer call callback. This * function finds the first event receiver with the provided callback. * * Parameters: * handle - handle to the i8sak instance struct * cb - callback function to search for. * * Returned Value: * OK on success; a negated errno on failure * * Assumptions: * ****************************************************************************/ int i8sak_eventlistener_removereceiver(FAR struct i8sak_s *i8sak, i8sak_eventcallback_t cb) { FAR struct i8sak_eventreceiver_s *receiver; int ret; ret = sem_wait(&i8sak->eventsem); if (ret != OK) { fprintf(stderr, "failed to get exlusive access: %d\n", ret); return ret; } /* Search through frame receivers until either we match the callback, or * there is no more receivers to check. */ receiver = (FAR struct i8sak_eventreceiver_s *)sq_peek( &i8sak->eventreceivers); while (receiver != NULL) { /* Check if callback matches */ if (receiver->cb == cb) { /* Unlink the receiver from the list */ sq_rem((FAR sq_entry_t *)receiver, &i8sak->eventreceivers); /* Link the receiver back into the free list */ sq_addlast((FAR sq_entry_t *)receiver, &i8sak->eventreceivers_free); sem_post(&i8sak->eventsem); return OK; } receiver = (FAR struct i8sak_eventreceiver_s *)sq_next( (FAR sq_entry_t *)receiver); } sem_post(&i8sak->eventsem); fprintf(stderr, "failed to remove receiver"); return ERROR; }