static void _cp_packet_process_data(gnrc_netif_t *netif, gnrc_gomach_packet_info_t *info, gnrc_pktsnip_t *pkt) { if (memcmp(&netif->l2addr, &info->dst_addr.addr, netif->l2addr_len) == 0) { /* The data is for itself, now update the sender's queue-length indicator. */ gnrc_gomach_indicator_update(netif, pkt, info); /* Check that whether this is a duplicate packet. */ if ((gnrc_gomach_check_duplicate(netif, info))) { gnrc_pktbuf_release(pkt); LOG_DEBUG("[GOMACH]: received a duplicate packet.\n"); return; } gnrc_gomach_dispatch_defer(netif->mac.rx.dispatch_buffer, pkt); gnrc_mac_dispatch(&netif->mac.rx); #if (GNRC_GOMACH_ENABLE_DUTYCYLE_RECORD == 1) /* Output radio duty-cycle ratio */ uint64_t duty; duty = xtimer_now_usec64(); duty = (netif->mac.prot.gomach.awake_duration_sum_ticks) * 100 / (duty - netif->mac.prot.gomach.system_start_time_ticks); printf("[GoMacH]: achieved radio duty-cycle: %lu %% \n", (uint32_t)duty); #endif } else { /* If the data is not for the device, release it. */ gnrc_pktbuf_release(pkt); } }
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); } }
static bool _wait_preamble_ack_data(gnrc_netif_t *netif, gnrc_gomach_packet_info_t *info, gnrc_pktsnip_t *pkt) { if (memcmp(&netif->l2addr, &info->dst_addr.addr, netif->l2addr_len) == 0) { /* The data is for itself, now update the sender's queue-length indicator. */ gnrc_gomach_indicator_update(netif, pkt, info); /* Check that whether this is a duplicate packet. */ if ((gnrc_gomach_check_duplicate(netif, info))) { gnrc_pktbuf_release(pkt); LOG_DEBUG("[GOMACH] t2u: received a duplicate packet.\n"); return false; } gnrc_gomach_dispatch_defer(netif->mac.rx.dispatch_buffer, pkt); gnrc_mac_dispatch(&netif->mac.rx); } else { /* If the data is not for the device, release it. */ gnrc_pktbuf_release(pkt); } return true; }
static uint8_t _packet_process_in_wait_for_wr(gnrc_netdev_t *gnrc_netdev) { uint8_t rx_info = 0; gnrc_pktsnip_t *pkt; assert(gnrc_netdev != 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); rx_info |= GNRC_LWMAC_RX_FOUND_BROADCAST; /* quit listening period to avoid receiving duplicate broadcast packets */ gnrc_netdev_lwmac_set_quit_rx(gnrc_netdev, true); /* quit TX in this cycle to avoid collisions with broadcast packets */ gnrc_netdev_lwmac_set_quit_tx(gnrc_netdev, true); break; } if (info.header->type != GNRC_LWMAC_FRAMETYPE_WR) { LOG_DEBUG("[LWMAC-rx] Packet is not WR: 0x%02x\n", info.header->type); gnrc_pktbuf_release(pkt); continue; } /* No need to keep pkt anymore */ gnrc_pktbuf_release(pkt); if (!(memcmp(&info.dst_addr.addr, &gnrc_netdev->l2_addr, gnrc_netdev->l2_addr_len) == 0)) { LOG_DEBUG("[LWMAC-rx] Packet is WR but not for us\n"); /* quit TX in this cycle to avoid collisions with other senders, since * found ongoing WR (preamble) stream */ gnrc_netdev_lwmac_set_quit_tx(gnrc_netdev, true); continue; } /* If reach here, the node gets a WR for itself. */ /* Save source address for later addressing */ gnrc_netdev->rx.l2_addr = info.src_addr; rx_info |= GNRC_LWMAC_RX_FOUND_WR; break; } return rx_info; }
static inline void _cp_packet_process_bcast(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt) { /* Receive a broadcast packet, quit the listening period to avoid receive duplicate * broadcast packet. */ gnrc_gomach_set_quit_cycle(netif, true); gnrc_gomach_dispatch_defer(netif->mac.rx.dispatch_buffer, pkt); gnrc_mac_dispatch(&netif->mac.rx); }
static void _lwmac_update_listening(gnrc_netif_t *netif) { /* In case has pending packet to send, clear rtt alarm thus to goto * transmission initialization (in SLEEPING management) right after the * listening period */ if ((_next_tx_neighbor(netif) != NULL) || (netif->mac.tx.current_neighbor != NULL)) { rtt_handler(GNRC_LWMAC_EVENT_RTT_PAUSE, netif); } /* Set timeout for if there's no successful rx transaction that will * change state to SLEEPING. */ if (!gnrc_lwmac_timeout_is_running(netif, GNRC_LWMAC_TIMEOUT_WAKEUP_PERIOD)) { gnrc_lwmac_set_timeout(netif, GNRC_LWMAC_TIMEOUT_WAKEUP_PERIOD, GNRC_LWMAC_WAKEUP_DURATION_US); } else if (gnrc_lwmac_timeout_is_expired(netif, GNRC_LWMAC_TIMEOUT_WAKEUP_PERIOD)) { /* Dispatch first as there still may be broadcast packets. */ gnrc_mac_dispatch(&netif->mac.rx); netif->mac.lwmac.state = GNRC_LWMAC_SLEEPING; /* Enable duty cycling again */ rtt_handler(GNRC_LWMAC_EVENT_RTT_RESUME, netif); _gnrc_lwmac_set_netdev_state(netif, NETOPT_STATE_SLEEP); gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_WAKEUP_PERIOD); /* if there is a packet for transmission, schedule update to start * transmission initialization immediately. */ gnrc_mac_tx_neighbor_t *neighbour = _next_tx_neighbor(netif); if ((neighbour != NULL) || (netif->mac.tx.current_neighbor != NULL)) { /* This triggers packet sending procedure in sleeping immediately. */ lwmac_schedule_update(netif); return; } } if (gnrc_priority_pktqueue_length(&netif->mac.rx.queue) > 0) { /* Do wake-up extension in each packet reception. */ gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_WAKEUP_PERIOD); lwmac_set_state(netif, GNRC_LWMAC_RECEIVING); } }
void gnrc_gomach_packet_process_in_vtdma(gnrc_netif_t *netif) { assert(netif != NULL); gnrc_pktsnip_t *pkt; gnrc_gomach_packet_info_t receive_packet_info; while ((pkt = gnrc_priority_pktqueue_pop(&netif->mac.rx.queue)) != NULL) { /* Parse the received packet. */ int res = _parse_packet(netif, pkt, &receive_packet_info); if (res != 0) { LOG_DEBUG("[GOMACH] vtdma: Packet could not be parsed: %i\n", res); gnrc_pktbuf_release(pkt); continue; } switch (receive_packet_info.header->type) { case GNRC_GOMACH_FRAME_DATA: { gnrc_gomach_indicator_update(netif, pkt, &receive_packet_info); if ((gnrc_gomach_check_duplicate(netif, &receive_packet_info))) { gnrc_pktbuf_release(pkt); LOG_DEBUG("[GOMACH] vtdma: received a duplicate packet.\n"); return; } gnrc_gomach_dispatch_defer(netif->mac.rx.dispatch_buffer, pkt); gnrc_mac_dispatch(&netif->mac.rx); break; } default: { gnrc_pktbuf_release(pkt); break; } } } }
static uint8_t _packet_process_in_wait_for_wa(gnrc_netif_t *netif) { assert(netif != NULL); uint8_t tx_info = 0; gnrc_pktsnip_t *pkt; bool found_wa = false; bool postponed = false; bool from_expected_destination = false; while ((pkt = gnrc_priority_pktqueue_pop(&netif->mac.rx.queue)) != NULL) { LOG_DEBUG("[LWMAC-tx] Inspecting pkt @ %p\n", pkt); /* Parse packet */ gnrc_lwmac_packet_info_t info; int ret = _gnrc_lwmac_parse_packet(pkt, &info); if (ret != 0) { LOG_DEBUG("[LWMAC-tx] Packet could not be parsed: %i\n", ret); gnrc_pktbuf_release(pkt); continue; } if (memcmp(&info.src_addr.addr, &netif->mac.tx.current_neighbor->l2_addr, netif->mac.tx.current_neighbor->l2_addr_len) == 0) { from_expected_destination = true; } if (info.header->type == GNRC_LWMAC_FRAMETYPE_BROADCAST) { _gnrc_lwmac_dispatch_defer(netif->mac.rx.dispatch_buffer, pkt); gnrc_mac_dispatch(&netif->mac.rx); /* Drop pointer to it can't get released */ pkt = NULL; continue; } /* Check if destination is talking to another node. It will sleep * after a finished transaction so there's no point in trying any * further now. */ if (!(memcmp(&info.dst_addr.addr, &netif->l2addr, netif->l2addr_len) == 0) && from_expected_destination) { 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; postponed = true; gnrc_pktbuf_release(pkt); break; } /* if found anther node is also trying to send data, * quit this cycle for collision avoidance. */ if (info.header->type == GNRC_LWMAC_FRAMETYPE_WR) { 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; postponed = true; gnrc_pktbuf_release(pkt); break; } if (info.header->type != GNRC_LWMAC_FRAMETYPE_WA) { LOG_DEBUG("[LWMAC-tx] Packet is not WA: 0x%02x\n", info.header->type); gnrc_pktbuf_release(pkt); continue; } if (from_expected_destination) { /* calculate the phase of the receiver based on WA */ netif->mac.tx.timestamp = _gnrc_lwmac_phase_now(); gnrc_lwmac_frame_wa_t *wa_hdr; wa_hdr = (gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_LWMAC))->data; if (netif->mac.tx.timestamp >= wa_hdr->current_phase) { netif->mac.tx.timestamp = netif->mac.tx.timestamp - wa_hdr->current_phase; } else { netif->mac.tx.timestamp += RTT_US_TO_TICKS(GNRC_LWMAC_WAKEUP_INTERVAL_US); netif->mac.tx.timestamp -= wa_hdr->current_phase; } uint32_t own_phase; own_phase = _gnrc_lwmac_ticks_to_phase(netif->mac.prot.lwmac.last_wakeup); if (own_phase >= netif->mac.tx.timestamp) { own_phase = own_phase - netif->mac.tx.timestamp; } else { own_phase = netif->mac.tx.timestamp - own_phase; } if ((own_phase < RTT_US_TO_TICKS((3 * GNRC_LWMAC_WAKEUP_DURATION_US / 2))) || (own_phase > RTT_US_TO_TICKS(GNRC_LWMAC_WAKEUP_INTERVAL_US - (3 * GNRC_LWMAC_WAKEUP_DURATION_US / 2)))) { gnrc_lwmac_set_phase_backoff(netif, true); LOG_WARNING("WARNING: [LWMAC-tx] phase close\n"); } } /* No need to keep pkt anymore */ gnrc_pktbuf_release(pkt); if (!from_expected_destination) { LOG_DEBUG("[LWMAC-tx] Packet is not from expected destination\n"); break; } /* All checks passed so this must be a valid WA */ gnrc_lwmac_clear_timeout(netif, GNRC_LWMAC_TIMEOUT_WR); found_wa = true; break; } if (postponed) { LOG_INFO("[LWMAC-tx] Destination is talking to another node, postpone\n"); tx_info |= GNRC_LWMAC_TX_FAIL; return tx_info; } if (!found_wa) { LOG_DEBUG("[LWMAC-tx] No WA yet\n"); return tx_info; } /* Save newly calculated phase for destination */ netif->mac.tx.current_neighbor->phase = netif->mac.tx.timestamp; LOG_INFO("[LWMAC-tx] New phase: %" PRIu32 "\n", netif->mac.tx.timestamp); /* We've got our WA, so discard the rest, TODO: no flushing */ gnrc_priority_pktqueue_flush(&netif->mac.rx.queue); tx_info |= GNRC_LWMAC_TX_SUCCESS; return tx_info; }
void gnrc_gomach_packet_process_in_wait_beacon(gnrc_netif_t *netif) { assert(netif != NULL); gnrc_pktsnip_t *pkt; gnrc_gomach_packet_info_t receive_packet_info; while ((pkt = gnrc_priority_pktqueue_pop(&netif->mac.rx.queue)) != NULL) { /* Parse the received packet. */ int res = _parse_packet(netif, pkt, &receive_packet_info); if (res != 0) { LOG_DEBUG("[GOMACH] t2k: Packet could not be parsed: %i\n", res); gnrc_pktbuf_release(pkt); continue; } switch (receive_packet_info.header->type) { case GNRC_GOMACH_FRAME_BEACON: { if (memcmp(&netif->mac.tx.current_neighbor->l2_addr, &receive_packet_info.src_addr.addr, netif->mac.tx.current_neighbor->l2_addr_len) == 0) { gnrc_gomach_clear_timeout(netif, GNRC_GOMACH_TIMEOUT_WAIT_BEACON); gnrc_gomach_beacon_process(netif, pkt); } gnrc_pktbuf_release(pkt); break; } case GNRC_GOMACH_FRAME_PREAMBLE: { /* Release preamble packet no matter the preamble is for it or not, * and quit the t2k procedure. */ gnrc_gomach_set_quit_cycle(netif, true); gnrc_pktbuf_release(pkt); break; } case GNRC_GOMACH_FRAME_DATA: { /* It is unlikely that we will received a data for us here. * This means the device' CP is close with its destination's. */ if (memcmp(&netif->l2addr, &receive_packet_info.dst_addr.addr, netif->l2addr_len) == 0) { gnrc_gomach_indicator_update(netif, pkt, &receive_packet_info); if ((gnrc_gomach_check_duplicate(netif, &receive_packet_info))) { gnrc_pktbuf_release(pkt); LOG_DEBUG("[GOMACH]: received a duplicate packet.\n"); return; } gnrc_gomach_dispatch_defer(netif->mac.rx.dispatch_buffer, pkt); gnrc_mac_dispatch(&netif->mac.rx); } else { gnrc_pktbuf_release(pkt); } break; } case GNRC_GOMACH_FRAME_BROADCAST: { gnrc_gomach_set_quit_cycle(netif, true); gnrc_pktbuf_release(pkt); break; } default: { gnrc_pktbuf_release(pkt); break; } } } }
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; }