-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathranging.c
685 lines (590 loc) · 18.3 KB
/
ranging.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
/*
* libdeca - UWB Library for Qorvo/Decawave DW3000
*
* Copyright (C) 2016 - 2024 Bruno Randolf (br@einfach.org)
*
* This source code is licensed under the GNU Lesser General Public License,
* Version 3. See the file LICENSE.txt for more details.
*/
#include <math.h>
#include <stdlib.h>
#ifdef __ZEPHYR__
#include <zephyr/random/random.h>
#endif
#include "dwhw.h"
#include "dwmac.h"
#include "dwphy.h"
#include "dwproto.h"
#include "dwtime.h"
#include "dwutil.h"
#include "log.h"
#include "mac802154.h"
#include "ranging.h"
#define TWR_DEBUG_CALCULATION 0
#define TWR_MAX_RETRY 3
#define TWR_RETRY_DELAY 20 /* random with this maximum in ms */
#define TWR_SPI_US_PER_BYTE 2.3 /* TODO: measured with 8MHz DMA for 12 byte */
/*
* TWR Message definitions
*/
#define TWR_MSG_INIT 0x20
#define TWR_MSG_POLL 0x21
#define TWR_MSG_RESP 0x22
#define TWR_MSG_SSPOLL 0x23
#define TWR_MSG_SSRESP 0x24
#define TWR_MSG_FINA 0x29
#define TWR_MSG_REPO 0x2A
struct twr_msg_final {
uint32_t round;
uint32_t delay;
uint16_t cnum; // sequence number / TWR ID
} __attribute__((packed));
struct twr_msg_ss_resp {
uint32_t poll_rx_ts;
uint32_t resp_tx_ts;
} __attribute__((packed));
struct twr_msg_report {
uint16_t cnum; // sequence number / TWR ID
uint16_t dist;
} __attribute__((packed));
#ifndef __ZEPHYR__
static const char* LOG_TAG = "TWR";
#endif
/* calculated in init */
static uint64_t twr_delay_dtu;
static uint32_t twr_rx_delay; // UUS
static uint16_t twr_pto;
static bool twr_send_report;
/* state */
static twr_cb_t twr_observer_cb;
static uint64_t twr_dst;
static uint16_t twr_cnum = 0;
static bool single_sided = false;
static uint8_t expected_msg = 0;
static int retry = 0;
static bool in_progress = false;
static uint64_t last_poll_rx_ts;
static void twr_retry(void);
static void twr_handle_timeout(uint32_t status);
static void twr_handle_result(uint64_t src, uint64_t dst, uint16_t dist,
uint16_t cnum, bool reported, bool initiator);
static uint64_t twr_my_mac(uint64_t other_addr)
{
if (IS_SHORT_ADDR(other_addr)) {
return dwmac_get_mac16();
} else {
return dwmac_get_mac64();
}
}
/*
* TWR messages
*/
/* TAG -> ANCOR */
static bool twr_send_poll(uint64_t ancor)
{
struct txbuf* tx = dwmac_txbuf_get();
if (tx == NULL)
return false;
dwprot_prepare(tx, 0, single_sided ? TWR_MSG_SSPOLL : TWR_MSG_POLL, ancor);
dwmac_tx_set_ranging(tx);
dwmac_tx_expect_response(tx, twr_rx_delay);
dwmac_tx_set_preamble_timeout(tx, twr_pto);
dwmac_tx_set_timeout_handler(tx, twr_handle_timeout);
bool res = dwmac_transmit(tx);
if (res) {
DBG_UWB("Sent Poll to " LADDR_FMT, LADDR_PAR(ancor));
expected_msg = single_sided ? TWR_MSG_SSRESP : TWR_MSG_RESP;
} else {
LOG_ERR("Failed to send Poll to " LADDR_FMT, LADDR_PAR(ancor));
twr_retry();
}
return res;
}
/* ANCOR -> TAG */
static bool twr_send_response(uint64_t tag, uint64_t poll_rx_ts)
{
struct txbuf* tx = dwmac_txbuf_get();
if (tx == NULL) {
return false;
}
last_poll_rx_ts = poll_rx_ts;
uint64_t resp_tx_time = poll_rx_ts + twr_delay_dtu;
dwprot_prepare(tx, 0, TWR_MSG_RESP, tag);
dwmac_tx_set_ranging(tx);
dwmac_tx_expect_response(tx, twr_rx_delay);
dwmac_tx_set_preamble_timeout(tx, twr_pto);
dwmac_tx_set_txtime(tx, resp_tx_time);
bool res = dwmac_transmit(tx);
if (res) {
DBG_UWB("Sent Response to " LADDR_FMT " after %dus", LADDR_PAR(tag),
(int)DTU_TO_US(resp_tx_time - poll_rx_ts));
expected_msg = TWR_MSG_FINA;
} else {
LOG_ERR("Failed to send Response to " LADDR_FMT, LADDR_PAR(tag));
LOG_INF_TS("rx_ts", poll_rx_ts);
LOG_INF_TS("tx_ts", resp_tx_time);
LOG_INF_TS("delay", twr_delay_dtu);
expected_msg = 0;
}
return res;
}
/* ANCOR -> TAG */
static bool twr_send_ss_response(uint64_t tag, uint64_t poll_rx_ts)
{
struct txbuf* tx = dwmac_txbuf_get();
if (tx == NULL) {
return false;
}
/* Delayed TX time has a 8ns resolution because the last 9 bit of the
* DTU are ignored when programming the delayed TX time. We need to do
* the same in the calculated TX time */
uint64_t resp_tx_time = (poll_rx_ts + twr_delay_dtu) & DTU_DELAYEDTRX_MASK;
struct twr_msg_ss_resp* msg = dwprot_prepare(
tx, sizeof(struct twr_msg_ss_resp), TWR_MSG_SSRESP, tag);
msg->poll_rx_ts = (uint32_t)poll_rx_ts;
msg->resp_tx_ts = (uint32_t)(resp_tx_time + DWPHY_ANTENNA_DELAY);
dwmac_tx_set_ranging(tx);
dwmac_tx_set_txtime(tx, resp_tx_time);
bool res = dwmac_transmit(tx);
if (res) {
DBG_UWB("Sent SS Response to " LADDR_FMT " after %dus", LADDR_PAR(tag),
(int)DTU_TO_US(resp_tx_time - poll_rx_ts));
// LOG_DBG_TS("\tPoll RX TS:\t", poll_rx_ts);
// LOG_DBG_TS("\tResp TX TS:\t", resp_tx_time);
expected_msg = 0;
} else {
LOG_ERR("Failed to send Response to " LADDR_FMT, LADDR_PAR(tag));
expected_msg = 0;
}
return res;
}
/* TAG -> ANCOR */
static bool twr_send_final(uint64_t ancor, uint64_t resp_rx_ts)
{
struct txbuf* tx = dwmac_txbuf_get();
if (tx == NULL) {
return false;
}
uint64_t poll_tx_ts = dw_get_tx_timestamp();
/* Delayed TX time has a 8ns resolution because the last 9 bit of the
* DTU are ignored when programming the delayed TX time. We need to do
* the same in the calculated TX time */
uint64_t final_tx_time = (resp_rx_ts + twr_delay_dtu) & DTU_DELAYEDTRX_MASK;
/* Final TX timestamp is the transmission time we programmed plus the TX
* antenna delay. */
uint64_t final_tx_ts = (final_tx_time + DWPHY_ANTENNA_DELAY) & DTU_MASK;
struct twr_msg_final* final_msg
= dwprot_prepare(tx, sizeof(struct twr_msg_final), TWR_MSG_FINA, ancor);
final_msg->cnum = twr_cnum;
final_msg->round = resp_rx_ts - poll_tx_ts;
final_msg->delay = final_tx_ts - resp_rx_ts;
dwmac_tx_set_ranging(tx);
dwmac_tx_set_txtime(tx, final_tx_time);
if (twr_send_report) {
dwmac_tx_expect_response(tx, twr_rx_delay);
dwmac_tx_set_preamble_timeout(tx, twr_pto);
dwmac_tx_set_timeout_handler(tx, twr_handle_timeout);
}
bool res = dwmac_transmit(tx);
if (res) {
DBG_UWB("Sent Final to " LADDR_FMT " after %dus", LADDR_PAR(ancor),
(int)DTU_TO_US(final_tx_time - resp_rx_ts));
// LOG_DBG_TS("\tPoll TX TS:\t", poll_tx_ts);
// LOG_DBG_TS("\tResp RX TS:\t", resp_rx_ts);
// LOG_DBG_TS("\tFina TX TS:\t", final_tx_time);
expected_msg = twr_send_report ? TWR_MSG_REPO : 0;
} else {
LOG_ERR("Failed to send Final");
twr_retry();
}
if (!twr_send_report) {
/* if reports are not sent by the other side, we assume everything is OK
* if the final message was sent. We don't know the distance, so we
* just record "OK" */
twr_handle_result(twr_my_mac(ancor), ancor, TWR_OK_VALUE, twr_cnum,
false, true);
in_progress = false;
}
return res;
}
/* ANCOR -> TAG */
static bool twr_send_report_msg(uint64_t tag, uint16_t dist, uint16_t cnum,
uint64_t final_rx_ts)
{
struct txbuf* tx = dwmac_txbuf_get();
if (tx == NULL) {
return false;
}
expected_msg = 0;
struct twr_msg_report* msg
= dwprot_prepare(tx, sizeof(struct twr_msg_report), TWR_MSG_REPO, tag);
msg->cnum = cnum;
msg->dist = dist;
uint64_t rep_tx_time = (final_rx_ts + twr_delay_dtu) & DTU_DELAYEDTRX_MASK;
dwmac_tx_set_txtime(tx, rep_tx_time);
bool res = dwmac_transmit(tx);
LOG_TX_RES(res, "Report to " LADDR_FMT ": distance %u cm", LADDR_PAR(tag),
dist);
// we have been the destination of this TWR sequence
twr_handle_result(tag, twr_my_mac(tag), dist, cnum, false, false);
return res;
}
/*
* Distance calculation
*/
static uint16_t twr_fixup_distance(int dist)
{
if (dist <= -100 || dist > TWR_FAILED_VALUE) { // out of range: -1m - 655m
return TWR_FAILED_VALUE;
} else if (dist < 0) {
/* distance will be unsigned 16 bit from now on, but we allow
* for a negative result up to 1m to be "equal" to 0 */
return 0;
} else {
return dist;
}
}
double twr_distance_calculation_dtu(uint32_t poll_rx_ts, uint32_t resp_tx_ts,
uint32_t final_rx_ts, uint32_t Ra,
uint32_t Da)
{
/* 32 bit is enough for the timestamps themselves, but since we multiply
* them below we need a larger data type. Having one with 64 bit will
* automatically upgrade the others */
int64_t Rb = final_rx_ts - resp_tx_ts;
int64_t Db = resp_tx_ts - poll_rx_ts;
/* This formula comes from the decawave documentation and source code
* A proof of it can be found here:
* https://forum.bitcraze.io/viewtopic.php?t=1944 */
double tof_dtu = (double)(Ra * Rb - Da * Db) / (Ra + Rb + Da + Db);
if (TWR_DEBUG_CALCULATION) {
LOG_DBG("Poll RX TS:\t%" PRIu32, poll_rx_ts);
LOG_DBG("Resp TX TS:\t%" PRIu32, resp_tx_ts);
LOG_DBG("Fina RX TS:\t%" PRIu32, final_rx_ts);
LOG_DBG("round1 (Ra)*:\t%" PRIu32, Ra);
LOG_DBG("round2 (Rb):\t%" PRIu32, (uint32_t)Rb);
LOG_DBG("reply1 (Da)*:\t%" PRIu32, Da);
LOG_DBG("reply2 (Db):\t%" PRIu32, (uint32_t)Db);
LOG_DBG("ToF DTU\t\t%d", (int)tof_dtu);
} else if (tof_dtu < 0) {
LOG_ERR("ToF DTU %d", (int)tof_dtu);
}
return tof_dtu;
}
int twr_distance_calculation(uint32_t poll_rx_ts, uint32_t resp_tx_ts,
uint32_t final_rx_ts, uint32_t Ra, uint32_t Da)
{
double tof_dtu = twr_distance_calculation_dtu(poll_rx_ts, resp_tx_ts,
final_rx_ts, Ra, Da);
double tof = DTU_TO_PS(tof_dtu);
int dist = round(TIME_TO_DISTANCE(tof) * 100.0); // in cm, rounded
#if TWR_DEBUG_CALCULATION
LOG_DBG("ToF PicoSec\t%d", (int)(tof * 1000000000000.0));
LOG_DBG("Distance:\t%d cm", dist);
#endif
return dist;
}
/*
* Management
*/
static void twr_callback(uint64_t src, uint64_t dst, uint16_t dist,
uint16_t cnum)
{
if (twr_observer_cb) {
twr_observer_cb(src, dst, dist, cnum);
}
}
static void twr_retry(void)
{
if (++retry < TWR_MAX_RETRY) {
#ifdef __ZEPHYR__
int d = sys_rand32_get() % TWR_RETRY_DELAY;
#else
int d = rand() % TWR_RETRY_DELAY;
#endif
deca_sleep(d);
LOG_INF("retry %d to " LADDR_FMT " after %d ms", retry,
LADDR_PAR(twr_dst), d);
twr_send_poll(twr_dst);
} else {
LOG_ERR("retry limit exceeded " LADDR_FMT, LADDR_PAR(twr_dst));
twr_callback(twr_my_mac(twr_dst), twr_dst, TWR_FAILED_VALUE, twr_cnum);
in_progress = false;
}
}
static void twr_handle_timeout(uint32_t status)
{
LOG_ERR("RX timeout from " LADDR_FMT, LADDR_PAR(twr_dst));
if (expected_msg == TWR_MSG_RESP || expected_msg == TWR_MSG_REPO
|| expected_msg == TWR_MSG_SSRESP) {
/* The TAG (Initiator) side can retry the whole exchange */
twr_retry();
} else if (expected_msg == TWR_MSG_FINA) {
/* The ANCOR (Passive) side can only log the error */
LOG_ERR("RX timeout, did not receive final");
// dev_update_state(current_anc_idx, TWR_FAIL);
expected_msg = 0;
in_progress = false;
}
}
static void twr_handle_result(uint64_t src, uint64_t dst, uint16_t dist,
uint16_t cnum, bool reported, bool initiator)
{
if (dist == TWR_FAILED_VALUE) {
LOG_ERR("#%d " LADDR_FMT " -> " LADDR_FMT
": Distance calculation failed %s",
cnum, LADDR_PAR(src), LADDR_PAR(dst), reported ? "REP" : "");
if (initiator) {
twr_retry();
}
} else if (dist == 0) {
// distance reported as 0, may be too close, or may be failed: retry
LOG_INF("#%d " LADDR_FMT " -> " LADDR_FMT ": %u cm %s", cnum,
LADDR_PAR(src), LADDR_PAR(dst), dist, reported ? "REP" : "");
if (initiator) {
twr_retry();
}
} else if (dist == TWR_OK_VALUE) {
// this is on initiator side when no reports are expected, we don't know
// the distance
LOG_INF("#%d " LADDR_FMT " -> " LADDR_FMT ": OK", cnum, LADDR_PAR(src),
LADDR_PAR(dst));
} else {
LOG_INF("#%d " LADDR_FMT " -> " LADDR_FMT ": %u cm %s", cnum,
LADDR_PAR(src), LADDR_PAR(dst), dist, reported ? "REP" : "");
twr_callback(src, dst, dist, cnum);
in_progress = false;
}
}
/*
* Message handlers
*/
/* ANCOR */
static void twr_handle_final(const struct twr_msg_final* msg_final,
uint64_t final_rx_ts, uint64_t src)
{
DBG_UWB("Received Final from " LADDR_FMT, LADDR_PAR(src));
expected_msg = 0;
uint32_t resp_tx_ts = dwt_readtxtimestamplo32();
int dist
= twr_distance_calculation(last_poll_rx_ts, resp_tx_ts, final_rx_ts,
msg_final->round, msg_final->delay);
dist = twr_fixup_distance(dist);
if (twr_send_report) {
// result will be handled after sending the report (time critical)
twr_send_report_msg(src, dist, msg_final->cnum, final_rx_ts);
} else {
// add result. we have been the destination of this TWR sequence
twr_handle_result(src, twr_my_mac(src), dist, msg_final->cnum, false,
false);
}
}
/* TAG */
static void twr_handle_report(const struct twr_msg_report* msg, uint64_t src)
{
/* no more messages expected */
expected_msg = 0;
/* distance back to me (tag) */
twr_handle_result(twr_my_mac(src), src, msg->dist, msg->cnum, true, true);
}
static void twr_handle_ss_response(const struct rxbuf* rx, uint64_t src)
{
const struct twr_msg_ss_resp* msg = dwprot_get_payload(rx->buf);
uint32_t poll_tx_ts = dwt_readtxtimestamplo32();
uint32_t resp_rx_ts = (uint32_t)rx->ts;
uint32_t rtd_init = resp_rx_ts - poll_tx_ts;
uint32_t rtd_resp = msg->resp_tx_ts - msg->poll_rx_ts;
#if CONFIG_DECA_USE_CARRIERINTEG
float clockOffsetRatio = -dwphy_get_rx_clock_offset_ci(rx->ci) / 1.0e6;
#else
float clockOffsetRatio
= ((float)dwt_readclockoffset()) / (uint32_t)(1 << 26);
#endif
double tof
= DTU_TO_PS((rtd_init - rtd_resp * (1 - (double)clockOffsetRatio)) / 2.0);
int dist = TIME_TO_DISTANCE(tof) * 100;
dist = twr_fixup_distance(dist);
twr_handle_result(twr_my_mac(src), src, dist, twr_cnum, false, true);
}
static size_t twr_get_msg_len(uint8_t func)
{
switch (func) {
case TWR_MSG_POLL:
return 0;
case TWR_MSG_RESP:
return 0;
case TWR_MSG_FINA:
return sizeof(struct twr_msg_final);
case TWR_MSG_REPO:
return sizeof(struct twr_msg_report);
case TWR_MSG_SSPOLL:
return 0;
case TWR_MSG_SSRESP:
return sizeof(struct twr_msg_ss_resp);
}
return 0;
}
void twr_handle_message(const struct rxbuf* rx)
{
uint64_t src = dwprot_get_src(rx->buf);
uint8_t func = dwprot_get_func(rx->buf);
/* drop unexpected messages, but always allow POLL in case the sender needs
* to retry */
if (expected_msg != 0 && func != expected_msg && func != TWR_MSG_POLL) {
LOG_ERR("Drop unexpected MSG %X from " LADDR_FMT, func, LADDR_PAR(src));
return;
}
/* check length */
if (dwprot_get_payload_len(rx->buf, rx->len) != twr_get_msg_len(func)) {
LOG_ERR("Drop invalid length MSG %X from " LADDR_FMT, func,
LADDR_PAR(src));
return;
}
switch (func) {
case TWR_MSG_POLL:
twr_send_response(src, rx->ts);
break;
case TWR_MSG_RESP:
twr_send_final(src, rx->ts);
break;
case TWR_MSG_FINA:
twr_handle_final(dwprot_get_payload(rx->buf), rx->ts, src);
break;
case TWR_MSG_REPO:
twr_handle_report(dwprot_get_payload(rx->buf), src);
break;
case TWR_MSG_SSPOLL:
twr_send_ss_response(src, rx->ts);
break;
case TWR_MSG_SSRESP:
twr_handle_ss_response(rx, src);
break;
default:
LOG_ERR("Unknown MSG %X from " LADDR_FMT, func, LADDR_PAR(src));
}
}
/*
* API
*/
void twr_init(uint32_t processing_delay_us, bool send_report)
{
twr_send_report = send_report;
uint8_t rate_dw = dwphy_get_rate();
uint8_t plen_dw = dwphy_get_plen();
uint8_t prf_dw = dwphy_get_prf();
/* Calculate reply delay: To make the ToF calculation error as small as
* possible in the presence of clock drift, the reply delays on both
* sides should be
* - as short as possible
* - as close as possible (small difference)
*
* For calculation of the biggest necessary delay in the TWR sequence
* we need to consider the time between RESP (with MAC_PROTO_MIN_LEN)
* has been received and FINAL can be sent.
*/
/* the processing time is a constant plus the time it takes to transfer
* the packet data over SPI */
uint32_t proc_time_us
= processing_delay_us + TWR_SPI_US_PER_BYTE * DWMAC_PROTO_SHORT_LEN
+ TWR_SPI_US_PER_BYTE
* (DWMAC_PROTO_SHORT_LEN + sizeof(struct twr_msg_final));
/* TODO: CHECK: Processing time is higher when debugging is on */
#if CONFIG_DECA_DEBUG_IRQ_TIME || CONFIG_DECA_DEBUG_RX_DUMP \
|| CONFIG_DECA_DEBUG_TX_DUMP || CONFIG_DECA_DEBUG_TX_TIME \
|| CONFIG_DECA_DEBUG_RX_STATUS || CONFIG_DECA_READ_RXDIAG \
|| TWR_DEBUG_CALCULATION
proc_time_us += 400;
#endif
/* Calculate delay from packet times
*
* From the RMARKER time (RX timestamp) we need
* 1) Time of PHY header
* 2) Time to receive data packet (RESP which is MAC_PROTO_MIN_LEN)
* 3) Processing time
* 4) Time for preamble + SFD until RMARKER of TX frame
*
* The first step is the packet times in picoseconds / 10, then we
* switch to microseconds */
uint32_t twr_delay_us
= dwphy_calc_phyhdr_time(rate_dw)
+ dwphy_calc_data_time(rate_dw, DWMAC_PROTO_SHORT_LEN)
+ dwphy_calc_preamble_time(plen_dw, prf_dw, rate_dw);
twr_delay_us = PKTTIME_TO_USEC(twr_delay_us);
twr_delay_us += proc_time_us;
twr_delay_dtu = US_TO_DTU(twr_delay_us);
/* RX delay is the time between the packet was sent completely (end of
* data) until we need to turn the RX on to receive the next packet.
* This is the processing time in UUS */
twr_rx_delay = US_TO_UUS(proc_time_us);
twr_pto = dwphy_get_recommended_preambletimeout();
#if CONFIG_DECA_DEBUG_IRQ_TIME || CONFIG_DECA_DEBUG_RX_DUMP \
|| CONFIG_DECA_DEBUG_TX_DUMP || CONFIG_DECA_DEBUG_TX_TIME \
|| CONFIG_DECA_DEBUG_RX_STATUS || CONFIG_DECA_READ_RXDIAG
twr_pto += 3;
#endif
LOG_INF("delay %" PRIu32 " us RX delay %" PRIu32
" us PTO %d (%d us) rep %d",
twr_delay_us, proc_time_us, twr_pto, dwphy_pac_to_usec(twr_pto),
send_report);
#if 0
// distance formula test
twr_distance_calculation(0xb2ad1f34, 0xf5155e34, 0x377d8aed,
0x42685421, 0x42684034);
//-> expect 49 cm
twr_distance_calculation(0xc786537d, 0x09ee9234, 0x4c56c3cf,
0x42684E28, 0x42684034);
//-> expect 25 cm
#endif
}
bool twr_start(uint64_t dst)
{
if (!dwhw_is_ready()) {
LOG_ERR("Not ready");
return false;
}
twr_dst = dst;
single_sided = false;
twr_cnum++;
in_progress = true;
retry = 0;
return twr_send_poll(twr_dst);
}
bool twr_start_ss(uint64_t dst)
{
if (!dwhw_is_ready()) {
LOG_ERR("Not ready");
return false;
}
twr_dst = dst;
single_sided = true;
twr_cnum++;
in_progress = true;
retry = 0;
return twr_send_poll(twr_dst);
}
void twr_cancel(void)
{
in_progress = false;
retry = 0;
expected_msg = 0;
}
void twr_set_observer(twr_cb_t cb)
{
twr_observer_cb = cb;
}
bool twr_in_progress(void)
{
return in_progress;
}
uint16_t twr_get_cnum(void)
{
return twr_cnum;
}
uint64_t twr_get_source_mac(void)
{
if (IS_SHORT_ADDR(twr_dst)) {
return dwmac_get_mac16();
} else {
return dwmac_get_mac64();
}
}