Exemple #1
0
/**
 * @brief   Function called by the device driver on device events
 *
 * @param[in] event         type of event
 * @param[in] data          optional parameter
 */
static void _lwmac_event_cb(netdev_t *dev, netdev_event_t event)
{
    gnrc_netif_t *netif = (gnrc_netif_t *) dev->context;

    if (event == NETDEV_EVENT_ISR) {
        msg_t msg;

        msg.type = NETDEV_MSG_TYPE_EVENT;
        msg.content.ptr = (void *) netif;

        if (msg_send(&msg, netif->pid) <= 0) {
            LOG_WARNING("WARNING: [LWMAC] gnrc_netdev: possibly lost interrupt.\n");
        }
    }
    else {
        DEBUG("gnrc_netdev: event triggered -> %i\n", event);
        switch (event) {
            case NETDEV_EVENT_RX_STARTED: {
                LOG_DEBUG("[LWMAC] NETDEV_EVENT_RX_STARTED\n");
                gnrc_netif_set_rx_started(netif, true);
                break;
            }
            case NETDEV_EVENT_RX_COMPLETE: {
                LOG_DEBUG("[LWMAC] NETDEV_EVENT_RX_COMPLETE\n");
                gnrc_pktsnip_t *pkt = netif->ops->recv(netif);

                /* Prevent packet corruption when a packet is sent before the previous
                 * received packet has been downloaded. This happens e.g. when a timeout
                 * expires that causes the tx state machine to send a packet. When a
                 * packet arrives after the timeout, the notification is queued but the
                 * tx state machine continues to send and then destroys the received
                 * packet in the frame buffer. After completion, the queued notification
                 * will be handled a corrupted packet will be downloaded. Therefore
                 * keep track that RX_STARTED is followed by RX_COMPLETE.
                 *
                 * TODO: transceivers might have 2 frame buffers, so make this optional
                 */
                if (pkt == NULL) {
                    gnrc_netif_set_rx_started(netif, false);
                    break;
                }

                gnrc_netif_set_rx_started(netif, false);

                if (!gnrc_mac_queue_rx_packet(&netif->mac.rx, 0, pkt)) {
                    LOG_ERROR("ERROR: [LWMAC] Can't push RX packet @ %p, memory full?\n", pkt);
                    gnrc_pktbuf_release(pkt);
                    break;
                }
                lwmac_schedule_update(netif);
                break;
            }
            case NETDEV_EVENT_TX_STARTED: {
                gnrc_netif_set_tx_feedback(netif, TX_FEEDBACK_UNDEF);
                gnrc_netif_set_rx_started(netif, false);
                break;
            }
            case NETDEV_EVENT_TX_COMPLETE: {
                gnrc_netif_set_tx_feedback(netif, TX_FEEDBACK_SUCCESS);
                gnrc_netif_set_rx_started(netif, false);
                lwmac_schedule_update(netif);
                break;
            }
            case NETDEV_EVENT_TX_NOACK: {
                gnrc_netif_set_tx_feedback(netif, TX_FEEDBACK_NOACK);
                gnrc_netif_set_rx_started(netif, false);
                lwmac_schedule_update(netif);
                break;
            }
            case NETDEV_EVENT_TX_MEDIUM_BUSY: {
                gnrc_netif_set_tx_feedback(netif, TX_FEEDBACK_BUSY);
                gnrc_netif_set_rx_started(netif, false);
                lwmac_schedule_update(netif);
                break;
            }
            default:
                LOG_WARNING("WARNING: [LWMAC] Unhandled netdev event: %u\n", event);
        }
    }

    /* Execute main state machine because something just happend*/
    while (gnrc_lwmac_get_reschedule(netif)) {
        lwmac_update(netif);
    }
}
Exemple #2
0
static uint8_t _packet_process_in_wait_for_data(gnrc_netdev_t *gnrc_netdev)
{
    uint8_t rx_info = 0;
    gnrc_pktsnip_t *pkt;

    assert(gnrc_netdev != NULL);

    pkt = NULL;

    while ((pkt = gnrc_priority_pktqueue_pop(&gnrc_netdev->rx.queue)) != NULL) {
        LOG_DEBUG("[LWMAC-rx] Inspecting pkt @ %p\n", pkt);

        /* Parse packet */
        gnrc_lwmac_packet_info_t info;

        if (_gnrc_lwmac_parse_packet(pkt, &info) != 0) {
            LOG_DEBUG("[LWMAC-rx] Packet could not be parsed\n");
            gnrc_pktbuf_release(pkt);
            continue;
        }

        if (info.header->type == GNRC_LWMAC_FRAMETYPE_BROADCAST) {
            _gnrc_lwmac_dispatch_defer(gnrc_netdev->rx.dispatch_buffer, pkt);
            gnrc_mac_dispatch(&gnrc_netdev->rx);
            /* quit listening period to avoid receiving duplicate broadcast packets */
            gnrc_netdev_lwmac_set_quit_rx(gnrc_netdev, true);
            continue;
        }

        if (!(memcmp(&info.src_addr.addr, &gnrc_netdev->rx.l2_addr.addr,
                     gnrc_netdev->rx.l2_addr.len) == 0)) {
            LOG_DEBUG("[LWMAC-rx] Packet is not from destination\n");
            gnrc_pktbuf_release(pkt);
            /* Reset timeout to wait for the data packet */
            gnrc_lwmac_clear_timeout(gnrc_netdev, GNRC_LWMAC_TIMEOUT_DATA);
            gnrc_lwmac_set_timeout(gnrc_netdev, GNRC_LWMAC_TIMEOUT_DATA, GNRC_LWMAC_DATA_DELAY_US);
            continue;
        }

        if (!(memcmp(&info.dst_addr.addr, &gnrc_netdev->l2_addr,
                     gnrc_netdev->l2_addr_len) == 0)) {
            LOG_DEBUG("[LWMAC-rx] Packet is not for us\n");
            gnrc_pktbuf_release(pkt);
            /* Reset timeout to wait for the data packet */
            gnrc_lwmac_clear_timeout(gnrc_netdev, GNRC_LWMAC_TIMEOUT_DATA);
            gnrc_lwmac_set_timeout(gnrc_netdev, GNRC_LWMAC_TIMEOUT_DATA, GNRC_LWMAC_DATA_DELAY_US);
            continue;
        }

        /* Sender maybe didn't get the WA */
        if (info.header->type == GNRC_LWMAC_FRAMETYPE_WR) {
            LOG_DEBUG("[LWMAC-rx] Found a WR while waiting for DATA\n");
            gnrc_lwmac_clear_timeout(gnrc_netdev, GNRC_LWMAC_TIMEOUT_DATA);
            rx_info |= GNRC_LWMAC_RX_FOUND_WR;
            /* Push WR back to rx queue */
            gnrc_mac_queue_rx_packet(&gnrc_netdev->rx, 0, pkt);
            break;
        }

        switch (info.header->type) {
            case GNRC_LWMAC_FRAMETYPE_DATA:
            case GNRC_LWMAC_FRAMETYPE_DATA_PENDING: {
                /* Receiver gets the data packet */
                _gnrc_lwmac_dispatch_defer(gnrc_netdev->rx.dispatch_buffer, pkt);
                gnrc_mac_dispatch(&gnrc_netdev->rx);
                LOG_DEBUG("[LWMAC-rx] Found DATA!\n");
                gnrc_lwmac_clear_timeout(gnrc_netdev, GNRC_LWMAC_TIMEOUT_DATA);
                rx_info |= GNRC_LWMAC_RX_FOUND_DATA;
                return rx_info;
            }
            default: {
                gnrc_pktbuf_release(pkt);
            }
        }
    }

    return rx_info;
}