diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 6df2367cebf..572c41e578b 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -256,6 +256,49 @@ static int nrf5_set_txpower(struct device *dev, s16_t dbm) return 0; } +static int handle_ack(struct nrf5_802154_data *nrf5_radio) +{ + u8_t ack_len = nrf5_radio->ack_frame.psdu[0] - NRF5_FCS_LENGTH; + struct net_pkt *ack_pkt; + int err = 0; + + ack_pkt = net_pkt_alloc_with_buffer(nrf5_radio->iface, ack_len, + AF_UNSPEC, 0, K_NO_WAIT); + if (!ack_pkt) { + LOG_ERR("No free packet available."); + err = -ENOMEM; + goto free_nrf_ack; + } + + /* Upper layers expect the frame to start at the MAC header, skip the + * PHY header (1 byte). + */ + if (net_pkt_write(ack_pkt, nrf5_radio->ack_frame.psdu + 1, + ack_len) < 0) { + LOG_ERR("Failed to write to a packet."); + err = -ENOMEM; + goto free_net_ack; + } + + net_pkt_set_ieee802154_lqi(ack_pkt, nrf5_radio->ack_frame.lqi); + net_pkt_set_ieee802154_rssi(ack_pkt, nrf5_radio->ack_frame.rssi); + + net_pkt_cursor_init(ack_pkt); + + if (ieee802154_radio_handle_ack(nrf5_radio->iface, ack_pkt) != NET_OK) { + LOG_INF("ACK packet not handled - releasing."); + } + +free_net_ack: + net_pkt_unref(ack_pkt); + +free_nrf_ack: + nrf_802154_buffer_free_raw(nrf5_radio->ack_frame.psdu); + nrf5_radio->ack_frame.psdu = NULL; + + return err; +} + static int nrf5_tx(struct device *dev, struct net_pkt *pkt, struct net_buf *frag) @@ -294,14 +337,13 @@ static int nrf5_tx(struct device *dev, LOG_DBG("Result: %d", nrf5_data.tx_result); if (nrf5_radio->tx_result == NRF_802154_TX_ERROR_NONE) { - /* ACK frame not used currently. */ - if (nrf5_radio->ack != NULL) { - nrf_802154_buffer_free_raw(nrf5_radio->ack); + if (nrf5_radio->ack_frame.psdu == NULL) { + /* No ACK was requested. */ + return 0; } - nrf5_radio->ack = NULL; - - return 0; + /* Handle ACK packet. */ + return handle_ack(nrf5_radio); } return -EIO; @@ -466,7 +508,9 @@ void nrf_802154_transmitted_raw(const uint8_t *frame, uint8_t *ack, ARG_UNUSED(lqi); nrf5_data.tx_result = NRF_802154_TX_ERROR_NONE; - nrf5_data.ack = ack; + nrf5_data.ack_frame.psdu = ack; + nrf5_data.ack_frame.rssi = power; + nrf5_data.ack_frame.lqi = lqi; k_sem_give(&nrf5_data.tx_wait); } diff --git a/drivers/ieee802154/ieee802154_nrf5.h b/drivers/ieee802154/ieee802154_nrf5.h index a61f1986637..a469d6b320b 100644 --- a/drivers/ieee802154/ieee802154_nrf5.h +++ b/drivers/ieee802154/ieee802154_nrf5.h @@ -61,10 +61,10 @@ struct nrf5_802154_data { /* TX result, updated in radio transmit callbacks. */ u8_t tx_result; - /* A pointer to the received ACK frame. May be NULL if no ACK was - * requested/received. + /* A buffer for the received ACK frame. psdu pointer be NULL if no + * ACK was requested/received. */ - u8_t *ack; + struct nrf5_802154_rx_frame ack_frame; }; #endif /* ZEPHYR_DRIVERS_IEEE802154_IEEE802154_NRF5_H_ */