@@ -33,6 +33,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_OPENTHREAD_L2_LOG_LEVEL);
33
33
#include <openthread/instance.h>
34
34
#include <openthread/platform/radio.h>
35
35
#include <openthread/platform/diag.h>
36
+ #include <openthread/platform/time.h>
36
37
#include <openthread/message.h>
37
38
38
39
#include "platform-zephyr.h"
@@ -237,6 +238,84 @@ void handle_radio_event(const struct device *dev, enum ieee802154_event evt,
237
238
}
238
239
}
239
240
241
+ #if defined(CONFIG_NET_PKT_TXTIME ) || defined(CONFIG_OPENTHREAD_CSL_RECEIVER )
242
+ /**
243
+ * @brief Convert 32-bit (potentially wrapped) OpenThread microsecond timestamps
244
+ * to 64-bit Zephyr network subsystem nanosecond timestamps.
245
+ *
246
+ * This is a workaround until OpenThread is able to schedule 64-bit RX/TX time.
247
+ *
248
+ * @param target_time_ns_wrapped time in nanoseconds referred to the radio clock
249
+ * modulo UINT32_MAX.
250
+ *
251
+ * @return 64-bit nanosecond timestamp
252
+ */
253
+ static net_time_t convert_32bit_us_wrapped_to_64bit_ns (uint32_t target_time_us_wrapped )
254
+ {
255
+ /**
256
+ * OpenThread provides target time as a (potentially wrapped) 32-bit
257
+ * integer defining a moment in time in the microsecond domain.
258
+ *
259
+ * The target time can point to a moment in the future, but can be
260
+ * overdue as well. In order to determine what's the case and correctly
261
+ * set the absolute (non-wrapped) target time, it's necessary to compare
262
+ * the least significant 32 bits of the current 64-bit network subsystem
263
+ * time with the provided 32-bit target time. Let's assume that half of
264
+ * the 32-bit range can be used for specifying target times in the
265
+ * future, and the other half - in the past.
266
+ */
267
+ uint64_t now_us = otPlatTimeGet ();
268
+ uint32_t now_us_wrapped = (uint32_t )now_us ;
269
+ uint32_t time_diff = target_time_us_wrapped - now_us_wrapped ;
270
+ uint64_t result = UINT64_C (0 );
271
+
272
+ if (time_diff < 0x80000000 ) {
273
+ /**
274
+ * Target time is assumed to be in the future. Check if a 32-bit overflow
275
+ * occurs between the current time and the target time.
276
+ */
277
+ if (now_us_wrapped > target_time_us_wrapped ) {
278
+ /**
279
+ * Add a 32-bit overflow and replace the least significant 32 bits
280
+ * with the provided target time.
281
+ */
282
+ result = now_us + UINT32_MAX + 1 ;
283
+ result &= ~(uint64_t )UINT32_MAX ;
284
+ result |= target_time_us_wrapped ;
285
+ } else {
286
+ /**
287
+ * Leave the most significant 32 bits and replace the least significant
288
+ * 32 bits with the provided target time.
289
+ */
290
+ result = (now_us & (~(uint64_t )UINT32_MAX )) | target_time_us_wrapped ;
291
+ }
292
+ } else {
293
+ /**
294
+ * Target time is assumed to be in the past. Check if a 32-bit overflow
295
+ * occurs between the target time and the current time.
296
+ */
297
+ if (now_us_wrapped > target_time_us_wrapped ) {
298
+ /**
299
+ * Leave the most significant 32 bits and replace the least significant
300
+ * 32 bits with the provided target time.
301
+ */
302
+ result = (now_us & (~(uint64_t )UINT32_MAX )) | target_time_us_wrapped ;
303
+ } else {
304
+ /**
305
+ * Subtract a 32-bit overflow and replace the least significant
306
+ * 32 bits with the provided target time.
307
+ */
308
+ result = now_us - UINT32_MAX - 1 ;
309
+ result &= ~(uint64_t )UINT32_MAX ;
310
+ result |= target_time_us_wrapped ;
311
+ }
312
+ }
313
+
314
+ __ASSERT_NO_MSG (result <= INT64_MAX / NSEC_PER_USEC );
315
+ return (net_time_t )result * NSEC_PER_USEC ;
316
+ }
317
+ #endif /* CONFIG_NET_PKT_TXTIME || CONFIG_OPENTHREAD_CSL_RECEIVER */
318
+
240
319
static void dataInit (void )
241
320
{
242
321
tx_pkt = net_pkt_alloc (K_NO_WAIT );
@@ -315,11 +394,13 @@ void transmit_message(struct k_work *tx_job)
315
394
316
395
if ((radio_api -> get_capabilities (radio_dev ) & IEEE802154_HW_TXTIME ) &&
317
396
(sTransmitFrame .mInfo .mTxInfo .mTxDelay != 0 )) {
318
- uint64_t tx_at = sTransmitFrame .mInfo .mTxInfo .mTxDelayBaseTime +
397
+ #if defined(CONFIG_NET_PKT_TXTIME )
398
+ uint32_t tx_at = sTransmitFrame .mInfo .mTxInfo .mTxDelayBaseTime +
319
399
sTransmitFrame .mInfo .mTxInfo .mTxDelay ;
320
- struct net_ptp_time timestamp = ns_to_net_ptp_time ( tx_at * NSEC_PER_USEC );
321
-
400
+ struct net_ptp_time timestamp =
401
+ ns_to_net_ptp_time ( convert_32bit_us_wrapped_to_64bit_ns ( tx_at ));
322
402
net_pkt_set_timestamp (tx_pkt , & timestamp );
403
+ #endif
323
404
tx_err =
324
405
radio_api -> tx (radio_dev , IEEE802154_TX_MODE_TXTIME_CCA , tx_pkt , tx_payload );
325
406
} else if (sTransmitFrame .mInfo .mTxInfo .mCsmaCaEnabled ) {
@@ -666,7 +747,7 @@ otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel,
666
747
667
748
struct ieee802154_config config = {
668
749
.rx_slot .channel = aChannel ,
669
- .rx_slot .start = ( net_time_t ) aStart * NSEC_PER_USEC ,
750
+ .rx_slot .start = convert_32bit_us_wrapped_to_64bit_ns ( aStart ) ,
670
751
.rx_slot .duration = (net_time_t )aDuration * NSEC_PER_USEC ,
671
752
};
672
753
@@ -1195,7 +1276,8 @@ void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, uint32_t aCslSampleTi
1195
1276
{
1196
1277
ARG_UNUSED (aInstance );
1197
1278
1198
- struct ieee802154_config config = { .csl_rx_time = aCslSampleTime * NSEC_PER_USEC };
1279
+ struct ieee802154_config config = {
1280
+ .csl_rx_time = convert_32bit_us_wrapped_to_64bit_ns (aCslSampleTime )};
1199
1281
1200
1282
(void )radio_api -> configure (radio_dev , IEEE802154_CONFIG_CSL_RX_TIME , & config );
1201
1283
}
0 commit comments