From 5d5dcfa0b98c1b3b237a326176d9de9655489f82 Mon Sep 17 00:00:00 2001 From: Lukasz Maciejonczyk Date: Wed, 27 Apr 2022 09:11:45 +0200 Subject: [PATCH] drivers: ieee802154_nrf5: fix target time for indirect transmission After change in RD into 64-bit time, target time must be express in absolute 64-bit time. Upper layer e.g. OpenThread still utilizes only LSB of the RD time therefore the conversion is required. Make sure that target time is absolute 64-bit target time. Signed-off-by: Lukasz Maciejonczyk --- drivers/ieee802154/ieee802154_nrf5.c | 136 +++++++++++++-------------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 18112af4f6b..c64f67de4f1 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -465,6 +465,73 @@ static bool nrf5_tx_csma_ca(struct net_pkt *pkt, uint8_t *payload) #endif #if IS_ENABLED(CONFIG_NET_PKT_TXTIME) +/** + * @brief Convert 32-bit target time to absolute 64-bit target time. + */ +static uint64_t target_time_convert_to_64_bits(uint32_t target_time) +{ + /** + * Target time is provided as two 32-bit integers defining a moment in time + * in microsecond domain. In order to use bit-shifting instead of modulo + * division, calculations are performed in microsecond domain, not in RTC ticks. + * + * The target time can point to a moment in the future, but can be overdue + * as well. In order to determine what's the case and correctly set the + * absolute target time, it's necessary to compare the least significant + * 32 bits of the current time, 64-bit time with the provided 32-bit target + * time. Let's assume that half of the 32-bit range can be used for specifying + * target times in the future, and the other half - in the past. + */ + uint64_t now_us = nrf_802154_time_get(); + uint32_t now_us_wrapped = (uint32_t)now_us; + uint32_t time_diff = target_time - now_us_wrapped; + uint64_t result = UINT64_C(0); + + if (time_diff < 0x80000000) { + /** + * Target time is assumed to be in the future. Check if a 32-bit overflow + * occurs between the current time and the target time. + */ + if (now_us_wrapped > target_time) { + /** + * Add a 32-bit overflow and replace the least significant 32 bits + * with the provided target time. + */ + result = now_us + UINT32_MAX + 1; + result &= ~(uint64_t)UINT32_MAX; + result |= target_time; + } else { + /** + * Leave the most significant 32 bits and replace the least significant + * 32 bits with the provided target time. + */ + result = (now_us & (~(uint64_t)UINT32_MAX)) | target_time; + } + } else { + /** + * Target time is assumed to be in the past. Check if a 32-bit overflow + * occurs between the target time and the current time. + */ + if (now_us_wrapped > target_time) { + /** + * Leave the most significant 32 bits and replace the least significant + * 32 bits with the provided target time. + */ + result = (now_us & (~(uint64_t)UINT32_MAX)) | target_time; + } else { + /** + * Subtract a 32-bit overflow and replace the least significant + * 32 bits with the provided target time. + */ + result = now_us - UINT32_MAX - 1; + result &= ~(uint64_t)UINT32_MAX; + result |= target_time; + } + } + + return result; +} + static bool nrf5_tx_at(struct net_pkt *pkt, uint8_t *payload, bool cca) { nrf_802154_transmit_at_metadata_t metadata = { @@ -475,7 +542,7 @@ static bool nrf5_tx_at(struct net_pkt *pkt, uint8_t *payload, bool cca) .cca = cca, .channel = nrf_802154_channel_get(), }; - uint64_t tx_at = net_pkt_txtime(pkt) / NSEC_PER_USEC; + uint64_t tx_at = target_time_convert_to_64_bits(net_pkt_txtime(pkt) / NSEC_PER_USEC); bool ret; ret = nrf_802154_transmit_raw_at(payload, @@ -737,73 +804,6 @@ static void nrf5_config_mac_keys(struct ieee802154_key *mac_keys) #endif /* CONFIG_IEEE802154_2015 */ #if defined(CONFIG_IEEE802154_CSL_ENDPOINT) -/** - * @brief Convert 32-bit target time to absolute 64-bit target time. - */ -static uint64_t target_time_convert_to_64_bits(uint32_t target_time) -{ - /** - * Target time is provided as two 32-bit integers defining a moment in time - * in microsecond domain. In order to use bit-shifting instead of modulo - * division, calculations are performed in microsecond domain, not in RTC ticks. - * - * The target time can point to a moment in the future, but can be overdue - * as well. In order to determine what's the case and correctly set the - * absolute target time, it's necessary to compare the least significant - * 32 bits of the current time, 64-bit time with the provided 32-bit target - * time. Let's assume that half of the 32-bit range can be used for specifying - * target times in the future, and the other half - in the past. - */ - uint64_t now_us = nrf_802154_time_get(); - uint32_t now_us_wrapped = (uint32_t)now_us; - uint32_t time_diff = target_time - now_us_wrapped; - uint64_t result = UINT64_C(0); - - if (time_diff < 0x80000000) { - /** - * Target time is assumed to be in the future. Check if a 32-bit overflow - * occurs between the current time and the target time. - */ - if (now_us_wrapped > target_time) { - /** - * Add a 32-bit overflow and replace the least significant 32 bits - * with the provided target time. - */ - result = now_us + UINT32_MAX + 1; - result &= ~(uint64_t)UINT32_MAX; - result |= target_time; - } else { - /** - * Leave the most significant 32 bits and replace the least significant - * 32 bits with the provided target time. - */ - result = (now_us & (~(uint64_t)UINT32_MAX)) | target_time; - } - } else { - /** - * Target time is assumed to be in the past. Check if a 32-bit overflow - * occurs between the target time and the current time. - */ - if (now_us_wrapped > target_time) { - /** - * Leave the most significant 32 bits and replace the least significant - * 32 bits with the provided target time. - */ - result = (now_us & (~(uint64_t)UINT32_MAX)) | target_time; - } else { - /** - * Subtract a 32-bit overflow and replace the least significant - * 32 bits with the provided target time. - */ - result = now_us - UINT32_MAX - 1; - result &= ~(uint64_t)UINT32_MAX; - result |= target_time; - } - } - - return result; -} - static void nrf5_receive_at(uint32_t start, uint32_t duration, uint8_t channel, uint32_t id) { /*