amiro-lld / source / DW1000 / v1 / deca_instance_common_v1.c @ 4172c48d
History | View | Annotate | Download (73.043 KB)
1 | 69a601a5 | Cung Sang | /*! ----------------------------------------------------------------------------
|
---|---|---|---|
2 | * @file instance_common.c
|
||
3 | * @brief DecaWave application level common instance functions
|
||
4 | *
|
||
5 | * @attention
|
||
6 | *
|
||
7 | * Copyright 2015 (c) DecaWave Ltd, Dublin, Ireland.
|
||
8 | *
|
||
9 | * All rights reserved.
|
||
10 | *
|
||
11 | * @author DecaWave
|
||
12 | */
|
||
13 | |||
14 | #include <alld_DW1000.h> |
||
15 | |||
16 | #if (defined(AMIROLLD_CFG_DW1000) && (AMIROLLD_CFG_DW1000 == 1)) || defined(__DOXYGEN__) |
||
17 | |||
18 | #include "module.h" |
||
19 | #include <string.h> |
||
20 | #include <math.h> |
||
21 | 33f54213 | Cung Sang | #include <v1/deca_instance_v1.h> |
22 | |||
23 | |||
24 | /*! @brief Software defined configuration settings for RTLS applications */
|
||
25 | /*! Configuration for DecaRangeRTLS TREK Modes (4 default use cases selected by the switch S1 [2,3] on EVB1000, indexed 0 to 3 )*/
|
||
26 | instanceConfig_t chConfig[4] ={
|
||
27 | //mode 1 - S1: 2 off, 3 off
|
||
28 | { |
||
29 | .channelNumber = 2, // channel |
||
30 | .preambleCode = 4, // preambleCode |
||
31 | .pulseRepFreq = DWT_PRF_16M, // prf
|
||
32 | .dataRate = DWT_BR_110K, // datarate
|
||
33 | .preambleLen = DWT_PLEN_1024, // preambleLength
|
||
34 | .pacSize = DWT_PAC32, // pacSize
|
||
35 | .nsSFD = 1, // non-standard SFD |
||
36 | .sfdTO = (1025 + 64 - 32) // SFD timeout |
||
37 | }, |
||
38 | //mode 2 - S1: 2 on, 3 off
|
||
39 | { |
||
40 | .channelNumber = 2, // channel |
||
41 | .preambleCode = 4, // preambleCode |
||
42 | .pulseRepFreq = DWT_PRF_16M, // prf
|
||
43 | .dataRate = DWT_BR_6M8, // datarate
|
||
44 | .preambleLen = DWT_PLEN_128, // preambleLength
|
||
45 | .pacSize = DWT_PAC8, // pacSize
|
||
46 | .nsSFD = 0, // non-standard SFD |
||
47 | .sfdTO = (129 + 8 - 8) // SFD timeout |
||
48 | }, |
||
49 | //mode 3 - S1: 2 off, 3 on
|
||
50 | { |
||
51 | .channelNumber = 5, // channel |
||
52 | .preambleCode = 3, // preambleCode |
||
53 | .pulseRepFreq = DWT_PRF_16M, // prf
|
||
54 | .dataRate = DWT_BR_110K, // datarate
|
||
55 | .preambleLen = DWT_PLEN_1024, // preambleLength
|
||
56 | .pacSize = DWT_PAC32, // pacSize
|
||
57 | .nsSFD = 1, // non-standard SFD |
||
58 | .sfdTO = (1025 + 64 - 32) // SFD timeout |
||
59 | }, |
||
60 | //mode 4 - S1: 2 on, 3 on
|
||
61 | { |
||
62 | .channelNumber = 5, // channel |
||
63 | .preambleCode = 3, // preambleCode |
||
64 | .pulseRepFreq = DWT_PRF_16M, // prf
|
||
65 | .dataRate = DWT_BR_6M8, // datarate
|
||
66 | .preambleLen = DWT_PLEN_128, // preambleLength
|
||
67 | .pacSize = DWT_PAC8, // pacSize
|
||
68 | .nsSFD = 0, // non-standard SFD |
||
69 | .sfdTO = (129 + 8 - 8) // SFD timeout |
||
70 | } |
||
71 | }; |
||
72 | 69a601a5 | Cung Sang | |
73 | |||
74 | 33f54213 | Cung Sang | /*! Slot and Superframe Configuration for DecaRangeRTLS TREK Modes (4 default use cases selected by the switch S1 [2,3] on EVB1000, indexed 0 to 3 )*/
|
75 | sfConfig_t sfConfig[4] ={
|
||
76 | //mode 1 - S1: 2 off, 3 off
|
||
77 | { |
||
78 | .slotPeriod = (28), //slot duration in milliseconds (NOTE: the ranging exchange must be able to complete in this time |
||
79 | //e.g. tag sends a poll, 4 anchors send responses and tag sends the final + processing time
|
||
80 | .numSlots = (10), //number of slots in the superframe (8 tag slots and 2 used for anchor to anchor ranging), |
||
81 | .sfPeriod = (10*28), //in ms => 280ms frame means 3.57 Hz location rate |
||
82 | .pollSleepDly = (10*28), //tag period in ms (sleep time + ranging time) |
||
83 | .replyDly = (25000) //poll to final delay in microseconds (needs to be adjusted according to lengths of ranging frames) |
||
84 | }, |
||
85 | #if (DISCOVERY == 1) |
||
86 | //mode 2 - S1: 2 on, 3 off
|
||
87 | { |
||
88 | .slotPeriod = (10), //slot duration in milliseconds (NOTE: the ranging exchange must be able to complete in this time |
||
89 | //e.g. tag sends a poll, 4 anchors send responses and tag sends the final + processing time
|
||
90 | .numSlots = (100), //number of slots in the superframe (98 tag slots and 2 used for anchor to anchor ranging), |
||
91 | .sfPeriod = (10*100), //in ms => 1000 ms frame means 1 Hz location rate |
||
92 | .pollSleepDly = (10*100), //tag period in ms (sleep time + ranging time) |
||
93 | .replyDly = (2500) //poll to final delay in microseconds (needs to be adjusted according to lengths of ranging frames) |
||
94 | |||
95 | }, |
||
96 | #else
|
||
97 | //mode 2 - S1: 2 on, 3 off
|
||
98 | { |
||
99 | .slotPeriod = (10), //slot duration in milliseconds (NOTE: the ranging exchange must be able to complete in this time |
||
100 | //e.g. tag sends a poll, 4 anchors send responses and tag sends the final + processing time
|
||
101 | .numSlots = (10), //number of slots in the superframe (8 tag slots and 2 used for anchor to anchor ranging), |
||
102 | .sfPeriod = (10*10), //in ms => 100 ms frame means 10 Hz location rate |
||
103 | .pollSleepDly = (10*10), //tag period in ms (sleep time + ranging time) |
||
104 | .replyDly = (2500) //poll to final delay in microseconds (needs to be adjusted according to lengths of ranging frames) |
||
105 | }, |
||
106 | #endif
|
||
107 | //mode 3 - S1: 2 off, 3 on
|
||
108 | { |
||
109 | .slotPeriod = (28), //slot duration in milliseconds (NOTE: the ranging exchange must be able to complete in this time |
||
110 | //e.g. tag sends a poll, 4 anchors send responses and tag sends the final + processing time
|
||
111 | .numSlots = (10), //number of slots in the superframe (8 tag slots and 2 used for anchor to anchor ranging), |
||
112 | .sfPeriod = (10*28), //in ms => 280ms frame means 3.57 Hz location rate |
||
113 | .pollSleepDly = (10*28), //tag period in ms (sleep time + ranging time) |
||
114 | .replyDly = (20000) //poll to final delay in microseconds (needs to be adjusted according to lengths of ranging frames) |
||
115 | |||
116 | }, |
||
117 | //mode 4 - S1: 2 on, 3 on
|
||
118 | { |
||
119 | .slotPeriod = (10), //slot duration in milliseconds (NOTE: the ranging exchange must be able to complete in this time |
||
120 | //e.g. tag sends a poll, 4 anchors send responses and tag sends the final + processing time
|
||
121 | .numSlots = (10), //number of slots in the superframe (8 tag slots and 2 used for anchor to anchor ranging), |
||
122 | .sfPeriod = (10*10), //in ms => 100 ms frame means 10 Hz location rate |
||
123 | .pollSleepDly = (10*10), //tag period in ms (sleep time + ranging time) |
||
124 | .replyDly = (2500) //poll to final delay in microseconds (needs to be adjusted according to lengths of ranging frames) |
||
125 | } |
||
126 | }; |
||
127 | 69a601a5 | Cung Sang | |
128 | |||
129 | // -------------------------------------------------------------------------------------------------------------------
|
||
130 | |||
131 | //The table below specifies the default TX spectrum configuration parameters... this has been tuned for DW EVK hardware units
|
||
132 | //the table is set for smart power - see below in the instance_config function how this is used when not using smart power
|
||
133 | const tx_struct txSpectrumConfig[8] = |
||
134 | { |
||
135 | //Channel 0 ----- this is just a place holder so the next array element is channel 1
|
||
136 | { |
||
137 | 0x0, //0 |
||
138 | { |
||
139 | 0x0, //0 |
||
140 | 0x0 //0 |
||
141 | } |
||
142 | }, |
||
143 | //Channel 1
|
||
144 | { |
||
145 | 0xc9, //PG_DELAY |
||
146 | { |
||
147 | 0x15355575, //16M prf power |
||
148 | 0x07274767 //64M prf power |
||
149 | } |
||
150 | |||
151 | }, |
||
152 | //Channel 2
|
||
153 | { |
||
154 | 0xc2, //PG_DELAY |
||
155 | { |
||
156 | 0x15355575, //16M prf power |
||
157 | 0x07274767 //64M prf power |
||
158 | } |
||
159 | }, |
||
160 | //Channel 3
|
||
161 | { |
||
162 | 0xc5, //PG_DELAY |
||
163 | { |
||
164 | 0x0f2f4f6f, //16M prf power |
||
165 | 0x2b4b6b8b //64M prf power |
||
166 | } |
||
167 | }, |
||
168 | //Channel 4
|
||
169 | { |
||
170 | 0x95, //PG_DELAY |
||
171 | { |
||
172 | 0x1f1f3f5f, //16M prf power |
||
173 | 0x3a5a7a9a //64M prf power |
||
174 | } |
||
175 | }, |
||
176 | //Channel 5
|
||
177 | { |
||
178 | 0xc0, //PG_DELAY |
||
179 | { |
||
180 | 0x0E082848, //16M prf power |
||
181 | 0x25456585 //64M prf power |
||
182 | } |
||
183 | }, |
||
184 | //Channel 6 ----- this is just a place holder so the next array element is channel 7
|
||
185 | { |
||
186 | 0x0, //0 |
||
187 | { |
||
188 | 0x0, //0 |
||
189 | 0x0 //0 |
||
190 | } |
||
191 | }, |
||
192 | //Channel 7
|
||
193 | { |
||
194 | 0x93, //PG_DELAY |
||
195 | { |
||
196 | 0x32527292, //16M prf power |
||
197 | 0x5171B1d1 //64M prf power |
||
198 | } |
||
199 | } |
||
200 | }; |
||
201 | |||
202 | //these are default antenna delays for EVB1000, these can be used if there is no calibration data in the DW1000,
|
||
203 | //or instead of the calibration data
|
||
204 | const uint16_t rfDelays[2] = { |
||
205 | (uint16_t) ((DWT_PRF_16M_RFDLY/ 2.0) * 1e-9 / DWT_TIME_UNITS),//PRF 16 |
||
206 | (uint16_t) ((DWT_PRF_64M_RFDLY/ 2.0) * 1e-9 / DWT_TIME_UNITS) |
||
207 | }; |
||
208 | |||
209 | //these are default TREK Tag/Anchor antenna delays
|
||
210 | const uint16_t rfDelaysTREK[2] = { |
||
211 | (uint16_t) ((514.83f/ 2.0) * 1e-9 / DWT_TIME_UNITS),//channel 2 |
||
212 | (uint16_t) ((514.65f/ 2.0) * 1e-9 / DWT_TIME_UNITS) //channel 5 |
||
213 | }; |
||
214 | |||
215 | //int instance_starttxtest(int framePeriod)
|
||
216 | //{
|
||
217 | // //define some test data for the tx buffer
|
||
218 | // uint8 msg[127] = "The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the l";
|
||
219 | |||
220 | // //NOTE: SPI frequency must be < 3MHz
|
||
221 | // port_set_dw1000_slowrate(); //max SPI before PLLs configured is ~4M
|
||
222 | |||
223 | // // the value here 0x1000 gives a period of 32.82 µs
|
||
224 | // //this is setting 0x1000 as frame period (125MHz clock cycles) (time from Tx en - to next - Tx en)
|
||
225 | // dwt_configcontinuousframemode(framePeriod);
|
||
226 | |||
227 | // dwt_writetxdata(127, (uint8 *) msg, 0) ;
|
||
228 | // dwt_writetxfctrl(127, 0, 0);
|
||
229 | |||
230 | // //to start the first frame - set TXSTRT
|
||
231 | // dwt_starttx(DWT_START_TX_IMMEDIATE);
|
||
232 | |||
233 | // //measure the power
|
||
234 | // //Spectrum Analyser set:
|
||
235 | // //FREQ to be channel default e.g. 3.9936 GHz for channel 2
|
||
236 | // //SPAN to 1GHz
|
||
237 | // //SWEEP TIME 1s
|
||
238 | // //RBW and VBW 1MHz
|
||
239 | // //measure channel power
|
||
240 | |||
241 | // return DWT_SUCCESS ;
|
||
242 | //}
|
||
243 | |||
244 | // -------------------------------------------------------------------------------------------------------------------
|
||
245 | // Data Definitions
|
||
246 | // -------------------------------------------------------------------------------------------------------------------
|
||
247 | |||
248 | instance_data_t instance_data[NUM_INST] ; |
||
249 | |||
250 | static double inst_tdist[MAX_TAG_LIST_SIZE] ; |
||
251 | static double inst_idist[MAX_ANCHOR_LIST_SIZE] ; |
||
252 | static double inst_idistraw[MAX_ANCHOR_LIST_SIZE] ; |
||
253 | |||
254 | // TODO: Instance_data declaration in .c. Not on .h (extern only)
|
||
255 | instance_data_t instance_data[NUM_INST] ; |
||
256 | |||
257 | /* TODO: Custom data declarations */
|
||
258 | typedef struct |
||
259 | { |
||
260 | uint32_t deviceID ; |
||
261 | uint8_t chan; // added chan here - used in the reading of acc
|
||
262 | uint16_t rfrxDly; // rf delay (delay though the RF blocks before the signal comes out of the antenna i.e. "antenna delay")
|
||
263 | uint16_t rftxDly; // rf delay (delay though the RF blocks before the signal comes out of the antenna i.e. "antenna delay")
|
||
264 | uint32_t antennaDly; // antenna delay read from OTP 64 PRF value is in high 16 bits and 16M PRF in low 16 bits
|
||
265 | uint32_t antennaCals[4]; // antenna delays for the TREKs (Anchor high 16-bits, Tag low 16-bits) |
||
266 | uint32_t txPowCfg[12]; // stores the Tx power configuration read from OTP (6 channels consecutively with PRF16 then 64, e.g. Ch 1 PRF16 is index 0 and 64 index 1) |
||
267 | uint32_t states[3] ; //MP workaround debug states register |
||
268 | uint8_t statescount ; |
||
269 | int prfIndex ;
|
||
270 | uint32_t ldoTune ; //low 32 bits of LDO tune value
|
||
271 | } platform_local_data_t ; |
||
272 | |||
273 | static platform_local_data_t platformLocalData ; // Static local device data |
||
274 | |||
275 | // -------------------------------------------------------------------------------------------------------------------
|
||
276 | // Functions
|
||
277 | // -------------------------------------------------------------------------------------------------------------------
|
||
278 | |||
279 | // -------------------------------------------------------------------------------------------------------------------
|
||
280 | // convert microseconds to device time
|
||
281 | uint64_t convertmicrosectodevicetimeu (double microsecu){
|
||
282 | uint64_t dt; |
||
283 | long double dtime; |
||
284 | |||
285 | dtime = (microsecu / (double) DWT_TIME_UNITS) / 1e6 ; |
||
286 | |||
287 | dt = (uint64_t) (dtime) ; |
||
288 | |||
289 | return dt;
|
||
290 | } |
||
291 | |||
292 | double convertdevicetimetosec(int32_t dt){
|
||
293 | double f = 0; |
||
294 | |||
295 | f = dt * DWT_TIME_UNITS ; // seconds #define TIME_UNITS (1.0/499.2e6/128.0) = 15.65e-12
|
||
296 | |||
297 | return f ;
|
||
298 | } |
||
299 | |||
300 | #pragma GCC optimize ("O3") |
||
301 | int reportTOF(int idx, uint32_t tofx){ |
||
302 | double distance ;
|
||
303 | double distance_to_correct;
|
||
304 | double tof ;
|
||
305 | int32_t tofi ; |
||
306 | |||
307 | // check for negative results and accept them making them proper negative integers
|
||
308 | tofi = (int32_t) tofx ; // make it signed
|
||
309 | if (tofi > 0x7FFFFFFF){ // close up TOF may be negative |
||
310 | tofi -= 0x80000000 ; // |
||
311 | } |
||
312 | |||
313 | // convert to seconds (as floating point)
|
||
314 | tof = convertdevicetimetosec(tofi) ; //this is divided by 4 to get single time of flight
|
||
315 | inst_idistraw[idx] = distance = tof * SPEED_OF_LIGHT; |
||
316 | |||
317 | #if (CORRECT_RANGE_BIAS == 1) |
||
318 | //for the 6.81Mb data rate we assume gating gain of 6dB is used,
|
||
319 | //thus a different range bias needs to be applied
|
||
320 | //if(inst->configData.dataRate == DWT_BR_6M8)
|
||
321 | if(instance_data[0].configData.smartPowerEn){ |
||
322 | //1.31 for channel 2 and 1.51 for channel 5
|
||
323 | if(instance_data[0].configData.chan == 5){ |
||
324 | distance_to_correct = distance/1.51; |
||
325 | } |
||
326 | else{ //channel 2 |
||
327 | distance_to_correct = distance/1.31; |
||
328 | } |
||
329 | } |
||
330 | else{
|
||
331 | distance_to_correct = distance; |
||
332 | } |
||
333 | |||
334 | distance = distance - dwt_getrangebias(instance_data[0].configData.chan, (float) distance_to_correct, instance_data[0].configData.prf); |
||
335 | #endif
|
||
336 | |||
337 | if ((distance < 0) || (distance > 20000.000)) // discard any results less than <0 cm or >20 km |
||
338 | return 0; |
||
339 | |||
340 | inst_idist[idx] = distance; |
||
341 | |||
342 | instance_data[0].longTermRangeCount++ ; // for computing a long term average |
||
343 | |||
344 | return 1; |
||
345 | }// end of reportTOF
|
||
346 | |||
347 | void setTagDist(int tidx, int aidx){ |
||
348 | inst_tdist[tidx] = inst_idist[aidx]; |
||
349 | } |
||
350 | |||
351 | double getTagDist(int idx){ |
||
352 | return inst_tdist[idx];
|
||
353 | } |
||
354 | |||
355 | void clearDistTable(int idx){ |
||
356 | inst_idistraw[idx] = 0;
|
||
357 | inst_idist[idx] = 0;
|
||
358 | } |
||
359 | |||
360 | void instancecleardisttableall(void){ |
||
361 | int i;
|
||
362 | |||
363 | for(i=0; i<MAX_ANCHOR_LIST_SIZE; i++) { |
||
364 | inst_idistraw[i] = 0xffff;
|
||
365 | inst_idist[i] = 0xffff;
|
||
366 | } |
||
367 | } |
||
368 | |||
369 | // -------------------------------------------------------------------------------------------------------------------
|
||
370 | #if NUM_INST != 1 |
||
371 | #error These functions assume one instance only
|
||
372 | #else
|
||
373 | |||
374 | |||
375 | // -------------------------------------------------------------------------------------------------------------------
|
||
376 | // Set this instance role as the Tag, Anchor or Listener
|
||
377 | void instancesetrole(int inst_mode){ |
||
378 | // assume instance 0, for this
|
||
379 | instance_data[0].mode = inst_mode; // set the role |
||
380 | } |
||
381 | |||
382 | int instancegetrole(void){ |
||
383 | return instance_data[0].mode; |
||
384 | } |
||
385 | |||
386 | int instancenewrange(void){ |
||
387 | int x = instance_data[0].newRange; |
||
388 | instance_data[0].newRange = TOF_REPORT_NUL;
|
||
389 | return x;
|
||
390 | } |
||
391 | |||
392 | int instancenewrangeancadd(void){ |
||
393 | return instance_data[0].newRangeAncAddress; |
||
394 | } |
||
395 | |||
396 | int instancenewrangetagadd(void){ |
||
397 | return instance_data[0].newRangeTagAddress; |
||
398 | } |
||
399 | |||
400 | int instancenewrangetim(void){ |
||
401 | return instance_data[0].newRangeTime; |
||
402 | } |
||
403 | |||
404 | // -------------------------------------------------------------------------------------------------------------------
|
||
405 | // function to clear counts/averages/range values
|
||
406 | //
|
||
407 | void instanceclearcounts(void){ |
||
408 | int instance = 0 ; |
||
409 | int i= 0 ; |
||
410 | |||
411 | instance_data[instance].rxTimeouts = 0 ;
|
||
412 | |||
413 | dwt_configeventcounters(1); //enable and clear - NOTE: the counters are not preserved when in DEEP SLEEP |
||
414 | |||
415 | instance_data[instance].frameSN = 0;
|
||
416 | |||
417 | instance_data[instance].longTermRangeCount = 0;
|
||
418 | |||
419 | |||
420 | for(i=0; i<MAX_ANCHOR_LIST_SIZE; i++){ |
||
421 | instance_data[instance].tofArray[i] = INVALID_TOF; |
||
422 | } |
||
423 | |||
424 | for(i=0; i<MAX_TAG_LIST_SIZE; i++){ |
||
425 | instance_data[instance].tof[i] = INVALID_TOF; |
||
426 | } |
||
427 | |||
428 | } // end instanceclearcounts()
|
||
429 | |||
430 | |||
431 | // -------------------------------------------------------------------------------------------------------------------
|
||
432 | // function to initialise instance structures
|
||
433 | //
|
||
434 | // Returns 0 on success and -1 on error
|
||
435 | 33f54213 | Cung Sang | int instance_init(DW1000Driver* drv){
|
436 | 69a601a5 | Cung Sang | int instance = 0 ; |
437 | int i;
|
||
438 | int result;
|
||
439 | |||
440 | instance_data[instance].mode = ANCHOR; // assume listener,
|
||
441 | instance_data[instance].testAppState = TA_INIT ; |
||
442 | instance_data[instance].instToSleep = FALSE; |
||
443 | |||
444 | |||
445 | // Reset the IC (might be needed if not getting here from POWER ON)
|
||
446 | // ARM code: Remove soft reset here as using hard reset in the inittestapplication() in the main.c file
|
||
447 | //dwt_softreset();
|
||
448 | |||
449 | //this initialises DW1000 and uses specified configurations from OTP/ROM
|
||
450 | 33f54213 | Cung Sang | result = dwt_initialise(DWT_LOADUCODE, drv) ; // TODO
|
451 | // result = dwt_initialise(DWT_LOADUCODE) ;
|
||
452 | 69a601a5 | Cung Sang | |
453 | //this is platform dependent - only program if DW EVK/EVB
|
||
454 | dwt_setleds(3) ; //configure the GPIOs which control the leds on EVBs |
||
455 | |||
456 | if (DWT_SUCCESS != result){
|
||
457 | return (-1) ; // device initialise has failed |
||
458 | } |
||
459 | |||
460 | |||
461 | instanceclearcounts() ; |
||
462 | |||
463 | instance_data[instance].panID = 0xdeca ;
|
||
464 | |||
465 | instance_data[instance].wait4ack = 0;
|
||
466 | instance_data[instance].stopTimer = 0;
|
||
467 | instance_data[instance].instanceTimerEn = 0;
|
||
468 | |||
469 | instance_clearevents(); |
||
470 | |||
471 | //dwt_geteui(instance_data[instance].eui64);
|
||
472 | memset(instance_data[instance].eui64, 0, ADDR_BYTE_SIZE_L);
|
||
473 | |||
474 | instance_data[instance].tagSleepCorrection = 0;
|
||
475 | |||
476 | // dwt_setautorxreenable(0); //disable auto RX re-enable
|
||
477 | dwt_setdblrxbuffmode(0); //disable double RX buffer |
||
478 | |||
479 | // if using auto CRC check (DWT_INT_RFCG and DWT_INT_RFCE) are used instead of DWT_INT_RDFR flag
|
||
480 | // other errors which need to be checked (as they disable receiver) are
|
||
481 | //dwt_setinterrupt(DWT_INT_TFRS | DWT_INT_RFCG | (DWT_INT_SFDT | DWT_INT_RFTO /*| DWT_INT_RXPTO*/), 1);
|
||
482 | dwt_setinterrupt(DWT_INT_TFRS | DWT_INT_RFCG | (DWT_INT_ARFE | DWT_INT_RFSL | DWT_INT_SFDT | DWT_INT_RPHE | DWT_INT_RFCE | DWT_INT_RFTO | DWT_INT_RXPTO), 1);
|
||
483 | |||
484 | dwt_setcallbacks(instance_txcallback, instance_rxcallback, instance_rxtimeoutcallback,instance_rxerrorcallback ); |
||
485 | |||
486 | instance_data[instance].monitor = 0;
|
||
487 | |||
488 | instance_data[instance].lateTX = 0;
|
||
489 | instance_data[instance].lateRX = 0;
|
||
490 | |||
491 | instance_data[instance].responseTO = -1; //initialise |
||
492 | for(i=0; i<256; i++) { |
||
493 | instance_data[instance].rxResps[i] = -10;
|
||
494 | } |
||
495 | |||
496 | instance_data[instance].delayedReplyTime = 0;
|
||
497 | |||
498 | return 0 ; |
||
499 | } |
||
500 | |||
501 | // -------------------------------------------------------------------------------------------------------------------
|
||
502 | //
|
||
503 | // Return the Device ID register value, enables higher level validation of physical device presence
|
||
504 | //
|
||
505 | |||
506 | uint32_t instancereaddeviceid(void){
|
||
507 | return dwt_readdevid() ;
|
||
508 | } |
||
509 | |||
510 | |||
511 | // -------------------------------------------------------------------------------------------------------------------
|
||
512 | //
|
||
513 | // function to allow application configuration be passed into instance and affect underlying device operation
|
||
514 | //
|
||
515 | 4172c48d | Cung Sang | void instance_config(instanceConfig_t *config, sfConfig_t *sfConfig, DW1000Driver* drv){
|
516 | 69a601a5 | Cung Sang | int instance = 0 ; |
517 | uint32_t power = 0;
|
||
518 | uint8_t otprev ; |
||
519 | |||
520 | instance_data[instance].configData.chan = config->channelNumber ; |
||
521 | instance_data[instance].configData.rxCode = config->preambleCode ; |
||
522 | instance_data[instance].configData.txCode = config->preambleCode ; |
||
523 | instance_data[instance].configData.prf = config->pulseRepFreq ; |
||
524 | instance_data[instance].configData.dataRate = config->dataRate ; |
||
525 | instance_data[instance].configData.txPreambLength = config->preambleLen ; |
||
526 | instance_data[instance].configData.rxPAC = config->pacSize ; |
||
527 | instance_data[instance].configData.nsSFD = config->nsSFD ; |
||
528 | instance_data[instance].configData.phrMode = DWT_PHRMODE_STD ; |
||
529 | instance_data[instance].configData.sfdTO = config->sfdTO; |
||
530 | |||
531 | //the DW1000 will automatically use gating gain for frames < 1ms duration (i.e. 6.81Mbps data rate)
|
||
532 | //smartPowerEn should be set based on the frame length, but we can also use dtaa rate.
|
||
533 | if(instance_data[instance].configData.dataRate == DWT_BR_6M8) {
|
||
534 | instance_data[instance].configData.smartPowerEn = 1;
|
||
535 | } |
||
536 | else{
|
||
537 | instance_data[instance].configData.smartPowerEn = 0;
|
||
538 | } |
||
539 | |||
540 | //configure the channel parameters
|
||
541 | dwt_configure(&instance_data[instance].configData) ; |
||
542 | |||
543 | instance_data[instance].configTX.PGdly = txSpectrumConfig[config->channelNumber].PGdelay ; //Default
|
||
544 | |||
545 | //firstly check if there are calibrated TX power value in the DW1000 OTP
|
||
546 | power = dwt_getotptxpower(config->pulseRepFreq, instance_data[instance].configData.chan); |
||
547 | |||
548 | if((power == 0x0) || (power == 0xFFFFFFFF)) { //if there are no calibrated values... need to use defaults |
||
549 | power = txSpectrumConfig[config->channelNumber].txPwr[config->pulseRepFreq- DWT_PRF_16M]; |
||
550 | } |
||
551 | |||
552 | //Configure TX power
|
||
553 | instance_data[instance].configTX.power = power; |
||
554 | |||
555 | //configure the tx spectrum parameters (power and PG delay)
|
||
556 | dwt_configuretxrf(&instance_data[instance].configTX); |
||
557 | |||
558 | otprev = dwt_otprevision() ; // this revision tells us how OTP is programmed.
|
||
559 | |||
560 | if ((2 == otprev) || (3 == otprev)) { // board is calibrated with TREK1000 with antenna delays set for each use case) |
||
561 | uint8_t mode = (instance_data[instance].mode == ANCHOR ? 1 : 0); |
||
562 | uint8_t chanindex = 0;
|
||
563 | |||
564 | instance_data[instance].txAntennaDelay |
||
565 | = dwt_getTREKOTPantennadelay(mode, |
||
566 | instance_data[instance].configData.chan, |
||
567 | instance_data[instance].configData.dataRate) ; |
||
568 | |||
569 | // if nothing was actually programmed then set a reasonable value anyway
|
||
570 | if ((instance_data[instance].txAntennaDelay == 0) |
||
571 | || (instance_data[instance].txAntennaDelay == 0xffff)){
|
||
572 | if(instance_data[instance].configData.chan == 5){ |
||
573 | chanindex = 1;
|
||
574 | } |
||
575 | |||
576 | instance_data[instance].txAntennaDelay = rfDelaysTREK[chanindex]; |
||
577 | } |
||
578 | |||
579 | } |
||
580 | else { // assume it is older EVK1000 programming. |
||
581 | //get the antenna delay that was read from the OTP calibration area
|
||
582 | instance_data[instance].txAntennaDelay = dwt_readantennadelay(config->pulseRepFreq) >> 1;
|
||
583 | |||
584 | // if nothing was actually programmed then set a reasonable value anyway
|
||
585 | if ((instance_data[instance].txAntennaDelay == 0) |
||
586 | || (instance_data[instance].txAntennaDelay == 0xffff)){
|
||
587 | instance_data[instance].txAntennaDelay = rfDelays[config->pulseRepFreq - DWT_PRF_16M]; |
||
588 | } |
||
589 | } |
||
590 | |||
591 | // -------------------------------------------------------------------------------------------------------------------
|
||
592 | // set the antenna delay, we assume that the RX is the same as TX.
|
||
593 | dwt_setrxantennadelay(instance_data[instance].txAntennaDelay); |
||
594 | dwt_settxantennadelay(instance_data[instance].txAntennaDelay); |
||
595 | |||
596 | instance_data[instance].rxAntennaDelay = instance_data[instance].txAntennaDelay; |
||
597 | |||
598 | if(config->preambleLen == DWT_PLEN_64) { //if preamble length is 64 |
||
599 | //reduce SPI to < 3MHz
|
||
600 | 4172c48d | Cung Sang | setHighSpeed_SPI(FALSE, drv); |
601 | 69a601a5 | Cung Sang | dwt_loadopsettabfromotp(0);
|
602 | //increase SPI to max
|
||
603 | 4172c48d | Cung Sang | setHighSpeed_SPI(TRUE, drv); |
604 | 69a601a5 | Cung Sang | } |
605 | |||
606 | instancesettagsleepdelay(sfConfig->pollSleepDly); //set the Tag sleep time
|
||
607 | instance_data[instance].sframePeriod = sfConfig->sfPeriod; |
||
608 | instance_data[instance].slotPeriod = sfConfig->slotPeriod; |
||
609 | instance_data[instance].tagSleepRnd = sfConfig->slotPeriod; |
||
610 | instance_data[instance].numSlots = sfConfig->numSlots; |
||
611 | |||
612 | //last two slots are used for anchor to anchor ranging
|
||
613 | instance_data[instance].a0SlotTime = (instance_data[instance].numSlots-2) * instance_data[instance].slotPeriod;
|
||
614 | |||
615 | //set the default response delays
|
||
616 | instancesetreplydelay(sfConfig->replyDly); |
||
617 | |||
618 | } |
||
619 | |||
620 | // -------------------------------------------------------------------------------------------------------------------
|
||
621 | // function to set the tag sleep time (in ms)
|
||
622 | //
|
||
623 | void instancesettagsleepdelay(int sleepdelay) { //sleep in ms |
||
624 | int instance = 0 ; |
||
625 | instance_data[instance].tagSleepTime_ms = sleepdelay; //subtract the micro system delays (time it takes to switch states etc.)
|
||
626 | } |
||
627 | |||
628 | |||
629 | int instancegetrnum(void) { //get ranging number |
||
630 | return instance_data[0].rangeNum; |
||
631 | } |
||
632 | |||
633 | int instancegetrnuma(int idx){ //get ranging number |
||
634 | return instance_data[0].rangeNumA[idx]; |
||
635 | } |
||
636 | |||
637 | int instancegetrnumanc(int idx){ //get ranging number |
||
638 | return instance_data[0].rangeNumAAnc[idx]; |
||
639 | } |
||
640 | |||
641 | int instancegetlcount(void) { //get count of ranges used for calculation of lt avg |
||
642 | int x = instance_data[0].longTermRangeCount; |
||
643 | |||
644 | return (x);
|
||
645 | } |
||
646 | |||
647 | double instancegetidist(int idx) { //get instantaneous range |
||
648 | double x ;
|
||
649 | |||
650 | idx &= (MAX_ANCHOR_LIST_SIZE - 1);
|
||
651 | |||
652 | x = inst_idist[idx]; |
||
653 | |||
654 | return (x);
|
||
655 | } |
||
656 | |||
657 | double instancegetidistraw(int idx) { //get instantaneous range (uncorrected) |
||
658 | double x ;
|
||
659 | |||
660 | idx &= (MAX_ANCHOR_LIST_SIZE - 1);
|
||
661 | |||
662 | x = inst_idistraw[idx]; |
||
663 | |||
664 | return (x);
|
||
665 | } |
||
666 | |||
667 | int instancegetidist_mm(int idx) { //get instantaneous range |
||
668 | int x ;
|
||
669 | |||
670 | idx &= (MAX_ANCHOR_LIST_SIZE - 1);
|
||
671 | |||
672 | x = (int)(inst_idist[idx]*1000); |
||
673 | |||
674 | return (x);
|
||
675 | } |
||
676 | |||
677 | int instancegetidistraw_mm(int idx) { //get instantaneous range (uncorrected) |
||
678 | int x ;
|
||
679 | |||
680 | idx &= (MAX_ANCHOR_LIST_SIZE - 1);
|
||
681 | |||
682 | x = (int)(inst_idistraw[idx]*1000); |
||
683 | |||
684 | return (x);
|
||
685 | } |
||
686 | |||
687 | void instance_backtoanchor(instance_data_t *inst){
|
||
688 | //stay in RX and behave as anchor
|
||
689 | inst->testAppState = TA_RXE_WAIT ; |
||
690 | inst->mode = ANCHOR ; |
||
691 | dwt_setrxtimeout(0);
|
||
692 | dwt_setpreambledetecttimeout(0);
|
||
693 | dwt_setrxaftertxdelay(0);
|
||
694 | } |
||
695 | |||
696 | |||
697 | #pragma GCC optimize ("O3") |
||
698 | void inst_processrxtimeout(instance_data_t *inst){
|
||
699 | |||
700 | //inst->responseTimeouts ++ ;
|
||
701 | inst->rxTimeouts ++ ; |
||
702 | inst->done = INST_NOT_DONE_YET; |
||
703 | |||
704 | if(inst->mode == ANCHOR) { //we did not receive the final - wait for next poll |
||
705 | //only enable receiver when not using double buffering
|
||
706 | inst->testAppState = TA_RXE_WAIT ; // wait for next frame
|
||
707 | dwt_setrxtimeout(0);
|
||
708 | } |
||
709 | |||
710 | else if(inst->mode == TAG) { |
||
711 | //if tag times out - no response (check if we are to send a final)
|
||
712 | //send the final only if it has received response from anchor 0
|
||
713 | if((inst->previousState == TA_TXPOLL_WAIT_SEND) && ((inst->rxResponseMask & 0x1) == 0)) { |
||
714 | inst->instToSleep = TRUE ; //set sleep to TRUE so that tag will go to DEEP SLEEP before next ranging attempt
|
||
715 | inst->testAppState = TA_TXE_WAIT ; |
||
716 | inst->nextState = TA_TXPOLL_WAIT_SEND ; |
||
717 | } |
||
718 | else if (inst->previousState == TA_TXFINAL_WAIT_SEND) { //got here from main (error sending final - handle as timeout) |
||
719 | dwt_forcetrxoff(); //this will clear all events
|
||
720 | inst->instToSleep = TRUE ; |
||
721 | // initiate the re-transmission of the poll that was not responded to
|
||
722 | inst->testAppState = TA_TXE_WAIT ; |
||
723 | inst->nextState = TA_TXPOLL_WAIT_SEND ; |
||
724 | } |
||
725 | else { //send the final |
||
726 | // initiate the re-transmission of the poll that was not responded to
|
||
727 | inst->testAppState = TA_TXE_WAIT ; |
||
728 | inst->nextState = TA_TXFINAL_WAIT_SEND ; |
||
729 | } |
||
730 | |||
731 | } |
||
732 | else { //ANCHOR_RNG |
||
733 | //no Response form the other anchor
|
||
734 | if(
|
||
735 | ((inst->previousState == TA_TXPOLL_WAIT_SEND) |
||
736 | && ((A1_ANCHOR_ADDR == inst->instanceAddress16) && ((inst->rxResponseMaskAnc & 0x4) == 0))) |
||
737 | || |
||
738 | ((inst->previousState == TA_TXPOLL_WAIT_SEND) |
||
739 | && ((GATEWAY_ANCHOR_ADDR == inst->instanceAddress16) && ((inst->rxResponseMaskAnc & 0x2) == 0))) |
||
740 | ) { |
||
741 | instance_backtoanchor(inst); |
||
742 | } |
||
743 | else if (inst->previousState == TA_TXFINAL_WAIT_SEND) { //got here from main (error ending final - handle as timeout) |
||
744 | instance_backtoanchor(inst); |
||
745 | } |
||
746 | else { //send the final |
||
747 | // initiate the re-transmission of the poll that was not responded to
|
||
748 | inst->testAppState = TA_TXE_WAIT ; |
||
749 | inst->nextState = TA_TXFINAL_WAIT_SEND ; |
||
750 | } |
||
751 | } |
||
752 | |||
753 | //timeout - disable the radio (if using SW timeout the rx will not be off)
|
||
754 | //dwt_forcetrxoff() ;
|
||
755 | } |
||
756 | |||
757 | //
|
||
758 | // NB: This function is called from the (TX) interrupt handler
|
||
759 | //
|
||
760 | #pragma GCC optimize ("O3") |
||
761 | void instance_txcallback(const dwt_cb_data_t *txd){ |
||
762 | |||
763 | (void) txd;
|
||
764 | int instance = 0; |
||
765 | uint8_t txTimeStamp[5] = {0, 0, 0, 0, 0}; |
||
766 | // uint8 txevent = txd->event;
|
||
767 | event_data_t dw_event; |
||
768 | |||
769 | dw_event.uTimeStamp = portGetTickCnt(); |
||
770 | |||
771 | // chprintf((BaseSequentialStream *)&SD2, " TX callback! \r\n");
|
||
772 | |||
773 | // if(txevent == DWT_SIG_TX_DONE) {
|
||
774 | //uint32_t txtimestamp = 0;
|
||
775 | |||
776 | //NOTE - we can only get TX good (done) while here
|
||
777 | //dwt_readtxtimestamp((uint8*) &instance_data[instance].txu.txTimeStamp);
|
||
778 | |||
779 | dwt_readtxtimestamp(txTimeStamp) ; |
||
780 | dw_event.timeStamp32l = (uint32_t)txTimeStamp[0] + ((uint32_t)txTimeStamp[1] << 8) + ((uint32_t)txTimeStamp[2] << 16) + ((uint32_t)txTimeStamp[3] << 24); |
||
781 | dw_event.timeStamp = txTimeStamp[4];
|
||
782 | dw_event.timeStamp <<= 32;
|
||
783 | dw_event.timeStamp += dw_event.timeStamp32l; |
||
784 | dw_event.timeStamp32h = ((uint32_t)txTimeStamp[4] << 24) + (dw_event.timeStamp32l >> 8); |
||
785 | |||
786 | instance_data[instance].stopTimer = 0;
|
||
787 | |||
788 | dw_event.rxLength = instance_data[instance].psduLength; |
||
789 | dw_event.type = 0;
|
||
790 | dw_event.type_pend = 0;
|
||
791 | dw_event.type_save = DWT_SIG_TX_DONE; |
||
792 | |||
793 | memcpy((uint8_t *)&dw_event.msgu.frame[0], (uint8_t *)&instance_data[instance].msg_f, instance_data[instance].psduLength);
|
||
794 | |||
795 | instance_putevent(dw_event, DWT_SIG_TX_DONE); |
||
796 | |||
797 | instance_data[instance].txMsgCount++; |
||
798 | // }
|
||
799 | // else if(txevent == DWT_SIG_TX_AA_DONE) {
|
||
800 | // //auto ACK confirmation
|
||
801 | // dw_event.rxLength = 0;
|
||
802 | // dw_event.type = 0;
|
||
803 | // dw_event.type_save = DWT_SIG_TX_AA_DONE;
|
||
804 | //
|
||
805 | // instance_putevent(dw_event, DWT_SIG_TX_AA_DONE);
|
||
806 | //
|
||
807 | // //printf("TX AA time %f ecount %d\n",convertdevicetimetosecu(instance_data[instance].txu.txTimeStamp), instance_data[instance].dweventCnt);
|
||
808 | // }
|
||
809 | |||
810 | instance_data[instance].monitor = 0;
|
||
811 | } |
||
812 | |||
813 | /**
|
||
814 | * @brief function to re-enable the receiver and also adjust the timeout before sending the final message
|
||
815 | * if it is time so send the final message, the callback will notify the application, else the receiver is
|
||
816 | * automatically re-enabled
|
||
817 | *
|
||
818 | * this function is only used for tag when ranging to other anchors
|
||
819 | */
|
||
820 | uint8_t tagrxreenable(uint16_t sourceAddress){ |
||
821 | uint8_t type_pend = DWT_SIG_DW_IDLE; |
||
822 | uint8_t anc = sourceAddress & 0x3;
|
||
823 | int instance = 0; |
||
824 | |||
825 | switch(anc){
|
||
826 | //if we got Response from anchor 3 - this is the last expected response - send the final
|
||
827 | case 3: |
||
828 | type_pend = DWT_SIG_DW_IDLE; |
||
829 | break;
|
||
830 | |||
831 | //if we got Response from anchor 0, 1, or 2 - go back to wait for next anchor's response
|
||
832 | case 0: |
||
833 | case 1: |
||
834 | case 2: |
||
835 | default:
|
||
836 | if(instance_data[instance].responseTO > 0) { //can get here as result of error frame so need to check |
||
837 | dwt_setrxtimeout((uint16_t)instance_data[instance].fwtoTime_sy * instance_data[instance].responseTO); //reconfigure the timeout
|
||
838 | dwt_rxenable(DWT_START_RX_IMMEDIATE) ; |
||
839 | type_pend = DWT_SIG_RX_PENDING ; |
||
840 | } |
||
841 | else //last response was not received (got error/frame was corrupt) |
||
842 | { |
||
843 | type_pend = DWT_SIG_DW_IDLE; //report timeout - send the final
|
||
844 | } |
||
845 | break;
|
||
846 | } |
||
847 | |||
848 | return type_pend;
|
||
849 | } |
||
850 | |||
851 | /**
|
||
852 | * @brief function to re-enable the receiver and also adjust the timeout before sending the final message
|
||
853 | * if it is time so send the final message, the callback will notify the application, else the receiver is
|
||
854 | * automatically re-enabled
|
||
855 | *
|
||
856 | * this function is only used for anchors (having a role of ANCHOR_RNG) when ranging to other anchors
|
||
857 | */
|
||
858 | uint8_t ancsendfinalorrxreenable(uint16_t sourceAddress){ |
||
859 | uint8_t type_pend = DWT_SIG_DW_IDLE; |
||
860 | uint8_t anc = sourceAddress & 0x3;
|
||
861 | int instance = 0; |
||
862 | |||
863 | if(instance_data[instance].instanceAddress16 == GATEWAY_ANCHOR_ADDR) {
|
||
864 | switch(anc) {
|
||
865 | //if we got Response from anchor 1 - go back to wait for next anchor's response
|
||
866 | case 1: |
||
867 | dwt_setrxtimeout((uint16_t)instance_data[instance].fwtoTime_sy); //reconfigure the timeout
|
||
868 | dwt_rxenable(DWT_START_RX_IMMEDIATE) ; |
||
869 | type_pend = DWT_SIG_RX_PENDING ; |
||
870 | break;
|
||
871 | |||
872 | //if we got Response from anchor 2 - this is the last expected response - send the final
|
||
873 | case 2: |
||
874 | default:
|
||
875 | type_pend = DWT_SIG_DW_IDLE; |
||
876 | break;
|
||
877 | } |
||
878 | } |
||
879 | |||
880 | if(instance_data[instance].instanceAddress16 == A1_ANCHOR_ADDR){
|
||
881 | switch(anc)
|
||
882 | { |
||
883 | //if we got Response from anchor 2 - this is the last expected response - send the final
|
||
884 | case 2: |
||
885 | default:
|
||
886 | type_pend = DWT_SIG_DW_IDLE; |
||
887 | break;
|
||
888 | } |
||
889 | } |
||
890 | return type_pend;
|
||
891 | } |
||
892 | |||
893 | /**
|
||
894 | * @brief this function either enables the receiver (delayed)
|
||
895 | *
|
||
896 | **/
|
||
897 | void ancenablerx(void){ |
||
898 | int instance = 0; |
||
899 | //subtract preamble length
|
||
900 | dwt_setdelayedtrxtime(instance_data[instance].delayedReplyTime - instance_data[instance].fixedReplyDelayAncP) ; |
||
901 | if(dwt_rxenable(DWT_START_RX_DELAYED)) { //delayed rx |
||
902 | //if the delayed RX failed - time has passed - do immediate enable
|
||
903 | //led_on(LED_PC9);
|
||
904 | dwt_setrxtimeout((uint16_t)instance_data[instance].fwtoTimeAnc_sy*2); //reconfigure the timeout before enable |
||
905 | //longer timeout as we cannot do delayed receive... so receiver needs to stay on for longer
|
||
906 | dwt_rxenable(DWT_START_RX_IMMEDIATE); |
||
907 | dwt_setrxtimeout((uint16_t)instance_data[instance].fwtoTimeAnc_sy); //restore the timeout for next RX enable
|
||
908 | instance_data[instance].lateRX++; |
||
909 | //led_off(LED_PC9);
|
||
910 | } |
||
911 | |||
912 | } |
||
913 | |||
914 | /**
|
||
915 | * @brief this function either re-enables the receiver (delayed or immediate) or transmits the response frame
|
||
916 | *
|
||
917 | * @param the sourceAddress is the address of the sender of the current received frame
|
||
918 | * @param ancToAncTWR == 1 means that the anchor is ranging to another anchor, if == 0 then ranging to a tag
|
||
919 | *
|
||
920 | */
|
||
921 | #pragma GCC optimize ("O0") |
||
922 | uint8_t anctxorrxreenable(uint16_t sourceAddress, int ancToAncTWR){
|
||
923 | uint8_t type_pend = DWT_SIG_DW_IDLE; |
||
924 | int sendResp = 0; |
||
925 | int instance = 0; |
||
926 | |||
927 | if(instance_data[instance].responseTO == 0) { //go back to RX without TO - ranging has finished. (wait for Final but no TO) |
||
928 | dwt_setrxtimeout(0); //reconfigure the timeout |
||
929 | dwt_setpreambledetecttimeout(0);
|
||
930 | } |
||
931 | |||
932 | if((ancToAncTWR & 1) == 1) { |
||
933 | if(instance_data[instance].responseTO == 1) { //if one response left to receive (send a response now) |
||
934 | sendResp = 1;
|
||
935 | } |
||
936 | //if A0 or A3 go back to RX as they do not send any responses when Anchor to Anchor ranging
|
||
937 | if((instance_data[instance].gatewayAnchor)
|
||
938 | || (instance_data[instance].shortAdd_idx == 3)) { //if this is anchor ID 3 do not reply to anchor poll |
||
939 | dwt_setrxtimeout(0);
|
||
940 | dwt_rxenable(DWT_START_RX_IMMEDIATE); |
||
941 | return DWT_SIG_RX_PENDING ;
|
||
942 | } |
||
943 | } |
||
944 | |||
945 | //configure delayed reply time (this is incremented for each received frame) it is timed from Poll rx time
|
||
946 | instance_data[instance].delayedReplyTime += (instance_data[instance].fixedReplyDelayAnc >> 8);
|
||
947 | |||
948 | //this checks if to send a frame
|
||
949 | if((((ancToAncTWR & 1) == 0) && ((instance_data[instance].responseTO + instance_data[instance].shortAdd_idx) == NUM_EXPECTED_RESPONSES)) //it's our turn to tx |
||
950 | || (sendResp == 1)) {
|
||
951 | //led_on(LED_PC9);
|
||
952 | //response is expected
|
||
953 | instance_data[instance].wait4ack = DWT_RESPONSE_EXPECTED; //re has/will be re-enabled
|
||
954 | |||
955 | dwt_setdelayedtrxtime(instance_data[instance].delayedReplyTime) ; |
||
956 | if(dwt_starttx(DWT_START_TX_DELAYED | DWT_RESPONSE_EXPECTED)) {
|
||
957 | //if TX has failed - we need to re-enable RX for the next response or final reception...
|
||
958 | dwt_setrxaftertxdelay(0);
|
||
959 | instance_data[instance].wait4ack = 0; //clear the flag as the TX has failed the TRX is off |
||
960 | instance_data[instance].lateTX++; |
||
961 | instance_data[instance].delayedReplyTime += 2*(instance_data[instance].fixedReplyDelayAnc >> 8); //to take into account W4R |
||
962 | ancenablerx(); |
||
963 | type_pend = DWT_SIG_RX_PENDING ; |
||
964 | } |
||
965 | else {
|
||
966 | instance_data[instance].delayedReplyTime += (instance_data[instance].fixedReplyDelayAnc >> 8); //to take into account W4R |
||
967 | type_pend = DWT_SIG_TX_PENDING ; // exit this interrupt and notify the application/instance that TX is in progress.
|
||
968 | instance_data[instance].timeofTx = portGetTickCnt(); |
||
969 | instance_data[instance].monitor = 1;
|
||
970 | } |
||
971 | //led_off(LED_PC9);
|
||
972 | } |
||
973 | else { //stay in receive |
||
974 | if(sourceAddress == 0) { //we got here after RX error, as we don't need to TX, we just enable RX |
||
975 | dwt_setrxtimeout(0);
|
||
976 | dwt_rxenable(DWT_START_RX_IMMEDIATE); |
||
977 | } |
||
978 | else{
|
||
979 | //led_on(LED_PC9);
|
||
980 | ancenablerx(); |
||
981 | //led_off(LED_PC9);
|
||
982 | } |
||
983 | |||
984 | type_pend = DWT_SIG_RX_PENDING ; |
||
985 | } |
||
986 | //if time to send a response
|
||
987 | |||
988 | return type_pend;
|
||
989 | } |
||
990 | |||
991 | /**
|
||
992 | * @brief this function handles frame error event, it will either signal TO or re-enable the receiver
|
||
993 | */
|
||
994 | void handle_error_unknownframe(event_data_t dw_event){
|
||
995 | int instance = 0; |
||
996 | //re-enable the receiver (after error frames as we are not using auto re-enable
|
||
997 | //for ranging application rx error frame is same as TO - as we are not going to get the expected frame
|
||
998 | if(instance_data[instance].mode == ANCHOR){
|
||
999 | //if we are participating in the ranging (i.e. Poll was received)
|
||
1000 | //and we get an rx error (in one of the responses)
|
||
1001 | //need to consider this as a timeout as we could be sending our response next and
|
||
1002 | //the applications needs to know to change the state
|
||
1003 | //
|
||
1004 | if(instance_data[instance].responseTO > 0){ |
||
1005 | instance_data[instance].responseTO--; |
||
1006 | |||
1007 | //send a response or re-enable rx
|
||
1008 | dw_event.type_pend = anctxorrxreenable(0, 0); |
||
1009 | dw_event.type = 0;
|
||
1010 | dw_event.type_save = 0x40 | DWT_SIG_RX_TIMEOUT;
|
||
1011 | dw_event.rxLength = 0;
|
||
1012 | |||
1013 | instance_putevent(dw_event, DWT_SIG_RX_TIMEOUT); |
||
1014 | } |
||
1015 | else{
|
||
1016 | dwt_setrxtimeout(0); //reconfigure the timeout |
||
1017 | dwt_rxenable(DWT_START_RX_IMMEDIATE) ; |
||
1018 | } |
||
1019 | } |
||
1020 | else if(instance_data[instance].mode == LISTENER){ |
||
1021 | dwt_rxenable(DWT_START_RX_IMMEDIATE) ; |
||
1022 | } |
||
1023 | else{
|
||
1024 | instance_data[instance].responseTO--; //got something (need to reduce timeout (for remaining responses))
|
||
1025 | |||
1026 | dw_event.type_pend = tagrxreenable(0); //check if receiver will be re-enabled or it's time to send the final |
||
1027 | dw_event.type = 0;
|
||
1028 | dw_event.type_save = 0x40 | DWT_SIG_RX_TIMEOUT;
|
||
1029 | dw_event.rxLength = 0;
|
||
1030 | |||
1031 | instance_putevent(dw_event, DWT_SIG_RX_TIMEOUT); |
||
1032 | } |
||
1033 | } |
||
1034 | |||
1035 | |||
1036 | /**
|
||
1037 | * @brief this function prepares and writes the anchor to anchor response frame into the TX buffer
|
||
1038 | * it is called after anchor receives a Poll from an anchor
|
||
1039 | */
|
||
1040 | void ancprepareresponse2(uint16_t sourceAddress, uint8_t srcAddr_index, uint8_t fcode_index, uint8_t *frame){
|
||
1041 | uint16_t frameLength = 0;
|
||
1042 | uint8_t tof_idx = (sourceAddress) & 0x3 ;
|
||
1043 | int instance = 0; |
||
1044 | |||
1045 | instance_data[instance].psduLength = frameLength = ANCH_RESPONSE_MSG_LEN + FRAME_CRTL_AND_ADDRESS_S + FRAME_CRC; |
||
1046 | //set the destination address (copy source as this is a reply)
|
||
1047 | memcpy(&instance_data[instance].msg_f.destAddr[0], &frame[srcAddr_index], ADDR_BYTE_SIZE_S); //remember who to send the reply to (set destination address) |
||
1048 | instance_data[instance].msg_f.sourceAddr[0] = instance_data[instance].eui64[0]; |
||
1049 | instance_data[instance].msg_f.sourceAddr[1] = instance_data[instance].eui64[1]; |
||
1050 | // Write calculated TOF into response message (get the previous ToF+range number from that anchor)
|
||
1051 | memcpy(&(instance_data[instance].msg_f.messageData[TOFR]), &instance_data[instance].tofAnc[tof_idx], 4);
|
||
1052 | instance_data[instance].msg_f.messageData[TOFRN] = instance_data[instance].rangeNumAAnc[tof_idx]; //get the previous range number
|
||
1053 | |||
1054 | instance_data[instance].rangeNumAAnc[tof_idx] = 0; //clear the entry |
||
1055 | instance_data[instance].rangeNumAnc = frame[POLL_RNUM + fcode_index] ; |
||
1056 | instance_data[instance].msg_f.seqNum = instance_data[instance].frameSN++; |
||
1057 | |||
1058 | //set the delayed rx on time (the final message will be sent after this delay)
|
||
1059 | dwt_setrxaftertxdelay(instance_data[instance].ancRespRxDelay); //units are 1.0256us - wait for wait4respTIM before RX on (delay RX)
|
||
1060 | |||
1061 | instance_data[instance].tagSleepCorrection = 0;
|
||
1062 | instance_data[instance].msg_f.messageData[RES_TAG_SLP0] = 0 ;
|
||
1063 | instance_data[instance].msg_f.messageData[RES_TAG_SLP1] = 0 ;
|
||
1064 | |||
1065 | instance_data[instance].msg_f.messageData[FCODE] = RTLS_DEMO_MSG_ANCH_RESP2; //message function code (specifies if message is a poll, response or other...)
|
||
1066 | |||
1067 | //write the TX data
|
||
1068 | dwt_writetxfctrl(frameLength, 0, 1); |
||
1069 | dwt_writetxdata(frameLength, (uint8_t *) &instance_data[instance].msg_f, 0) ; // write the frame data |
||
1070 | |||
1071 | } |
||
1072 | |||
1073 | /**
|
||
1074 | * @brief this function prepares and writes the anchor to tag response frame into the TX buffer
|
||
1075 | * it is called after anchor receives a Poll from a tag
|
||
1076 | */
|
||
1077 | void ancprepareresponse(uint16_t sourceAddress, uint8_t srcAddr_index, uint8_t fcode_index, uint8_t *frame, uint32_t uTimeStamp){
|
||
1078 | uint16_t frameLength = 0;
|
||
1079 | uint8_t tof_idx = (sourceAddress) & 0x7 ;
|
||
1080 | int instance = 0; |
||
1081 | |||
1082 | instance_data[instance].psduLength = frameLength = ANCH_RESPONSE_MSG_LEN + FRAME_CRTL_AND_ADDRESS_S + FRAME_CRC; |
||
1083 | memcpy(&instance_data[instance].msg_f.destAddr[0], &frame[srcAddr_index], ADDR_BYTE_SIZE_S); //remember who to send the reply to (set destination address) |
||
1084 | instance_data[instance].msg_f.sourceAddr[0] = instance_data[instance].eui64[0]; |
||
1085 | instance_data[instance].msg_f.sourceAddr[1] = instance_data[instance].eui64[1]; |
||
1086 | // Write calculated TOF into response message (get the previous ToF+range number from that tag)
|
||
1087 | memcpy(&(instance_data[instance].msg_f.messageData[TOFR]), &instance_data[instance].tof[tof_idx], 4);
|
||
1088 | instance_data[instance].msg_f.messageData[TOFRN] = instance_data[instance].rangeNumA[tof_idx]; //get the previous range number
|
||
1089 | |||
1090 | instance_data[instance].rangeNumA[tof_idx] = 0; //clear after copy above... |
||
1091 | instance_data[instance].rangeNum = frame[POLL_RNUM+fcode_index] ; |
||
1092 | instance_data[instance].msg_f.seqNum = instance_data[instance].frameSN++; |
||
1093 | |||
1094 | //we have our range - update the own mask entry...
|
||
1095 | if(instance_data[instance].tof[tof_idx] != INVALID_TOF) { //check the last ToF entry is valid and copy into the current array |
||
1096 | instance_data[instance].rxResponseMask = (0x1 << instance_data[instance].shortAdd_idx);
|
||
1097 | instance_data[instance].tofArray[instance_data[instance].shortAdd_idx] = instance_data[instance].tof[tof_idx]; |
||
1098 | } |
||
1099 | else { //reset response mask |
||
1100 | instance_data[instance].tofArray[instance_data[instance].shortAdd_idx] = INVALID_TOF ; |
||
1101 | instance_data[instance].rxResponseMask = 0; //reset the mask of received responses when rx poll |
||
1102 | } |
||
1103 | //set the delayed rx on time (the final message will be sent after this delay)
|
||
1104 | dwt_setrxaftertxdelay(instance_data[instance].ancRespRxDelay); //units are 1.0256us - wait for wait4respTIM before RX on (delay RX)
|
||
1105 | |||
1106 | //if this is gateway anchor - calculate the slot period correction
|
||
1107 | if(instance_data[instance].gatewayAnchor) {
|
||
1108 | int error = 0; |
||
1109 | int currentSlotTime = 0; |
||
1110 | int expectedSlotTime = 0; |
||
1111 | //find the time in the current superframe
|
||
1112 | currentSlotTime = uTimeStamp % instance_data[instance].sframePeriod; |
||
1113 | |||
1114 | //this is the slot time the poll should be received in (Mask 0x07 for the 8 MAX tags we support in TREK)
|
||
1115 | expectedSlotTime = (sourceAddress&0xFF) * instance_data[instance].slotPeriod; // |
||
1116 | |||
1117 | //error = expectedSlotTime - currentSlotTime
|
||
1118 | error = expectedSlotTime - currentSlotTime; |
||
1119 | |||
1120 | if(error < (-(instance_data[instance].sframePeriod>>1))) { //if error is more negative than 0.5 period, add whole period to give up to 1.5 period sleep |
||
1121 | instance_data[instance].tagSleepCorrection = (instance_data[instance].sframePeriod + error); |
||
1122 | } |
||
1123 | else { //the minimum Sleep time will be 0.5 period |
||
1124 | instance_data[instance].tagSleepCorrection = error; |
||
1125 | } |
||
1126 | instance_data[instance].msg_f.messageData[RES_TAG_SLP0] = instance_data[instance].tagSleepCorrection & 0xFF ;
|
||
1127 | instance_data[instance].msg_f.messageData[RES_TAG_SLP1] = (instance_data[instance].tagSleepCorrection >> 8) & 0xFF; |
||
1128 | } |
||
1129 | else {
|
||
1130 | instance_data[instance].tagSleepCorrection = 0;
|
||
1131 | instance_data[instance].msg_f.messageData[RES_TAG_SLP0] = 0 ;
|
||
1132 | instance_data[instance].msg_f.messageData[RES_TAG_SLP1] = 0 ;
|
||
1133 | } |
||
1134 | instance_data[instance].msg_f.messageData[FCODE] = RTLS_DEMO_MSG_ANCH_RESP; //message function code (specifies if message is a poll, response or other...)
|
||
1135 | |||
1136 | //write the TX data
|
||
1137 | dwt_writetxfctrl(frameLength, 0, 1); |
||
1138 | dwt_writetxdata(frameLength, (uint8_t *) &instance_data[instance].msg_f, 0) ; // write the frame data |
||
1139 | } |
||
1140 | |||
1141 | /**
|
||
1142 | * @brief this is the receive event callback handler, the received event is processed and the instance either
|
||
1143 | * responds by sending a response frame or re-enables the receiver to await the next frame
|
||
1144 | * once the immediate action is taken care of the event is queued up for application to process
|
||
1145 | */
|
||
1146 | #pragma GCC optimize ("O3") |
||
1147 | void instance_rxcallback(const dwt_cb_data_t *rxd){ |
||
1148 | int instance = 0; |
||
1149 | uint8_t rxTimeStamp[5] = {0, 0, 0, 0, 0}; |
||
1150 | |||
1151 | uint8_t rxd_event = 0;
|
||
1152 | uint8_t fcode_index = 0;
|
||
1153 | uint8_t srcAddr_index = 0;
|
||
1154 | event_data_t dw_event; |
||
1155 | |||
1156 | //microcontroller time at which we received the frame
|
||
1157 | dw_event.uTimeStamp = portGetTickCnt(); |
||
1158 | |||
1159 | //if we got a frame with a good CRC - RX OK
|
||
1160 | // if(rxd->event == DWT_SIG_RX_OKAY) { // Timeout and error are handle separately in the driver itself
|
||
1161 | dw_event.rxLength = rxd->datalength; |
||
1162 | |||
1163 | //need to process the frame control bytes to figure out what type of frame we have received
|
||
1164 | if(((rxd->fctrl[0] == 0x41) || (rxd->fctrl[0] == 0x61)) |
||
1165 | && |
||
1166 | ((rxd->fctrl[1] & 0xCC) == 0x88)) { //short address |
||
1167 | fcode_index = FRAME_CRTL_AND_ADDRESS_S; //function code is in first byte after source address
|
||
1168 | srcAddr_index = FRAME_CTRLP + ADDR_BYTE_SIZE_S; |
||
1169 | rxd_event = DWT_SIG_RX_OKAY; |
||
1170 | } |
||
1171 | else {
|
||
1172 | rxd_event = SIG_RX_UNKNOWN; //not supported - all TREK1000 frames are short addressed
|
||
1173 | } |
||
1174 | |||
1175 | //read RX timestamp
|
||
1176 | dwt_readrxtimestamp(rxTimeStamp) ; |
||
1177 | dwt_readrxdata((uint8_t *)&dw_event.msgu.frame[0], rxd->datalength, 0); // Read Data Frame |
||
1178 | dw_event.timeStamp32l = (uint32_t)rxTimeStamp[0] + ((uint32_t)rxTimeStamp[1] << 8) + ((uint32_t)rxTimeStamp[2] << 16) + ((uint32_t)rxTimeStamp[3] << 24); |
||
1179 | dw_event.timeStamp = rxTimeStamp[4];
|
||
1180 | dw_event.timeStamp <<= 32;
|
||
1181 | dw_event.timeStamp += dw_event.timeStamp32l; |
||
1182 | dw_event.timeStamp32h = ((uint32_t)rxTimeStamp[4] << 24) + (dw_event.timeStamp32l >> 8); |
||
1183 | |||
1184 | dw_event.type = 0; //type will be added as part of adding to event queue |
||
1185 | dw_event.type_save = rxd_event; |
||
1186 | dw_event.type_pend = DWT_SIG_DW_IDLE; |
||
1187 | |||
1188 | //if Listener then just report the received frame to the instance (application)
|
||
1189 | if(rxd_event == DWT_SIG_RX_OKAY) { //Process good/known frame types |
||
1190 | uint16_t sourceAddress = (((uint16_t)dw_event.msgu.frame[srcAddr_index+1]) << 8) + dw_event.msgu.frame[srcAddr_index]; |
||
1191 | |||
1192 | if(instance_data[instance].mode != LISTENER) {
|
||
1193 | if(instance_data[instance].mode == TAG) //if tag got a good frame - this is probably a response, but could also be some other non-ranging frame |
||
1194 | //(although due to frame filtering this is limited as non-addressed frames are filtered out)
|
||
1195 | { |
||
1196 | instance_data[instance].responseTO--; //got 1 more response or other RX frame - need to reduce timeout (for next response)
|
||
1197 | } |
||
1198 | |||
1199 | //check if this is a TWR message (and also which one)
|
||
1200 | switch(dw_event.msgu.frame[fcode_index]){
|
||
1201 | //poll message from an anchor
|
||
1202 | case RTLS_DEMO_MSG_ANCH_POLL:{
|
||
1203 | //the anchor to anchor ranging poll frames are ignored by A0 and A3
|
||
1204 | if(instance_data[instance].gatewayAnchor || (instance_data[instance].instanceAddress16 > A2_ANCHOR_ADDR)){
|
||
1205 | //ignore poll from anchor 1 if gateway or anchor 3
|
||
1206 | //anchors 2 and 3 will never send polls
|
||
1207 | dw_event.type_pend = DWT_SIG_DW_IDLE ; |
||
1208 | break;
|
||
1209 | } |
||
1210 | |||
1211 | if(instance_data[instance].mode == TAG) { //tag should ignore any other Polls from anchors |
||
1212 | instance_data[instance].responseTO++; //as will be decremented in the function and was also decremented above
|
||
1213 | handle_error_unknownframe(dw_event); |
||
1214 | instance_data[instance].stopTimer = 1;
|
||
1215 | instance_data[instance].rxMsgCount++; |
||
1216 | return;
|
||
1217 | } |
||
1218 | |||
1219 | //update the response index and number of responses received tables
|
||
1220 | instance_data[instance].rxRespsIdx = (uint8_t) ((dw_event.msgu.frame[POLL_RNUM+fcode_index] & 0xf)
|
||
1221 | + (((sourceAddress&0x3) + 8) << 4)); |
||
1222 | instance_data[instance].rxResps[instance_data[instance].rxRespsIdx] = 0;
|
||
1223 | //debug LED on
|
||
1224 | // led_on(LED_PC9);
|
||
1225 | |||
1226 | //prepare the response and write it to the tx buffer
|
||
1227 | ancprepareresponse2(sourceAddress, srcAddr_index, fcode_index, &dw_event.msgu.frame[0]);
|
||
1228 | |||
1229 | //A2 does not need timeout if ranging to A1
|
||
1230 | if(sourceAddress != A1_ANCHOR_ADDR){
|
||
1231 | dwt_setrxtimeout((uint16_t)instance_data[instance].fwtoTimeAnc_sy); //reconfigure the timeout for response
|
||
1232 | } |
||
1233 | |||
1234 | //set the bast reply time (the actual will be Poll rx time + instance_data[0].fixedReplyDelayAnc)
|
||
1235 | instance_data[instance].delayedReplyTime = dw_event.timeStamp32h ; |
||
1236 | instance_data[instance].responseTO = (instance_data[instance].instanceAddress16 - sourceAddress) & 0x3; //set number of expected responses |
||
1237 | |||
1238 | dw_event.type_pend = anctxorrxreenable(instance_data[instance].instanceAddress16, 2+1); |
||
1239 | |||
1240 | instance_data[instance].tofAnc[sourceAddress & 0x3] = INVALID_TOF; //clear ToF .. |
||
1241 | //debug LED off
|
||
1242 | // led_off(LED_PC9);
|
||
1243 | break;
|
||
1244 | } |
||
1245 | |||
1246 | case RTLS_DEMO_MSG_TAG_POLL:{
|
||
1247 | if(instance_data[instance].mode == TAG) { //tag should ignore any other Polls from tags |
||
1248 | instance_data[instance].responseTO++; //as will be decremented in the function and was also decremented above
|
||
1249 | handle_error_unknownframe(dw_event); |
||
1250 | instance_data[instance].stopTimer = 1;
|
||
1251 | instance_data[instance].rxMsgCount++; |
||
1252 | return;
|
||
1253 | } |
||
1254 | instance_data[instance].rxRespsIdx = (int8_t) ((dw_event.msgu.frame[POLL_RNUM+fcode_index] & 0xf)
|
||
1255 | + ((sourceAddress&0x7) << 4)); |
||
1256 | instance_data[instance].rxResps[instance_data[instance].rxRespsIdx] = 0;
|
||
1257 | |||
1258 | //prepare the response and write it to the tx buffer
|
||
1259 | ancprepareresponse(sourceAddress, srcAddr_index, fcode_index, &dw_event.msgu.frame[0], dw_event.uTimeStamp);
|
||
1260 | |||
1261 | dwt_setrxtimeout((uint16_t)instance_data[instance].fwtoTimeAnc_sy); //reconfigure the timeout for response
|
||
1262 | |||
1263 | instance_data[0].delayedReplyTime = dw_event.timeStamp32h /*+ (instance_data[0].fixedReplyDelayAnc >> 8)*/ ; |
||
1264 | instance_data[instance].responseTO = NUM_EXPECTED_RESPONSES; //set number of expected responses to 3 (from other anchors)
|
||
1265 | |||
1266 | dw_event.type_pend = anctxorrxreenable(instance_data[instance].instanceAddress16, 2+0); |
||
1267 | |||
1268 | instance_data[instance].tof[sourceAddress & 0x7] = INVALID_TOF; //clear ToF .. |
||
1269 | } |
||
1270 | break;
|
||
1271 | |||
1272 | //we got a response from a "responder" (anchor)
|
||
1273 | case RTLS_DEMO_MSG_ANCH_RESP:
|
||
1274 | case RTLS_DEMO_MSG_ANCH_RESP2:{
|
||
1275 | |||
1276 | //we are a tag
|
||
1277 | if(instance_data[instance].mode == TAG){
|
||
1278 | uint8_t index ; |
||
1279 | instance_data[instance].rxResps[instance_data[instance].rangeNum]++; |
||
1280 | dw_event.type_pend = tagrxreenable(sourceAddress); //responseTO decremented above...
|
||
1281 | index = RRXT0 + 5*(sourceAddress & 0x3); |
||
1282 | |||
1283 | instance_data[instance].rxResponseMask |= (0x1 << (sourceAddress & 0x3)); //add anchor ID to the mask |
||
1284 | // Write Response RX time field of Final message
|
||
1285 | memcpy(&(instance_data[instance].msg_f.messageData[index]), rxTimeStamp, 5);
|
||
1286 | |||
1287 | } |
||
1288 | else if (instance_data[instance].mode == ANCHOR_RNG) { //A0 and A1 only when ranging to other anchors |
||
1289 | uint8_t index ; |
||
1290 | instance_data[instance].rxResps[instance_data[instance].rangeNumAnc]++; |
||
1291 | dw_event.type_pend = ancsendfinalorrxreenable(sourceAddress); |
||
1292 | index = RRXT0 + 5*(sourceAddress & 0x3); |
||
1293 | |||
1294 | instance_data[instance].rxResponseMaskAnc |= (0x1 << (sourceAddress & 0x3)); //add anchor ID to the mask |
||
1295 | // Write Response RX time field of Final message
|
||
1296 | memcpy(&(instance_data[instance].msg_f.messageData[index]), rxTimeStamp, 5);
|
||
1297 | } |
||
1298 | else { //normal anchor mode |
||
1299 | //got a response... (check if we got a Poll with the same range number as in this response)
|
||
1300 | if(RTLS_DEMO_MSG_ANCH_RESP == dw_event.msgu.frame[fcode_index]){
|
||
1301 | if((instance_data[instance].rxResps[instance_data[instance].rxRespsIdx] >= 0) //we got the poll else ignore this response |
||
1302 | && (instance_data[instance].responseTO > 0) ) { //if responseTO == 0 we have already received all of the responses - meaning should not be here => error |
||
1303 | instance_data[instance].rxResps[instance_data[instance].rxRespsIdx]++; //increment the number of responses received
|
||
1304 | instance_data[instance].responseTO--; |
||
1305 | |||
1306 | //send a response or re-enable rx
|
||
1307 | dw_event.type_pend = anctxorrxreenable(sourceAddress, 4+0); |
||
1308 | } |
||
1309 | else { //like a timeout (error) ... |
||
1310 | |||
1311 | //send a response or re-enable rx
|
||
1312 | dwt_setrxtimeout(0); //reconfigure the timeout |
||
1313 | dwt_rxenable(DWT_START_RX_IMMEDIATE) ; |
||
1314 | dw_event.type_pend = DWT_SIG_RX_PENDING ; |
||
1315 | } |
||
1316 | } |
||
1317 | else { //in anchor mode and got RTLS_DEMO_MSG_ANCH_RESP2 |
||
1318 | if((instance_data[instance].gatewayAnchor) &&
|
||
1319 | (instance_data[instance].rxResps[instance_data[instance].rangeNumAnc]) == 2){ //got two responses A1 and A2 this is third (A2's to A1) |
||
1320 | instance_data[instance].rxResps[instance_data[instance].rangeNumAnc]++; |
||
1321 | instance_data[instance].rxResponseMaskAnc |= 0x8 ;
|
||
1322 | |||
1323 | dw_event.type_pend = anctxorrxreenable(sourceAddress, 4+1); //re-enable the RX |
||
1324 | } |
||
1325 | //A2 got A1's response to A0 - send A2 response (but only if we got the Poll from A0)
|
||
1326 | else if((instance_data[instance].instanceAddress16 == A2_ANCHOR_ADDR) && |
||
1327 | (instance_data[instance].rxResps[instance_data[instance].rxRespsIdx] >= 0) ){
|
||
1328 | instance_data[instance].rxResps[instance_data[instance].rxRespsIdx]++; |
||
1329 | instance_data[instance].responseTO--; |
||
1330 | |||
1331 | dwt_setrxtimeout(0);
|
||
1332 | dwt_setrxaftertxdelay(0); //clear rx on delay as Final will come sooner than if we were waiting for next Response |
||
1333 | dw_event.type_pend = anctxorrxreenable(sourceAddress, 1);
|
||
1334 | } |
||
1335 | else { // if other anchor A1, A2, A3 .. ignore these responses when in ANCHOR mode |
||
1336 | dwt_setrxtimeout(0); //reconfigure the timeout |
||
1337 | dwt_rxenable(DWT_START_RX_IMMEDIATE) ; |
||
1338 | dw_event.type_pend = DWT_SIG_RX_PENDING ; |
||
1339 | } |
||
1340 | } |
||
1341 | } |
||
1342 | |||
1343 | } |
||
1344 | break;
|
||
1345 | |||
1346 | case RTLS_DEMO_MSG_TAG_FINAL:
|
||
1347 | case RTLS_DEMO_MSG_ANCH_FINAL:
|
||
1348 | if(instance_data[instance].mode == TAG) { //tag should ignore any other Final from anchors |
||
1349 | instance_data[instance].responseTO++; //as will be decremented in the function and was also decremented above
|
||
1350 | handle_error_unknownframe(dw_event); |
||
1351 | instance_data[instance].stopTimer = 1;
|
||
1352 | instance_data[instance].rxMsgCount++; |
||
1353 | return;
|
||
1354 | } |
||
1355 | break; // TODO: fallthourgh for anchor |
||
1356 | // __attribute__ ((fallthrough));
|
||
1357 | |||
1358 | //if anchor fall into case below and process the frame
|
||
1359 | default: { //process rx frame |
||
1360 | dw_event.type_pend = DWT_SIG_DW_IDLE; |
||
1361 | } |
||
1362 | break;
|
||
1363 | |||
1364 | } |
||
1365 | }//end of if not Listener mode
|
||
1366 | instance_data[instance].stopTimer = 1;
|
||
1367 | |||
1368 | instance_putevent(dw_event, rxd_event); |
||
1369 | |||
1370 | instance_data[instance].rxMsgCount++; |
||
1371 | } |
||
1372 | else { //if (rxd_event == SIG_RX_UNKNOWN) //need to re-enable the rx (got unknown frame type) |
||
1373 | handle_error_unknownframe(dw_event); |
||
1374 | } |
||
1375 | // }
|
||
1376 | } |
||
1377 | |||
1378 | |||
1379 | /*TODO: Callback funtion for RX timeout (available from newer driver version) */
|
||
1380 | #pragma GCC optimize ("O3") |
||
1381 | void instance_rxtimeoutcallback(const dwt_cb_data_t *rxd){ |
||
1382 | |||
1383 | (void) rxd;
|
||
1384 | event_data_t dw_event; |
||
1385 | |||
1386 | int instance = 0; |
||
1387 | |||
1388 | dw_event.type_pend = DWT_SIG_DW_IDLE; |
||
1389 | |||
1390 | if(instance_data[instance].mode == ANCHOR) {
|
||
1391 | //check if anchor has received all of the responses from other anchors (it could have received only 1 or 2)
|
||
1392 | //it's timed out (re-enable rx or tx response)
|
||
1393 | if(instance_data[instance].responseTO > 0) { |
||
1394 | instance_data[instance].responseTO--; |
||
1395 | //send a response or re-enable rx
|
||
1396 | dw_event.type_pend = anctxorrxreenable(instance_data[instance].instanceAddress16, 6+0); |
||
1397 | // Print_On_Uart("Re-enable RX in rxtimeout callback\r\n");
|
||
1398 | } |
||
1399 | } |
||
1400 | dw_event.type = 0;
|
||
1401 | dw_event.type_save = DWT_SIG_RX_TIMEOUT; |
||
1402 | dw_event.rxLength = 0;
|
||
1403 | dw_event.timeStamp = 0;
|
||
1404 | dw_event.timeStamp32l = 0;
|
||
1405 | dw_event.timeStamp32h = 0;
|
||
1406 | |||
1407 | instance_putevent(dw_event, DWT_SIG_RX_TIMEOUT); |
||
1408 | // printf("RX timeout while in %d\n", instance_data[instance].testAppState);
|
||
1409 | |||
1410 | } |
||
1411 | |||
1412 | |||
1413 | /*TODO: Callback funtion for RX error (available from newer driver version) */
|
||
1414 | #pragma GCC optimize ("O3") |
||
1415 | void instance_rxerrorcallback(const dwt_cb_data_t *rxd) { |
||
1416 | |||
1417 | (void) rxd;
|
||
1418 | event_data_t dw_event; |
||
1419 | |||
1420 | dw_event.uTimeStamp = portGetTickCnt(); |
||
1421 | |||
1422 | handle_error_unknownframe(dw_event); |
||
1423 | } |
||
1424 | |||
1425 | |||
1426 | |||
1427 | #pragma GCC optimize ("O3") |
||
1428 | int instance_peekevent(void){ |
||
1429 | int instance = 0; |
||
1430 | return instance_data[instance].dwevent[instance_data[instance].dweventPeek].type; //return the type of event that is in front of the queue |
||
1431 | } |
||
1432 | |||
1433 | #pragma GCC optimize ("O3") |
||
1434 | void instance_saveevent(event_data_t newevent, uint8_t etype){
|
||
1435 | int instance = 0; |
||
1436 | |||
1437 | instance_data[instance].saved_dwevent = newevent; |
||
1438 | instance_data[instance].saved_dwevent.type = etype; |
||
1439 | } |
||
1440 | |||
1441 | #pragma GCC optimize ("O3") |
||
1442 | event_data_t instance_getsavedevent(void){
|
||
1443 | int instance = 0; |
||
1444 | |||
1445 | return instance_data[instance].saved_dwevent;
|
||
1446 | } |
||
1447 | |||
1448 | #pragma GCC optimize ("O3") |
||
1449 | void instance_putevent(event_data_t newevent, uint8_t etype){
|
||
1450 | int instance = 0; |
||
1451 | //newevent.eventtime = portGetTickCnt();
|
||
1452 | newevent.gotit = 0 ; //newevent.eventtimeclr = 0; |
||
1453 | |||
1454 | //copy event
|
||
1455 | instance_data[instance].dwevent[instance_data[instance].dweventIdxIn] = newevent; |
||
1456 | |||
1457 | //set type - this makes it a new event (making sure the event data is copied before event is set as new)
|
||
1458 | //to make sure that the get event function does not get an incomplete event
|
||
1459 | instance_data[instance].dwevent[instance_data[instance].dweventIdxIn].type = etype; |
||
1460 | |||
1461 | instance_data[instance].dweventIdxIn++; |
||
1462 | |||
1463 | if(MAX_EVENT_NUMBER == instance_data[instance].dweventIdxIn)
|
||
1464 | { |
||
1465 | instance_data[instance].dweventIdxIn = 0;
|
||
1466 | } |
||
1467 | //eventIncount++;
|
||
1468 | |||
1469 | //printf("put %d - in %d out %d @ %d\n", newevent.type, instance_data[instance].dweventCntIn, instance_data[instance].dweventCntOut, ptime);
|
||
1470 | } |
||
1471 | |||
1472 | event_data_t dw_event_g; |
||
1473 | |||
1474 | #pragma GCC optimize ("O3") |
||
1475 | event_data_t* instance_getevent(int x){
|
||
1476 | int instance = 0; |
||
1477 | int indexOut = instance_data[instance].dweventIdxOut;
|
||
1478 | |||
1479 | //dw_event_g = instance_data[instance].dwevent[instance_data[instance].dweventCntOut]; //this holds any TX/RX events
|
||
1480 | |||
1481 | //memcpy(&dw_event_g, &instance_data[instance].dwevent[instance_data[instance].dweventCntOut], sizeof(event_data_t));
|
||
1482 | |||
1483 | if(instance_data[instance].dwevent[indexOut].type == 0) { //exit with "no event" |
||
1484 | dw_event_g.type = 0;
|
||
1485 | dw_event_g.type_save = 0;
|
||
1486 | return &dw_event_g;
|
||
1487 | } |
||
1488 | |||
1489 | //copy the event
|
||
1490 | dw_event_g.type_save = instance_data[instance].dwevent[indexOut].type_save ; |
||
1491 | dw_event_g.type_pend = instance_data[instance].dwevent[indexOut].type_pend ; |
||
1492 | dw_event_g.rxLength = instance_data[instance].dwevent[indexOut].rxLength ; |
||
1493 | dw_event_g.timeStamp = instance_data[instance].dwevent[indexOut].timeStamp ; |
||
1494 | dw_event_g.timeStamp32l = instance_data[instance].dwevent[indexOut].timeStamp32l ; |
||
1495 | dw_event_g.timeStamp32h = instance_data[instance].dwevent[indexOut].timeStamp32h ; |
||
1496 | dw_event_g.uTimeStamp = instance_data[instance].dwevent[indexOut].uTimeStamp ; |
||
1497 | //dw_event_g.eventtime = instance_data[instance].dwevent[indexOut].eventtime ;
|
||
1498 | //dw_event_g.eventtimeclr = instance_data[instance].dwevent[indexOut].eventtimeclr ;
|
||
1499 | //dw_event_g.gotit = instance_data[instance].dwevent[indexOut].gotit ;
|
||
1500 | |||
1501 | memcpy(&dw_event_g.msgu, &instance_data[instance].dwevent[indexOut].msgu, sizeof(instance_data[instance].dwevent[indexOut].msgu));
|
||
1502 | |||
1503 | dw_event_g.type = instance_data[instance].dwevent[indexOut].type ; |
||
1504 | |||
1505 | |||
1506 | instance_data[instance].dwevent[indexOut].gotit = x; |
||
1507 | |||
1508 | //instance_data[instance].dwevent[indexOut].eventtimeclr = portGetTickCnt();
|
||
1509 | |||
1510 | instance_data[instance].dwevent[indexOut].type = 0; //clear the event |
||
1511 | |||
1512 | instance_data[instance].dweventIdxOut++; |
||
1513 | if(MAX_EVENT_NUMBER == instance_data[instance].dweventIdxOut){ //wrap the counter |
||
1514 | instance_data[instance].dweventIdxOut = 0;
|
||
1515 | } |
||
1516 | instance_data[instance].dweventPeek = instance_data[instance].dweventIdxOut; //set the new peek value
|
||
1517 | |||
1518 | //if(dw_event.type) printf("get %d - in %d out %d @ %d\n", dw_event.type, instance_data[instance].dweventCntIn, instance_data[instance].dweventCntOut, ptime);
|
||
1519 | |||
1520 | //eventOutcount++;
|
||
1521 | |||
1522 | |||
1523 | return &dw_event_g;
|
||
1524 | } |
||
1525 | |||
1526 | void instance_clearevents(void){ |
||
1527 | int i = 0; |
||
1528 | int instance = 0; |
||
1529 | |||
1530 | for(i=0; i<MAX_EVENT_NUMBER; i++) { |
||
1531 | memset(&instance_data[instance].dwevent[i], 0, sizeof(event_data_t)); |
||
1532 | } |
||
1533 | |||
1534 | instance_data[instance].dweventIdxIn = 0;
|
||
1535 | instance_data[instance].dweventIdxOut = 0;
|
||
1536 | instance_data[instance].dweventPeek = 0;
|
||
1537 | |||
1538 | //eventOutcount = 0;
|
||
1539 | //eventIncount = 0;
|
||
1540 | } |
||
1541 | |||
1542 | // -------------------------------------------------------------------------------------------------------------------
|
||
1543 | #pragma GCC optimize ("O3") |
||
1544 | int instance_run(void){ |
||
1545 | int instance = 0 ; |
||
1546 | int done = INST_NOT_DONE_YET;
|
||
1547 | int message = instance_peekevent(); //get any of the received events from ISR |
||
1548 | |||
1549 | |||
1550 | while(done == INST_NOT_DONE_YET){
|
||
1551 | //int state = instance_data[instance].testAppState;
|
||
1552 | done = testapprun(&instance_data[instance], message) ; // run the communications application
|
||
1553 | |||
1554 | //we've processed message
|
||
1555 | message = 0;
|
||
1556 | } |
||
1557 | |||
1558 | |||
1559 | |||
1560 | if(done == INST_DONE_WAIT_FOR_NEXT_EVENT_TO) { //we are in RX and need to timeout (Tag needs to send another poll if no Rx frame) |
||
1561 | if(instance_data[instance].mode == TAG) { //Tag (is either in RX or sleeping) |
||
1562 | int32_t nextPeriod ; |
||
1563 | |||
1564 | // next period will be a positive number because correction is -0.5 to +1.5 periods, (and tagSleepTime_ms is the period)
|
||
1565 | nextPeriod = instance_data[instance].tagSleepRnd + instance_data[instance].tagSleepTime_ms + instance_data[instance].tagSleepCorrection; |
||
1566 | |||
1567 | instance_data[instance].nextSleepPeriod = (uint32_t) nextPeriod ; //set timeout time, CAST the positive period to UINT for correct wrapping.
|
||
1568 | instance_data[instance].tagSleepCorrection2 = instance_data[instance].tagSleepCorrection; |
||
1569 | instance_data[instance].tagSleepCorrection = 0; //clear the correction |
||
1570 | instance_data[instance].instanceTimerEn = 1; //start timer |
||
1571 | } |
||
1572 | instance_data[instance].stopTimer = 0 ; //clear the flag - timer can run if instancetimer_en set (set above) |
||
1573 | instance_data[instance].done = INST_NOT_DONE_YET; |
||
1574 | } |
||
1575 | |||
1576 | //check if timer has expired
|
||
1577 | if((instance_data[instance].instanceTimerEn == 1) && (instance_data[instance].stopTimer == 0)) { |
||
1578 | if(instance_data[instance].mode == TAG) {
|
||
1579 | if((portGetTickCnt() - instance_data[instance].instanceWakeTime) > instance_data[instance].nextSleepPeriod) {
|
||
1580 | event_data_t dw_event; |
||
1581 | instance_data[instance].instanceTimerEn = 0;
|
||
1582 | dw_event.rxLength = 0;
|
||
1583 | dw_event.type = 0;
|
||
1584 | dw_event.type_save = 0x80 | DWT_SIG_RX_TIMEOUT;
|
||
1585 | //printf("PC timeout DWT_SIG_RX_TIMEOUT\n");
|
||
1586 | instance_putevent(dw_event, DWT_SIG_RX_TIMEOUT); |
||
1587 | } |
||
1588 | } |
||
1589 | #if (ANCTOANCTWR == 1) //allow anchor to anchor ranging |
||
1590 | else if(instance_data[instance].mode == ANCHOR) { |
||
1591 | uint32_t slotTime = portGetTickCnt() % instance_data[instance].sframePeriod; |
||
1592 | |||
1593 | if(instance_data[instance].gatewayAnchor) {
|
||
1594 | //if we are in the last slot - then A0 ranges to A1 and A2
|
||
1595 | if( slotTime >= instance_data[instance].a0SlotTime) {
|
||
1596 | port_DisableEXT_IRQ(); //enable ScenSor IRQ before starting
|
||
1597 | //anchor0 sends poll to anchor1
|
||
1598 | instance_data[instance].mode = ANCHOR_RNG; //change to ranging initiator
|
||
1599 | dwt_forcetrxoff(); //disable DW1000
|
||
1600 | instance_clearevents(); //clear any events
|
||
1601 | //change state to send a Poll
|
||
1602 | instance_data[instance].testAppState = TA_TXPOLL_WAIT_SEND ; |
||
1603 | instance_data[instance].msg_f.destAddr[0] = 0x1 ; |
||
1604 | instance_data[instance].msg_f.destAddr[1] = (GATEWAY_ANCHOR_ADDR >> 8); |
||
1605 | instance_data[instance].instanceTimerEn = 0;
|
||
1606 | instance_data[instance].rangeNumAnc++; |
||
1607 | port_EnableEXT_IRQ(); //enable ScenSor IRQ before starting
|
||
1608 | } |
||
1609 | } |
||
1610 | else if (instance_data[instance].instanceAddress16 == A1_ANCHOR_ADDR) { //A1 ranges to A2 in the 2nd half of last slot |
||
1611 | if(portGetTickCnt() >= instance_data[instance].a1SlotTime) {
|
||
1612 | port_DisableEXT_IRQ(); //enable ScenSor IRQ before starting
|
||
1613 | //anchor1 sends poll to anchor2
|
||
1614 | instance_data[instance].mode = ANCHOR_RNG; //change to ranging initiator
|
||
1615 | dwt_forcetrxoff(); //disable DW1000
|
||
1616 | instance_clearevents(); //clear any events
|
||
1617 | //change state to send a Poll
|
||
1618 | instance_data[instance].testAppState = TA_TXPOLL_WAIT_SEND ; |
||
1619 | instance_data[instance].msg_f.destAddr[0] = 0x2 ; |
||
1620 | instance_data[instance].msg_f.destAddr[1] = (GATEWAY_ANCHOR_ADDR >> 8); |
||
1621 | |||
1622 | instance_data[instance].instanceTimerEn = 0;
|
||
1623 | //instance_data[instance].a1SlotTime = 0;
|
||
1624 | port_EnableEXT_IRQ(); //enable ScenSor IRQ before starting
|
||
1625 | } |
||
1626 | } |
||
1627 | } |
||
1628 | #endif
|
||
1629 | } |
||
1630 | |||
1631 | #if (ANCTOANCTWR == 1) //allow anchor to anchor ranging |
||
1632 | else if (instance_data[instance].instanceTimerEn == 0){ |
||
1633 | if((instance_data[instance].mode == ANCHOR) && (instance_data[instance].gatewayAnchor)){
|
||
1634 | uint32_t slotTime = portGetTickCnt() % instance_data[instance].sframePeriod; |
||
1635 | //enable the timer in 1st slot
|
||
1636 | if(slotTime < instance_data[instance].slotPeriod){
|
||
1637 | instance_data[instance].instanceTimerEn = 1;
|
||
1638 | } |
||
1639 | } |
||
1640 | } |
||
1641 | #endif
|
||
1642 | return 0 ; |
||
1643 | } |
||
1644 | |||
1645 | |||
1646 | void instance_close(void){ |
||
1647 | //wake up device from low power mode
|
||
1648 | //NOTE - in the ARM code just drop chip select for 200us
|
||
1649 | 4172c48d | Cung Sang | clear_SPI_chip_select(); //CS low
|
1650 | 69a601a5 | Cung Sang | Sleep(1); //200 us to wake up then waits 5ms for DW1000 XTAL to stabilise |
1651 | 4172c48d | Cung Sang | set_SPI_chip_select(); //CS high
|
1652 | 69a601a5 | Cung Sang | Sleep(5);
|
1653 | dwt_entersleepaftertx(0); // clear the "enter deep sleep after tx" bit |
||
1654 | dwt_setinterrupt(0xFFFFFFFF, 0); //don't allow any interrupts |
||
1655 | |||
1656 | } |
||
1657 | |||
1658 | |||
1659 | void instance_notify_DW1000_inIDLE(int idle){ |
||
1660 | instance_data[0].dwIDLE = idle;
|
||
1661 | } |
||
1662 | |||
1663 | void instanceconfigtxpower(uint32_t txpower){
|
||
1664 | instance_data[0].txPower = txpower ;
|
||
1665 | |||
1666 | instance_data[0].txPowerChanged = 1; |
||
1667 | |||
1668 | } |
||
1669 | |||
1670 | void instancesettxpower(void){ |
||
1671 | if(instance_data[0].txPowerChanged == 1){ |
||
1672 | //Configure TX power
|
||
1673 | dwt_write32bitreg(0x1E, instance_data[0].txPower); |
||
1674 | |||
1675 | instance_data[0].txPowerChanged = 0; |
||
1676 | } |
||
1677 | } |
||
1678 | |||
1679 | void instanceconfigantennadelays(uint16_t tx, uint16_t rx){
|
||
1680 | instance_data[0].txAntennaDelay = tx ;
|
||
1681 | instance_data[0].rxAntennaDelay = rx ;
|
||
1682 | |||
1683 | instance_data[0].antennaDelayChanged = 1; |
||
1684 | } |
||
1685 | |||
1686 | void instancesetantennadelays(void){ |
||
1687 | if(instance_data[0].antennaDelayChanged == 1){ |
||
1688 | dwt_setrxantennadelay(instance_data[0].rxAntennaDelay);
|
||
1689 | dwt_settxantennadelay(instance_data[0].txAntennaDelay);
|
||
1690 | |||
1691 | instance_data[0].antennaDelayChanged = 0; |
||
1692 | } |
||
1693 | } |
||
1694 | |||
1695 | |||
1696 | uint16_t instancetxantdly(void){
|
||
1697 | return instance_data[0].txAntennaDelay; |
||
1698 | } |
||
1699 | |||
1700 | uint16_t instancerxantdly(void){
|
||
1701 | return instance_data[0].rxAntennaDelay; |
||
1702 | } |
||
1703 | |||
1704 | uint8_t instancevalidranges(void){
|
||
1705 | uint8_t x = instance_data[0].rxResponseMaskReport;
|
||
1706 | instance_data[0].rxResponseMaskReport = 0; //reset mask as we have printed out the ToFs |
||
1707 | return x;
|
||
1708 | } |
||
1709 | #endif
|
||
1710 | |||
1711 | |||
1712 | /*! TODO: the following Functions are added for user application (previously on the API )*/
|
||
1713 | |||
1714 | /*! ------------------------------------------------------------------------------------------------------------------
|
||
1715 | * @fn dwt_getotptxpower()
|
||
1716 | *
|
||
1717 | * @brief This API function returns the tx power value read from OTP memory as part of initialisation
|
||
1718 | *
|
||
1719 | * input parameters
|
||
1720 | * @param prf - this is the PRF e.g. DWT_PRF_16M or DWT_PRF_64M
|
||
1721 | * @param chan - this is the channel e.g. 1 to 7
|
||
1722 | *
|
||
1723 | * output parameters
|
||
1724 | *
|
||
1725 | * returns tx power value for a given PRF and channel
|
||
1726 | */
|
||
1727 | uint32_t dwt_getotptxpower(uint8_t prf, uint8_t chan){ |
||
1728 | return platformLocalData.txPowCfg[(prf - DWT_PRF_16M) + (chan_idx[chan] * 2)]; |
||
1729 | } |
||
1730 | |||
1731 | /*! ------------------------------------------------------------------------------------------------------------------
|
||
1732 | * @fn dwt_getTREKOTPantennadelay()
|
||
1733 | *
|
||
1734 | * @brief This API function returns the antenna delay read from the OTP memory as part of device initialisation
|
||
1735 | * Note: the antenna delay will only be read if dwt_initialise is called with DWT_LOADANTDLY bit set in the config parameter
|
||
1736 | * The values of antenna delay are only valid for TREK use case modes.
|
||
1737 | *
|
||
1738 | * input parameters:
|
||
1739 | * @param anchor - this is the mode (Tag or Anchor) if Tag set to 0, if Anchor set to 1
|
||
1740 | * @param chan - this is the channel (1, 2, 3, 4, 5, 7)
|
||
1741 | * @param datarate - this is the datarate DWT_BR_6M8, DWT_BR_110K or DWT_BR_850K
|
||
1742 | *
|
||
1743 | */
|
||
1744 | uint16_t dwt_getTREKOTPantennadelay(uint8_t anchor, uint8_t chan, uint8_t datarate){ |
||
1745 | uint32_t dly = 0;
|
||
1746 | |||
1747 | // 32-bit antenna delay value previously read from OTP, high 16 bits is value for Anchor mode, low 16-bits for Tag mode
|
||
1748 | switch(chan){
|
||
1749 | case 2: |
||
1750 | if(datarate == DWT_BR_6M8)
|
||
1751 | dly = platformLocalData.antennaCals[0];
|
||
1752 | else if(datarate == DWT_BR_110K) |
||
1753 | dly = platformLocalData.antennaCals[1];
|
||
1754 | break;
|
||
1755 | case 5: |
||
1756 | if(datarate == DWT_BR_6M8)
|
||
1757 | dly = platformLocalData.antennaCals[2];
|
||
1758 | else if(datarate == DWT_BR_110K) |
||
1759 | dly = platformLocalData.antennaCals[3];
|
||
1760 | break;
|
||
1761 | default:
|
||
1762 | dly = 0;
|
||
1763 | break;
|
||
1764 | } |
||
1765 | |||
1766 | return (dly >> (16*(anchor & 0x1))) & 0xFFFF; |
||
1767 | } |
||
1768 | |||
1769 | /*! ------------------------------------------------------------------------------------------------------------------
|
||
1770 | * @fn dwt_readantennadelay()
|
||
1771 | *
|
||
1772 | * @brief This API function returns the antenna delay read from the OTP memory as part of device initialisation
|
||
1773 | * Note: the antenna delay will only be read if dwt_initialise is called with DWT_LOADANTDLY bit set in the config parameter
|
||
1774 | *
|
||
1775 | * input parameters:
|
||
1776 | * @param prf - this is the PRF e.g. DWT_PRF_16M or DWT_PRF_64M
|
||
1777 | *
|
||
1778 | */
|
||
1779 | uint16_t dwt_readantennadelay(uint8_t prf){ |
||
1780 | // 32-bit antenna delay value previously read from OTP, high 16 bits is value for 64 MHz PRF, low 16-bits for 16 MHz PRF
|
||
1781 | return (platformLocalData.antennaDly >> (16*(prf-DWT_PRF_16M))) & 0xFFFF; |
||
1782 | } |
||
1783 | |||
1784 | |||
1785 | /* ==========================================================
|
||
1786 | |||
1787 | Notes:
|
||
1788 | |||
1789 | Previously code handled multiple instances in a single console application
|
||
1790 | |||
1791 | Now have changed it to do a single instance only. With minimal code changes...(i.e. kept [instance] index but it is always 0.
|
||
1792 | |||
1793 | Windows application should call instance_init() once and then in the "main loop" call instance_run().
|
||
1794 | |||
1795 | */
|
||
1796 | |||
1797 | #endif /* defined(AMIROLLD_CFG_DW1000) && (AMIROLLD_CFG_DW1000 == 1) */ |