/** * @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); } }
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; }