Esempio n. 1
0
static void _rx_management_success(gnrc_netif_t *netif)
{
    LOG_DEBUG("[LWMAC] Reception was successful\n");
    gnrc_lwmac_rx_stop(netif);
    /* Dispatch received packets, timing is not critical anymore */
    gnrc_mac_dispatch(&netif->mac.rx);

    /* Here we check if we are close to the end of the cycle. If yes,
     * go to sleep. Firstly, get the relative phase. */
    uint32_t phase = rtt_get_counter();
    if (phase < netif->mac.lwmac.last_wakeup) {
        phase = (RTT_US_TO_TICKS(GNRC_LWMAC_PHASE_MAX) - netif->mac.lwmac.last_wakeup) +
                phase;
    }
    else {
        phase = phase - netif->mac.lwmac.last_wakeup;
    }
    /* If the relative phase is beyond 4/5 cycle time, go to sleep. */
    if (phase > (4 * RTT_US_TO_TICKS(GNRC_LWMAC_WAKEUP_INTERVAL_US) / 5)) {
        gnrc_lwmac_set_quit_rx(netif, true);
    }

    if (gnrc_lwmac_get_quit_rx(netif)) {
        lwmac_set_state(netif, GNRC_LWMAC_SLEEPING);
    }
    else {
        /* Go back to LISTENING after successful reception */
        lwmac_set_state(netif, GNRC_LWMAC_LISTENING);
    }
}
Esempio n. 2
0
static void _rx_management_failed(gnrc_netif_t *netif)
{
    /* This may happen frequently because we'll receive WA from
     * every node in range. */
    LOG_DEBUG("[LWMAC] Reception was NOT successful\n");
    gnrc_lwmac_rx_stop(netif);

    if (netif->mac.rx.rx_bad_exten_count >= GNRC_LWMAC_MAX_RX_EXTENSION_NUM) {
        gnrc_lwmac_set_quit_rx(netif, true);
    }

    /* Here we check if we are close to the end of the cycle. If yes,
     * go to sleep. Firstly, get the relative phase. */
    uint32_t phase = rtt_get_counter();
    if (phase < netif->mac.lwmac.last_wakeup) {
        phase = (RTT_US_TO_TICKS(GNRC_LWMAC_PHASE_MAX) - netif->mac.lwmac.last_wakeup) +
                phase;
    }
    else {
        phase = phase - netif->mac.lwmac.last_wakeup;
    }
    /* If the relative phase is beyond 4/5 cycle time, go to sleep. */
    if (phase > (4 * RTT_US_TO_TICKS(GNRC_LWMAC_WAKEUP_INTERVAL_US) / 5)) {
        gnrc_lwmac_set_quit_rx(netif, true);
    }

    if (gnrc_lwmac_get_quit_rx(netif)) {
        lwmac_set_state(netif, GNRC_LWMAC_SLEEPING);
    }
    else {
        /* Go back to LISTENING for keep hearing on the channel */
        lwmac_set_state(netif, GNRC_LWMAC_LISTENING);
    }
}
Esempio n. 3
0
int rtc_get_time(struct tm *time)
{
    time_t t = (time_t)rtt_get_counter();

    gmtime_r(&t, time);

    return 0;
}
Esempio n. 4
0
static uint32_t _next_inphase_event(uint32_t last, uint32_t interval)
{
    /* Counter did overflow since last wakeup */
    if (rtt_get_counter() < last) {
        /* TODO: Not sure if this was tested :) */
        uint32_t tmp = -last;
        tmp /= interval;
        tmp++;
        last += tmp * interval;
    }

    /* Add margin to next wakeup so that it will be at least 2ms in the future */
    while (last < (rtt_get_counter() + GNRC_LWMAC_RTT_EVENT_MARGIN_TICKS)) {
        last += interval;
    }

    return last;
}
Esempio n. 5
0
void rtt_handler(uint32_t event, gnrc_netif_t *netif)
{
    uint32_t alarm;

    switch (event & 0xffff) {
        case GNRC_LWMAC_EVENT_RTT_WAKEUP_PENDING: {
            /* A new cycle starts, set sleep timing and initialize related MAC-info flags. */
            netif->mac.lwmac.last_wakeup = rtt_get_alarm();
            alarm = _next_inphase_event(netif->mac.lwmac.last_wakeup,
                                        RTT_US_TO_TICKS(GNRC_LWMAC_WAKEUP_DURATION_US));
            rtt_set_alarm(alarm, rtt_cb, (void *) GNRC_LWMAC_EVENT_RTT_SLEEP_PENDING);
            gnrc_lwmac_set_quit_tx(netif, false);
            gnrc_lwmac_set_quit_rx(netif, false);
            gnrc_lwmac_set_phase_backoff(netif, false);
            netif->mac.rx.rx_bad_exten_count = 0;
            lwmac_set_state(netif, GNRC_LWMAC_LISTENING);
            break;
        }
        case GNRC_LWMAC_EVENT_RTT_SLEEP_PENDING: {
            /* Set next wake-up timing. */
            alarm = _next_inphase_event(netif->mac.lwmac.last_wakeup,
                                        RTT_US_TO_TICKS(GNRC_LWMAC_WAKEUP_INTERVAL_US));
            rtt_set_alarm(alarm, rtt_cb, (void *) GNRC_LWMAC_EVENT_RTT_WAKEUP_PENDING);
            lwmac_set_state(netif, GNRC_LWMAC_SLEEPING);
            break;
        }
        /* Set initial wake-up alarm that starts the cycle */
        case GNRC_LWMAC_EVENT_RTT_START: {
            LOG_DEBUG("[LWMAC] RTT: Initialize duty cycling\n");
            alarm = rtt_get_counter() + RTT_US_TO_TICKS(GNRC_LWMAC_WAKEUP_DURATION_US);
            rtt_set_alarm(alarm, rtt_cb, (void *) GNRC_LWMAC_EVENT_RTT_SLEEP_PENDING);
            gnrc_lwmac_set_dutycycle_active(netif, true);
            break;
        }
        case GNRC_LWMAC_EVENT_RTT_STOP:
        case GNRC_LWMAC_EVENT_RTT_PAUSE: {
            rtt_clear_alarm();
            LOG_DEBUG("[LWMAC] RTT: Stop duty cycling, now in state %u\n",
                      netif->mac.lwmac.state);
            gnrc_lwmac_set_dutycycle_active(netif, false);
            break;
        }
        case GNRC_LWMAC_EVENT_RTT_RESUME: {
            LOG_DEBUG("[LWMAC] RTT: Resume duty cycling\n");
            rtt_clear_alarm();
            alarm = _next_inphase_event(netif->mac.lwmac.last_wakeup,
                                        RTT_US_TO_TICKS(GNRC_LWMAC_WAKEUP_INTERVAL_US));
            rtt_set_alarm(alarm, rtt_cb, (void *) GNRC_LWMAC_EVENT_RTT_WAKEUP_PENDING);
            gnrc_lwmac_set_dutycycle_active(netif, true);
            break;
        }
        default:
            break;
    }
}
Esempio n. 6
0
static void _lwmac_init(gnrc_netif_t *netif)
{
    netdev_t *dev;

    dev = netif->dev;
    dev->event_callback = _lwmac_event_cb;

    /* RTT is used for scheduling wakeup */
    rtt_init();

    /* Store pid globally, so that IRQ can use it to send msg */
    lwmac_pid = netif->pid;

    /* Enable RX- and TX-started interrupts  */
    netopt_enable_t enable = NETOPT_ENABLE;
    dev->driver->set(dev, NETOPT_RX_START_IRQ, &enable, sizeof(enable));
    dev->driver->set(dev, NETOPT_TX_START_IRQ, &enable, sizeof(enable));
    dev->driver->set(dev, NETOPT_TX_END_IRQ, &enable, sizeof(enable));

    uint16_t src_len = IEEE802154_LONG_ADDRESS_LEN;
    dev->driver->set(dev, NETOPT_SRC_LEN, &src_len, sizeof(src_len));

    /* Get own address from netdev */
    netif->l2addr_len = dev->driver->get(dev, NETOPT_ADDRESS_LONG,
                                         &netif->l2addr,
                                         IEEE802154_LONG_ADDRESS_LEN);

    /* Initialize broadcast sequence number. This at least differs from board
     * to board */
    netif->mac.tx.bcast_seqnr = netif->l2addr[0];

    /* Reset all timeouts just to be sure */
    gnrc_lwmac_reset_timeouts(netif);

    /* Start duty cycling */
    lwmac_set_state(netif, GNRC_LWMAC_START);

#if (GNRC_LWMAC_ENABLE_DUTYCYLE_RECORD == 1)
    /* Start duty cycle recording */
    netif->mac.lwmac.system_start_time_ticks = rtt_get_counter();
    netif->mac.lwmac.last_radio_on_time_ticks = netif->mac.lwmac.system_start_time_ticks;
    netif->mac.lwmac.awake_duration_sum_ticks = 0;
    netif->mac.lwmac.lwmac_info |= GNRC_LWMAC_RADIO_IS_ON;
#endif
}
Esempio n. 7
0
void gnrc_lwmac_tx_start(gnrc_netif_t *netif,
                         gnrc_pktsnip_t *pkt,
                         gnrc_mac_tx_neighbor_t *neighbor)
{
    assert(netif != NULL);
    assert(pkt != NULL);
    assert(neighbor != NULL);

    if (netif->mac.tx.packet) {
        LOG_WARNING("WARNING: [LWMAC-tx] Starting but tx.packet is still set\n");
        gnrc_pktbuf_release(netif->mac.tx.packet);
    }

    netif->mac.tx.packet = pkt;
    netif->mac.tx.current_neighbor = neighbor;
    netif->mac.tx.state = GNRC_LWMAC_TX_STATE_INIT;
    netif->mac.tx.wr_sent = 0;

#if (LWMAC_ENABLE_DUTYCYLE_RECORD == 1)
    netif->mac.prot.lwmac.pkt_start_sending_time_ticks = rtt_get_counter();
#endif
}
Esempio n. 8
0
static void _sleep_management(gnrc_netif_t *netif)
{
    /* If a packet is scheduled, no other (possible earlier) packet can be
     * sent before the first one is handled, even no broadcast
     */
    if (!gnrc_lwmac_timeout_is_running(netif, GNRC_LWMAC_TIMEOUT_WAIT_DEST_WAKEUP)) {
        gnrc_mac_tx_neighbor_t *neighbour;

        /* Check if there is packet remaining for retransmission */
        if (netif->mac.tx.current_neighbor != NULL) {
            neighbour = netif->mac.tx.current_neighbor;
        }
        else {
            /* Check if there are broadcasts to send and transmit immediately */
            if (gnrc_priority_pktqueue_length(&(netif->mac.tx.neighbors[0].queue)) > 0) {
                netif->mac.tx.current_neighbor = &(netif->mac.tx.neighbors[0]);
                lwmac_set_state(netif, GNRC_LWMAC_TRANSMITTING);
                return;
            }
            neighbour = _next_tx_neighbor(netif);
        }

        if (neighbour != NULL) {
            /* if phase is unknown, send immediately. */
            if (neighbour->phase > RTT_TICKS_TO_US(GNRC_LWMAC_WAKEUP_INTERVAL_US)) {
                netif->mac.tx.current_neighbor = neighbour;
                gnrc_lwmac_set_tx_continue(netif, false);
                netif->mac.tx.tx_burst_count = 0;
                lwmac_set_state(netif, GNRC_LWMAC_TRANSMITTING);
                return;
            }

            /* Offset in microseconds when the earliest (phase) destination
             * node wakes up that we have packets for. */
            uint32_t time_until_tx = RTT_TICKS_TO_US(_gnrc_lwmac_ticks_until_phase(neighbour->phase));

            /* If there's not enough time to prepare a WR to catch the phase
             * postpone to next interval */
            if (time_until_tx < GNRC_LWMAC_WR_PREPARATION_US) {
                time_until_tx += GNRC_LWMAC_WAKEUP_INTERVAL_US;
            }
            time_until_tx -= GNRC_LWMAC_WR_PREPARATION_US;

            /* add a random time before goto TX, for avoiding one node for
             * always holding the medium (if the receiver's phase is recorded earlier in this
             * particular node) */
            uint32_t random_backoff;
            random_backoff = random_uint32_range(0, GNRC_LWMAC_TIME_BETWEEN_WR_US);
            time_until_tx = time_until_tx + random_backoff;

            gnrc_lwmac_set_timeout(netif, GNRC_LWMAC_TIMEOUT_WAIT_DEST_WAKEUP, time_until_tx);

            /* Register neighbour to be the next */
            netif->mac.tx.current_neighbor = neighbour;

            /* Stop dutycycling, we're preparing to send. This prevents the
             * timeout arriving late, so that the destination phase would
             * be missed. */
            /* TODO: bad for power savings */
            rtt_handler(GNRC_LWMAC_EVENT_RTT_PAUSE, netif);
        }
    }
    else if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_WAIT_DEST_WAKEUP)) {
        LOG_DEBUG("[LWMAC] Got timeout for dest wakeup, ticks: %" PRIu32 "\n", rtt_get_counter());
        gnrc_lwmac_set_tx_continue(netif, false);
        netif->mac.tx.tx_burst_count = 0;
        lwmac_set_state(netif, GNRC_LWMAC_TRANSMITTING);
    }
}
Esempio n. 9
0
void lwmac_set_state(gnrc_netif_t *netif, gnrc_lwmac_state_t newstate)
{
    gnrc_lwmac_state_t oldstate = netif->mac.lwmac.state;

    if (newstate == oldstate) {
        return;
    }

    if (newstate >= GNRC_LWMAC_STATE_COUNT) {
        LOG_ERROR("ERROR: [LWMAC] Trying to set invalid state %u\n", newstate);
        return;
    }

    /* Already change state, but might be reverted to oldstate when needed */
    netif->mac.lwmac.state = newstate;

    /* Actions when leaving old state */
    switch (oldstate) {
        case GNRC_LWMAC_RECEIVING:
        case GNRC_LWMAC_TRANSMITTING: {
            /* Enable duty cycling again */
            rtt_handler(GNRC_LWMAC_EVENT_RTT_RESUME, netif);
#if (GNRC_LWMAC_ENABLE_DUTYCYLE_RECORD == 1)
            /* Output duty-cycle ratio */
            uint64_t duty;
            duty = (uint64_t) rtt_get_counter();
            duty = ((uint64_t) netif->mac.lwmac.awake_duration_sum_ticks) * 100 /
                   (duty - (uint64_t)netif->mac.lwmac.system_start_time_ticks);
            printf("[LWMAC]: achieved duty-cycle: %lu %% \n", (uint32_t)duty);
#endif
            break;
        }
        case GNRC_LWMAC_SLEEPING: {
            gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_WAKEUP_PERIOD);
            break;
        }
        default:
            break;
    }

    /* Actions when entering new state */
    switch (newstate) {
        /*********************** Operation states *********************************/
        case GNRC_LWMAC_LISTENING: {
            _gnrc_lwmac_set_netdev_state(netif, NETOPT_STATE_IDLE);
            break;
        }
        case GNRC_LWMAC_SLEEPING: {
            /* Put transceiver to sleep */
            _gnrc_lwmac_set_netdev_state(netif, NETOPT_STATE_SLEEP);
            /* We may have come here through RTT handler, so timeout may still be active */
            gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_WAKEUP_PERIOD);

            if (gnrc_lwmac_get_phase_backoff(netif)) {
                gnrc_lwmac_set_phase_backoff(netif, false);
                uint32_t alarm;

                rtt_clear_alarm();
                alarm = random_uint32_range(RTT_US_TO_TICKS((3 * GNRC_LWMAC_WAKEUP_DURATION_US / 2)),
                                            RTT_US_TO_TICKS(GNRC_LWMAC_WAKEUP_INTERVAL_US -
                                                            (3 * GNRC_LWMAC_WAKEUP_DURATION_US / 2)));
                LOG_WARNING("WARNING: [LWMAC] phase backoffed: %lu us\n", RTT_TICKS_TO_US(alarm));
                netif->mac.lwmac.last_wakeup = netif->mac.lwmac.last_wakeup + alarm;
                alarm = _next_inphase_event(netif->mac.lwmac.last_wakeup,
                                            RTT_US_TO_TICKS(GNRC_LWMAC_WAKEUP_INTERVAL_US));
                rtt_set_alarm(alarm, rtt_cb, (void *) GNRC_LWMAC_EVENT_RTT_WAKEUP_PENDING);
            }

            /* Return immediately, so no rescheduling */
            return;
        }
        /* Trying to send data */
        case GNRC_LWMAC_TRANSMITTING: {
            rtt_handler(GNRC_LWMAC_EVENT_RTT_PAUSE, netif);         /**< No duty cycling while RXing */
            _gnrc_lwmac_set_netdev_state(netif, NETOPT_STATE_IDLE); /**< Power up netdev */
            break;
        }
        /* Receiving incoming data */
        case GNRC_LWMAC_RECEIVING: {
            rtt_handler(GNRC_LWMAC_EVENT_RTT_PAUSE, netif);         /**< No duty cycling while TXing */
            _gnrc_lwmac_set_netdev_state(netif, NETOPT_STATE_IDLE); /**< Power up netdev */
            break;
        }
        case GNRC_LWMAC_STOPPED: {
            _gnrc_lwmac_set_netdev_state(netif, NETOPT_STATE_OFF);
            break;
        }
        /*********************** Control states ***********************************/
        case GNRC_LWMAC_START: {
            rtt_handler(GNRC_LWMAC_EVENT_RTT_START, netif);
            lwmac_set_state(netif, GNRC_LWMAC_LISTENING);
            break;
        }
        case GNRC_LWMAC_STOP: {
            rtt_handler(GNRC_LWMAC_EVENT_RTT_STOP, netif);
            lwmac_set_state(netif, GNRC_LWMAC_STOPPED);
            break;
        }
        case GNRC_LWMAC_RESET: {
            LOG_WARNING("WARNING: [LWMAC] Reset not yet implemented\n");
            lwmac_set_state(netif, GNRC_LWMAC_STOP);
            lwmac_set_state(netif, GNRC_LWMAC_START);
            break;
        }
        /**************************************************************************/
        default: {
            LOG_DEBUG("[LWMAC] No actions for entering state %u\n", newstate);
            return;
        }
    }

    lwmac_schedule_update(netif);
}
Esempio n. 10
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;
}