diff --git a/README.md b/README.md index 02da9bb3..6ba553e5 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ The main reason for this fork is because the development there is really slow (d We also wanted to change how the ranging logic works.
Rather than providing a ranging loop, we wanted to provide functions to send the different Two way ranging flow frames, giving the user more control over the program.
The base driver was also re-written in a lot of places, to make every API function more independent from each other. +We also plan to make very high-level abstractions to hack projects fast. Features ------------ diff --git a/examples/BasicConnectivityTest/BasicConnectivityTest.ino b/examples/BasicConnectivityTest/BasicConnectivityTest.ino index 30c291da..4f1840b7 100644 --- a/examples/BasicConnectivityTest/BasicConnectivityTest.ino +++ b/examples/BasicConnectivityTest/BasicConnectivityTest.ino @@ -51,9 +51,16 @@ #include // connection pins +#if defined(ESP8266) +const uint8_t PIN_RST = 5; // reset pin +const uint8_t PIN_IRQ = 4; // irq pin +const uint8_t PIN_SS = 15; // spi select pin +#else const uint8_t PIN_RST = 9; // reset pin const uint8_t PIN_IRQ = 2; // irq pin const uint8_t PIN_SS = SS; // spi select pin +#endif + void setup() { // DEBUG monitoring diff --git a/examples/BasicReceiver/BasicReceiver.ino b/examples/BasicReceiver/BasicReceiver.ino index 0bc063a2..24f517cf 100644 --- a/examples/BasicReceiver/BasicReceiver.ino +++ b/examples/BasicReceiver/BasicReceiver.ino @@ -50,15 +50,17 @@ #include #include -// connection pins -const uint8_t PIN_RST = 9; // reset pin -const uint8_t PIN_IRQ = 2; // irq pin +#if defined(ESP8266) +//const uint8_t PIN_RST = 5; // reset pin +//const uint8_t PIN_IRQ = 4; // irq pin +const uint8_t PIN_SS = 15; // spi select pin +#else +//const uint8_t PIN_RST = 9; // reset pin +//const uint8_t PIN_IRQ = 2; // irq pin const uint8_t PIN_SS = SS; // spi select pin +#endif -// DEBUG packet sent status and count -volatile boolean received = false; -volatile boolean error = false; -volatile int16_t numReceived = 0; // todo check int type +int16_t numReceived = 0; // todo check int type String message; device_configuration_t DEFAULT_CONFIG = { @@ -75,24 +77,15 @@ device_configuration_t DEFAULT_CONFIG = { PreambleCode::CODE_3 }; -interrupt_configuration_t DEFAULT_INTERRUPT_CONFIG = { - true, - true, - true, - false, - true -}; - void setup() { // DEBUG monitoring Serial.begin(9600); Serial.println(F("### DW1000Ng-arduino-receiver-test ###")); // initialize the driver - DW1000Ng::initialize(PIN_SS, PIN_IRQ, PIN_RST); + DW1000Ng::initializeNoInterrupt(PIN_SS); Serial.println(F("DW1000Ng initialized ...")); DW1000Ng::applyConfiguration(DEFAULT_CONFIG); - DW1000Ng::applyInterruptConfiguration(DEFAULT_INTERRUPT_CONFIG); DW1000Ng::setDeviceAddress(6); DW1000Ng::setNetworkId(10); @@ -109,40 +102,21 @@ void setup() { Serial.print("Network ID & Device Address: "); Serial.println(msg); DW1000Ng::getPrintableDeviceMode(msg); Serial.print("Device mode: "); Serial.println(msg); - // attach callback for (successfully) received messages - DW1000Ng::attachReceivedHandler(handleReceived); - DW1000Ng::attachReceiveFailedHandler(handleError); - DW1000Ng::attachErrorHandler(handleError); - // start reception - DW1000Ng::startReceive(); -} - -void handleReceived() { - // status change on reception success - received = true; -} - -void handleError() { - error = true; } void loop() { - // enter on confirmation of ISR status change (successfully received) - if (received) { - received = false; - numReceived++; - // get data as string - DW1000Ng::getReceivedData(message); - Serial.print("Received message ... #"); Serial.println(numReceived); - Serial.print("Data is ... "); Serial.println(message); - Serial.print("RX power is [dBm] ... "); Serial.println(DW1000Ng::getReceivePower()); - Serial.print("Signal quality is ... "); Serial.println(DW1000Ng::getReceiveQuality()); - DW1000Ng::startReceive(); - } - if (error) { - error = false; - Serial.println("Error receiving a message"); - DW1000Ng::getReceivedData(message); - Serial.print("Error data is ... "); Serial.println(message); + DW1000Ng::startReceive(); + while(!DW1000Ng::isReceiveDone()) { + #if defined(ESP8266) + yield(); + #endif } + DW1000Ng::clearReceiveStatus(); + numReceived++; + // get data as string + DW1000Ng::getReceivedData(message); + Serial.print("Received message ... #"); Serial.println(numReceived); + Serial.print("Data is ... "); Serial.println(message); + Serial.print("RX power is [dBm] ... "); Serial.println(DW1000Ng::getReceivePower()); + Serial.print("Signal quality is ... "); Serial.println(DW1000Ng::getReceiveQuality()); } diff --git a/examples/BasicSender/BasicSender.ino b/examples/BasicSender/BasicSender.ino index 9dfe4129..f95ac043 100644 --- a/examples/BasicSender/BasicSender.ino +++ b/examples/BasicSender/BasicSender.ino @@ -49,14 +49,17 @@ #include #include -// connection pins -const uint8_t PIN_RST = 9; // reset pin -const uint8_t PIN_IRQ = 2; // irq pin +#if defined(ESP8266) +//const uint8_t PIN_RST = 5; // reset pin +//const uint8_t PIN_IRQ = 4; // irq pin +const uint8_t PIN_SS = 15; // spi select pin +#else +//const uint8_t PIN_RST = 9; // reset pin +//const uint8_t PIN_IRQ = 2; // irq pin const uint8_t PIN_SS = SS; // spi select pin +#endif // DEBUG packet sent status and count -boolean sent = false; -volatile boolean sentAck = false; volatile unsigned long delaySent = 0; int16_t sentNum = 0; // todo check int type @@ -74,24 +77,16 @@ device_configuration_t DEFAULT_CONFIG = { PreambleCode::CODE_3 }; -interrupt_configuration_t DEFAULT_INTERRUPT_CONFIG = { - true, - true, - true, - false, - true -}; - void setup() { // DEBUG monitoring Serial.begin(9600); Serial.println(F("### DW1000Ng-arduino-sender-test ###")); // initialize the driver - DW1000Ng::initialize(PIN_SS, PIN_IRQ, PIN_RST); + DW1000Ng::initializeNoInterrupt(PIN_SS); Serial.println(F("DW1000Ng initialized ...")); DW1000Ng::applyConfiguration(DEFAULT_CONFIG); - DW1000Ng::applyInterruptConfiguration(DEFAULT_INTERRUPT_CONFIG); + //DW1000Ng::applyInterruptConfiguration(DEFAULT_INTERRUPT_CONFIG); DW1000Ng::setDeviceAddress(5); DW1000Ng::setNetworkId(10); @@ -109,15 +104,17 @@ void setup() { DW1000Ng::getPrintableDeviceMode(msg); Serial.print("Device mode: "); Serial.println(msg); // attach callback for (successfully) sent messages - DW1000Ng::attachSentHandler(handleSent); + //DW1000Ng::attachSentHandler(handleSent); // start a transmission transmit(); } +/* void handleSent() { // status change on sent success sentAck = true; } +*/ void transmit() { // transmit some data @@ -128,19 +125,19 @@ void transmit() { delay(1000); DW1000Ng::startTransmit(TransmitMode::IMMEDIATE); delaySent = millis(); + while(!DW1000Ng::isTransmitDone()) { + #if defined(ESP8266) + yield(); + #endif + } + sentNum++; + DW1000Ng::clearTransmitStatus(); } void loop() { - if (sentAck) { - // continue on success confirmation - // (we are here after the given amount of send delay time has passed) - sentAck = false; + transmit(); // update and print some information about the sent message Serial.print("ARDUINO delay sent [ms] ... "); Serial.println(millis() - delaySent); uint64_t newSentTime = DW1000Ng::getTransmitTimestamp(); Serial.print("Processed packet ... #"); Serial.println(sentNum); - sentNum++; - // again, transmit some data - transmit(); - } } diff --git a/examples/StandardRTLSAnchorB_TWR/StandardRTLSAnchorB_TWR.ino b/examples/StandardRTLSAnchorB_TWR/StandardRTLSAnchorB_TWR.ino index 072e57a3..d485a4f0 100644 --- a/examples/StandardRTLSAnchorB_TWR/StandardRTLSAnchorB_TWR.ino +++ b/examples/StandardRTLSAnchorB_TWR/StandardRTLSAnchorB_TWR.ino @@ -19,38 +19,17 @@ #include // connection pins -const uint8_t PIN_RST = 9; // reset pin -const uint8_t PIN_IRQ = 2; // irq pin +#if defined(ESP8266) +const uint8_t PIN_SS = 15; +#else +const uint8_t PIN_RST = 9; const uint8_t PIN_SS = SS; // spi select pin - -// message sent/received state -volatile boolean sentAck = false; -volatile boolean receivedAck = false; - -volatile byte SEQ_NUMBER = 0; - -// timestamps to remember -volatile uint64_t timePollSent; -volatile uint64_t timePollReceived; -volatile uint64_t timePollAckSent; -volatile uint64_t timePollAckReceived; -volatile uint64_t timeRangeSent; -volatile uint64_t timeRangeReceived; - -volatile double distance; - -// watchdog and reset period -volatile uint32_t lastActivity; -volatile uint32_t resetPeriod = 250; -// reply times (same on both sides for symm. ranging) -uint16_t replyDelayTimeUS = 3000; - -byte target_eui[8]; -byte tag_shortAddress[] = {0x05, 0x00}; +#endif byte main_anchor_address[] = {0x01, 0x00}; -byte next_anchor_range[] = {0x03, 0x00}; +uint16_t next_anchor = 3; +double range_self; device_configuration_t DEFAULT_CONFIG = { false, @@ -66,15 +45,6 @@ device_configuration_t DEFAULT_CONFIG = { PreambleCode::CODE_3 }; -interrupt_configuration_t DEFAULT_INTERRUPT_CONFIG = { - true, - true, - false, - false, - false, - false -}; - frame_filtering_configuration_t ANCHOR_FRAME_FILTER_CONFIG = { false, false, @@ -91,15 +61,22 @@ void setup() { Serial.begin(115200); Serial.println(F("### arduino-DW1000Ng-ranging-anchor-B ###")); // initialize the driver - DW1000Ng::initialize(PIN_SS, PIN_IRQ, PIN_RST); + #if defined(ESP8266) + DW1000Ng::initializeNoInterrupt(PIN_SS); + #else + DW1000Ng::initializeNoInterrupt(PIN_SS, PIN_RST); + #endif Serial.println(F("DW1000Ng initialized ...")); // general configuration DW1000Ng::applyConfiguration(DEFAULT_CONFIG); - DW1000Ng::applyInterruptConfiguration(DEFAULT_INTERRUPT_CONFIG); DW1000Ng::enableFrameFiltering(ANCHOR_FRAME_FILTER_CONFIG); DW1000Ng::setEUI("AA:BB:CC:DD:EE:FF:00:02"); + DW1000Ng::setPreambleDetectionTimeout(64); + DW1000Ng::setSfdDetectionTimeout(273); + DW1000Ng::setReceiveFrameWaitTimeoutPeriod(5000); + DW1000Ng::setNetworkId(RTLS_APP_ID); DW1000Ng::setDeviceAddress(2); @@ -116,129 +93,28 @@ void setup() { Serial.print("Network ID & Device Address: "); Serial.println(msg); DW1000Ng::getPrintableDeviceMode(msg); Serial.print("Device mode: "); Serial.println(msg); - // attach callback for (successfully) sent and received messages - DW1000Ng::attachSentHandler(handleSent); - DW1000Ng::attachReceivedHandler(handleReceived); - - // anchor starts in receiving mode, awaiting a ranging poll message - receive(); -} - -void noteActivity() { - // update activity timestamp, so that we do not reach "resetPeriod" - lastActivity = millis(); -} - -void receive() { - DW1000Ng::startReceive(); - noteActivity(); -} - -void resetInactive() { - // anchor listens for POLL - DW1000Ng::forceTRxOff(); - receive(); -} - -void handleSent() { - // status change on sent success - sentAck = true; -} - -void handleReceived() { - // status change on received success - receivedAck = true; -} - -void transmitResponseToPoll() { - byte pollAck[] = {DATA, SHORT_SRC_AND_DEST, SEQ_NUMBER++, 0,0, 0,0, 0,0, ACTIVITY_CONTROL, RANGING_CONTINUE, 0, 0}; - DW1000Ng::getNetworkId(&pollAck[3]); - memcpy(&pollAck[5], tag_shortAddress, 2); - DW1000Ng::getDeviceAddress(&pollAck[7]); - DW1000Ng::setTransmitData(pollAck, sizeof(pollAck)); - DW1000Ng::startTransmit(); -} - -void transmitRangingConfirm() { - byte rangingConfirm[] = {DATA, SHORT_SRC_AND_DEST, SEQ_NUMBER++, 0,0, 0,0, 0,0, ACTIVITY_CONTROL, RANGING_CONFIRM, next_anchor_range[0], next_anchor_range[1]}; - DW1000Ng::getNetworkId(&rangingConfirm[3]); - memcpy(&rangingConfirm[5], tag_shortAddress, 2); - DW1000Ng::getDeviceAddress(&rangingConfirm[7]); - DW1000Ng::setTransmitData(rangingConfirm, sizeof(rangingConfirm)); - DW1000Ng::startTransmit(); + } void transmitRangeReport() { - byte rangingReport[] = {DATA, SHORT_SRC_AND_DEST, SEQ_NUMBER++, 0,0, 0,0, 0,0, 0x60, 0,0 }; + byte rangingReport[] = {DATA, SHORT_SRC_AND_DEST, DW1000NgRTLS::increaseSequenceNumber(), 0,0, 0,0, 0,0, 0x60, 0,0 }; DW1000Ng::getNetworkId(&rangingReport[3]); memcpy(&rangingReport[5], main_anchor_address, 2); DW1000Ng::getDeviceAddress(&rangingReport[7]); - DW1000NgUtils::writeValueToBytes(&rangingReport[10], static_cast((distance*1000)), 2); + DW1000NgUtils::writeValueToBytes(&rangingReport[10], static_cast((range_self*1000)), 2); DW1000Ng::setTransmitData(rangingReport, sizeof(rangingReport)); DW1000Ng::startTransmit(); } -void loop() { - if (!sentAck && !receivedAck) { - // check if inactive - if (millis() - lastActivity > resetPeriod) { - resetInactive(); - } - return; - } - - if (sentAck) { - sentAck = false; - DW1000Ng::startReceive(); - } - - if (receivedAck) { - receivedAck = false; - // get message and parse - size_t recv_len = DW1000Ng::getReceivedDataLength(); - byte recv_data[recv_len]; - DW1000Ng::getReceivedData(recv_data, recv_len); - - if (recv_data[9] == RANGING_TAG_POLL) { - timePollReceived = DW1000Ng::getReceiveTimestamp(); - transmitResponseToPoll(); - noteActivity(); - return; - } - - if (recv_data[9] == RANGING_TAG_FINAL_RESPONSE_EMBEDDED) { - - timePollAckSent = DW1000Ng::getTransmitTimestamp(); - timeRangeReceived = DW1000Ng::getReceiveTimestamp(); - - timePollSent = DW1000NgUtils::bytesAsValue(recv_data + 10, LENGTH_TIMESTAMP); - timePollAckReceived = DW1000NgUtils::bytesAsValue(recv_data + 14, LENGTH_TIMESTAMP); - timeRangeSent = DW1000NgUtils::bytesAsValue(recv_data + 18, LENGTH_TIMESTAMP); - // (re-)compute range as two-way ranging is done - distance = DW1000NgRanging::computeRangeAsymmetric(timePollSent, - timePollReceived, - timePollAckSent, - timePollAckReceived, - timeRangeSent, - timeRangeReceived); - /* Apply bias correction */ - distance = DW1000NgRanging::correctRange(distance); +void loop() { + RangeAcceptResult result = DW1000NgRTLS::anchorRangeAccept(NextActivity::RANGING_CONFIRM, next_anchor); + if(result.success) { + delay(3); // Tweak based on your hardware + range_self = result.range; + transmitRangeReport(); - /* In case of wrong read due to bad device calibration */ - if(distance <= 0) - distance = 0.001; - - String rangeString = "Range: "; rangeString += distance; rangeString += " m"; + String rangeString = "Range: "; rangeString += range_self; rangeString += " m"; rangeString += "\t RX power: "; rangeString += DW1000Ng::getReceivePower(); rangeString += " dBm"; Serial.println(rangeString); - - transmitRangingConfirm(); - noteActivity(); - delay(1);//Sending message to the DW1000 chip too frequently, the earlier messages won't send out successfully. - transmitRangeReport(); - noteActivity(); - return; } - } } - diff --git a/examples/StandardRTLSAnchorC_TWR/StandardRTLSAnchorC_TWR.ino b/examples/StandardRTLSAnchorC_TWR/StandardRTLSAnchorC_TWR.ino index 7c2ba4eb..281aaa92 100644 --- a/examples/StandardRTLSAnchorC_TWR/StandardRTLSAnchorC_TWR.ino +++ b/examples/StandardRTLSAnchorC_TWR/StandardRTLSAnchorC_TWR.ino @@ -19,37 +19,19 @@ #include // connection pins -const uint8_t PIN_RST = 9; // reset pin -const uint8_t PIN_IRQ = 2; // irq pin +#if defined(ESP8266) +const uint8_t PIN_SS = 15; +#else +const uint8_t PIN_RST = 9; const uint8_t PIN_SS = SS; // spi select pin +#endif -// message sent/received state -volatile boolean sentAck = false; -volatile boolean receivedAck = false; - -volatile byte SEQ_NUMBER = 0; - -// timestamps to remember -volatile uint64_t timePollSent; -volatile uint64_t timePollReceived; -volatile uint64_t timePollAckSent; -volatile uint64_t timePollAckReceived; -volatile uint64_t timeRangeSent; -volatile uint64_t timeRangeReceived; - -volatile double distance; - -// watchdog and reset period -volatile uint32_t lastActivity; -volatile uint32_t resetPeriod = 250; -// reply times (same on both sides for symm. ranging) -uint16_t replyDelayTimeUS = 3000; - -byte target_eui[8]; -byte tag_shortAddress[] = {0x05, 0x00}; +double range_self; byte main_anchor_address[] = {0x01, 0x00}; +uint16_t blink_rate = 200; + device_configuration_t DEFAULT_CONFIG = { false, true, @@ -64,15 +46,6 @@ device_configuration_t DEFAULT_CONFIG = { PreambleCode::CODE_3 }; -interrupt_configuration_t DEFAULT_INTERRUPT_CONFIG = { - true, - true, - false, - false, - false, - false -}; - frame_filtering_configuration_t ANCHOR_FRAME_FILTER_CONFIG = { false, false, @@ -89,15 +62,22 @@ void setup() { Serial.begin(115200); Serial.println(F("### arduino-DW1000Ng-ranging-anchor-C ###")); // initialize the driver - DW1000Ng::initialize(PIN_SS, PIN_IRQ, PIN_RST); + #if defined(ESP8266) + DW1000Ng::initializeNoInterrupt(PIN_SS); + #else + DW1000Ng::initializeNoInterrupt(PIN_SS, PIN_RST); + #endif Serial.println(F("DW1000Ng initialized ...")); // general configuration DW1000Ng::applyConfiguration(DEFAULT_CONFIG); - DW1000Ng::applyInterruptConfiguration(DEFAULT_INTERRUPT_CONFIG); DW1000Ng::enableFrameFiltering(ANCHOR_FRAME_FILTER_CONFIG); DW1000Ng::setEUI("AA:BB:CC:DD:EE:FF:00:03"); + DW1000Ng::setPreambleDetectionTimeout(64); + DW1000Ng::setSfdDetectionTimeout(273); + DW1000Ng::setReceiveFrameWaitTimeoutPeriod(5000); + DW1000Ng::setNetworkId(RTLS_APP_ID); DW1000Ng::setDeviceAddress(3); @@ -114,130 +94,28 @@ void setup() { Serial.print("Network ID & Device Address: "); Serial.println(msg); DW1000Ng::getPrintableDeviceMode(msg); Serial.print("Device mode: "); Serial.println(msg); - // attach callback for (successfully) sent and received messages - DW1000Ng::attachSentHandler(handleSent); - DW1000Ng::attachReceivedHandler(handleReceived); - - // anchor starts in receiving mode, awaiting a ranging poll message - receive(); -} - -void noteActivity() { - // update activity timestamp, so that we do not reach "resetPeriod" - lastActivity = millis(); -} - -void receive() { - DW1000Ng::startReceive(); - noteActivity(); -} - -void resetInactive() { - // anchor listens for POLL - DW1000Ng::forceTRxOff(); - receive(); -} - -void handleSent() { - // status change on sent success - sentAck = true; -} - -void handleReceived() { - // status change on received success - receivedAck = true; -} - -void transmitResponseToPoll() { - byte pollAck[] = {DATA, SHORT_SRC_AND_DEST, SEQ_NUMBER++, 0,0, 0,0, 0,0, ACTIVITY_CONTROL, RANGING_CONTINUE, 0, 0}; - DW1000Ng::getNetworkId(&pollAck[3]); - memcpy(&pollAck[5], tag_shortAddress, 2); - DW1000Ng::getDeviceAddress(&pollAck[7]); - DW1000Ng::setTransmitData(pollAck, sizeof(pollAck)); - DW1000Ng::startTransmit(); -} - -void transmitActivityFinished() { - /* I send the new blink rate to the tag */ - byte MS_200 = 0xC8; - byte rangingConfirm[] = {DATA, SHORT_SRC_AND_DEST, SEQ_NUMBER++, 0,0, 0,0, 0,0, ACTIVITY_CONTROL, ACTIVITY_FINISHED, MS_200, 0x00}; - DW1000Ng::getNetworkId(&rangingConfirm[3]); - memcpy(&rangingConfirm[5], tag_shortAddress, 2); - DW1000Ng::getDeviceAddress(&rangingConfirm[7]); - DW1000Ng::setTransmitData(rangingConfirm, sizeof(rangingConfirm)); - DW1000Ng::startTransmit(); } void transmitRangeReport() { - byte rangingReport[] = {DATA, SHORT_SRC_AND_DEST, SEQ_NUMBER++, 0,0, 0,0, 0,0, 0x60, 0,0 }; + byte rangingReport[] = {DATA, SHORT_SRC_AND_DEST, DW1000NgRTLS::increaseSequenceNumber(), 0,0, 0,0, 0,0, 0x60, 0,0 }; DW1000Ng::getNetworkId(&rangingReport[3]); memcpy(&rangingReport[5], main_anchor_address, 2); DW1000Ng::getDeviceAddress(&rangingReport[7]); - DW1000NgUtils::writeValueToBytes(&rangingReport[10], static_cast((distance*1000)), 2); + DW1000NgUtils::writeValueToBytes(&rangingReport[10], static_cast((range_self*1000)), 2); DW1000Ng::setTransmitData(rangingReport, sizeof(rangingReport)); DW1000Ng::startTransmit(); } void loop() { - if (!sentAck && !receivedAck) { - // check if inactive - if (millis() - lastActivity > resetPeriod) { - resetInactive(); - } - return; - } - - if (sentAck) { - sentAck = false; - DW1000Ng::startReceive(); - } - - if (receivedAck) { - receivedAck = false; - // get message and parse - size_t recv_len = DW1000Ng::getReceivedDataLength(); - byte recv_data[recv_len]; - DW1000Ng::getReceivedData(recv_data, recv_len); - - if (recv_data[9] == RANGING_TAG_POLL) { - timePollReceived = DW1000Ng::getReceiveTimestamp(); - transmitResponseToPoll(); - noteActivity(); - return; - } - - if (recv_data[9] == RANGING_TAG_FINAL_RESPONSE_EMBEDDED) { - - timePollAckSent = DW1000Ng::getTransmitTimestamp(); - timeRangeReceived = DW1000Ng::getReceiveTimestamp(); - - timePollSent = DW1000NgUtils::bytesAsValue(recv_data + 10, LENGTH_TIMESTAMP); - timePollAckReceived = DW1000NgUtils::bytesAsValue(recv_data + 14, LENGTH_TIMESTAMP); - timeRangeSent = DW1000NgUtils::bytesAsValue(recv_data + 18, LENGTH_TIMESTAMP); - // (re-)compute range as two-way ranging is done - distance = DW1000NgRanging::computeRangeAsymmetric(timePollSent, - timePollReceived, - timePollAckSent, - timePollAckReceived, - timeRangeSent, - timeRangeReceived); - /* Apply bias correction */ - distance = DW1000NgRanging::correctRange(distance); - - /* In case of wrong read due to bad device calibration */ - if(distance <= 0) - distance = 0.001; - - String rangeString = "Range: "; rangeString += distance; rangeString += " m"; - rangeString += "\t RX power: "; rangeString += DW1000Ng::getReceivePower(); rangeString += " dBm"; - Serial.println(rangeString); - - transmitActivityFinished(); - delay(1);//Sending message to the DW1000 chip too frequently, the earlier messages won't send out successfully. - noteActivity(); - transmitRangeReport(); - return; - } - } + RangeAcceptResult result = DW1000NgRTLS::anchorRangeAccept(NextActivity::ACTIVITY_FINISHED, blink_rate); + if(result.success) { + delay(1); // Tweak based on your hardware + range_self = result.range; + transmitRangeReport(); + + String rangeString = "Range: "; rangeString += range_self; rangeString += " m"; + rangeString += "\t RX power: "; rangeString += DW1000Ng::getReceivePower(); rangeString += " dBm"; + Serial.println(rangeString); + } } diff --git a/examples/StandardRTLSAnchorMain_TWR/StandardRTLSAnchorMain_TWR.ino b/examples/StandardRTLSAnchorMain_TWR/StandardRTLSAnchorMain_TWR.ino index a96b7185..352300e7 100644 --- a/examples/StandardRTLSAnchorMain_TWR/StandardRTLSAnchorMain_TWR.ino +++ b/examples/StandardRTLSAnchorMain_TWR/StandardRTLSAnchorMain_TWR.ino @@ -24,42 +24,29 @@ typedef struct Position { } Position; // connection pins -const uint8_t PIN_RST = 9; // reset pin -const uint8_t PIN_IRQ = 2; // irq pin +#if defined(ESP8266) +const uint8_t PIN_SS = 15; +#else +const uint8_t PIN_RST = 9; const uint8_t PIN_SS = SS; // spi select pin +#endif -// message sent/received state -volatile boolean sentAck = false; -volatile boolean receivedAck = false; - -volatile byte SEQ_NUMBER = 0; - -// timestamps to remember -volatile uint64_t timePollSent; -volatile uint64_t timePollReceived; -volatile uint64_t timePollAckSent; -volatile uint64_t timePollAckReceived; -volatile uint64_t timeRangeSent; -volatile uint64_t timeRangeReceived; Position position_self = {0,0}; Position position_B = {3,0}; Position position_C = {3,2.5}; -volatile double range_self; -volatile double range_B; -volatile double range_C; +double range_self; +double range_B; +double range_C; -// watchdog and reset period -volatile uint32_t lastActivity; -volatile uint32_t resetPeriod = 250; -// reply times (same on both sides for symm. ranging) -uint16_t replyDelayTimeUS = 3000; +boolean received_B = false; byte target_eui[8]; byte tag_shortAddress[] = {0x05, 0x00}; byte anchor_b[] = {0x02, 0x00}; +uint16_t next_anchor = 2; byte anchor_c[] = {0x03, 0x00}; device_configuration_t DEFAULT_CONFIG = { @@ -76,15 +63,6 @@ device_configuration_t DEFAULT_CONFIG = { PreambleCode::CODE_3 }; -interrupt_configuration_t DEFAULT_INTERRUPT_CONFIG = { - true, - true, - false, - false, - false, - false -}; - frame_filtering_configuration_t ANCHOR_FRAME_FILTER_CONFIG = { false, false, @@ -101,15 +79,22 @@ void setup() { Serial.begin(115200); Serial.println(F("### DW1000Ng-arduino-ranging-anchorMain ###")); // initialize the driver - DW1000Ng::initialize(PIN_SS, PIN_IRQ, PIN_RST); + #if defined(ESP8266) + DW1000Ng::initializeNoInterrupt(PIN_SS); + #else + DW1000Ng::initializeNoInterrupt(PIN_SS, PIN_RST); + #endif Serial.println(F("DW1000Ng initialized ...")); // general configuration DW1000Ng::applyConfiguration(DEFAULT_CONFIG); - DW1000Ng::applyInterruptConfiguration(DEFAULT_INTERRUPT_CONFIG); DW1000Ng::enableFrameFiltering(ANCHOR_FRAME_FILTER_CONFIG); DW1000Ng::setEUI("AA:BB:CC:DD:EE:FF:00:01"); + DW1000Ng::setPreambleDetectionTimeout(64); + DW1000Ng::setSfdDetectionTimeout(273); + DW1000Ng::setReceiveFrameWaitTimeoutPeriod(5000); + DW1000Ng::setNetworkId(RTLS_APP_ID); DW1000Ng::setDeviceAddress(1); @@ -125,67 +110,7 @@ void setup() { DW1000Ng::getPrintableNetworkIdAndShortAddress(msg); Serial.print("Network ID & Device Address: "); Serial.println(msg); DW1000Ng::getPrintableDeviceMode(msg); - Serial.print("Device mode: "); Serial.println(msg); - // attach callback for (successfully) sent and received messages - DW1000Ng::attachSentHandler(handleSent); - DW1000Ng::attachReceivedHandler(handleReceived); - - // anchor starts in receiving mode, awaiting a ranging poll message - receive(); -} - -void noteActivity() { - // update activity timestamp, so that we do not reach "resetPeriod" - lastActivity = millis(); -} - -void receive() { - DW1000Ng::startReceive(); - noteActivity(); -} - -void resetInactive() { - // anchor listens for POLL - DW1000Ng::forceTRxOff(); - receive(); -} - -void handleSent() { - // status change on sent success - sentAck = true; -} - -void handleReceived() { - // status change on received success - receivedAck = true; -} - -void transmitRangingInitiation() { - byte RangingInitiation[] = {DATA, SHORT_SRC_LONG_DEST, SEQ_NUMBER++, 0,0, 0,0,0,0,0,0,0,0, 0,0, RANGING_INITIATION, 0,0}; - DW1000Ng::getNetworkId(&RangingInitiation[3]); - memcpy(&RangingInitiation[5], target_eui, 8); - DW1000Ng::getDeviceAddress(&RangingInitiation[13]); - memcpy(&RangingInitiation[16], tag_shortAddress, 2); - DW1000Ng::setTransmitData(RangingInitiation, sizeof(RangingInitiation)); - DW1000Ng::startTransmit(); -} - -void transmitResponseToPoll() { - byte pollAck[] = {DATA, SHORT_SRC_AND_DEST, SEQ_NUMBER++, 0,0, 0,0, 0,0, ACTIVITY_CONTROL, RANGING_CONTINUE, 0, 0}; - DW1000Ng::getNetworkId(&pollAck[3]); - memcpy(&pollAck[5], tag_shortAddress, 2); - DW1000Ng::getDeviceAddress(&pollAck[7]); - DW1000Ng::setTransmitData(pollAck, sizeof(pollAck)); - DW1000Ng::startTransmit(); -} - -void transmitRangingConfirm() { - byte rangingConfirm[] = {DATA, SHORT_SRC_AND_DEST, SEQ_NUMBER++, 0,0, 0,0, 0,0, ACTIVITY_CONTROL, RANGING_CONFIRM, anchor_b[0], anchor_b[1]}; - DW1000Ng::getNetworkId(&rangingConfirm[3]); - memcpy(&rangingConfirm[5], tag_shortAddress, 2); - DW1000Ng::getDeviceAddress(&rangingConfirm[7]); - DW1000Ng::setTransmitData(rangingConfirm, sizeof(rangingConfirm)); - DW1000Ng::startTransmit(); + Serial.print("Device mode: "); Serial.println(msg); } /* using https://math.stackexchange.com/questions/884807/find-x-location-using-3-known-x-y-location-using-trilateration */ @@ -202,74 +127,35 @@ void calculatePosition(double &x, double &y) { x = (C*E-F*B) / (E*A-B*D); y = (C*D-A*F) / (B*D-A*E); } - -void loop() { - if (!sentAck && !receivedAck) { - // check if inactive - if (millis() - lastActivity > resetPeriod) { - resetInactive(); - } - return; - } - - if (sentAck) { - sentAck = false; - DW1000Ng::startReceive(); - } - if (receivedAck) { - receivedAck = false; - // get message and parse +void loop() { + if(DW1000NgRTLS::receiveFrame()){ size_t recv_len = DW1000Ng::getReceivedDataLength(); byte recv_data[recv_len]; DW1000Ng::getReceivedData(recv_data, recv_len); - if (recv_data[9] == RANGING_TAG_POLL) { - timePollReceived = DW1000Ng::getReceiveTimestamp(); - transmitResponseToPoll(); - noteActivity(); - return; - } - - if (recv_data[9] == RANGING_TAG_FINAL_RESPONSE_EMBEDDED) { - timePollAckSent = DW1000Ng::getTransmitTimestamp(); - timeRangeReceived = DW1000Ng::getReceiveTimestamp(); + if(recv_data[0] == BLINK) { + DW1000NgRTLS::transmitRangingInitiation(&recv_data[2], tag_shortAddress); + DW1000NgRTLS::waitForTransmission(); - timePollSent = DW1000NgUtils::bytesAsValue(recv_data + 10, LENGTH_TIMESTAMP); - timePollAckReceived = DW1000NgUtils::bytesAsValue(recv_data + 14, LENGTH_TIMESTAMP); - timeRangeSent = DW1000NgUtils::bytesAsValue(recv_data + 18, LENGTH_TIMESTAMP); - // (re-)compute range as two-way ranging is done - range_self = DW1000NgRanging::computeRangeAsymmetric(timePollSent, - timePollReceived, - timePollAckSent, - timePollAckReceived, - timeRangeSent, - timeRangeReceived); - /* Apply bias correction */ - range_self = DW1000NgRanging::correctRange(range_self); + RangeAcceptResult result = DW1000NgRTLS::anchorRangeAccept(NextActivity::RANGING_CONFIRM, next_anchor); + if(!result.success) return; + range_self = result.range; - /* In case of wrong read due to bad device calibration */ - if(range_self <= 0) - range_self = 0.001; - String rangeString = "Range: "; rangeString += range_self; rangeString += " m"; rangeString += "\t RX power: "; rangeString += DW1000Ng::getReceivePower(); rangeString += " dBm"; Serial.println(rangeString); - - transmitRangingConfirm(); - noteActivity(); - return; - } - if(recv_data[9] == 0x60) { + } else if(recv_data[9] == 0x60) { double range = static_cast(DW1000NgUtils::bytesAsValue(&recv_data[10],2) / 1000.0); String rangeReportString = "Range from: "; rangeReportString += recv_data[7]; rangeReportString += " = "; rangeReportString += range; Serial.println(rangeReportString); - if(recv_data[7] == anchor_b[0] && recv_data[8] == anchor_b[1]) { + if(received_B == false && recv_data[7] == anchor_b[0] && recv_data[8] == anchor_b[1]) { range_B = range; - } else if(recv_data[7] == anchor_c[0] && recv_data[8] == anchor_c[1]){ + received_B = true; + } else if(received_B == true && recv_data[7] == anchor_c[0] && recv_data[8] == anchor_c[1]){ range_C = range; double x,y; calculatePosition(x,y); @@ -277,20 +163,12 @@ void loop() { positioning += x; positioning +=" y: "; positioning += y; Serial.println(positioning); + received_B = false; + } else { + received_B = false; } - DW1000Ng::startReceive(); - noteActivity(); - return; - } - - if(recv_data[0] == BLINK) { - /* Is blink */ - memcpy(target_eui, &recv_data[2], 8); - transmitRangingInitiation(); - noteActivity(); - return; } - } -} + +} \ No newline at end of file diff --git a/examples/StandardRTLSTag_TWR/StandardRTLSTag_TWR.ino b/examples/StandardRTLSTag_TWR/StandardRTLSTag_TWR.ino index 899a91c7..e638da9b 100644 --- a/examples/StandardRTLSTag_TWR/StandardRTLSTag_TWR.ino +++ b/examples/StandardRTLSTag_TWR/StandardRTLSTag_TWR.ino @@ -21,28 +21,14 @@ #include // connection pins -const uint8_t PIN_RST = 9; // reset pin -const uint8_t PIN_IRQ = 2; // irq pin +#if defined(ESP8266) +const uint8_t PIN_SS = 15; +#else const uint8_t PIN_SS = SS; // spi select pin +const uint8_t PIN_RST = 9; +#endif -// message flow state -// message sent/received state -volatile boolean sentAck = false; -volatile boolean receivedAck = false; - -byte SEQ_NUMBER = 0; - -byte anchor_address[2]; - -// timestamps to remember -volatile uint64_t timePollSent; -volatile uint64_t timePollAckReceived; -volatile uint64_t timeRangeSent; -// watchdog and reset period -volatile uint32_t lastActivity; -volatile uint32_t resetPeriod = 250; -// reply times (same on both sides for symm. ranging) -uint16_t replyDelayTimeUS = 3000; +volatile uint32_t blink_rate = 200; device_configuration_t DEFAULT_CONFIG = { false, @@ -58,15 +44,6 @@ device_configuration_t DEFAULT_CONFIG = { PreambleCode::CODE_3 }; -interrupt_configuration_t DEFAULT_INTERRUPT_CONFIG = { - true, - true, - false, - false, - false, - false -}; - frame_filtering_configuration_t TAG_FRAME_FILTER_CONFIG = { false, false, @@ -83,11 +60,14 @@ void setup() { Serial.begin(115200); Serial.println(F("### DW1000Ng-arduino-ranging-tag ###")); // initialize the driver - DW1000Ng::initialize(PIN_SS, PIN_IRQ, PIN_RST); + #if defined(ESP8266) + DW1000Ng::initializeNoInterrupt(PIN_SS); + #else + DW1000Ng::initializeNoInterrupt(PIN_SS, PIN_RST); + #endif Serial.println("DW1000Ng initialized ..."); // general configuration DW1000Ng::applyConfiguration(DEFAULT_CONFIG); - DW1000Ng::applyInterruptConfiguration(DEFAULT_INTERRUPT_CONFIG); DW1000Ng::enableFrameFiltering(TAG_FRAME_FILTER_CONFIG); DW1000Ng::setEUI("AA:BB:CC:DD:EE:FF:00:00"); @@ -95,6 +75,10 @@ void setup() { DW1000Ng::setNetworkId(RTLS_APP_ID); DW1000Ng::setAntennaDelay(16436); + + DW1000Ng::setPreambleDetectionTimeout(15); + DW1000Ng::setSfdDetectionTimeout(273); + DW1000Ng::setReceiveFrameWaitTimeoutPeriod(2000); Serial.println(F("Committed configuration ...")); // DEBUG chip info and registers pretty printed @@ -106,153 +90,16 @@ void setup() { DW1000Ng::getPrintableNetworkIdAndShortAddress(msg); Serial.print("Network ID & Device Address: "); Serial.println(msg); DW1000Ng::getPrintableDeviceMode(msg); - Serial.print("Device mode: "); Serial.println(msg); - // attach callback for (successfully) sent and received messages - DW1000Ng::attachSentHandler(handleSent); - DW1000Ng::attachReceivedHandler(handleReceived); - // anchor starts by transmitting a POLL message - transmitBlink(); - noteActivity(); -} - -void noteActivity() { - // update activity timestamp, so that we do not reach "resetPeriod" - lastActivity = millis(); -} - -void reset() { - // tag returns to Idle and sends POLL - DW1000Ng::forceTRxOff(); - transmitBlink(); - noteActivity(); -} - -void handleSent() { - sentAck = true; -} - -void handleReceived() { - receivedAck = true; -} - -void transmitBlink() { - byte Blink[] = {BLINK, SEQ_NUMBER++, 0,0,0,0,0,0,0,0, NO_BATTERY_STATUS | NO_EX_ID, TAG_LISTENING_NOW}; - DW1000Ng::getEUI(&Blink[2]); - DW1000Ng::setTransmitData(Blink, sizeof(Blink)); - DW1000Ng::startTransmit(); -} - -void transmitPoll() { - byte Poll[] = {DATA, SHORT_SRC_AND_DEST, SEQ_NUMBER++, 0,0, 0,0, 0,0 , RANGING_TAG_POLL}; - DW1000Ng::getNetworkId(&Poll[3]); - memcpy(&Poll[5], anchor_address, 2); - DW1000Ng::getDeviceAddress(&Poll[7]); - DW1000Ng::setTransmitData(Poll, sizeof(Poll)); - DW1000Ng::startTransmit(); -} - - -void transmitFinalMessage() { - /* Calculation of future time */ - byte futureTimeBytes[LENGTH_TIMESTAMP]; - - timeRangeSent = DW1000Ng::getSystemTimestamp(); - timeRangeSent += DW1000NgTime::microsecondsToUWBTime(replyDelayTimeUS); - DW1000NgUtils::writeValueToBytes(futureTimeBytes, timeRangeSent, LENGTH_TIMESTAMP); - DW1000Ng::setDelayedTRX(futureTimeBytes); - timeRangeSent += DW1000Ng::getTxAntennaDelay(); - - byte finalMessage[] = {DATA, SHORT_SRC_AND_DEST, SEQ_NUMBER++, 0,0, 0,0, 0,0, RANGING_TAG_FINAL_RESPONSE_EMBEDDED, - 0,0,0,0,0,0,0,0,0,0,0,0 - }; - - DW1000Ng::getNetworkId(&finalMessage[3]); - memcpy(&finalMessage[5], anchor_address, 2); - DW1000Ng::getDeviceAddress(&finalMessage[7]); - - DW1000NgUtils::writeValueToBytes(finalMessage + 10, (uint32_t) timePollSent, 4); - DW1000NgUtils::writeValueToBytes(finalMessage + 14, (uint32_t) timePollAckReceived, 4); - DW1000NgUtils::writeValueToBytes(finalMessage + 18, (uint32_t) timeRangeSent, 4); - DW1000Ng::setTransmitData(finalMessage, sizeof(finalMessage)); - DW1000Ng::startTransmit(TransmitMode::DELAYED); + Serial.print("Device mode: "); Serial.println(msg); } void loop() { - if (!sentAck && !receivedAck) { - // check if inactive - if (millis() - lastActivity > resetPeriod) { - String tempString= "Time out! The lost anchor is:" ; tempString += (char)anchor_address[0] + (char)anchor_address[1]; - Serial.println(tempString); - reset(); - } - return; - } - - if (sentAck) { - sentAck = false; - DW1000Ng::startReceive(); - } - - if (receivedAck) { - receivedAck = false; - /* Parse received message */ - size_t recv_len = DW1000Ng::getReceivedDataLength(); - byte recv_data[recv_len]; - DW1000Ng::getReceivedData(recv_data, recv_len); - - /* RTLS standard message */ - if(recv_data[9] == ACTIVITY_CONTROL) { - if (recv_data[10] == RANGING_CONTINUE) { - /* Received Response to poll */ - timePollSent = DW1000Ng::getTransmitTimestamp(); - timePollAckReceived = DW1000Ng::getReceiveTimestamp(); - transmitFinalMessage(); - String tempString= "Receiving messages from:" ; tempString += (char)anchor_address[0] + (char)anchor_address[1]; - tempString +=" and send it back."; - Serial.println(tempString); - noteActivity(); - return; - } else if (recv_data[10] == RANGING_CONFIRM) { - /* Received ranging confirm */ - memcpy(anchor_address, &recv_data[11], 2); - transmitPoll(); - String tempString= "Sending messages to NEW Anchor:" ; tempString += (char) anchor_address[0] + (char)anchor_address[1]; - Serial.println(tempString); - noteActivity(); - return; - } else if(recv_data[10] == ACTIVITY_FINISHED) { - resetPeriod = recv_data[11] + static_cast(((recv_data[12] & 0x3F) << 8)); - byte multiplier = ((recv_data[12] & 0xC0) >> 6); - if(multiplier == 0x01) { - resetPeriod *= 25; - } else if(multiplier == 0x02) { - resetPeriod *= 1000; - } - Serial.println("One Range is finishend, and the modules is going to sleep."); - - /* Sleep until next blink to save power */ - DW1000Ng::deepSleep(); - delay(resetPeriod); - DW1000Ng::spiWakeup(); + DW1000Ng::deepSleep(); + delay(blink_rate); + DW1000Ng::spiWakeup(); + DW1000Ng::setEUI("AA:BB:CC:DD:EE:FF:00:00"); - transmitBlink(); - noteActivity(); - return; - } else { - reset(); - return; - } - } - - if(recv_data[15] == RANGING_INITIATION) { - DW1000Ng::setDeviceAddress(DW1000NgUtils::bytesAsValue(&recv_data[16], 2)); - memcpy(anchor_address, &recv_data[13], 2); - transmitPoll(); - String tempString= "Receiving messages from:" ; tempString += (char)anchor_address[0] + (char)anchor_address[1]; - tempString +=" and send it back."; - Serial.println(tempString); - noteActivity(); - return; - } - } -} \ No newline at end of file + RangeInfrastructureResult res = DW1000NgRTLS::tagTwrLocalize(1500); + if(res.success) + blink_rate = res.new_blink_rate; +} diff --git a/library.properties b/library.properties index 270f9630..c7e5916c 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=DW1000-ng -version=0.0.0 +version=0.1.0 author=Michele Biondi , Andrea Salvatori maintainer=Michele Biondi , Andrea Salvatori sentence=Arduino library to use Decawave's DW1000 IC. diff --git a/src/DW1000Ng.cpp b/src/DW1000Ng.cpp index 0f430041..878f7cf6 100644 --- a/src/DW1000Ng.cpp +++ b/src/DW1000Ng.cpp @@ -233,6 +233,26 @@ namespace DW1000Ng { // end read mode _writeByte(OTP_IF, OTP_CTRL_SUB, 0x00); } + + void _writeBitToRegister(byte bitRegister, uint16_t RegisterOffset, uint16_t bitRegister_LEN, uint16_t selectedBit, boolean value) { + uint16_t idx; + uint8_t bitPosition; + + idx = selectedBit/8; + if(idx >= bitRegister_LEN) { + return; // TODO proper error handling: out of bounds + } + byte targetByte; memset(&targetByte, 0, 1); + bitPosition = selectedBit%8; + _readBytes(bitRegister, RegisterOffset+idx, &targetByte, 1); + + value ? bitSet(targetByte, bitPosition) : bitClear(targetByte, bitPosition); + + if(RegisterOffset == NO_SUB) + RegisterOffset = 0x00; + + _writeBytesToRegister(bitRegister, RegisterOffset+idx, &targetByte, 1); + } /* Steps used to get Temp and Voltage */ void _vbatAndTempSteps() { @@ -1222,7 +1242,8 @@ namespace DW1000Ng { // pin and basic member setup // attach interrupt // TODO throw error if pin is not a interrupt pin - attachInterrupt(digitalPinToInterrupt(_irq), pollForEvents, RISING); + if(_irq != 0xff) + attachInterrupt(digitalPinToInterrupt(_irq), interruptServiceRoutine, RISING); select(); // reset chip (either soft or hard) @@ -1255,9 +1276,14 @@ namespace DW1000Ng { _writeToRegister(AON, AON_CFG1_SUB, 0x00, LEN_AON_CFG1); } + void initializeNoInterrupt(uint8_t ss, uint8_t rst) { + initialize(ss, 0xff, rst); + } + void select() { #if !defined(ESP32) && !defined(ESP8266) - SPI.usingInterrupt(digitalPinToInterrupt(_irq)); + if(_irq != 0xff) + SPI.usingInterrupt(digitalPinToInterrupt(_irq)); #endif pinMode(_ss, OUTPUT); digitalWrite(_ss, HIGH); @@ -1292,7 +1318,7 @@ namespace DW1000Ng { _handleReceiveTimestampAvailable = handleReceiveTimestampAvailable; } - void pollForEvents() { + void interruptServiceRoutine() { // read current status and handle via callbacks _readSystemEventStatusRegister(); if(_isClockProblem() /* TODO and others */ && _handleError != 0) { @@ -1327,6 +1353,46 @@ namespace DW1000Ng { } } + boolean isTransmitDone(){ + _readSystemEventStatusRegister(); + return _isTransmitDone(); + } + + void clearTransmitStatus() { + _clearTransmitStatus(); + } + + boolean isReceiveDone() { + _readSystemEventStatusRegister(); + return _isReceiveDone(); + } + + void clearReceiveStatus() { + _clearReceiveStatus(); + } + + boolean isReceiveFailed() { + _readSystemEventStatusRegister(); + return _isReceiveFailed(); + } + + void clearReceiveFailedStatus() { + _clearReceiveFailedStatus(); + forceTRxOff(); + _resetReceiver(); + } + + boolean isReceiveTimeout() { + _readSystemEventMaskRegister(); + return _isReceiveTimeout(); + } + + void clearReceiveTimeoutStatus() { + _clearReceiveTimeoutStatus(); + forceTRxOff(); + _resetReceiver(); + } + void enableDebounceClock() { byte pmscctrl0[LEN_PMSC_CTRL0]; memset(pmscctrl0, 0, LEN_PMSC_CTRL0); diff --git a/src/DW1000Ng.hpp b/src/DW1000Ng.hpp index 3822ecb1..33a629d0 100644 --- a/src/DW1000Ng.hpp +++ b/src/DW1000Ng.hpp @@ -62,6 +62,8 @@ namespace DW1000Ng { @param[in] rst The reset line/pin for hard resets of ICs that connect to the Arduino. Value 0xff means soft reset. */ void initialize(uint8_t ss, uint8_t irq, uint8_t rst = 0xff); + + void initializeNoInterrupt(uint8_t ss, uint8_t rst = 0xff); /** (Re-)selects a specific DW1000 chip for communication. Used in case you switched SPI to another device. @@ -379,11 +381,27 @@ namespace DW1000Ng { void attachReceiveTimestampAvailableHandler(void (* handleReceiveTimestampAvailable)(void)); /** - Poll the DW1000 for system events and handles them + Handles dw1000 events triggered by interrupt By default this is attached to the interrupt pin callback */ - void pollForEvents(); + void interruptServiceRoutine(); + boolean isTransmitDone(); + + void clearTransmitStatus(); + + boolean isReceiveDone(); + + void clearReceiveStatus(); + + boolean isReceiveFailed(); + + void clearReceiveFailedStatus(); + + boolean isReceiveTimeout(); + + void clearReceiveTimeoutStatus(); + /** Stops the transceiver immediately, this actually sets the device in Idle mode. */ @@ -463,18 +481,18 @@ namespace DW1000Ng { @param [in] mode IMMEDIATE or DELAYED transmission */ void startTransmit(TransmitMode mode = TransmitMode::IMMEDIATE); - + /** Gets the temperature inside the DW1000 Device - @param [out] temp The temperature + returns The temperature */ float getTemperature(); /** Gets the voltage in input of the DW1000 - @param [out] vbat The input voltage + returns The input voltage */ float getBatteryVoltage(); diff --git a/src/DW1000NgRTLS.cpp b/src/DW1000NgRTLS.cpp new file mode 100644 index 00000000..0ea686e6 --- /dev/null +++ b/src/DW1000NgRTLS.cpp @@ -0,0 +1,303 @@ +/* + * MIT License + * + * Copyright (c) 2018 Michele Biondi, Andrea Salvatori + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*/ + +#include +#include "DW1000NgRTLS.hpp" +#include "DW1000Ng.hpp" +#include "DW1000NgUtils.hpp" +#include "DW1000NgTime.hpp" +#include "DW1000NgRanging.hpp" + +static byte SEQ_NUMBER = 0; + +namespace DW1000NgRTLS { + + byte increaseSequenceNumber(){ + return ++SEQ_NUMBER; + } + + void transmitTwrShortBlink() { + byte Blink[] = {BLINK, SEQ_NUMBER++, 0,0,0,0,0,0,0,0, NO_BATTERY_STATUS | NO_EX_ID, TAG_LISTENING_NOW}; + DW1000Ng::getEUI(&Blink[2]); + DW1000Ng::setTransmitData(Blink, sizeof(Blink)); + DW1000Ng::startTransmit(); + } + + void transmitRangingInitiation(byte tag_eui[], byte tag_short_address[]) { + byte RangingInitiation[] = {DATA, SHORT_SRC_LONG_DEST, SEQ_NUMBER++, 0,0, 0,0,0,0,0,0,0,0, 0,0, RANGING_INITIATION, 0,0}; + DW1000Ng::getNetworkId(&RangingInitiation[3]); + memcpy(&RangingInitiation[5], tag_eui, 8); + DW1000Ng::getDeviceAddress(&RangingInitiation[13]); + memcpy(&RangingInitiation[16], tag_short_address, 2); + DW1000Ng::setTransmitData(RangingInitiation, sizeof(RangingInitiation)); + DW1000Ng::startTransmit(); + } + + void transmitPoll(byte anchor_address[]){ + byte Poll[] = {DATA, SHORT_SRC_AND_DEST, SEQ_NUMBER++, 0,0, 0,0, 0,0 , RANGING_TAG_POLL}; + DW1000Ng::getNetworkId(&Poll[3]); + memcpy(&Poll[5], anchor_address, 2); + DW1000Ng::getDeviceAddress(&Poll[7]); + DW1000Ng::setTransmitData(Poll, sizeof(Poll)); + DW1000Ng::startTransmit(); + } + + void transmitResponseToPoll(byte tag_short_address[]) { + byte pollAck[] = {DATA, SHORT_SRC_AND_DEST, SEQ_NUMBER++, 0,0, 0,0, 0,0, ACTIVITY_CONTROL, RANGING_CONTINUE, 0, 0}; + DW1000Ng::getNetworkId(&pollAck[3]); + memcpy(&pollAck[5], tag_short_address, 2); + DW1000Ng::getDeviceAddress(&pollAck[7]); + DW1000Ng::setTransmitData(pollAck, sizeof(pollAck)); + DW1000Ng::startTransmit(); + } + + void transmitFinalMessage(byte anchor_address[], uint16_t reply_delay, uint64_t timePollSent, uint64_t timeResponseToPollReceived) { + /* Calculation of future time */ + byte futureTimeBytes[LENGTH_TIMESTAMP]; + + uint64_t timeFinalMessageSent = DW1000Ng::getSystemTimestamp(); + timeFinalMessageSent += DW1000NgTime::microsecondsToUWBTime(reply_delay); + DW1000NgUtils::writeValueToBytes(futureTimeBytes, timeFinalMessageSent, LENGTH_TIMESTAMP); + DW1000Ng::setDelayedTRX(futureTimeBytes); + timeFinalMessageSent += DW1000Ng::getTxAntennaDelay(); + + byte finalMessage[] = {DATA, SHORT_SRC_AND_DEST, SEQ_NUMBER++, 0,0, 0,0, 0,0, RANGING_TAG_FINAL_RESPONSE_EMBEDDED, + 0,0,0,0,0,0,0,0,0,0,0,0 + }; + + DW1000Ng::getNetworkId(&finalMessage[3]); + memcpy(&finalMessage[5], anchor_address, 2); + DW1000Ng::getDeviceAddress(&finalMessage[7]); + + DW1000NgUtils::writeValueToBytes(finalMessage + 10, (uint32_t) timePollSent, 4); + DW1000NgUtils::writeValueToBytes(finalMessage + 14, (uint32_t) timeResponseToPollReceived, 4); + DW1000NgUtils::writeValueToBytes(finalMessage + 18, (uint32_t) timeFinalMessageSent, 4); + DW1000Ng::setTransmitData(finalMessage, sizeof(finalMessage)); + DW1000Ng::startTransmit(TransmitMode::DELAYED); + } + + void transmitRangingConfirm(byte tag_short_address[], byte next_anchor[]) { + byte rangingConfirm[] = {DATA, SHORT_SRC_AND_DEST, SEQ_NUMBER++, 0,0, 0,0, 0,0, ACTIVITY_CONTROL, RANGING_CONFIRM, next_anchor[0], next_anchor[1]}; + DW1000Ng::getNetworkId(&rangingConfirm[3]); + memcpy(&rangingConfirm[5], tag_short_address, 2); + DW1000Ng::getDeviceAddress(&rangingConfirm[7]); + DW1000Ng::setTransmitData(rangingConfirm, sizeof(rangingConfirm)); + DW1000Ng::startTransmit(); + } + + void transmitActivityFinished(byte tag_short_address[], byte blink_rate[]) { + /* I send the new blink rate to the tag */ + byte rangingConfirm[] = {DATA, SHORT_SRC_AND_DEST, SEQ_NUMBER++, 0,0, 0,0, 0,0, ACTIVITY_CONTROL, ACTIVITY_FINISHED, blink_rate[0], blink_rate[1]}; + DW1000Ng::getNetworkId(&rangingConfirm[3]); + memcpy(&rangingConfirm[5], tag_short_address, 2); + DW1000Ng::getDeviceAddress(&rangingConfirm[7]); + DW1000Ng::setTransmitData(rangingConfirm, sizeof(rangingConfirm)); + DW1000Ng::startTransmit(); + } + + static uint32_t calculateNewBlinkRate(byte frame[]) { + uint32_t blinkRate = frame[11] + static_cast(((frame[12] & 0x3F) << 8)); + byte multiplier = ((frame[12] & 0xC0) >> 6); + if(multiplier == 0x01) { + blinkRate *= 25; + } else if(multiplier == 0x02) { + blinkRate *= 1000; + } + + return blinkRate; + } + + void waitForTransmission() { + while(!DW1000Ng::isTransmitDone()) { + #if defined(ESP8266) + yield(); + #endif + } + DW1000Ng::clearTransmitStatus(); + } + + boolean receiveFrame() { + DW1000Ng::startReceive(); + while(!DW1000Ng::isReceiveDone()) { + if(DW1000Ng::isReceiveTimeout() ) { + DW1000Ng::clearReceiveTimeoutStatus(); + return false; + } + #if defined(ESP8266) + yield(); + #endif + } + DW1000Ng::clearReceiveStatus(); + return true; + } + + static boolean waitForNextRangingStep() { + DW1000NgRTLS::waitForTransmission(); + if(!DW1000NgRTLS::receiveFrame()) return false; + return true; + } + + RangeRequestResult tagRangeRequest() { + DW1000NgRTLS::transmitTwrShortBlink(); + + if(!DW1000NgRTLS::waitForNextRangingStep()) return {false, 0}; + + size_t init_len = DW1000Ng::getReceivedDataLength(); + byte init_recv[init_len]; + DW1000Ng::getReceivedData(init_recv, init_len); + + if(!(init_len > 17 && init_recv[15] == RANGING_INITIATION)) { + return { false, 0}; + } + + DW1000Ng::setDeviceAddress(DW1000NgUtils::bytesAsValue(&init_recv[16], 2)); + return { true, DW1000NgUtils::bytesAsValue(&init_recv[13], 2) }; + } + + static RangeResult tagFinishRange(uint16_t anchor, uint16_t replyDelayUs) { + byte target_anchor[2]; + DW1000NgUtils::writeValueToBytes(target_anchor, anchor, 2); + DW1000NgRTLS::transmitPoll(target_anchor); + /* Start of poll control for range */ + if(!DW1000NgRTLS::waitForNextRangingStep()) return {false, false, 0, 0}; + size_t cont_len = DW1000Ng::getReceivedDataLength(); + byte cont_recv[cont_len]; + DW1000Ng::getReceivedData(cont_recv, cont_len); + + if (cont_len > 10 && cont_recv[9] == ACTIVITY_CONTROL && cont_recv[10] == RANGING_CONTINUE) { + /* Received Response to poll */ + DW1000NgRTLS::transmitFinalMessage( + &cont_recv[7], + replyDelayUs, + DW1000Ng::getTransmitTimestamp(), // Poll transmit time + DW1000Ng::getReceiveTimestamp() // Response to poll receive time + ); + } else { + return {false, false, 0, 0}; + } + + if(!DW1000NgRTLS::waitForNextRangingStep()) return {false, false, 0, 0}; + + size_t act_len = DW1000Ng::getReceivedDataLength(); + byte act_recv[act_len]; + DW1000Ng::getReceivedData(act_recv, act_len); + + if(act_len > 10 && act_recv[9] == ACTIVITY_CONTROL) { + if (act_len > 12 && act_recv[10] == RANGING_CONFIRM) { + return {true, true, DW1000NgUtils::bytesAsValue(&act_recv[11], 2), 0}; + } else if(act_len > 12 && act_recv[10] == ACTIVITY_FINISHED) { + return {true, false, 0, calculateNewBlinkRate(act_recv)}; + } + } else { + return {false, false, 0, 0}; + } + } + + RangeInfrastructureResult tagRangeInfrastructure(uint16_t target_anchor, uint16_t finalMessageDelay) { + RangeResult result = tagFinishRange(target_anchor, finalMessageDelay); + if(!result.success) return {false , 0}; + + while(result.success && result.next) { + result = tagFinishRange(result.next_anchor, finalMessageDelay); + if(!result.success) return {false , 0}; + + #if defined(ESP8266) + yield(); + #endif + } + + if(result.success && result.new_blink_rate != 0) { + return { true, result.new_blink_rate }; + } else { + if(!result.success) + return { false , 0 }; + } + } + + RangeInfrastructureResult tagTwrLocalize(uint16_t finalMessageDelay) { + RangeRequestResult request_result = DW1000NgRTLS::tagRangeRequest(); + + if(request_result.success) { + + RangeInfrastructureResult result = DW1000NgRTLS::tagRangeInfrastructure(request_result.target_anchor, finalMessageDelay); + + if(result.success) + return result; + } + return {false, 0}; + } + + RangeAcceptResult anchorRangeAccept(NextActivity next, uint16_t value) { + double range; + if(!DW1000NgRTLS::receiveFrame()) return {false, 0}; + + size_t poll_len = DW1000Ng::getReceivedDataLength(); + byte poll_data[poll_len]; + DW1000Ng::getReceivedData(poll_data, poll_len); + + if(poll_len > 9 && poll_data[9] == RANGING_TAG_POLL) { + uint64_t timePollReceived = DW1000Ng::getReceiveTimestamp(); + DW1000NgRTLS::transmitResponseToPoll(&poll_data[7]); + DW1000NgRTLS::waitForTransmission(); + uint64_t timeResponseToPoll = DW1000Ng::getTransmitTimestamp(); + delayMicroseconds(1500); + if(!DW1000NgRTLS::receiveFrame()) return {false, 0}; + + size_t rfinal_len = DW1000Ng::getReceivedDataLength(); + byte rfinal_data[rfinal_len]; + DW1000Ng::getReceivedData(rfinal_data, rfinal_len); + if(rfinal_len > 18 && rfinal_data[9] == RANGING_TAG_FINAL_RESPONSE_EMBEDDED) { + uint64_t timeFinalMessageReceive = DW1000Ng::getReceiveTimestamp(); + + byte finishValue[2]; + DW1000NgUtils::writeValueToBytes(finishValue, value, 2); + + if(next == NextActivity::RANGING_CONFIRM) + DW1000NgRTLS::transmitRangingConfirm(&rfinal_data[7], finishValue); + else + DW1000NgRTLS::transmitActivityFinished(&rfinal_data[7], finishValue); + + DW1000NgRTLS::waitForTransmission(); + + range = DW1000NgRanging::computeRangeAsymmetric( + DW1000NgUtils::bytesAsValue(rfinal_data + 10, LENGTH_TIMESTAMP), // Poll send time + timePollReceived, + timeResponseToPoll, // Response to poll sent time + DW1000NgUtils::bytesAsValue(rfinal_data + 14, LENGTH_TIMESTAMP), // Response to Poll Received + DW1000NgUtils::bytesAsValue(rfinal_data + 18, LENGTH_TIMESTAMP), // Final Message send time + timeFinalMessageReceive // Final message receive time + ); + + range = DW1000NgRanging::correctRange(range); + + /* In case of wrong read due to bad device calibration */ + if(range <= 0) + range = 0.000001; + + return {true, range}; + } + } + } + +} \ No newline at end of file diff --git a/src/DW1000NgRTLS.hpp b/src/DW1000NgRTLS.hpp index addde004..30abe999 100644 --- a/src/DW1000NgRTLS.hpp +++ b/src/DW1000NgRTLS.hpp @@ -65,4 +65,69 @@ constexpr byte NO_EX_ID = 0x40; /* BLINK Ext Header */ constexpr byte BLINK_RATE_AND_LISTENING = 0x01; -constexpr byte TAG_LISTENING_NOW = 0x02; \ No newline at end of file +constexpr byte TAG_LISTENING_NOW = 0x02; + +enum class NextActivity { + ACTIVITY_FINISHED, + RANGING_CONFIRM +}; + +typedef struct RangeRequestResult { + boolean success; + uint16_t target_anchor; +} RangeRequestResult; + +typedef struct RangeResult { + boolean success; + boolean next; + uint16_t next_anchor; + uint32_t new_blink_rate; +} RangeResult; + +typedef struct RangeInfrastructureResult { + boolean success; + uint16_t new_blink_rate; +} RangeInfrastructureResult; + +typedef struct RangeAcceptResult { + boolean success; + double range; +} RangeAcceptResult; + +namespace DW1000NgRTLS { + /*** TWR functions used in ISO/IEC 24730-62:2013, refer to the standard or the decawave manual for details about TWR ***/ + byte increaseSequenceNumber(); + void transmitTwrShortBlink(); + void transmitRangingInitiation(byte tag_eui[], byte tag_short_address[]); + void transmitPoll(byte anchor_address[]); + void transmitResponseToPoll(byte tag_short_address[]); + void transmitFinalMessage(byte anchor_address[], uint16_t reply_delay, uint64_t timePollSent, uint64_t timeResponseToPollReceived); + void transmitRangingConfirm(byte tag_short_address[], byte next_anchor[]); + void transmitActivityFinished(byte tag_short_address[], byte blink_rate[]); + + boolean receiveFrame(); + void waitForTransmission(); + /*** End of TWR functions ***/ + + /* Send a request range from tag to the rtls infrastructure */ + RangeRequestResult tagRangeRequest(); + + /* Used by an anchor to accept an incoming tagRangeRequest by means of the infrastructure + NextActivity is used to indicate the tag what to do next after the ranging process (Activity finished is to return to blink (range request), + Continue range is to tell the tag to range a new anchor) + value is the value relative to the next activity (Activity finished = new blink rante, continue range = new anchor address) + */ + RangeAcceptResult anchorRangeAccept(NextActivity next, uint16_t value); + + /* Used by tag to range after range request accept of the infrastructure + Target anchor is given after a range request success + Finalmessagedelay is used in the process of TWR, a value of 1500 works on 8mhz-80mhz range devices, + you could try to decrease it to improve system performance. + */ + RangeInfrastructureResult tagRangeInfrastructure(uint16_t target_anchor, uint16_t finalMessageDelay); + + /* Can be used as a single function start the localization process from the tag. + Finalmessagedelay is the same as in function tagRangeInfrastructure + */ + RangeInfrastructureResult tagTwrLocalize(uint16_t finalMessageDelay); +} \ No newline at end of file