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