Exemplo n.º 1
0
/* Returns whether rescheduling is needed or not */
static bool _lwmac_tx_update(gnrc_netif_t *netif)
{
    assert(netif != NULL);

    bool reschedule = false;

    switch (netif->mac.tx.state) {
        case GNRC_LWMAC_TX_STATE_INIT: {
            gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_WR);
            gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_NO_RESPONSE);
            gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_NEXT_BROADCAST);
            gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_BROADCAST_END);

            /* if found ongoing transmission,
             * quit this cycle for collision avoidance. */
            if (_gnrc_lwmac_get_netdev_state(netif) == NETOPT_STATE_RX) {
                if (!gnrc_mac_queue_tx_packet(&netif->mac.tx, 0, netif->mac.tx.packet)) {
                    gnrc_pktbuf_release(netif->mac.tx.packet);
                    LOG_WARNING("WARNING: [LWMAC-tx] TX queue full, drop packet\n");
                }
                /* drop pointer so it wont be free'd */
                netif->mac.tx.packet = NULL;
                netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
                reschedule = true;
                break;
            }

            /* check if the packet is for broadcast */
            if (gnrc_netif_hdr_get_flag(netif->mac.tx.packet) &
                (GNRC_NETIF_HDR_FLAGS_BROADCAST | GNRC_NETIF_HDR_FLAGS_MULTICAST)) {
                /* Set CSMA retries as configured and enable */
                uint8_t csma_retries = GNRC_LWMAC_BROADCAST_CSMA_RETRIES;
                netif->dev->driver->set(netif->dev, NETOPT_CSMA_RETRIES,
                                        &csma_retries, sizeof(csma_retries));
                netif->mac.mac_info |= GNRC_NETIF_MAC_INFO_CSMA_ENABLED;
                netopt_enable_t csma_enable = NETOPT_ENABLE;
                netif->dev->driver->set(netif->dev, NETOPT_CSMA,
                                        &csma_enable, sizeof(csma_enable));

                netif->mac.tx.state = GNRC_LWMAC_TX_STATE_SEND_BROADCAST;
                reschedule = true;
                break;
            }
            else {
                /* Use CSMA for the first WR */
                netif->mac.mac_info |= GNRC_NETIF_MAC_INFO_CSMA_ENABLED;
                netopt_enable_t csma_disable = NETOPT_ENABLE;
                netif->dev->driver->set(netif->dev, NETOPT_CSMA,
                                        &csma_disable, sizeof(csma_disable));
                /* Set a timeout for the maximum transmission procedure */
                gnrc_lwmac_set_timeout(netif, GNRC_LWMAC_TIMEOUT_NO_RESPONSE, GNRC_LWMAC_PREAMBLE_DURATION_US);

                netif->mac.tx.state = GNRC_LWMAC_TX_STATE_SEND_WR;
                reschedule = true;
                break;
            }
        }
        case GNRC_LWMAC_TX_STATE_SEND_BROADCAST: {
            uint8_t tx_info = _send_bcast(netif);

            if (tx_info & GNRC_LWMAC_TX_SUCCESS) {
                netif->mac.tx.state = GNRC_LWMAC_TX_STATE_SUCCESSFUL;
                reschedule = true;
                break;
            }

            if (tx_info & GNRC_LWMAC_TX_FAIL) {
                netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
                reschedule = true;
                break;
            }

            break;
        }
        case GNRC_LWMAC_TX_STATE_SEND_WR: {
            /* In case of no Tx-isr error (e.g., no Tx-isr), goto TX failure. */
            if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_NO_RESPONSE)) {
                LOG_WARNING("WARNING: [LWMAC-tx] No response from destination, "
                            "probably no TX-ISR\n");
                netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
                reschedule = true;
                break;
            }
            LOG_DEBUG("[LWMAC-tx] GNRC_LWMAC_TX_STATE_SEND_WR\n");
            uint8_t tx_info = _send_wr(netif);

            if (tx_info & GNRC_LWMAC_TX_FAIL) {
                netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
                reschedule = true;
                break;
            }

            netif->mac.tx.state = GNRC_LWMAC_TX_STATE_WAIT_WR_SENT;
            reschedule = false;
            break;
        }
        case GNRC_LWMAC_TX_STATE_WAIT_WR_SENT: {
            LOG_DEBUG("[LWMAC-tx] GNRC_LWMAC_TX_STATE_WAIT_WR_SENT\n");

            /* In case of no Tx-isr error (e.g., no Tx-isr), goto TX failure. */
            if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_NO_RESPONSE)) {
                LOG_WARNING("WARNING: [LWMAC-tx] No response from destination\n");
                netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
                reschedule = true;
                break;
            }

            if (gnrc_netif_get_tx_feedback(netif) == TX_FEEDBACK_UNDEF) {
                LOG_DEBUG("[LWMAC-tx] WR not yet completely sent\n");
                break;
            }

            /* If found ongoing transmission, goto TX failure, i.e., postpone transmission to
             * next cycle. This is mainly for collision avoidance. */
            if (gnrc_netif_get_tx_feedback(netif) == TX_FEEDBACK_BUSY) {
                if (!gnrc_mac_queue_tx_packet(&netif->mac.tx, 0, netif->mac.tx.packet)) {
                    gnrc_pktbuf_release(netif->mac.tx.packet);
                    LOG_WARNING("WARNING: [LWMAC-tx] TX queue full, drop packet\n");
                }
                /* clear packet point to avoid TX retry */
                netif->mac.tx.packet = NULL;
                netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
                reschedule = true;
                break;
            }

            if (netif->mac.tx.wr_sent == 0) {
                /* Only the first WR use CSMA */
                netif->mac.mac_info &= ~GNRC_NETIF_MAC_INFO_CSMA_ENABLED;
                netopt_enable_t csma_disable = NETOPT_DISABLE;
                netif->dev->driver->set(netif->dev, NETOPT_CSMA,
                                        &csma_disable, sizeof(csma_disable));
            }

            netif->mac.tx.wr_sent++;

            /* Set timeout for next WR in case no WA will be received */
            gnrc_lwmac_set_timeout(netif, GNRC_LWMAC_TIMEOUT_WR, GNRC_LWMAC_TIME_BETWEEN_WR_US);

            /* Debug WR timing */
            LOG_DEBUG("[LWMAC-tx] Destination phase was: %" PRIu32 "\n",
                      netif->mac.tx.current_neighbor->phase);
            LOG_DEBUG("[LWMAC-tx] Phase when sent was:   %" PRIu32 "\n",
                      _gnrc_lwmac_ticks_to_phase(netif->mac.tx.timestamp));
            LOG_DEBUG("[LWMAC-tx] Ticks when sent was:   %" PRIu32 "\n",
                      netif->mac.tx.timestamp);
            _gnrc_lwmac_set_netdev_state(netif, NETOPT_STATE_IDLE);
            netif->mac.tx.state = GNRC_LWMAC_TX_STATE_WAIT_FOR_WA;
            reschedule = false;
            break;
        }
        case GNRC_LWMAC_TX_STATE_WAIT_FOR_WA: {
            LOG_DEBUG("[LWMAC-tx] GNRC_LWMAC_TX_STATE_WAIT_FOR_WA\n");

            if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_NO_RESPONSE)) {
                LOG_WARNING("WARNING: [LWMAC-tx] No response from destination\n");
                netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
                reschedule = true;
                break;
            }

            if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_WR)) {
                /* In case the sender is in consecutive (burst) transmission to the receiver,
                 * meaning that the sender has already successfully sent at least one data to
                 * the receiver, then the sender will only spend one WR for triggering the next
                 * transmission procedure. And, if this WR doesn't work (no WA replied), the
                 * sender regards consecutive transmission failed.
                 */
                if (gnrc_lwmac_get_tx_continue(netif)) {
                    LOG_DEBUG("[LWMAC-tx] Tx burst fail\n");
                    if (!gnrc_mac_queue_tx_packet(&netif->mac.tx, 0, netif->mac.tx.packet)) {
                        gnrc_pktbuf_release(netif->mac.tx.packet);
                        LOG_WARNING("WARNING: [LWMAC-tx] TX queue full, drop packet\n");
                    }
                    /* drop pointer so it wont be free'd */
                    netif->mac.tx.packet = NULL;

                    netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
                    reschedule = true;
                    break;
                }
                else {
                    /* If this is the first transmission to the receiver for locating the
                     * latter's wake-up period, the sender just keep sending WRs until it
                     * finds the WA.
                     */
                    netif->mac.tx.state = GNRC_LWMAC_TX_STATE_SEND_WR;
                    reschedule = true;
                    break;
                }
            }

            if (_gnrc_lwmac_get_netdev_state(netif) == NETOPT_STATE_RX) {
                /* Wait for completion of frame reception */
                break;
            }

            uint8_t tx_info = _packet_process_in_wait_for_wa(netif);

            if (tx_info & GNRC_LWMAC_TX_FAIL) {
                netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
                reschedule = true;
                break;
            }

            if (tx_info & GNRC_LWMAC_TX_SUCCESS) {
                netif->mac.tx.state = GNRC_LWMAC_TX_STATE_SEND_DATA;
                reschedule = true;
                break;
            }
            else {
                /* No WA yet */
                break;
            }
        }
        case GNRC_LWMAC_TX_STATE_SEND_DATA: {
            LOG_DEBUG("[LWMAC-tx] GNRC_LWMAC_TX_STATE_SEND_DATA\n");

            if (!_send_data(netif)) {
                netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
                reschedule = true;
                break;
            }

            netif->mac.tx.state = GNRC_LWMAC_TX_STATE_WAIT_FEEDBACK;
            reschedule = false;
            break;
        }
        case GNRC_LWMAC_TX_STATE_WAIT_FEEDBACK: {
            /* In case of no Tx-isr error, goto TX failure. */
            if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_NO_RESPONSE)) {
                netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
                reschedule = true;
                break;
            }

            LOG_DEBUG("[LWMAC-tx] GNRC_LWMAC_TX_STATE_WAIT_FEEDBACK\n");
            if (gnrc_netif_get_tx_feedback(netif) == TX_FEEDBACK_UNDEF) {
                break;
            }
            else if (gnrc_netif_get_tx_feedback(netif) == TX_FEEDBACK_SUCCESS) {
                netif->mac.tx.state = GNRC_LWMAC_TX_STATE_SUCCESSFUL;
                reschedule = true;
                break;
            }
            else if (gnrc_netif_get_tx_feedback(netif) == TX_FEEDBACK_NOACK) {
                LOG_ERROR("ERROR: [LWMAC-tx] Not ACKED\n");
                netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
                reschedule = true;
                break;
            }
            else if (gnrc_netif_get_tx_feedback(netif) == TX_FEEDBACK_BUSY) {
                LOG_ERROR("ERROR: [LWMAC-tx] Channel busy \n");
                netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
                reschedule = true;
                break;
            }

            LOG_ERROR("ERROR: [LWMAC-tx] Tx feedback unhandled: %i\n",
                      gnrc_netif_get_tx_feedback(netif));
            netif->mac.tx.state = GNRC_LWMAC_TX_STATE_FAILED;
            reschedule = true;
            break;
        }
        case GNRC_LWMAC_TX_STATE_SUCCESSFUL:
        case GNRC_LWMAC_TX_STATE_FAILED: {
            break;
        }
        case GNRC_LWMAC_TX_STATE_STOPPED: {
            LOG_DEBUG("[LWMAC-tx] Transmission state machine is stopped\n");
        }
    }

    return reschedule;
}
Exemplo n.º 2
0
static uint8_t _send_bcast(gnrc_netif_t *netif)
{
    assert(netif != NULL);

    uint8_t tx_info = 0;
    gnrc_pktsnip_t *pkt = netif->mac.tx.packet;
    bool first = false;

    if (gnrc_lwmac_timeout_is_running(netif, GNRC_LWMAC_TIMEOUT_BROADCAST_END)) {
        if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_BROADCAST_END)) {
            gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_NEXT_BROADCAST);
            gnrc_pktbuf_release(pkt);
            netif->mac.tx.packet = NULL;
            tx_info |= GNRC_LWMAC_TX_SUCCESS;
            return tx_info;
        }
    }
    else {
        LOG_INFO("[LWMAC-tx] Initialize broadcasting\n");
        gnrc_lwmac_set_timeout(netif, GNRC_LWMAC_TIMEOUT_BROADCAST_END,
                               GNRC_LWMAC_BROADCAST_DURATION_US);

        gnrc_pktsnip_t *pkt_payload;

        /* Prepare packet with LWMAC header*/
        gnrc_lwmac_frame_broadcast_t hdr;
        hdr.header.type = GNRC_LWMAC_FRAMETYPE_BROADCAST;
        hdr.seq_nr = netif->mac.tx.bcast_seqnr++;

        pkt_payload = pkt->next;
        pkt->next = gnrc_pktbuf_add(pkt->next, &hdr, sizeof(hdr), GNRC_NETTYPE_LWMAC);
        if (pkt->next == NULL) {
            LOG_ERROR("ERROR: [LWMAC-tx] Cannot allocate pktbuf of type FRAMETYPE_BROADCAST\n");
            netif->mac.tx.packet->next = pkt_payload;
            /* Drop the broadcast packet */
            LOG_ERROR("ERROR: [LWMAC-tx] Memory maybe full, drop the broadcast packet\n");
            gnrc_pktbuf_release(netif->mac.tx.packet);
            /* clear packet point to avoid TX retry */
            netif->mac.tx.packet = NULL;
            tx_info |= GNRC_LWMAC_TX_FAIL;
            return tx_info;
        }

        /* No Auto-ACK for broadcast packets */
        netopt_enable_t autoack = NETOPT_DISABLE;
        netif->dev->driver->set(netif->dev, NETOPT_AUTOACK, &autoack,
                                sizeof(autoack));
        first = true;
    }

    if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_NEXT_BROADCAST) ||
        first) {
        /* if found ongoing transmission, quit this cycle for collision avoidance.
        * Broadcast packet will be re-queued and try to send in the next cycle. */
        if (_gnrc_lwmac_get_netdev_state(netif) == NETOPT_STATE_RX) {
            /* save pointer to netif header */
            gnrc_pktsnip_t *netif_snip = pkt->next->next;

            /* remove LWMAC header */
            pkt->next->next = NULL;
            gnrc_pktbuf_release(pkt->next);

            /* make append netif header after payload again */
            pkt->next = netif_snip;

            if (!gnrc_mac_queue_tx_packet(&netif->mac.tx, 0, netif->mac.tx.packet)) {
                gnrc_pktbuf_release(netif->mac.tx.packet);
                LOG_WARNING("WARNING: [LWMAC-tx] TX queue full, drop packet\n");
            }
            /* drop pointer so it wont be free'd */
            netif->mac.tx.packet = NULL;
            tx_info |= GNRC_LWMAC_TX_FAIL;
            return tx_info;
        }

        /* Don't let the packet be released yet, we want to send it again */
        gnrc_pktbuf_hold(pkt, 1);

        int res = _gnrc_lwmac_transmit(netif, pkt);
        if (res < 0) {
            LOG_ERROR("ERROR: [LWMAC-tx] Send broadcast pkt failed.");
            tx_info |= GNRC_LWMAC_TX_FAIL;
            return tx_info;
        }

        gnrc_lwmac_set_timeout(netif, GNRC_LWMAC_TIMEOUT_NEXT_BROADCAST,
                               GNRC_LWMAC_TIME_BETWEEN_BROADCAST_US);
        LOG_INFO("[LWMAC-tx] Broadcast sent\n");
    }

    return tx_info;
}
Exemplo n.º 3
0
static uint8_t _send_wr(gnrc_netif_t *netif)
{
    assert(netif != NULL);

    uint8_t tx_info = 0;
    gnrc_pktsnip_t *pkt;
    gnrc_pktsnip_t *pkt_lwmac;
    gnrc_netif_hdr_t *nethdr;

    /* if found ongoing transmission, quit this cycle for collision avoidance.
     * Data packet will be re-queued and try to send in the next cycle. */
    if (_gnrc_lwmac_get_netdev_state(netif) == NETOPT_STATE_RX) {
        if (!gnrc_mac_queue_tx_packet(&netif->mac.tx, 0, netif->mac.tx.packet)) {
            gnrc_pktbuf_release(netif->mac.tx.packet);
            LOG_WARNING("WARNING: [LWMAC-tx] TX queue full, drop packet\n");
        }
        /* drop pointer so it wont be free'd */
        netif->mac.tx.packet = NULL;
        tx_info |= GNRC_LWMAC_TX_FAIL;
        return tx_info;
    }

    /* Assemble WR */
    gnrc_lwmac_frame_wr_t wr_hdr;
    wr_hdr.header.type = GNRC_LWMAC_FRAMETYPE_WR;
    memcpy(&(wr_hdr.dst_addr.addr), netif->mac.tx.current_neighbor->l2_addr,
           netif->mac.tx.current_neighbor->l2_addr_len);
    wr_hdr.dst_addr.len = netif->mac.tx.current_neighbor->l2_addr_len;

    pkt = gnrc_pktbuf_add(NULL, &wr_hdr, sizeof(wr_hdr), GNRC_NETTYPE_LWMAC);
    if (pkt == NULL) {
        LOG_ERROR("ERROR: [LWMAC-tx] Cannot allocate pktbuf of type GNRC_NETTYPE_LWMAC\n");
        gnrc_pktbuf_release(netif->mac.tx.packet);
        LOG_ERROR("ERROR: [LWMAC-tx] Memory maybe full, drop the data packet\n");
        /* clear packet point to avoid TX retry */
        netif->mac.tx.packet = NULL;
        tx_info |= GNRC_LWMAC_TX_FAIL;
        return tx_info;
    }

    /* track the location of this lwmac_frame_wr_t header */
    pkt_lwmac = pkt;

    pkt = gnrc_pktbuf_add(pkt, NULL, sizeof(gnrc_netif_hdr_t), GNRC_NETTYPE_NETIF);
    if (pkt == NULL) {
        LOG_ERROR("ERROR: [LWMAC-tx] Cannot allocate pktbuf of type GNRC_NETTYPE_NETIF\n");
        gnrc_pktbuf_release(pkt_lwmac);
        LOG_ERROR("ERROR: [LWMAC-tx] Memory maybe full, drop the data packet\n");
        gnrc_pktbuf_release(netif->mac.tx.packet);
        /* clear packet point to avoid TX retry */
        netif->mac.tx.packet = NULL;
        tx_info |= GNRC_LWMAC_TX_FAIL;
        return tx_info;
    }

    /* We wouldn't get here if adding the NETIF header had failed, so no
     * sanity checks needed */
    nethdr = (gnrc_netif_hdr_t *) (gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_NETIF))->data;

    /* Construct NETIF header and insert address for WR packet */
    gnrc_netif_hdr_init(nethdr, 0, 0);

    /* Send WR as broadcast*/
    nethdr->flags |= GNRC_NETIF_HDR_FLAGS_BROADCAST;

    /* Disable Auto ACK */
    netopt_enable_t autoack = NETOPT_DISABLE;
    netif->dev->driver->set(netif->dev, NETOPT_AUTOACK, &autoack,
                            sizeof(autoack));

    /* Prepare WR, this will discard any frame in the transceiver that has
    * possibly arrived in the meantime but we don't care at this point. */
    int res = _gnrc_lwmac_transmit(netif, pkt);
    if (res < 0) {
        LOG_ERROR("ERROR: [LWMAC-tx] Send WR failed.");
        if (pkt != NULL) {
            gnrc_pktbuf_release(pkt);
        }
        tx_info |= GNRC_LWMAC_TX_FAIL;
        return tx_info;
    }

    gnrc_priority_pktqueue_flush(&netif->mac.rx.queue);
    return tx_info;
}
Exemplo n.º 4
0
/* return false if send data failed, otherwise return true */
static bool _send_data(gnrc_netif_t *netif)
{
    assert(netif != NULL);

    gnrc_pktsnip_t *pkt = netif->mac.tx.packet;
    gnrc_pktsnip_t *pkt_payload;

    assert(pkt != NULL);
    /* Enable Auto ACK again */
    netopt_enable_t autoack = NETOPT_ENABLE;
    netif->dev->driver->set(netif->dev, NETOPT_AUTOACK,
                            &autoack, sizeof(autoack));

    /* It's okay to retry sending DATA. Timing doesn't matter anymore and
     * destination is waiting for a certain amount of time. */
    uint8_t csma_retries = GNRC_LWMAC_DATA_CSMA_RETRIES;
    netif->dev->driver->set(netif->dev, NETOPT_CSMA_RETRIES,
                            &csma_retries, sizeof(csma_retries));

    netif->mac.mac_info |= GNRC_NETIF_MAC_INFO_CSMA_ENABLED;
    netopt_enable_t csma_enable = NETOPT_ENABLE;
    netif->dev->driver->set(netif->dev, NETOPT_CSMA,
                            &csma_enable, sizeof(csma_enable));

    pkt_payload = pkt->next;

    /* Insert LWMAC header above NETIF header. The burst (consecutive) transmission
     * scheme works here (sender side). If the sender finds it has pending packets
     * for the receiver (and under burst limit), it sets the packet type to
     * FRAMETYPE_DATA_PENDING, to notice the receiver for next incoming packet.
     * In case the sender has no more packet for the receiver, it simply sets the
     * data type to FRAMETYPE_DATA. */
    gnrc_lwmac_hdr_t hdr;
    if ((gnrc_priority_pktqueue_length(&netif->mac.tx.current_neighbor->queue) > 0) &&
        (netif->mac.tx.tx_burst_count < GNRC_LWMAC_MAX_TX_BURST_PKT_NUM)) {
        hdr.type = GNRC_LWMAC_FRAMETYPE_DATA_PENDING;
        gnrc_lwmac_set_tx_continue(netif, true);
        netif->mac.tx.tx_burst_count++;
    }
    else {
        hdr.type = GNRC_LWMAC_FRAMETYPE_DATA;
        gnrc_lwmac_set_tx_continue(netif, false);
    }

    pkt->next = gnrc_pktbuf_add(pkt->next, &hdr, sizeof(hdr), GNRC_NETTYPE_LWMAC);
    if (pkt->next == NULL) {
        LOG_ERROR("ERROR: [LWMAC-tx] Cannot allocate pktbuf of type GNRC_NETTYPE_LWMAC\n");
        LOG_ERROR("ERROR: [LWMAC-tx] Memory maybe full, drop the data packet\n");
        netif->mac.tx.packet->next = pkt_payload;
        gnrc_pktbuf_release(netif->mac.tx.packet);
        /* clear packet point to avoid TX retry */
        netif->mac.tx.packet = NULL;
        return false;
    }

    /* if found ongoing transmission, quit this cycle for collision avoidance.
     * Data packet will be re-queued and try to send in the next cycle. */
    if (_gnrc_lwmac_get_netdev_state(netif) == NETOPT_STATE_RX) {
        /* save pointer to netif header */
        gnrc_pktsnip_t *netif_snip = pkt->next->next;

        /* remove LWMAC header */
        pkt->next->next = NULL;
        gnrc_pktbuf_release(pkt->next);

        /* make append netif header after payload again */
        pkt->next = netif_snip;

        if (!gnrc_mac_queue_tx_packet(&netif->mac.tx, 0, netif->mac.tx.packet)) {
            gnrc_pktbuf_release(netif->mac.tx.packet);
            LOG_WARNING("WARNING: [LWMAC-tx] TX queue full, drop packet\n");
        }
        /* drop pointer so it wont be free'd */
        netif->mac.tx.packet = NULL;
        return false;
    }

    /* Send data */
    int res = _gnrc_lwmac_transmit(netif, pkt);
    if (res < 0) {
        LOG_ERROR("ERROR: [LWMAC-tx] Send data failed.");
        gnrc_pktbuf_release(pkt);
        /* clear packet point to avoid TX retry */
        netif->mac.tx.packet = NULL;
        return false;
    }

    /* Packet has been released by netdev, so drop pointer */
    netif->mac.tx.packet = NULL;

    DEBUG("[LWMAC-tx]: spent %lu WR in TX\n",
          (unsigned long)netif->mac.tx.wr_sent);

#if (LWMAC_ENABLE_DUTYCYLE_RECORD == 1)
    netif->mac.prot.lwmac.pkt_start_sending_time_ticks =
        rtt_get_counter() - netif->mac.prot.lwmac.pkt_start_sending_time_ticks;
    DEBUG("[LWMAC-tx]: pkt sending delay in TX: %lu us\n",
          RTT_TICKS_TO_US(netif->mac.prot.lwmac.pkt_start_sending_time_ticks));
#endif

    return true;
}
Exemplo n.º 5
0
/* return false if send wa failed, otherwise return true */
static bool _send_wa(gnrc_netdev_t *gnrc_netdev)
{
    gnrc_pktsnip_t *pkt;
    gnrc_pktsnip_t *pkt_lwmac;
    gnrc_netif_hdr_t *nethdr_wa;

    assert(gnrc_netdev != NULL);
    assert(gnrc_netdev->rx.l2_addr.len != 0);

    /* if found ongoing transmission,
     * quit sending WA for collision avoidance. */
    if (_gnrc_lwmac_get_netdev_state(gnrc_netdev) == NETOPT_STATE_RX) {
        gnrc_netdev->rx.rx_bad_exten_count++;
        return false;
    }

    /* Assemble WA packet */
    gnrc_lwmac_frame_wa_t lwmac_hdr;
    lwmac_hdr.header.type = GNRC_LWMAC_FRAMETYPE_WA;
    lwmac_hdr.dst_addr = gnrc_netdev->rx.l2_addr;

    uint32_t phase_now = _gnrc_lwmac_phase_now();

    /* Embed the current 'relative phase timing' (counted from the start of this cycle)
     * of the receiver into its WA packet, thus to allow the sender to infer the
     * receiver's exact wake-up timing */
    if (phase_now > _gnrc_lwmac_ticks_to_phase(gnrc_netdev->lwmac.last_wakeup)) {
        lwmac_hdr.current_phase = (phase_now -
                                   _gnrc_lwmac_ticks_to_phase(gnrc_netdev->lwmac.last_wakeup));
    }
    else {
        lwmac_hdr.current_phase = (phase_now + RTT_US_TO_TICKS(GNRC_LWMAC_WAKEUP_INTERVAL_US)) -
                                  _gnrc_lwmac_ticks_to_phase(gnrc_netdev->lwmac.last_wakeup);
    }

    pkt = gnrc_pktbuf_add(NULL, &lwmac_hdr, sizeof(lwmac_hdr), GNRC_NETTYPE_LWMAC);
    if (pkt == NULL) {
        LOG_ERROR("ERROR: [LWMAC-rx] Cannot allocate pktbuf of type GNRC_NETTYPE_LWMAC\n");
        gnrc_netdev_lwmac_set_quit_rx(gnrc_netdev, true);
        return false;
    }
    pkt_lwmac = pkt;

    pkt = gnrc_pktbuf_add(pkt, NULL,
                          sizeof(gnrc_netif_hdr_t) + gnrc_netdev->rx.l2_addr.len,
                          GNRC_NETTYPE_NETIF);
    if (pkt == NULL) {
        LOG_ERROR("ERROR: [LWMAC-rx] Cannot allocate pktbuf of type GNRC_NETTYPE_NETIF\n");
        gnrc_pktbuf_release(pkt_lwmac);
        gnrc_netdev_lwmac_set_quit_rx(gnrc_netdev, true);
        return false;
    }

    /* We wouldn't get here if add the NETIF header had failed, so no
       sanity checks needed */
    nethdr_wa = (gnrc_netif_hdr_t *)(gnrc_pktsnip_search_type(pkt,
                                                              GNRC_NETTYPE_NETIF)->data);
    /* Construct NETIF header and insert address for WA packet */
    gnrc_netif_hdr_init(nethdr_wa, 0, gnrc_netdev->rx.l2_addr.len);

    /* Send WA as broadcast*/
    nethdr_wa->flags |= GNRC_NETIF_HDR_FLAGS_BROADCAST;

    /* Disable Auto ACK */
    netopt_enable_t autoack = NETOPT_DISABLE;
    gnrc_netdev->dev->driver->set(gnrc_netdev->dev, NETOPT_AUTOACK, &autoack,
                                  sizeof(autoack));

    /* Send WA */
    if (gnrc_netdev->send(gnrc_netdev, pkt) < 0) {
        LOG_ERROR("ERROR: [LWMAC-rx] Send WA failed.");
        if (pkt != NULL) {
            gnrc_pktbuf_release(pkt);
        }
        gnrc_netdev_lwmac_set_quit_rx(gnrc_netdev, true);
        return false;
    }

    /* Enable Auto ACK again for data reception */
    autoack = NETOPT_ENABLE;
    gnrc_netdev->dev->driver->set(gnrc_netdev->dev, NETOPT_AUTOACK, &autoack,
                                  sizeof(autoack));

    return true;
}