├── .DS_Store ├── examples ├── .DS_Store ├── ex_00a_reading_dev_id │ └── ex_00a_reading_dev_id.ino ├── ex_02a_simple_rx │ └── ex_02a_simple_rx.ino ├── ex_01a_simple_tx │ └── ex_01a_simple_tx.ino ├── ex_01c_tx_sleep_auto │ └── ex_01c_tx_sleep_auto.ino ├── ex_01b_tx_sleep │ └── ex_01b_tx_sleep.ino ├── ex_06b_ss_twr_responder │ └── ex_06b_ss_twr_responder.ino ├── ex_06a_ss_twr_initiator │ └── ex_06a_ss_twr_initiator.ino ├── ex_06b_ss_twr_responder_sts_no_data │ └── ex_06b_ss_twr_responder_sts_no_data.ino └── ex_06b_ss_twr_responder_sts │ └── ex_06b_ss_twr_responder_sts.ino ├── library.json ├── src ├── dw3000_uart.h ├── dw3000_uart.cpp ├── dw3000_types.h ├── dw3000.h ├── dw3000_version.h ├── dw3000_shared_defines.h ├── dw3000_mutex.cpp ├── dw3000_shared_functions.h ├── dw3000_port.h ├── dw3000_config_options.h ├── dw3000_mac_802_15_4.h ├── dw3000_mac_802_15_4.cpp ├── dw3000_vals.h ├── dw3000_shared_functions.cpp └── dw3000_port.cpp ├── library.properties ├── keywords.txt ├── LICENSE └── README.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PontusO/iLabs_UWB/HEAD/.DS_Store -------------------------------------------------------------------------------- /examples/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PontusO/iLabs_UWB/HEAD/examples/.DS_Store -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DW3000", 3 | "version": "0.1", 4 | "license": "Apache-2.0", 5 | "keywords": "wireless, communication", 6 | "description": "A library that offers functionality to use Decawave's DW3000 chips.", 7 | "frameworks": "arduino", 8 | "platforms": "*" 9 | } 10 | -------------------------------------------------------------------------------- /src/dw3000_uart.h: -------------------------------------------------------------------------------- 1 | /* 2 | * UART.h 3 | * 4 | * Created: 9/10/2021 12:32:28 PM 5 | * Author: Emin Eminof 6 | */ 7 | 8 | #ifndef UART_H_ 9 | #define UART_H_ 10 | 11 | #include "dw3000.h" 12 | 13 | void UART_init(void); 14 | void UART_putc(char data); 15 | void UART_puts(const char* s); 16 | 17 | void test_run_info(const char * s); 18 | 19 | #endif /* UART_H_ */ 20 | -------------------------------------------------------------------------------- /src/dw3000_uart.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * UART.c 3 | * 4 | * Created: 9/10/2021 12:32:14 PM 5 | * Author: Emin Eminof 6 | */ 7 | #include "dw3000_uart.h" 8 | 9 | 10 | void UART_init(void) 11 | { 12 | Serial.begin(115200); 13 | } 14 | 15 | void UART_putc(char data) 16 | { 17 | Serial.print(data); 18 | } 19 | 20 | void UART_puts(const char* s) 21 | { 22 | Serial.print(s); 23 | } 24 | 25 | void test_run_info(const char * s) 26 | { 27 | UART_puts(s); 28 | UART_puts("\r\n"); 29 | } 30 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=iLabs_UWB 2 | version=0.1 3 | author=Yannick SILVA , Pontus Oldberg 4 | maintainer=Pontus Oldberg 5 | sentence=A support library for the Challenger RP2040 UWB development board. 6 | paragraph=Supports transmission of messages, timestamp handling (for ranging and location sensing applications) and implements the different operation modes the DW1000 has to offer. The library design is intended to offer an easy-to-use interface to the otherwise complex and configuration intense handling of the DW1000. 7 | category=Communication 8 | url=https://ilabs.se 9 | architectures=* 10 | -------------------------------------------------------------------------------- /src/dw3000_types.h: -------------------------------------------------------------------------------- 1 | /*! ---------------------------------------------------------------------------- 2 | * @file deca_types.h 3 | * @brief Decawave general type definitions 4 | * 5 | * @attention 6 | * 7 | * Copyright 2013-2020 (c) Decawave Ltd, Dublin, Ireland. 8 | * 9 | * All rights reserved. 10 | * 11 | */ 12 | 13 | #ifndef _DECA_TYPES_H_ 14 | #define _DECA_TYPES_H_ 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | #include 21 | #include 22 | 23 | 24 | #ifndef NULL 25 | #define NULL ((void *)0UL) 26 | #endif 27 | 28 | #ifdef __cplusplus 29 | } 30 | #endif 31 | 32 | #endif /* DECA_TYPES_H_ */ 33 | -------------------------------------------------------------------------------- /src/dw3000.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef MAIN_H_ 4 | #define MAIN_H_ 5 | 6 | //#include // all the standard AVR functions 7 | #define __DELAY_BACKWARD_COMPATIBLE__ // this enables uint32 to be used in sleep functions 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "dw3000_uart.h" 17 | #include "dw3000_port.h" 18 | #include "dw3000_device_api.h" 19 | #include "dw3000_shared_functions.h" 20 | 21 | #define _BV(n) (1 << n) // sets 1 at position of BIT "n" 22 | #define __INLINE inline 23 | 24 | #endif /* MAIN_H_ */ 25 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For DW3000 3 | ####################################### 4 | 5 | ####################################### 6 | # Library (KEYWORD1) 7 | ####################################### 8 | 9 | DW3000 KEYWORD1 10 | DW3000Time KEYWORD1 11 | 12 | ####################################### 13 | # Methods and Functions (KEYWORD2) 14 | ####################################### 15 | 16 | begin KEYWORD2 17 | end KEYWORD2 18 | select KEYWORD2 19 | newConfiguration KEYWORD2 20 | commitConfiguration KEYWORD2 21 | newTransmit KEYWORD2 22 | startTransmit KEYWORD2 23 | newReceive KEYWORD2 24 | startReceive KEYWORD2 25 | setDefaults KEYWORD2 26 | # TODO ... 27 | 28 | ####################################### 29 | # Constants (LITERAL1) 30 | ####################################### 31 | 32 | # TODO ... 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 iLabs - Pontus Oldberg 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/dw3000_version.h: -------------------------------------------------------------------------------- 1 | /*! ---------------------------------------------------------------------------- 2 | * @file deca_version.h 3 | * @brief Defines the version info for the DW3000 device driver including its API 4 | * 5 | * @attention 6 | * 7 | * Copyright 2017-2020 (c) Decawave Ltd, Dublin, Ireland. 8 | * 9 | * All rights reserved. 10 | * 11 | */ 12 | 13 | #ifndef _DECA_VERSION_H_ 14 | #define _DECA_VERSION_H_ 15 | 16 | // 17 | // The DW3000 device driver is separately version numbered to any version the application using it may have 18 | // 19 | // Two symbols are defined here: one hexadecimal value and one string that includes the hex bytes. 20 | // Both should be updated together in a consistent way when the software is being modified. 21 | // 22 | // The format of the hex version is 0xAABBCC and the string ends with AA.BB.CC, where... 23 | // 24 | // Quantity CC is updated for minor changes/bug fixes that should not need user code changes 25 | // Quantity BB is updated for changes/bug fixes that may need user code changes 26 | // Quantity AA is updated for major changes that will need user code changes 27 | // 28 | 29 | #define DW3000_DRIVER_VERSION 0x040000 30 | #define DW3000_DEVICE_DRIVER_VER_STRING "DW3000 C0 Device Driver Version 04.00.00" 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /examples/ex_00a_reading_dev_id/ex_00a_reading_dev_id.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * _ _ _ 4 | * (_) | | | 5 | * _| | __ _| |__ ___ 6 | * | | | / _` | '_ \/ __| 7 | * | | |___| (_| | |_) \__ \ 8 | * |_|______\__,_|_.__/|___/ 9 | * 10 | * ---------------------------------------------------------------------------- 11 | * "THE BEER-WARE LICENSE" (Revision 42): 12 | * wrote this file. As long as you retain this notice you 13 | * can do whatever you want with this stuff. If we meet some day, and you think 14 | * this stuff is worth it, you can buy me a beer in return - Pontus Oldberg 15 | * ---------------------------------------------------------------------------- 16 | */ 17 | 18 | #include "dw3000.h" 19 | 20 | #define APP_NAME "READ DEV ID\r\n" 21 | 22 | void setup() { 23 | while (!Serial) 24 | delay(100); 25 | 26 | Serial.begin(115200); 27 | Serial.println(APP_NAME); 28 | 29 | /* Start SPI and get stuff going*/ 30 | spiBegin(); 31 | spiSelect(); 32 | 33 | delay(2); // Time needed for DW3000 to start up (transition from INIT_RC to IDLE_RC, or could wait for SPIRDY event) 34 | 35 | /* Reads and validate device ID returns DWT_ERROR if it does not match expected else DWT_SUCCESS */ 36 | if (dwt_check_dev_id() == DWT_SUCCESS) 37 | { 38 | Serial.println("DEV ID OK"); 39 | } 40 | else 41 | { 42 | Serial.println("DEV ID FAILED"); 43 | } 44 | } 45 | 46 | void loop() { 47 | // put your main code here, to run repeatedly: 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/dw3000_shared_defines.h: -------------------------------------------------------------------------------- 1 | /*! ---------------------------------------------------------------------------- 2 | * @file shared_defines.h 3 | * @brief Global definitions are found here 4 | * 5 | * @attention 6 | * 7 | * Copyright 2013-2020 (c) Decawave Ltd, Dublin, Ireland. 8 | * 9 | * All rights reserved. 10 | * 11 | */ 12 | 13 | #ifndef _SHARE_DEF_ 14 | #define _SHARE_DEF_ 15 | 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | #define SPEED_OF_LIGHT (299702547) 22 | #define FRAME_LEN_MAX (127) 23 | #define FRAME_LEN_MAX_EX (1023) 24 | 25 | #define RXFLEN_MASK 0x0000007FUL /* Receive Frame Length (0 to 127) */ 26 | #define RXFL_MASK_1023 0x000003FFUL /* Receive Frame Length Extension (0 to 1023) */ 27 | 28 | #define RESP_MSG_TS_LEN 4 29 | #define FINAL_MSG_TS_LEN 4 30 | 31 | /* UWB microsecond (uus) to device time unit (dtu, around 15.65 ps) conversion factor. 32 | * 1 uus = 512 / 499.2 µs and 1 µs = 499.2 * 128 dtu. */ 33 | #define UUS_TO_DWT_TIME 63898 34 | 35 | 36 | 37 | #define TX_CHANGEABLE_DATA (10)/*Can change the length of TX data by this size*/ 38 | #define MINIMAL_DATA_LENGTH (11)/*The TX length will be at least the buffer below*/ 39 | #define SIMPLE_TX_DATA_SIZE (MINIMAL_DATA_LENGTH+TX_CHANGEABLE_DATA) 40 | #define TX_LENGTH_BYTE_POS (2)/*This byte index represent the total length of the TX data*/ 41 | 42 | 43 | 44 | typedef enum 45 | { 46 | DBL_BUFF_ERR_TYPE_UNKNOWN=-1,/*Unknown yet*/ 47 | DBL_BUFF_ERR_TYPE_OK,/*No error*/ 48 | DBL_BUFF_ERR_TYPE_TIMEOUT,/*Timeout*/ 49 | DBL_BUFF_ERR_TYPE_ERROR,/*Error*/ 50 | DBL_BUFF_ERR_TYPE_GOT_UNNEEDED_DATA, 51 | }dbl_buff_error_type_e; 52 | 53 | typedef enum 54 | { 55 | AES_RES_OK=0, 56 | AES_RES_ERROR_LENGTH=-1, 57 | AES_RES_ERROR=-2, 58 | AES_RES_ERROR_FRAME=-3, 59 | AES_RES_ERROR_IGNORE_FRAME=-4 60 | }aes_results_e; 61 | 62 | 63 | 64 | #ifdef __cplusplus 65 | } 66 | #endif 67 | 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iLabs_UWB 2 | A support library for the Challenger RP2040 UWB boards with the DWM3000 module. 3 | 4 | drawing 5 | 6 | ## Introduction 7 | 8 | The DWM3000 is an ultra-wideband (UWB) transceiver module developed by Qorvo Inc. It operates in the frequency range of 3.1 GHz to 10.6 GHz and has a maximum output power of 4 dBm. The module uses the IEEE 802.15.4a standard for UWB communication, which enables highly accurate ranging and positioning with an accuracy of up to 10 cm. 9 | 10 | The DWM3000 module integrates a Qorvo DW3110 chip, which provides UWB communication capabilities. The module measures 21mm x 16mm x 2.5mm and has a power consumption of approximately 75mA during active mode and 1.5μA during sleep mode. It supports SPI and UART(Not supported on the Challenger board) interfaces for communication with external devices and has a built-in antenna for wireless communication. 11 | 12 | The DWM3000 is designed for use in a variety of indoor positioning and communication applications, such as asset tracking, inventory management, and personnel tracking. It also features a small form factor and low power consumption, making it suitable for battery-powered devices. 13 | 14 | Overall, the DWM3000 is a highly accurate UWB transceiver module designed for indoor positioning and communication applications that require high precision and low power consumption. 15 | 16 | It is IEEE 802.15.4a and IEEE 802.15.4z BPRF mode compliant and allows location of objects to a precision of 10 cm. The module has worldwide UWB support through its operation on UWB channel 5 (6.5 GHz) and channel 9 (8 GHz). The module is also interoperable with the Apple U1 chip and is designed to be compliant to the FiRa™ PHY and MAC specifications enabling interoperability with other FiRa™ compliant devices. 17 | 18 | We paired this marvelous module with our own proven RP2040 base design to create a powerfull and easy to use, and yet small enough to be usable, development board. This board follows the Feather form factor and includes technology to manage a LiPo battery. 19 | 20 | The included examples are all tested to work on our board so you can get started creating super cool stuff from day one. 21 | 22 | ## Usage 23 | 24 | (TBD) -------------------------------------------------------------------------------- /src/dw3000_mutex.cpp: -------------------------------------------------------------------------------- 1 | /*! ---------------------------------------------------------------------------- 2 | * @file deca_mutex.c 3 | * @brief IRQ interface / mutex implementation 4 | * 5 | * @attention 6 | * 7 | * Copyright 2015-2020 (c) DecaWave Ltd, Dublin, Ireland. 8 | * 9 | * All rights reserved. 10 | * 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | // --------------------------------------------------------------------------- 18 | // 19 | // NB: The purpose of this file is to provide for microprocessor interrupt enable/disable, this is used for 20 | // controlling mutual exclusion from critical sections in the code where interrupts and background 21 | // processing may interact. The code using this is kept to a minimum and the disabling time is also 22 | // kept to a minimum, so blanket interrupt disable may be the easiest way to provide this. But at a 23 | // minimum those interrupts coming from the decawave device should be disabled/re-enabled by this activity. 24 | // 25 | // In porting this to a particular microprocessor, the implementer may choose to use #defines in the 26 | // deca_irq.h include file to map these calls transparently to the target system. Alternatively the 27 | // appropriate code may be embedded in the functions provided below. 28 | // 29 | // This mutex dependent on HW port. 30 | // If HW port uses EXT_IRQ line to receive ready/busy status from DW1000 then mutex should use this signal 31 | // If HW port not use EXT_IRQ line (i.e. SW polling) then no necessary for decamutex(on/off) 32 | // 33 | // For critical section use this mutex instead 34 | // __save_intstate() 35 | // __restore_intstate() 36 | // --------------------------------------------------------------------------- 37 | 38 | 39 | /*! ------------------------------------------------------------------------------------------------------------------ 40 | * Function: decamutexon() 41 | * 42 | * Description: This function should disable interrupts. This is called at the start of a critical section 43 | * It returns the irq state before disable, this value is used to re-enable in decamutexoff call 44 | * 45 | * Note: The body of this function is defined in deca_mutex.c and is platform specific 46 | * 47 | * input parameters: 48 | * 49 | * output parameters 50 | * 51 | * returns the state of the DW1000 interrupt 52 | */ 53 | //portMUX_TYPE my_mutex = portMUX_INITIALIZER_UNLOCKED; 54 | decaIrqStatus_t decamutexon(void) 55 | { 56 | decaIrqStatus_t s = port_GetEXT_IRQStatus(); 57 | portENTER_CRITICAL(); 58 | /*portDISABLE_INTERRUPTS(); 59 | decaIrqStatus_t s = port_GetEXT_IRQStatus(); 60 | 61 | if(s) { 62 | port_DisableEXT_IRQ(); //disable the external interrupt line 63 | } 64 | return s ; // return state before disable, value is used to re-enable in decamutexoff call 65 | */ 66 | return s; 67 | } 68 | 69 | /*! ------------------------------------------------------------------------------------------------------------------ 70 | * Function: decamutexoff() 71 | * 72 | * Description: This function should re-enable interrupts, or at least restore their state as returned(&saved) by decamutexon 73 | * This is called at the end of a critical section 74 | * 75 | * Note: The body of this function is defined in deca_mutex.c and is platform specific 76 | * 77 | * input parameters: 78 | * @param s - the state of the DW1000 interrupt as returned by decamutexon 79 | * 80 | * output parameters 81 | * 82 | * returns the state of the DW1000 interrupt 83 | */ 84 | void decamutexoff(decaIrqStatus_t s) // put a function here that re-enables the interrupt at the end of the critical section 85 | { 86 | portEXIT_CRITICAL(); 87 | /*portENABLE_INTERRUPTS(); 88 | 89 | if(s) { //need to check the port state as we can't use level sensitive interrupt on the STM ARM 90 | port_EnableEXT_IRQ(); 91 | }*/ 92 | } 93 | -------------------------------------------------------------------------------- /src/dw3000_shared_functions.h: -------------------------------------------------------------------------------- 1 | #ifndef _SHARE_FUNC_ 2 | #define _SHARE_FUNC_ 3 | 4 | #ifdef __cplusplus 5 | //extern "C" { 6 | #endif 7 | 8 | #include "dw3000.h" 9 | #include "dw3000_types.h" 10 | #include "dw3000_regs.h" 11 | #include "dw3000_shared_defines.h" 12 | #include "dw3000_config_options.h" 13 | 14 | extern dwt_config_t config_options; 15 | 16 | /*! ------------------------------------------------------------------------------------------------------------------ 17 | * @fn check_for_status_errors() 18 | * 19 | * @brief This function is used to get a value to increase the delay timer by dependent on the current TX preamble length set. 20 | * 21 | * @param reg: uint32_t value representing the current status register value. 22 | * @param errors: pointer to a uint32_t buffer that contains the sum of different errors logged during program operation. 23 | * 24 | * @return none 25 | */ 26 | void check_for_status_errors(uint32_t reg, uint32_t * errors); 27 | 28 | /*! ------------------------------------------------------------------------------------------------------------------ 29 | * @fn get_rx_delay_time_txpreamble() 30 | * 31 | * @brief This function is used to get a value to increase the delay timer by dependent on the current TX preamble length set. 32 | * 33 | * @param None 34 | * 35 | * @return delay_time - a uint32_t value indicating the required increase needed to delay the time by. 36 | */ 37 | uint32_t get_rx_delay_time_txpreamble(void); 38 | 39 | /*! ------------------------------------------------------------------------------------------------------------------ 40 | * @fn get_rx_delay_time_data_rate() 41 | * 42 | * @brief This function is used to get a value to increase the delay timer by dependent on the current data rate set. 43 | * 44 | * @param None 45 | * 46 | * @return delay_time - a uint32_t value indicating the required increase needed to delay the time by. 47 | */ 48 | uint32_t get_rx_delay_time_data_rate(void); 49 | 50 | /*! ------------------------------------------------------------------------------------------------------------------ 51 | * @fn set_delayed_rx_time() 52 | * 53 | * @brief This function is used to set the delayed RX time before running dwt_rxenable() 54 | * 55 | * @param delay - This is a defined delay value (usually POLL_TX_TO_RESP_RX_DLY_UUS) 56 | * @param config_options - pointer to dwt_config_t configuration structure that is in use at the time this function 57 | * is called. 58 | * 59 | * @return None 60 | */ 61 | void set_delayed_rx_time(uint32_t delay, dwt_config_t *config_options); 62 | 63 | /*! ------------------------------------------------------------------------------------------------------------------ 64 | * @fn set_resp_rx_timeout() 65 | * 66 | * @brief This function is used to set the RX timeout value 67 | * 68 | * @param delay - This is a defined delay value (usually RESP_RX_TIMEOUT_UUS) 69 | * @param config_options - pointer to dwt_config_t configuration structure that is in use at the time this function 70 | * is called. 71 | * 72 | * @return None 73 | */ 74 | void set_resp_rx_timeout(uint32_t delay, dwt_config_t *config_options); 75 | 76 | /*! ------------------------------------------------------------------------------------------------------------------ 77 | * @fn resync_sts() 78 | * 79 | * @brief Resync the current device's STS value the given value 80 | * 81 | * @param newCount - The 32 bit value to set the STS to. 82 | * 83 | * @return None 84 | */ 85 | void resync_sts(uint32_t newCount); 86 | 87 | /*! ------------------------------------------------------------------------------------------------------------------ 88 | * @fn resp_msg_get_ts() 89 | * 90 | * @brief Read a given timestamp value from the response message. In the timestamp fields of the response message, the 91 | * least significant byte is at the lower address. 92 | * 93 | * @param ts_field pointer on the first byte of the timestamp field to get 94 | * ts timestamp value 95 | * 96 | * @return none 97 | */ 98 | void resp_msg_get_ts(uint8_t *ts_field, uint32_t *ts); 99 | uint64_t get_tx_timestamp_u64(void); 100 | uint64_t get_rx_timestamp_u64(void); 101 | void final_msg_get_ts(const uint8_t *ts_field, uint32_t *ts); 102 | void final_msg_set_ts(uint8_t *ts_field, uint64_t ts); 103 | void resp_msg_set_ts(uint8_t *ts_field, const uint64_t ts); 104 | 105 | 106 | 107 | #ifdef __cplusplus 108 | //} 109 | #endif 110 | 111 | 112 | #endif 113 | -------------------------------------------------------------------------------- /examples/ex_02a_simple_rx/ex_02a_simple_rx.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * _ _ _ 4 | * (_) | | | 5 | * _| | __ _| |__ ___ 6 | * | | | / _` | '_ \/ __| 7 | * | | |___| (_| | |_) \__ \ 8 | * |_|______\__,_|_.__/|___/ 9 | * 10 | * ---------------------------------------------------------------------------- 11 | * "THE BEER-WARE LICENSE" (Revision 42): 12 | * wrote this file. As long as you retain this notice you 13 | * can do whatever you want with this stuff. If we meet some day, and you think 14 | * this stuff is worth it, you can buy me a beer in return - Pontus Oldberg 15 | * ---------------------------------------------------------------------------- 16 | */ 17 | 18 | #include "dw3000.h" 19 | 20 | #define APP_NAME "SIMPLE RX v1.1" 21 | 22 | /* Default communication configuration. We use default non-STS DW mode. */ 23 | static dwt_config_t config = { 24 | 5, /* Channel number. */ 25 | DWT_PLEN_128, /* Preamble length. Used in TX only. */ 26 | DWT_PAC8, /* Preamble acquisition chunk size. Used in RX only. */ 27 | 9, /* TX preamble code. Used in TX only. */ 28 | 9, /* RX preamble code. Used in RX only. */ 29 | 1, /* 0 to use standard 8 symbol SFD, 1 to use non-standard 8 symbol, 2 for non-standard 16 symbol SFD and 3 for 4z 8 symbol SDF type */ 30 | DWT_BR_6M8, /* Data rate. */ 31 | DWT_PHRMODE_STD, /* PHY header mode. */ 32 | DWT_PHRRATE_STD, /* PHY header rate. */ 33 | (129 + 8 - 8), /* SFD timeout (preamble length + 1 + SFD length - PAC size). Used in RX only. */ 34 | DWT_STS_MODE_OFF, /* STS disabled */ 35 | DWT_STS_LEN_64, /* STS length see allowed values in Enum dwt_sts_lengths_e */ 36 | DWT_PDOA_M0 /* PDOA mode off */ 37 | }; 38 | 39 | /* Buffer to store received frame. See NOTE 1 below. */ 40 | static char rx_buffer[FRAME_LEN_MAX]; 41 | 42 | /* Hold copy of status register state here for reference so that it can be examined at a debug breakpoint. */ 43 | uint32_t status_reg; 44 | /* Hold copy of frame length of frame received (if good) so that it can be examined at a debug breakpoint. */ 45 | uint16_t frame_len; 46 | 47 | void setup() 48 | { 49 | pinMode(LED_BUILTIN, OUTPUT); 50 | digitalWrite(LED_BUILTIN, LOW); 51 | 52 | while (!Serial) 53 | delay(100); 54 | 55 | Serial.begin(115200); 56 | Serial.println(APP_NAME); 57 | 58 | /* Start SPI and get stuff going*/ 59 | spiBegin(); 60 | spiSelect(); 61 | 62 | delay(200); // Time needed for DW3000 to start up (transition from INIT_RC to IDLE_RC, or could wait for SPIRDY event) 63 | 64 | while (!dwt_checkidlerc()) // Need to make sure DW IC is in IDLE_RC before proceeding 65 | { 66 | Serial.println("IDLE FAILED !"); 67 | while (1) 68 | ; 69 | } 70 | 71 | dwt_softreset(); 72 | delay(200); 73 | 74 | while (!dwt_checkidlerc()) // Need to make sure DW IC is in IDLE_RC before proceeding 75 | { 76 | Serial.print("IDLE FAILED\r\n"); 77 | while (1); 78 | } 79 | 80 | if (dwt_initialise(DWT_DW_INIT) == DWT_ERROR) 81 | { 82 | Serial.print("INIT FAILED\r\n"); 83 | while (1) ; 84 | } 85 | 86 | // Configure DW IC. See NOTE 5 below. 87 | if (dwt_configure(&config)) // if the dwt_configure returns DWT_ERROR either the PLL or RX calibration has failed the host should reset the device 88 | { 89 | Serial.println("CONFIG FAILED !"); 90 | while (1) 91 | ; 92 | } 93 | } 94 | 95 | void loop() 96 | { 97 | /* TESTING BREAKPOINT LOCATION #1 */ 98 | 99 | /* Clear local RX buffer to avoid having leftovers from previous receptions This is not necessary but is included here to aid reading 100 | * the RX buffer. 101 | * This is a good place to put a breakpoint. Here (after first time through the loop) the local status register will be set for last event 102 | * and if a good receive has happened the data buffer will have the data in it, and frame_len will be set to the length of the RX frame. */ 103 | memset(rx_buffer, 0, sizeof(rx_buffer)); 104 | 105 | /* Activate reception immediately. See NOTE 2 below. */ 106 | dwt_rxenable(DWT_START_RX_IMMEDIATE); 107 | 108 | /* Poll until a frame is properly received or an error/timeout occurs. See NOTE 3 below. 109 | * STATUS register is 5 bytes long but, as the event we are looking at is in the first byte of the register, we can use this simplest API 110 | * function to access it. */ 111 | while (!((status_reg = dwt_read32bitreg(SYS_STATUS_ID)) & (SYS_STATUS_RXFCG_BIT_MASK | SYS_STATUS_ALL_RX_ERR))) 112 | { 113 | }; 114 | 115 | if (status_reg & SYS_STATUS_RXFCG_BIT_MASK) 116 | { 117 | /* A frame has been received, copy it to our local buffer. */ 118 | frame_len = dwt_read32bitreg(RX_FINFO_ID) & RX_FINFO_RXFLEN_BIT_MASK; 119 | if (frame_len <= FRAME_LEN_MAX) 120 | { 121 | dwt_readrxdata((uint8_t *)rx_buffer, frame_len - FCS_LEN, 0); /* No need to read the FCS/CRC. */ 122 | } 123 | 124 | /* Clear good RX frame event in the DW IC status register. */ 125 | dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_RXFCG_BIT_MASK); 126 | 127 | pinMode(LED_BUILTIN, OUTPUT); 128 | digitalWrite(LED_BUILTIN, HIGH); 129 | Serial.printf("Frame Received \'%s\'\n", rx_buffer+2); 130 | delay(25); 131 | pinMode(LED_BUILTIN, OUTPUT); 132 | digitalWrite(LED_BUILTIN, LOW); 133 | } 134 | else 135 | { 136 | /* Clear RX error events in the DW IC status register. */ 137 | dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_ALL_RX_ERR); 138 | } 139 | } 140 | /***************************************************************************************************************************************************** 141 | * NOTES: 142 | * 143 | * 1. In this example, maximum frame length is set to 127 bytes which is 802.15.4 UWB standard maximum frame length. DW IC supports an extended 144 | * frame length (up to 1023 bytes long) mode which is not used in this example. 145 | * 2. Manual reception activation is performed here but DW IC offers several features that can be used to handle more complex scenarios or to 146 | * optimise system's overall performance (e.g. timeout after a given time, automatic re-enabling of reception in case of errors, etc.). 147 | * 3. We use polled mode of operation here to keep the example as simple as possible, but RXFCG and error/timeout status events can be used to generate 148 | * interrupts. Please refer to DW IC User Manual for more details on "interrupts". 149 | ****************************************************************************************************************************************************/ 150 | -------------------------------------------------------------------------------- /src/dw3000_port.h: -------------------------------------------------------------------------------- 1 | /* 2 | * port.h 3 | * 4 | * Created: 9/10/2021 1:20:00 PM 5 | * Author: Emin Eminof 6 | */ 7 | 8 | #ifndef PORT_H_ 9 | #define PORT_H_ 10 | 11 | #include "dw3000.h" 12 | #include 13 | 14 | #define DDR_SPI DDRB 15 | #define DD_SCK DDB5 16 | #define DD_MISO DDB4 17 | #define DD_MOSI DDB3 18 | #define DD_SS 4 19 | 20 | #if defined(ARDUINO_CHALLENGER_2040_UWB_RP2040) 21 | #define DEFAULT_WAKE 15 22 | #define DEFAULT_IRQ 14 23 | #define DEFAULT_RST 13 24 | #define DEFAULT_SS 9 25 | #else 26 | #define DEFAULT_WAKE 15 27 | #define DEFAULT_IRQ 34 28 | #define DEFAULT_RST 27 29 | #define DEFAULT_SS 4 30 | #endif 31 | 32 | //#define DDR_PORTD DDRD 33 | #define DD_RESET_PIN 27 34 | 35 | #ifndef FALSE 36 | #define FALSE 0 37 | #endif 38 | 39 | #ifndef TRUE 40 | #define TRUE 1 41 | #endif 42 | 43 | // PMSC 44 | #define PMSC 0x36 45 | #define PMSC_CTRL0_SUB 0x00 46 | #define PMSC_CTRL1_SUB 0x04 47 | #define PMSC_LEDC_SUB 0x28 48 | #define LEN_PMSC_CTRL0 4 49 | #define LEN_PMSC_CTRL1 4 50 | #define LEN_PMSC_LEDC 4 51 | #define GPDCE_BIT 18 52 | #define KHZCLKEN_BIT 23 53 | #define BLNKEN 8 54 | 55 | #define ATXSLP_BIT 11 56 | #define ARXSLP_BIT 12 57 | 58 | // used for SPI ready w/o actual writes 59 | #define JUNK 0x00 60 | 61 | // no sub-address for register write 62 | #define NO_SUB 0xFF 63 | 64 | #define WRITE 0x80 65 | #define WRITE_SUB 0xC0 66 | #define READ 0x00 67 | #define READ_SUB 0x40 68 | #define RW_SUB_EXT 0x80 69 | 70 | // device control register 71 | #define SYS_CTRL 0x0D 72 | #define LEN_SYS_CTRL 4 73 | #define SFCST_BIT 0 74 | #define TXSTRT_BIT 1 75 | #define TXDLYS_BIT 2 76 | #define TRXOFF_BIT 6 77 | #define WAIT4RESP_BIT 7 78 | #define RXENAB_BIT 8 79 | #define RXDLYS_BIT 9 80 | 81 | // device configuration register 82 | #define SYS_CFG 0x04 83 | #define LEN_SYS_CFG 4 84 | #define FFEN_BIT 0 85 | #define FFBC_BIT 1 86 | #define FFAB_BIT 2 87 | #define FFAD_BIT 3 88 | #define FFAA_BIT 4 89 | #define FFAM_BIT 5 90 | #define FFAR_BIT 6 91 | #define DIS_DRXB_BIT 12 92 | #define DIS_STXP_BIT 18 93 | #define HIRQ_POL_BIT 9 94 | #define RXAUTR_BIT 29 95 | #define PHR_MODE_SUB 16 96 | #define LEN_PHR_MODE_SUB 2 97 | #define RXM110K_BIT 22 98 | 99 | // system event status register 100 | #define SYS_STATUS 0x0F 101 | #define LEN_SYS_STATUS 5 102 | #define CPLOCK_BIT 1 103 | #define AAT_BIT 3 104 | #define TXFRB_BIT 4 105 | #define TXPRS_BIT 5 106 | #define TXPHS_BIT 6 107 | #define TXFRS_BIT 7 108 | #define LDEDONE_BIT 10 109 | #define RXPHE_BIT 12 110 | #define RXDFR_BIT 13 111 | #define RXFCG_BIT 14 112 | #define RXFCE_BIT 15 113 | #define RXRFSL_BIT 16 114 | #define RXRFTO_BIT 17 115 | #define RXPTO_BIT 21 116 | #define RXSFDTO_BIT 26 117 | #define LDEERR_BIT 18 118 | #define RFPLL_LL_BIT 24 119 | #define CLKPLL_LL_BIT 25 120 | 121 | // transmit control 122 | #define TX_FCTRL 0x08 123 | #define LEN_TX_FCTRL 5 124 | 125 | // channel control 126 | #define CHAN_CTRL 0x1F 127 | #define LEN_CHAN_CTRL 4 128 | #define DWSFD_BIT 17 129 | #define TNSSFD_BIT 20 130 | #define RNSSFD_BIT 21 131 | 132 | // system event mask register 133 | // NOTE: uses the bit definitions of SYS_STATUS (below 32) 134 | #define SYS_MASK 0x0E 135 | #define LEN_SYS_MASK 4 136 | 137 | /* clocks available. */ 138 | #define AUTO_CLOCK 0x00 139 | #define XTI_CLOCK 0x01 140 | #define PLL_CLOCK 0x02 141 | 142 | // OTP control (for LDE micro code loading only) 143 | #define OTP_IF 0x2D 144 | #define OTP_ADDR_SUB 0x04 145 | #define OTP_CTRL_SUB 0x06 146 | #define OTP_RDAT_SUB 0x0A 147 | #define LEN_OTP_ADDR 2 148 | #define LEN_OTP_CTRL 2 149 | #define LEN_OTP_RDAT 4 150 | 151 | // enum to determine RX or TX mode of device 152 | #define IDLE_MODE 0x00 153 | #define RX_MODE 0x01 154 | #define TX_MODE 0x02 155 | 156 | // PAN identifier, short address register 157 | #define PANADR 0x03 158 | #define LEN_PANADR 4 159 | 160 | void readBytes(byte cmd, uint16_t offset, byte data[], uint16_t n); 161 | void readSystemEventStatusRegister(); 162 | void readSystemConfigurationRegister(); 163 | void writeSystemConfigurationRegister(); 164 | void readNetworkIdAndDeviceAddress(); 165 | void writeNetworkIdAndDeviceAddress(); 166 | void readSystemEventMaskRegister(); 167 | void writeSystemEventMaskRegister(); 168 | void readChannelControlRegister(); 169 | void writeChannelControlRegister(); 170 | void readTransmitFrameControlRegister(); 171 | void writeTransmitFrameControlRegister(); 172 | void setDoubleBuffering(boolean val); 173 | void setBit(byte data[], uint16_t n, uint16_t bit, boolean val); 174 | boolean getBit(byte data[], uint16_t n, uint16_t bit); 175 | void writeValueToBytes(byte data[], int32_t val, uint16_t n); 176 | void writeBytes(byte cmd, uint16_t offset, byte data[], uint16_t data_size); 177 | void writeByte(byte cmd, uint16_t offset, byte data); 178 | void reset(); 179 | void softReset(); 180 | void idle(); 181 | void spiBegin(uint8_t irq = DEFAULT_IRQ, uint8_t rst = DEFAULT_RST, uint8_t wake = DEFAULT_WAKE); 182 | void spiSelect(uint8_t ss = DEFAULT_SS); 183 | void enableClock(byte clock); 184 | int writetospi(uint16_t headerLength, uint8_t *headerBuffer, uint16_t bodyLength, uint8_t *bodyBuffer); 185 | int readfromspi(uint16_t headerLength, uint8_t *headerBuffer, uint16_t readLength, uint8_t *readBuffer); 186 | 187 | void Sleep(uint32_t d); 188 | void enableDebounceClock(); 189 | void wakeup_device_with_io(); 190 | 191 | void port_set_dw_ic_spi_fastrate(uint8_t irq = DEFAULT_IRQ, uint8_t rst = DEFAULT_RST, uint8_t ss = DEFAULT_SS, uint8_t wake = DEFAULT_WAKE); 192 | 193 | uint32_t port_GetEXT_IRQStatus(void); 194 | uint32_t port_CheckEXT_IRQ(void); 195 | void port_DisableEXT_IRQ(void); 196 | void port_EnableEXT_IRQ(void); 197 | 198 | /* DW IC IRQ (EXTI15_10_IRQ) handler type. */ 199 | typedef void (*port_dwic_isr_t)(void); 200 | 201 | /*! ------------------------------------------------------------------------------------------------------------------ 202 | * @fn port_set_DWIC_isr() 203 | * 204 | * @brief This function is used to install the handling function for DW1000 IRQ. 205 | * 206 | * NOTE: 207 | * - As EXTI9_5_IRQHandler does not check that port_deca_isr is not null, the user application must ensure that a 208 | * proper handler is set by calling this function before any DW1000 IRQ occurs! 209 | * - This function makes sure the DW1000 IRQ line is deactivated while the handler is installed. 210 | * 211 | * @param deca_isr function pointer to DW1000 interrupt handler to install 212 | * 213 | * @return none 214 | */ 215 | void port_set_dwic_isr(port_dwic_isr_t isr); 216 | 217 | #if 0 218 | void sleepms(uint32_t x); 219 | int sleepus(uint32_t x); 220 | void deca_sleep(uint8_t time_ms); 221 | void deca_usleep(uint8_t time_us); 222 | void open_spi(void); 223 | void close_spi(void); 224 | 225 | 226 | void port_set_dw_ic_spi_slowrate(void); 227 | void port_set_dw_ic_spi_fastrate(void); 228 | void reset_DWIC(void); 229 | int spi_tranceiver (uint8_t *data); 230 | #endif 231 | 232 | #endif /* PORT_H_ */ 233 | -------------------------------------------------------------------------------- /examples/ex_01a_simple_tx/ex_01a_simple_tx.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * _ _ _ 4 | * (_) | | | 5 | * _| | __ _| |__ ___ 6 | * | | | / _` | '_ \/ __| 7 | * | | |___| (_| | |_) \__ \ 8 | * |_|______\__,_|_.__/|___/ 9 | * 10 | * ---------------------------------------------------------------------------- 11 | * "THE BEER-WARE LICENSE" (Revision 42): 12 | * wrote this file. As long as you retain this notice you 13 | * can do whatever you want with this stuff. If we meet some day, and you think 14 | * this stuff is worth it, you can buy me a beer in return - Pontus Oldberg 15 | * ---------------------------------------------------------------------------- 16 | */ 17 | 18 | #include "dw3000.h" 19 | 20 | #define APP_NAME "SIMPLE TX v1.1" 21 | 22 | /* Default communication configuration. We use default non-STS DW mode. */ 23 | static dwt_config_t config = { 24 | 5, /* Channel number. */ 25 | DWT_PLEN_128, /* Preamble length. Used in TX only. */ 26 | DWT_PAC8, /* Preamble acquisition chunk size. Used in RX only. */ 27 | 9, /* TX preamble code. Used in TX only. */ 28 | 9, /* RX preamble code. Used in RX only. */ 29 | 1, /* 0 to use standard 8 symbol SFD, 1 to use non-standard 8 symbol, 2 for non-standard 16 symbol SFD and 3 for 4z 8 symbol SDF type */ 30 | DWT_BR_6M8, /* Data rate. */ 31 | DWT_PHRMODE_STD, /* PHY header mode. */ 32 | DWT_PHRRATE_STD, /* PHY header rate. */ 33 | (129 + 8 - 8), /* SFD timeout (preamble length + 1 + SFD length - PAC size). Used in RX only. */ 34 | DWT_STS_MODE_OFF, 35 | DWT_STS_LEN_64, /* STS length, see allowed values in Enum dwt_sts_lengths_e */ 36 | DWT_PDOA_M0 /* PDOA mode off */ 37 | }; 38 | 39 | /* The frame sent in this example is an 802.15.4e standard blink. It is a 12-byte frame composed of the following fields: 40 | * - byte 0: frame type (0xC5 for a blink). 41 | * - byte 1: sequence number, incremented for each new frame. 42 | * - byte 2 -> 9: device ID, see NOTE 1 below. 43 | */ 44 | static uint8_t tx_msg[] = {0xC5, 0, 'D', 'E', 'C', 'A', 'W', 'A', 'V', 'E'}; 45 | /* Index to access to sequence number of the blink frame in the tx_msg array. */ 46 | #define BLINK_FRAME_SN_IDX 1 47 | 48 | #define FRAME_LENGTH (sizeof(tx_msg) + FCS_LEN) // The real length that is going to be transmitted 49 | 50 | /* Inter-frame delay period, in milliseconds. */ 51 | #define TX_DELAY_MS 500 52 | 53 | extern dwt_txconfig_t txconfig_options; 54 | 55 | void setup() 56 | { 57 | pinMode(LED_BUILTIN, OUTPUT); 58 | digitalWrite(LED_BUILTIN, LOW); 59 | 60 | // while (!Serial) 61 | delay(100); 62 | 63 | Serial.begin(115200); 64 | Serial.println(APP_NAME); 65 | 66 | /* Start SPI and get stuff going*/ 67 | spiBegin(); 68 | spiSelect(); 69 | 70 | delay(200); // Time needed for DW3000 to start up (transition from INIT_RC to IDLE_RC, or could wait for SPIRDY event) 71 | 72 | while (!dwt_checkidlerc()) // Need to make sure DW IC is in IDLE_RC before proceeding 73 | { 74 | Serial.println("IDLE FAILED01"); 75 | while (1); 76 | } 77 | 78 | dwt_softreset(); 79 | delay(200); 80 | 81 | while (!dwt_checkidlerc()) // Need to make sure DW IC is in IDLE_RC before proceeding 82 | { 83 | Serial.println("IDLE FAILED02"); 84 | while (1); 85 | } 86 | 87 | // Serial.println("IDLE OK"); 88 | if (dwt_initialise(DWT_DW_INIT) == DWT_ERROR) 89 | { 90 | Serial.println("INIT FAILED"); 91 | while (1); 92 | } 93 | // Serial.println("INIT OK"); 94 | 95 | // Configure DW IC. See NOTE 5 below. 96 | if (dwt_configure(&config)) // if the dwt_configure returns DWT_ERROR either the PLL or RX calibration has failed the host should reset the device 97 | { 98 | Serial.println("CONFIG FAILED"); 99 | while (1); 100 | } 101 | // Serial.println("CONFIG OK"); 102 | /* Configure the TX spectrum parameters (power PG delay and PG Count) */ 103 | dwt_configuretxrf(&txconfig_options); 104 | } 105 | 106 | void loop() 107 | { 108 | /* Write frame data to DW IC and prepare transmission. See NOTE 3 below.*/ 109 | dwt_writetxdata(FRAME_LENGTH - FCS_LEN, tx_msg, 0); /* Zero offset in TX buffer. */ 110 | 111 | /* In this example since the length of the transmitted frame does not change, 112 | * nor the other parameters of the dwt_writetxfctrl function, the 113 | * dwt_writetxfctrl call could be outside the main while(1) loop. 114 | */ 115 | dwt_writetxfctrl(FRAME_LENGTH, 0, 0); /* Zero offset in TX buffer, no ranging. */ 116 | 117 | /* Start transmission. */ 118 | dwt_starttx(DWT_START_TX_IMMEDIATE); 119 | delay(10); // Sleep(TX_DELAY_MS); 120 | 121 | /* Poll DW IC until TX frame sent event set. See NOTE 4 below. 122 | * STATUS register is 4 bytes long but, as the event we are looking at is in the first byte of the register, we can use this simplest API 123 | * function to access it.*/ 124 | 125 | while (!(dwt_read32bitreg(SYS_STATUS_ID) & SYS_STATUS_TXFRS_BIT_MASK)) 126 | { 127 | Serial.println("WHAT!!!"); 128 | /* Reads and validate device ID returns DWT_ERROR if it does not match expected else DWT_SUCCESS */ 129 | // if (dwt_check_dev_id() == DWT_SUCCESS) 130 | { 131 | // UART_puts((char *)"DEV ID OK"); 132 | } 133 | // else 134 | { 135 | // UART_puts((char *)"DEV ID FAILED"); 136 | } 137 | // delay(500); 138 | // dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_TXFRS_BIT_MASK); 139 | // delay(1000); 140 | }; 141 | 142 | /* Clear TX frame sent event. */ 143 | dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_TXFRS_BIT_MASK); 144 | 145 | digitalWrite(LED_BUILTIN, HIGH); 146 | Serial.println("TX Frame Sent"); 147 | delay(25); 148 | digitalWrite(LED_BUILTIN, LOW); 149 | 150 | /* Execute a delay between transmissions. */ 151 | Sleep(TX_DELAY_MS); 152 | 153 | /* Increment the blink frame sequence number (modulo 256). */ 154 | tx_msg[BLINK_FRAME_SN_IDX]++; 155 | } 156 | 157 | /***************************************************************************************************************************************************** 158 | * NOTES: 159 | * 160 | * 1. The device ID is a hard coded constant in the blink to keep the example simple but for a real product every device should have a unique ID. 161 | * For development purposes it is possible to generate a DW IC unique ID by combining the Lot ID & Part Number values programmed into the 162 | * DW IC during its manufacture. However there is no guarantee this will not conflict with someone else�s implementation. We recommended that 163 | * customers buy a block of addresses from the IEEE Registration Authority for their production items. See "EUI" in the DW IC User Manual. 164 | * 2. In a real application, for optimum performance within regulatory limits, it may be necessary to set TX pulse bandwidth and TX power, (using 165 | * the dwt_configuretxrf API call) to per device calibrated values saved in the target system or the DW IC OTP memory. 166 | * 3. dwt_writetxdata() takes the full size of tx_msg as a parameter but only copies (size - 2) bytes as the check-sum at the end of the frame is 167 | * automatically appended by the DW IC. This means that our tx_msg could be two bytes shorter without losing any data (but the sizeof would not 168 | * work anymore then as we would still have to indicate the full length of the frame to dwt_writetxdata()). 169 | * 4. We use polled mode of operation here to keep the example as simple as possible, but the TXFRS status event can be used to generate an interrupt. 170 | * Please refer to DW IC User Manual for more details on "interrupts". 171 | * 5. Desired configuration by user may be different to the current programmed configuration. dwt_configure is called to set desired 172 | * configuration. 173 | ****************************************************************************************************************************************************/ 174 | -------------------------------------------------------------------------------- /src/dw3000_config_options.h: -------------------------------------------------------------------------------- 1 | /*! ---------------------------------------------------------------------------- 2 | * @file config_options.h 3 | * @brief Configuration options are selected here. 4 | * 5 | * @attention 6 | * 7 | * Copyright 2019(c) Decawave Ltd, Dublin, Ireland. 8 | * 9 | * All rights reserved. 10 | * 11 | */ 12 | 13 | #include "dw3000_device_api.h" 14 | 15 | #ifndef EXAMPLES_CONFIG_OPTIONS_H_ 16 | #define EXAMPLES_CONFIG_OPTIONS_H_ 17 | 18 | /* Index values for errors in array */ 19 | #define CRC_ERR_IDX 0 20 | #define RSE_ERR_IDX 1 21 | #define PHE_ERR_IDX 2 22 | #define SFDTO_ERR_IDX 3 23 | #define PTO_ERR_IDX 4 24 | #define RTO_ERR_IDX 5 25 | #define SPICRC_ERR_IDX 6 26 | #define TXTO_ERR_IDX 7 27 | #define ARFE_ERR_IDX 8 28 | #define TS_MISMATCH_ERR_IDX 9 29 | #define BAD_FRAME_ERR_IDX 10 30 | #define PREAMBLE_COUNT_ERR_IDX 11 31 | #define CP_QUAL_ERR_IDX 12 32 | #define STS_PREAMBLE_ERR 13 33 | #define STS_PEAK_GROWTH_RATE_ERR 14 34 | #define STS_ADC_COUNT_ERR 15 35 | #define STS_SFD_COUNT_ERR 16 36 | #define STS_LATE_FIRST_PATH_ERR 17 37 | #define STS_LATE_COARSE_EST_ERR 18 38 | #define STS_COARSE_EST_EMPTY_ERR 19 39 | #define STS_HIGH_NOISE_THREASH_ERR 20 40 | #define STS_NON_TRIANGLE_ERR 21 41 | #define STS_LOG_REG_FAILED_ERR 22 42 | 43 | /* 44 | * Number of ranges to attempt in test 45 | */ 46 | #define RANGE_COUNT 200 47 | 48 | /* Compensation value for CPU 49 | * The time taken to receive the poll frame, check for errors, 50 | * calculate length, read content, get poll timestamp, 51 | * calculate response timestamp and send delayed response with timestamp will 52 | * be different for each device. 53 | * Adjusting this value lower and lower until dwt_starttx() starts returning 54 | * DWT_ERROR status allows the user to tweak their system to calculate the 55 | * shortest turn-around time for messages. 56 | */ 57 | #define CPU_COMP 400 58 | 59 | /* 60 | * SPI Rate Configuration Settings 61 | */ 62 | #define CONFIG_SPI_FAST_RATE 63 | //#define CONFIG_SPI_SLOW_RATE 64 | 65 | /* 66 | * Changing threshold to 5ns for DW3000 B0 red board devices. 67 | * ~10% of ranging attempts have a larger than usual difference between Ipatov and STS. 68 | * A larger threshold allows for better coverage with this coverage. 69 | * This should be fixed for DW3000 C0 devices. 70 | */ 71 | #define TS_MISMATCH_THRESHOLD 5*64 /* 64 = 1 ns --> 5 ns */ 72 | 73 | /* 74 | * Please note that a PRF of 16 MHz and a STS PRF of 64 MHz will not be supported for the DW3000. 75 | */ 76 | 77 | /* Configuration option 01. 78 | * Channel 5, PRF 64M, Preamble Length 64, PAC 8, Preamble code 9, Data Rate 850k, STS Length 64 79 | */ 80 | //#define CONFIG_OPTION_01 81 | 82 | /* Configuration option 02. 83 | * Channel 9, PRF 64M, Preamble Length 64, PAC 8, Preamble code 9, Data Rate 850k, STS Length 64 84 | */ 85 | //#define CONFIG_OPTION_02 86 | 87 | /* Configuration option 03. 88 | * Channel 5, PRF 64M, Preamble Length 128, PAC 8, Preamble code 9, Data Rate 850k, STS Length 64 89 | */ 90 | //#define CONFIG_OPTION_03 91 | 92 | /* Configuration option 04. 93 | * Channel 9, PRF 64M, Preamble Length 128, PAC 8, Preamble code 9, Data Rate 850k, STS Length 64 94 | */ 95 | //#define CONFIG_OPTION_04 96 | 97 | /* Configuration option 05. 98 | * Channel 5, PRF 64M, Preamble Length 512, PAC 8, Preamble code 9, Data Rate 850k, STS Length 64 99 | */ 100 | //#define CONFIG_OPTION_05 101 | 102 | /* Configuration option 06. 103 | * Channel 9, PRF 64M, Preamble Length 512, PAC 8, Preamble code 9, Data Rate 850k, STS Length 64 104 | */ 105 | //#define CONFIG_OPTION_06 106 | 107 | /* Configuration option 07. 108 | * Channel 5, PRF 64M, Preamble Length 1024, PAC 8, Preamble code 9, Data Rate 850k, STS Length 64 109 | */ 110 | //#define CONFIG_OPTION_07 111 | 112 | /* Configuration option 08. 113 | * Channel 9, PRF 64M, Preamble Length 1024, PAC 8, Preamble code 9, Data Rate 850k, STS Length 64 114 | */ 115 | //#define CONFIG_OPTION_08 116 | 117 | /* Configuration option 09. 118 | * Channel 5, PRF 64M, Preamble Length 64, PAC 8, Preamble code 10, Data Rate 850k, STS Length 64 119 | */ 120 | //#define CONFIG_OPTION_09 121 | 122 | /* Configuration option 10. 123 | * Channel 9, PRF 64M, Preamble Length 64, PAC 8, Preamble code 10, Data Rate 850k, STS Length 64 124 | */ 125 | //#define CONFIG_OPTION_10 126 | 127 | /* Configuration option 11. 128 | * Channel 5, PRF 64M, Preamble Length 128, PAC 8, Preamble code 10, Data Rate 850k, STS Length 64 129 | */ 130 | //#define CONFIG_OPTION_11 131 | 132 | /* Configuration option 12. 133 | * Channel 9, PRF 64M, Preamble Length 128, PAC 8, Preamble code 10, Data Rate 850k, STS Length 64 134 | */ 135 | //#define CONFIG_OPTION_12 136 | 137 | /* Configuration option 13. 138 | * Channel 5, PRF 64M, Preamble Length 512, PAC 8, Preamble code 10, Data Rate 850k, STS Length 64 139 | */ 140 | //#define CONFIG_OPTION_13 141 | 142 | /* Configuration option 14. 143 | * Channel 9, PRF 64M, Preamble Length 512, PAC 8, Preamble code 10, Data Rate 850k, STS Length 64 144 | */ 145 | //#define CONFIG_OPTION_14 146 | 147 | /* Configuration option 15. 148 | * Channel 5, PRF 64M, Preamble Length 1024, PAC 8, Preamble code 10, Data Rate 850k, STS Length 64 149 | */ 150 | //#define CONFIG_OPTION_15 151 | 152 | /* Configuration option 16. 153 | * Channel 9, PRF 64M, Preamble Length 1024, PAC 8, Preamble code 10, Data Rate 850k, STS Length 64 154 | */ 155 | //#define CONFIG_OPTION_16 156 | 157 | /* Configuration option 17. 158 | * Channel 5, PRF 64M, Preamble Length 64, PAC 8, Preamble code 9, Data Rate 6.8M, STS Length 64 159 | */ 160 | //#define CONFIG_OPTION_17 161 | 162 | /* Configuration option 18. 163 | * Channel 9, PRF 64M, Preamble Length 64, PAC 8, Preamble code 9, Data Rate 6.8M, STS Length 64 164 | */ 165 | //#define CONFIG_OPTION_18 166 | 167 | /* Configuration option 19. 168 | * Channel 5, PRF 64M, Preamble Length 128, PAC 8, Preamble code 9, Data Rate 6.8M, STS Length 64 169 | */ 170 | //#define CONFIG_OPTION_19 171 | 172 | /* Configuration option 20. 173 | * Channel 9, PRF 64M, Preamble Length 128, PAC 8, Preamble code 9, Data Rate 6.8M, STS Length 64 174 | */ 175 | //#define CONFIG_OPTION_20 176 | 177 | /* Configuration option 21. 178 | * Channel 5, PRF 64M, Preamble Length 512, PAC 8, Preamble code 9, Data Rate 850k, STS Length 64 179 | */ 180 | //#define CONFIG_OPTION_21 181 | 182 | /* Configuration option 22. 183 | * Channel 9, PRF 64M, Preamble Length 512, PAC 8, Preamble code 9, Data Rate 6.8M, STS Length 64 184 | */ 185 | //#define CONFIG_OPTION_22 186 | 187 | /* Configuration option 23. 188 | * Channel 5, PRF 64M, Preamble Length 1024, PAC 8, Preamble code 9, Data Rate 6.8M, STS Length 64 189 | */ 190 | //#define CONFIG_OPTION_23 191 | 192 | /* Configuration option 24. 193 | * Channel 9, PRF 64M, Preamble Length 1024, PAC 8, Preamble code 9, Data Rate 6.8M, STS Length 64 194 | */ 195 | //#define CONFIG_OPTION_24 196 | 197 | /* Configuration option 25. 198 | * Channel 5, PRF 64M, Preamble Length 64, PAC 8, Preamble code 10, Data Rate 6.8M, STS Length 64 199 | */ 200 | //#define CONFIG_OPTION_25 201 | 202 | /* Configuration option 26. 203 | * Channel 9, PRF 64M, Preamble Length 64, PAC 8, Preamble code 10, Data Rate 6.8M, STS Length 64 204 | */ 205 | //#define CONFIG_OPTION_26 206 | 207 | /* Configuration option 27. 208 | * Channel 5, PRF 64M, Preamble Length 128, PAC 8, Preamble code 10, Data Rate 6.8M, STS Length 64 209 | */ 210 | //#define CONFIG_OPTION_27 211 | 212 | /* Configuration option 28. 213 | * Channel 9, PRF 64M, Preamble Length 128, PAC 8, Preamble code 10, Data Rate 6.8M, STS Length 64 214 | */ 215 | //#define CONFIG_OPTION_28 216 | 217 | /* Configuration option 29. 218 | * Channel 5, PRF 64M, Preamble Length 512, PAC 8, Preamble code 10, Data Rate 6.8M, STS Length 64 219 | */ 220 | //#define CONFIG_OPTION_29 221 | 222 | /* Configuration option 30. 223 | * Channel 9, PRF 64M, Preamble Length 512, PAC 8, Preamble code 10, Data Rate 6.8M, STS Length 64 224 | */ 225 | //#define CONFIG_OPTION_30 226 | 227 | /* Configuration option 31. 228 | * Channel 5, PRF 64M, Preamble Length 1024, PAC 8, Preamble code 10, Data Rate 6.8M, STS Length 64 229 | */ 230 | //#define CONFIG_OPTION_31 231 | 232 | /* Configuration option 32. 233 | * Channel 9, PRF 64M, Preamble Length 1024, PAC 8, Preamble code 10, Data Rate 6.8M, STS Length 64 234 | */ 235 | //#define CONFIG_OPTION_32 236 | 237 | /* Configuration option 33. 238 | * Channel 5, PRF 64M, Preamble Length 128, PAC 8, Preamble code 9, Data Rate 6.8M, STS Length 128 239 | */ 240 | #define CONFIG_OPTION_33 241 | 242 | extern char dist_str[16]; 243 | 244 | #endif /* EXAMPLES_CONFIG_OPTIONS_H_ */ 245 | -------------------------------------------------------------------------------- /examples/ex_01c_tx_sleep_auto/ex_01c_tx_sleep_auto.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * _ _ _ 4 | * (_) | | | 5 | * _| | __ _| |__ ___ 6 | * | | | / _` | '_ \/ __| 7 | * | | |___| (_| | |_) \__ \ 8 | * |_|______\__,_|_.__/|___/ 9 | * 10 | * ---------------------------------------------------------------------------- 11 | * "THE BEER-WARE LICENSE" (Revision 42): 12 | * wrote this file. As long as you retain this notice you 13 | * can do whatever you want with this stuff. If we meet some day, and you think 14 | * this stuff is worth it, you can buy me a beer in return - Pontus Oldberg 15 | * ---------------------------------------------------------------------------- 16 | */ 17 | 18 | #include "dw3000.h" 19 | 20 | #define APP_NAME "TX AUTO SLP v1.0" 21 | 22 | /* Default communication configuration. We use default non-STS DW mode. */ 23 | static dwt_config_t config = { 24 | 5, /* Channel number. */ 25 | DWT_PLEN_128, /* Preamble length. Used in TX only. */ 26 | DWT_PAC8, /* Preamble acquisition chunk size. Used in RX only. */ 27 | 9, /* TX preamble code. Used in TX only. */ 28 | 9, /* RX preamble code. Used in RX only. */ 29 | 1, /* 0 to use standard 8 symbol SFD, 1 to use non-standard 8 symbol, 2 for non-standard 16 symbol SFD and 3 for 4z 8 symbol SDF type */ 30 | DWT_BR_6M8, /* Data rate. */ 31 | DWT_PHRMODE_STD, /* PHY header mode. */ 32 | DWT_PHRRATE_STD, /* PHY header rate. */ 33 | (129 + 8 - 8), /* SFD timeout (preamble length + 1 + SFD length - PAC size). Used in RX only. */ 34 | DWT_STS_MODE_OFF, /* STS disabled */ 35 | DWT_STS_LEN_64,/* STS length see allowed values in Enum dwt_sts_lengths_e */ 36 | DWT_PDOA_M0 /* PDOA mode off */ 37 | }; 38 | 39 | /* The frame sent in this example is an 802.15.4e standard blink. It is a 12-byte frame composed of the following fields: 40 | * - byte 0: frame type (0xC5 for a blink). 41 | * - byte 1: sequence number, incremented for each new frame. 42 | * - byte 2 -> 9: device ID, see NOTE 1 below. 43 | * - byte 10/11: frame check-sum, automatically set by DW IC. */ 44 | static uint8_t tx_msg[] = {0xC5, 0, 'D', 'E', 'C', 'A', 'W', 'A', 'V', 'E', 0, 0}; 45 | 46 | /* Index to access to sequence number of the blink frame in the tx_msg array. */ 47 | #define BLINK_FRAME_SN_IDX 1 48 | 49 | /* Inter-frame delay period, in milliseconds. */ 50 | #define TX_DELAY_MS 5000 51 | 52 | uint32_t reg = 0; 53 | 54 | /* Values for the PG_DELAY and TX_POWER registers reflect the bandwidth and power of the spectrum at the current 55 | * temperature. These values can be calibrated prior to taking reference measurements. See NOTE 3 below. */ 56 | extern dwt_txconfig_t txconfig_options; 57 | 58 | void setup() { 59 | while (!Serial) 60 | delay(100); 61 | 62 | Serial.begin(115200); 63 | Serial.println(APP_NAME); 64 | 65 | /* Start SPI and get stuff going*/ 66 | spiBegin(); 67 | spiSelect(); 68 | 69 | delay(200); // Time needed for DW3000 to start up (transition from INIT_RC to IDLE_RC, or could wait for SPIRDY event) 70 | 71 | while (!dwt_checkidlerc()) // Need to make sure DW IC is in IDLE_RC before proceeding 72 | { 73 | Serial.print("IDLE FAILED\r\n"); 74 | while (1) ; 75 | } 76 | 77 | dwt_softreset(); 78 | delay(200); 79 | 80 | while (!dwt_checkidlerc()) // Need to make sure DW IC is in IDLE_RC before proceeding 81 | { 82 | Serial.println("IDLE FAILED02"); 83 | while (1); 84 | } 85 | 86 | if (dwt_initialise(DWT_DW_INIT) == DWT_ERROR) 87 | { 88 | Serial.print("INIT FAILED\r\n"); 89 | while (1) ; 90 | } 91 | 92 | /* Configure DW IC. See NOTE 6 below. */ 93 | if(dwt_configure(&config)) // if the dwt_configure returns DWT_ERROR either the PLL or RX calibration has failed the host should reset the device 94 | { 95 | Serial.print("CONFIG FAILED\r\n"); 96 | while (1) ; 97 | } 98 | 99 | /* Configure the TX spectrum parameters (power, PG delay and PG count) */ 100 | dwt_configuretxrf(&txconfig_options); 101 | 102 | /* Configure sleep and wake-up parameters. */ 103 | dwt_configuresleep(DWT_CONFIG, DWT_PRES_SLEEP | DWT_WAKE_WUP | DWT_SLP_EN); 104 | 105 | /* Configure DW IC to automatically enter sleep mode after transmission of a frame. */ 106 | dwt_entersleepaftertx(1); 107 | 108 | reg = dwt_read32bitreg(SYS_STATUS_ID); 109 | 110 | /* need to disable default interrupts, device will not go to sleep if interrupt line is high */ 111 | dwt_setinterrupt(SYS_ENABLE_LO_SPIRDY_ENABLE_BIT_MASK, 0, DWT_DISABLE_INT); 112 | 113 | dwt_write32bitreg(SYS_STATUS_ID, reg); //clear interrupt/events 114 | } 115 | 116 | void loop() { 117 | /* Write frame data to DW IC and prepare transmission. See NOTE 4 below. */ 118 | dwt_writetxdata(sizeof(tx_msg), tx_msg, 0); /* Zero offset in TX buffer. */ 119 | dwt_writetxfctrl(sizeof(tx_msg), 0, 0); /* Zero offset in TX buffer, no ranging. */ 120 | 121 | /* Start transmission. */ 122 | dwt_starttx(DWT_START_TX_IMMEDIATE); 123 | 124 | /* It is not possible to access DW IC registers once it has sent the frame and gone to sleep, and therefore we do not try to poll for TX 125 | * frame sent, but instead simply wait sufficient time for the DW IC to wake up again before we loop back to send another frame. 126 | * If interrupts are enabled, (e.g. if MTXFRS bit is set in the SYS_MASK register) then the TXFRS event will cause an active interrupt and 127 | * prevent the DW IC from sleeping. */ 128 | 129 | Serial.println("TX Frame Sent"); 130 | 131 | /* Execute a delay between transmissions. */ 132 | Sleep(TX_DELAY_MS); 133 | 134 | /* Wake DW IC up. See NOTE 2 below. */ 135 | dwt_wakeup_ic(); 136 | 137 | Sleep(2); // Time needed for DW3000 to start up (transition from INIT_RC to IDLE_RC, or could wait for SPIRDY event) 138 | 139 | while (!dwt_checkidlerc()) /* Need to make sure DW IC is in IDLE_RC before proceeding */ 140 | { }; 141 | 142 | /* Restore the required configurations on wake */ 143 | dwt_restoreconfig(); 144 | 145 | /* Increment the blink frame sequence number (modulo 256). */ 146 | tx_msg[BLINK_FRAME_SN_IDX]++; 147 | } 148 | 149 | /***************************************************************************************************************************************************** 150 | * NOTES: TODO review these 151 | * 152 | * 1. The device ID is a hard coded constant in the blink to keep the example simple but for a real product every device should have a unique ID. 153 | * For development purposes it is possible to generate a DW IC unique ID by combining the Lot ID & Part Number values programmed into the 154 | * DW IC during its manufacture. However there is no guarantee this will not conflict with someone else�s implementation. We recommended that 155 | * customers buy a block of addresses from the IEEE Registration Authority for their production items. See "EUI" in the DW IC User Manual. 156 | * 2. The chosen method for waking the DW IC up here is by maintaining SPI chip select line low for at least 500 us. This means that we need a buffer 157 | * to collect the data that DW IC outputs during this dummy SPI transaction. The length of the transaction, and then the time for which the SPI 158 | * chip select is held low, is determined by the buffer length given to dwt_spicswakeup() so this length must be chosen high enough so that the 159 | * DW IC has enough time to wake up. 160 | * 3. In a real application, for optimum performance within regulatory limits, it may be necessary to set TX pulse bandwidth and TX power, (using 161 | * the dwt_configuretxrf API call) to per device calibrated values saved in the target system or the DW IC OTP memory. 162 | * 4. dwt_writetxdata() takes the full size of tx_msg as a parameter but only copies (size - 2) bytes as the check-sum at the end of the frame is 163 | * automatically appended by the DW IC. This means that our tx_msg could be two bytes shorter without losing any data (but the sizeof would not 164 | * work anymore then as we would still have to indicate the full length of the frame to dwt_writetxdata()). 165 | * 5. Desired configuration by user may be different to the current programmed configuration. dwt_configure is called to set desired 166 | * configuration. 167 | ****************************************************************************************************************************************************/ 168 | -------------------------------------------------------------------------------- /examples/ex_01b_tx_sleep/ex_01b_tx_sleep.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * _ _ _ 4 | * (_) | | | 5 | * _| | __ _| |__ ___ 6 | * | | | / _` | '_ \/ __| 7 | * | | |___| (_| | |_) \__ \ 8 | * |_|______\__,_|_.__/|___/ 9 | * 10 | * ---------------------------------------------------------------------------- 11 | * "THE BEER-WARE LICENSE" (Revision 42): 12 | * wrote this file. As long as you retain this notice you 13 | * can do whatever you want with this stuff. If we meet some day, and you think 14 | * this stuff is worth it, you can buy me a beer in return - Pontus Oldberg 15 | * ---------------------------------------------------------------------------- 16 | */ 17 | 18 | #include "dw3000.h" 19 | 20 | #define APP_NAME "TX SLEEP v1.0" 21 | 22 | /* Default communication configuration. We use default non-STS DW mode. */ 23 | static dwt_config_t config = { 24 | 5, /* Channel number. */ 25 | DWT_PLEN_128, /* Preamble length. Used in TX only. */ 26 | DWT_PAC8, /* Preamble acquisition chunk size. Used in RX only. */ 27 | 9, /* TX preamble code. Used in TX only. */ 28 | 9, /* RX preamble code. Used in RX only. */ 29 | 1, /* 0 to use standard 8 symbol SFD, 1 to use non-standard 8 symbol, 2 for non-standard 16 symbol SFD and 3 for 4z 8 symbol SDF type */ 30 | DWT_BR_6M8, /* Data rate. */ 31 | DWT_PHRMODE_STD, /* PHY header mode. */ 32 | DWT_PHRRATE_STD, /* PHY header rate. */ 33 | (129 + 8 - 8), /* SFD timeout (preamble length + 1 + SFD length - PAC size). Used in RX only. */ 34 | DWT_STS_MODE_OFF, /* STS disabled */ 35 | DWT_STS_LEN_64, /* STS length see allowed values in Enum dwt_sts_lengths_e */ 36 | DWT_PDOA_M0 /* PDOA mode off */ 37 | }; 38 | 39 | 40 | /* The frame sent in this example is an 802.15.4e standard blink. It is a 12-byte frame composed of the following fields: 41 | * - byte 0: frame type (0xC5 for a blink). 42 | * - byte 1: sequence number, incremented for each new frame. 43 | * - byte 2 -> 9: device ID, see NOTE 1 below. 44 | * - */ 45 | static uint8_t tx_msg[] = {0xC5, 0, 'D', 'E', 'C', 'A', 'W', 'A', 'V', 'E'}; 46 | 47 | /* Index to access to sequence number of the blink frame in the tx_msg array. */ 48 | #define BLINK_FRAME_SN_IDX 1 49 | 50 | #define FRAME_LENGTH sizeof(tx_msg)+FCS_LEN//The real length that is going to be transmitted 51 | 52 | /* Inter-frame delay period, in milliseconds. */ 53 | #define TX_DELAY_MS 5000 54 | 55 | /* Values for the PG_DELAY and TX_POWER registers reflect the bandwidth and power of the spectrum at the current 56 | * temperature. These values can be calibrated prior to taking reference measurements. See NOTE 2 below. */ 57 | extern dwt_txconfig_t txconfig_options; 58 | 59 | void setup() { 60 | while (!Serial) 61 | delay(100); 62 | 63 | Serial.begin(115200); 64 | Serial.println(APP_NAME); 65 | 66 | /* Start SPI and get stuff going*/ 67 | spiBegin(); 68 | spiSelect(); 69 | 70 | delay(200); // Time needed for DW3000 to start up (transition from INIT_RC to IDLE_RC, or could wait for SPIRDY event) 71 | 72 | while (!dwt_checkidlerc()) // Need to make sure DW IC is in IDLE_RC before proceeding 73 | { 74 | Serial.print("IDLE FAILED\r\n"); 75 | while (1) ; 76 | } 77 | 78 | dwt_softreset(); 79 | delay(200); 80 | 81 | while (!dwt_checkidlerc()) // Need to make sure DW IC is in IDLE_RC before proceeding 82 | { 83 | Serial.println("IDLE FAILED02"); 84 | while (1); 85 | } 86 | 87 | if (dwt_initialise(DWT_DW_INIT) == DWT_ERROR) 88 | { 89 | Serial.print("INIT FAILED\r\n"); 90 | while (1) ; 91 | } 92 | 93 | /* Configure DW IC. See NOTE 6 below. */ 94 | if(dwt_configure(&config)) // if the dwt_configure returns DWT_ERROR either the PLL or RX calibration has failed the host should reset the device 95 | { 96 | Serial.print("CONFIG FAILED\r\n"); 97 | while (1) ; 98 | } 99 | Serial.println("CONFIG OK"); 100 | 101 | /* Configure the TX spectrum parameters (power, PG delay and PG count) */ 102 | dwt_configuretxrf(&txconfig_options); 103 | 104 | /* To help with debug or as information we can enable DW IC TX/RX states to drive LEDs 105 | * so that as frames are transmitted the TX LED flashes. 106 | * dwt_setleds(DWT_LEDS_ENABLE | DWT_LEDS_INIT_BLINK); 107 | */ 108 | //dwt_setlnapamode(DWT_LNA_ENABLE | DWT_PA_ENABLE); 109 | 110 | /* Configure sleep and wake-up parameters. */ 111 | dwt_configuresleep(DWT_CONFIG, DWT_PRES_SLEEP | DWT_PGFCAL | DWT_WAKE_CSN | DWT_WAKE_WUP | DWT_SLP_EN); 112 | Serial.println("Exiting setup !"); 113 | } 114 | 115 | void loop() { 116 | /* Write frame data to DW IC and prepare transmission. See NOTE 3 below. */ 117 | dwt_writetxdata(FRAME_LENGTH - FCS_LEN, tx_msg, 0); /* Zero offset in TX buffer. Data does not include the CRC */ 118 | 119 | /* In this example since the length of the transmitted frame does not change, 120 | * nor the other parameters of the dwt_writetxfctrl function, the 121 | * dwt_writetxfctrl call could be outside the main while(1) loop. 122 | */ 123 | dwt_writetxfctrl(FRAME_LENGTH, 0, 0); /* Zero offset in TX buffer, no ranging. */ 124 | 125 | /* Start transmission. */ 126 | dwt_starttx(DWT_START_TX_IMMEDIATE); 127 | delay(10); 128 | 129 | /* Poll DW IC until TX frame sent event set. See NOTE 4 below. 130 | * STATUS register is 5 bytes long but, as the event we are looking at is in the first byte of the register, we can use this simplest API 131 | * function to access it.*/ 132 | while (!(dwt_read32bitreg(SYS_STATUS_ID) & SYS_STATUS_TXFRS_BIT_MASK)) 133 | { }; 134 | 135 | /* Clear TX frame sent event. */ 136 | dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_TXFRS_BIT_MASK); 137 | 138 | Serial.println("TX Frame Sent"); 139 | 140 | Sleep(200); /* If using LEDs we need to add small delay to see the TX LED blink */ 141 | 142 | /* Put DW IC to sleep. Go to IDLE state after wakeup*/ 143 | dwt_entersleep(DWT_DW_IDLE); // DWT_DW_IDLE_RC 144 | 145 | /* Execute a delay between transmissions. */ 146 | Sleep(TX_DELAY_MS); 147 | 148 | /* Wake DW IC up. See NOTE 5 below. */ 149 | dwt_wakeup_ic(); 150 | 151 | Sleep(200); // Time needed for DW3000 to start up (transition from INIT_RC to IDLE_RC, or could wait for SPIRDY event) 152 | 153 | while(!dwt_checkidlerc()) 154 | delay(1); //check in IDLE_RC before proceeding 155 | 156 | /* Restore the required configurations on wake */ 157 | dwt_restoreconfig(); 158 | 159 | /* Increment the blink frame sequence number (modulo 256). */ 160 | tx_msg[BLINK_FRAME_SN_IDX]++; 161 | } 162 | 163 | /***************************************************************************************************************************************************** 164 | * NOTES: TODO review these 165 | * 166 | * 1. The device ID is a hard coded constant in the blink to keep the example simple but for a real product every device should have a unique ID. 167 | * For development purposes it is possible to generate a DW IC unique ID by combining the Lot ID & Part Number values programmed into the 168 | * DW IC during its manufacture. However there is no guarantee this will not conflict with someone else�s implementation. We recommended that 169 | * customers buy a block of addresses from the IEEE Registration Authority for their production items. See "EUI" in the DW IC User Manual. 170 | * 2. In a real application, for optimum performance within regulatory limits, it may be necessary to set TX pulse bandwidth and TX power, (using 171 | * the dwt_configuretxrf API call) to per device calibrated values saved in the target system or the DW IC OTP memory. 172 | * 3. dwt_writetxdata() takes the full size of tx_msg as a parameter but only copies (size - 2) bytes as the check-sum at the end of the frame is 173 | * automatically appended by the DW IC. This means that our tx_msg could be two bytes shorter without losing any data (but the sizeof would not 174 | * work anymore then as we would still have to indicate the full length of the frame to dwt_writetxdata()). 175 | * 4. We use polled mode of operation here to keep the example as simple as possible, but the TXFRS status event can be used to generate an interrupt. 176 | * Please refer to DW IC User Manual for more details on "interrupts". 177 | * 5. The chosen method for waking the DW IC up here is by toggling the WAKEUP pin high for at least 500 us. 178 | * 6. Desired configuration by user may be different to the current programmed configuration. dwt_configure is called to set desired 179 | * configuration. 180 | ****************************************************************************************************************************************************/ 181 | -------------------------------------------------------------------------------- /src/dw3000_mac_802_15_4.h: -------------------------------------------------------------------------------- 1 | /*! ---------------------------------------------------------------------------- 2 | * @file mac_802_15_4.h 3 | * @brief Functions that handle 802.15.4 frame 4 | * 5 | * @attention 6 | * 7 | * Copyright 2013-2019(c) Decawave Ltd, Dublin, Ireland. 8 | * 9 | * All rights reserved. 10 | * 11 | */ 12 | 13 | #ifndef _802_15_4_ 14 | #define _802_15_4_ 15 | 16 | #ifdef __cplusplus 17 | //extern "C" { 18 | #endif 19 | 20 | #include "dw3000_regs.h" 21 | #include "dw3000_device_api.h" 22 | #include "dw3000_shared_defines.h" 23 | 24 | #define NUM_OF_KEY_OPTIONS 3 25 | 26 | /* 802_15_4 general MAC frame format 27 | * 28 | * Octets: 1/2 0/1 0/2 0/2/8 0/2 0/2/8 Variable Variable Variable 2/4 29 | * Frame control Seq number Dest PAN ID Dest Addr Src PAN ID Src Addr Aux Sec Header IEs Frame Payload FCS 30 | */ 31 | 32 | 33 | /*Auxiliary security header bytes 34 | * 35 | * Octets: 1 0/4 0/1/5/9 36 | * Security ctrl Frame count Key identifier 37 | */ 38 | 39 | /*Auxiliary security header - Security ctrl byte 40 | * 41 | * Bits: 0-2 3-4 5 6 7 42 | * Security level Key identifier mode Frame count suppression ASN in Nonce Reserved 43 | */ 44 | 45 | /* Auxiliary security header bytes */ 46 | typedef struct 47 | { 48 | uint8_t security_ctrl; /* as defined above */ 49 | uint8_t frame_counter[4]; /* In the SS-TWR AES example, we are using a 4 byte counter */ 50 | uint8_t key_indentifier; /* as defined above used to identify which key is used*/ 51 | }aux_security_t; 52 | 53 | #define EXTENDED_ADDR 8 54 | 55 | /* MAC - MHR data fields. These field sizes are set for the sample frames of the SS-TWR AES demo 56 | * the demo uses data type frames with 2 byte frame control, seq number, dest PAN ID, 64-bit source 57 | * and destination addresses and the aux security header fields */ 58 | typedef struct 59 | { 60 | uint8_t frame_ctrl[2]; 61 | uint8_t sequence_num; 62 | uint8_t dest_pan_id[2]; 63 | uint8_t dest_addr[EXTENDED_ADDR]; 64 | uint8_t src_addr[EXTENDED_ADDR]; 65 | aux_security_t aux_security; /* As defined above */ 66 | /*IE fields not in use*/ 67 | }mhr_802_15_4_t; 68 | 69 | 70 | /* Aux security header byte 1, bits 0-2 */ 71 | typedef enum 72 | { 73 | AUX_SEC_LEVEL_DATA_CONF_OFF_MIC_0=0, /* Sec attribute None, data conf off, data auth No, MIC length 0 */ 74 | AUX_SEC_LEVEL_DATA_CONF_OFF_MIC_4, /* Sec attribute mic 32, data conf off, data auth Yes, MIC length 4 */ 75 | AUX_SEC_LEVEL_DATA_CONF_OFF_MIC_8, /* Sec attribute mic 64, data conf off, data auth Yes, MIC length 8 */ 76 | AUX_SEC_LEVEL_DATA_CONF_OFF_MIC_16, /* Sec attribute mic 128, data conf off, data auth Yes, MIC length 16 */ 77 | AUX_SEC_LEVEL_RESERVED, /* Reserved */ 78 | AUX_SEC_LEVEL_DATA_CONF_ON_MIC_4, /* Sec attribute mic 32, data conf on, data auth Yes, MIC length 4 */ 79 | AUX_SEC_LEVEL_DATA_CONF_ON_MIC_8, /* Sec attribute mic 64, data conf on, data auth Yes, MIC length 8 */ 80 | AUX_SEC_LEVEL_DATA_CONF_ON_MIC_16 /* Sec attribute mic 128, data conf on, data auth Yes, MIC length 16 */ 81 | }aux_security_level_e; 82 | 83 | 84 | /* Aux security header byte 1, bits 3-4 */ 85 | typedef enum 86 | { 87 | AUX_KEY_IDEN_MODE_ORIGINATOR_RECIPIENT=0, 88 | AUX_KEY_IDEN_MODE_KEY_INDEX, 89 | AUX_KEY_IDEN_MODE_4_OCTET_KEY_SOUCE_AND_INDEX, 90 | AUX_KEY_IDEN_MODE_8_OCTET_KEY_SOUCE_AND_INDEX 91 | }aux_key_indentifier_mode_e; 92 | 93 | /* Aux security header byte 1, bit 5 */ 94 | typedef enum 95 | { 96 | AUX_FRAME_CNT_SUPPRESS_OFF=0, /* Frame counter is carried */ 97 | AUX_FRAME_CNT_SUPPRESS_ON /* Frame counter is not carried */ 98 | }aux_frame_cnt_suppress_e; 99 | 100 | /* Aux security header byte 1, bit 6 */ 101 | typedef enum 102 | { 103 | AUX_ASN_IN_NOUNCE_FRAME_CNT_GEN_NONCE=0, 104 | AUX_ASN_IN_NOUNCE_FRAME_CNT_NOT_GEN_NONCE 105 | }aux_asn_in_nonce_e; 106 | 107 | #define AUX_SECURITY_LEVEL_SHIFT_VALUE 0 108 | #define AUX_KEY_IDENTIFIER_MODE_SHIFT_VALUE 3 109 | #define AUX_FRAME_CNT_SUPPRESSION_SHIFT_VALUE 5 110 | #define AUX_ASN_IN_NONCE 6 111 | 112 | #define AUX_FRAME_CNT_SIZE 4 113 | 114 | 115 | /* This is the frame type - bits 0-2 that reside in the first byte of frame control */ 116 | typedef enum 117 | { 118 | MAC_FRAME_TYPE_802_15_4_BEACON=0, 119 | MAC_FRAME_TYPE_802_15_4_DATA, 120 | MAC_FRAME_TYPE_802_15_4_ACK, 121 | MAC_FRAME_TYPE_802_15_4_MAC_CMD, 122 | MAC_FRAME_TYPE_802_15_4_RESERVED, 123 | MAC_FRAME_TYPE_802_15_4_MULTI, 124 | MAC_FRAME_TYPE_802_15_4_FRAGMENT, 125 | MAC_FRAME_TYPE_802_15_4_EXTENDED 126 | }mac_frame_type_802_15_4_e; 127 | 128 | 129 | /* This is the frame security enabled - bit 3 that reside in the first byte of frame control */ 130 | typedef enum 131 | { 132 | MAC_SEC_EN_UN_PROTECTED=0, 133 | MAC_SEC_EN_PROTECTED 134 | }mac_security_en_802_15_4_e; 135 | 136 | /* This is the frame pending - bit 4 that reside in the first byte of frame control */ 137 | typedef enum 138 | { 139 | MAC_PEND_FRAME_NO_MORE_DATA=0, 140 | MAC_PEND_FRAME_MORE_DATA 141 | }mac_pend_frame_802_15_4_e; 142 | 143 | /* This is the frame AR - bit 5 that reside in the first byte of frame control */ 144 | typedef enum 145 | { 146 | MAC_AR_NO_ACK=0, 147 | MAC_AR_ACK 148 | }mac_AR_802_15_4_e; 149 | 150 | /* This is the frame PAN ID compress - bit 6 that reside in the first byte of frame control */ 151 | typedef enum 152 | { 153 | MAC_PEND_ID_COMPRESS_DEST_EXIST_SOURCE_NOT=0, 154 | MAC_PEND_ID_COMPRESS_NO 155 | }mac_pand_id_compress_802_15_4_e; 156 | 157 | /* This is the Seq num suppress - bit 0 that reside in the second byte of frame control */ 158 | typedef enum 159 | { 160 | MAC_SEQ_NUM_SUPP_PRESENT=0, 161 | MAC_SEQ_NUM_SUPP_NOT_PRESENT 162 | }mac_seq_num_suppress_802_15_4_e; 163 | 164 | /* This is the IE present - bit 1 that reside in the second byte of frame control */ 165 | typedef enum 166 | { 167 | MAC_IE_PRESENT_NO=0, 168 | MAC_IE_PRESENT_YES 169 | }mac_ie_present_802_15_4_e; 170 | 171 | 172 | /* This is the dest addr mode - bits 2,3 that reside in the second byte of frame control */ 173 | typedef enum 174 | { 175 | MAC_DEST_ADDR_MODE_NO_PEND_AND_ADDR=0, 176 | MAC_DEST_ADDR_MODE_RESERVED, 177 | MAC_DEST_ADDR_MODE_SHORT_ADDR_16_BITS, 178 | MAC_DEST_ADDR_MODE_EXT_ADDR_64_BITS 179 | }mac_dest_addr_mode_802_15_4_e; 180 | 181 | 182 | /* This is the frame version - bits 4,5 that reside in the second byte of frame control */ 183 | #define DATA_FRAME_VERSION 2 /* IEEE Std 802.15.4 */ 184 | 185 | /* This is the dest src mode - bits 6,7 that reside in the second byte of frame control */ 186 | typedef enum 187 | { 188 | MAC_SRC_ADDR_MODE_NO_PEND_AND_ADDR=0, 189 | MAC_SRC_ADDR_MODE_RESERVED, 190 | MAC_SRC_ADDR_MODE_SHORT_ADDR_16_BITS, 191 | MAC_SRC_ADDR_MODE_EXT_ADDR_64_BITS 192 | }mac_src_addr_mode_802_15_4_e; 193 | 194 | 195 | 196 | /* Shift values to frame control byte 0 */ 197 | #define MAC_FRAME_TYPE_SHIFT_VALUE 0 198 | #define MAC_FRAME_SECURITY_ENABLED_SHIFT_VALUE 3 199 | #define MAC_FRAME_FRAME_PENDING_SHIFT_VALUE 4 200 | #define MAC_FRAME_AR_SHIFT_VALUE 5 201 | #define MAC_FRAME_PAN_ID_SHIFT_VALUE 6 202 | 203 | /* Shift values to frame control byte 1 */ 204 | #define MAC_FRAME_SEQ_NUM_SUPPRESS_SHIFT_VALUE 0 205 | #define MAC_FRAME_IE_PRESET_SHIFT_VALUE 1 206 | #define MAC_FRAME_DEST_ADDR_MODE_SHIFT_VALUE 2 207 | #define MAC_FRAME_FRAME_VER_SHIFT_VALUE 4 208 | #define MAC_FRAME_SRC_ADDR_MODE_SHIFT_VALUE 6 209 | 210 | #define SECURITY_ENABLE_BIT_MASK 0x8 211 | 212 | /* This is the structure of the MAC frame. The structure defined here applies for the SS-TWR AES example frames 213 | * the mhr_802_15_4_t defines a data frame with: with 2 byte frame control, seq number, dest PAN ID, 64-bit source 214 | * and destination addresses and the aux security header fields 215 | */ 216 | typedef struct 217 | { 218 | mhr_802_15_4_t mhr_802_15_4; /* MHR structure */ 219 | uint8_t *payload_ptr; /* Pointer to the payload */ 220 | /*FCS will be added when transmitting this data*/ 221 | }mac_frame_802_15_4_format_t; 222 | 223 | 224 | typedef enum 225 | { 226 | SECURITY_STATE_SECURE=0, 227 | SECURITY_STATE_NOT_SECURE 228 | }security_state_e; 229 | 230 | #define MAC_FRAME_HEADER_SIZE(mac_frame_ptr) sizeof((mac_frame_ptr)->mhr_802_15_4) 231 | #define MHR_802_15_4_PTR(mac_frame_ptr) &((mac_frame_ptr)->mhr_802_15_4) 232 | #define PAYLOAD_PTR_802_15_4(mac_frame_ptr) (mac_frame_ptr)->payload_ptr 233 | 234 | #define MAC_FRAME_FRAME_CTRL_802_15_4(mac_frame_ptr,index) (mac_frame_ptr)->mhr_802_15_4.frame_ctrl[index] 235 | #define MAC_FRAME_SEQ_NUM_802_15_4(mac_frame_ptr) (mac_frame_ptr)->mhr_802_15_4.sequence_num 236 | #define MAC_FRAME_DEST_PAN_ID_802_15_4(mac_frame_ptr,index) (mac_frame_ptr)->mhr_802_15_4.dest_pan_id[index] 237 | #define MAC_FRAME_DEST_ADDR_ID_802_15_4(mac_frame_ptr,index) (mac_frame_ptr)->mhr_802_15_4.dest_addr[index] 238 | //#define MAC_FRAME_SRC_PAN_ID_802_15_4(index) MAC_frame_802_15_4_format.MHR_802_15_4.src_pan_id[index] 239 | #define MAC_FRAME_SRC_ADDR_802_15_4(mac_frame_ptr,index) (mac_frame_ptr)->mhr_802_15_4.src_addr[index] 240 | #define MAC_FRAME_SRC_ADDR_PTR_802_15_4(mac_frame_ptr) (mac_frame_ptr)->mhr_802_15_4.src_addr 241 | 242 | #define MAC_FRAME_AUX_SECURITY_CTRL_802_15_4(mac_frame_ptr) (mac_frame_ptr)->mhr_802_15_4.aux_security.security_ctrl 243 | #define MAC_FRAME_AUX_FRAME_CNT_802_15_4(mac_frame_ptr,index) (mac_frame_ptr)->mhr_802_15_4.aux_security.frame_counter[index] 244 | #define MAC_FRAME_AUX_FRAME_CNT_PTR_802_15_4(mac_frame_ptr) (mac_frame_ptr)->mhr_802_15_4.aux_security.frame_counter 245 | #define MAC_FRAME_AUX_FRAME_GET_CNT_802_15_4_PTR(mac_frame_ptr) (uint8_t *)(&(mac_frame_ptr)->mhr_802_15_4.aux_security.frame_counter) 246 | #define MAC_FRAME_AUX_KEY_IDENTIFY_802_15_4(mac_frame_ptr) (mac_frame_ptr)->mhr_802_15_4.aux_security.key_indentifier 247 | 248 | void mac_frame_init_mac_frame_ctrl(mac_frame_802_15_4_format_t *mac_frame_ptr); 249 | void mac_frame_set_pan_ids_and_addresses_802_15_4(mac_frame_802_15_4_format_t *mac_frame_ptr,uint16_t dest_pan_id,uint64_t dest_addr/*,uint16_t src_pan_id*/,uint64_t src_addr); 250 | void mac_frame_update_sequence_number(mac_frame_802_15_4_format_t *mac_frame_ptr,uint8_t seq_num); 251 | void mac_frame_update_aux_frame_cnt(mac_frame_802_15_4_format_t *mac_frame_ptr,uint32_t frame_cnt); 252 | void mac_frame_set_aux_key_identifier(mac_frame_802_15_4_format_t *mac_frame_ptr,uint8_t key_index); 253 | uint8_t mac_frame_get_aux_key_identifier(mac_frame_802_15_4_format_t *mac_frame_ptr); 254 | uint32_t mac_frame_get_aux_frame_cnt(mac_frame_802_15_4_format_t *mac_frame_ptr); 255 | void mac_frame_get_nonce(mac_frame_802_15_4_format_t *mac_frame_ptr, uint8_t* aes_iv); 256 | void mac_frame_set_aux_security_control(mac_frame_802_15_4_format_t *mac_frame_ptr); 257 | uint8_t mac_frame_get_aux_mic_size(mac_frame_802_15_4_format_t *mac_frame_ptr); 258 | aes_results_e rx_aes_802_15_4(mac_frame_802_15_4_format_t *mac_frame_ptr,uint16_t frame_length,dwt_aes_job_t *aes_job,uint16_t max_payload, 259 | dwt_aes_key_t *aes_key_ptr,uint64_t exp_src_addr,uint64_t exp_dst_addr,dwt_aes_config_t *aes_config); 260 | security_state_e get_security_state(mac_frame_802_15_4_format_t *mac_frame_ptr); 261 | void get_src_and_dst_frame_addr(mac_frame_802_15_4_format_t *mac_frame_ptr,uint64_t *src, uint64_t *dst); 262 | 263 | 264 | 265 | #ifdef __cplusplus 266 | //} 267 | #endif 268 | 269 | 270 | #endif 271 | -------------------------------------------------------------------------------- /src/dw3000_mac_802_15_4.cpp: -------------------------------------------------------------------------------- 1 | /*! ---------------------------------------------------------------------------- 2 | * @file mac_802_15_4.c 3 | * @brief Functions that handle 802.15.4 frame 4 | * 5 | * @attention 6 | * 7 | * Copyright 2013-2019(c) Decawave Ltd, Dublin, Ireland. 8 | * 9 | * All rights reserved. 10 | * 11 | */ 12 | #include 13 | #include "dw3000_device_api.h" 14 | #include "dw3000_mac_802_15_4.h" 15 | 16 | 17 | /*Set the pan id src + dst and src and dst addresses*/ 18 | void mac_frame_set_pan_ids_and_addresses_802_15_4(mac_frame_802_15_4_format_t *mac_frame_ptr, uint16_t dest_pan_id, 19 | uint64_t dest_addr/*,uint16_t src_pan_id*/, uint64_t src_addr) 20 | { 21 | /*Doing this kind of assignment to support big/little Endian*/ 22 | uint8_t cnt; 23 | 24 | for (cnt=0;cnt>=8; 28 | MAC_FRAME_DEST_ADDR_ID_802_15_4(mac_frame_ptr,cnt)=(uint8_t)(dest_addr); 29 | dest_addr>>=8; 30 | } 31 | 32 | MAC_FRAME_DEST_PAN_ID_802_15_4(mac_frame_ptr,0)=(uint8_t)dest_pan_id; 33 | MAC_FRAME_DEST_PAN_ID_802_15_4(mac_frame_ptr,1)=(uint8_t)(dest_pan_id>>8); 34 | 35 | //SRC_PAN_ID_802_15_4(0)=(uint8_t)src_pan_id; 36 | //SRC_PAN_ID_802_15_4(1)=(uint8_t)(src_pan_id>>8); 37 | } 38 | 39 | 40 | /*Set the first 2 bytes of the MAC frame - Frame control*/ 41 | void mac_frame_init_mac_frame_ctrl(mac_frame_802_15_4_format_t *mac_frame_ptr) 42 | { 43 | /* 44 | * Frame control[0]= Data, protected, no more data, no ACK, PEND ID for dest (no for source) 45 | * Frame control[1]=Has seq num, no IE, dest addr extended, frame ver 2 (IEEE Std 802.15.4), source extended 46 | */ 47 | MAC_FRAME_FRAME_CTRL_802_15_4(mac_frame_ptr,0)=(MAC_FRAME_TYPE_802_15_4_DATA<>=8; 85 | } 86 | } 87 | 88 | /* Get the key identifier value, in our case it is one byte - key index */ 89 | uint8_t mac_frame_get_AUX_key_identifier(mac_frame_802_15_4_format_t *mac_frame_ptr) 90 | { 91 | return MAC_FRAME_AUX_KEY_IDENTIFY_802_15_4(mac_frame_ptr); 92 | } 93 | 94 | /* Get the frame counter in the MAC frame - AUX security - Frame counter */ 95 | uint32_t mac_frame_get_aux_frame_cnt(mac_frame_802_15_4_format_t *mac_frame_ptr) 96 | { 97 | int8_t cnt; 98 | uint32_t frame_cnt=0; 99 | 100 | for (cnt=0;cnt= aes_job->header_len) 167 | { 168 | /* Get the MAC unencrypted data (MHR) */ 169 | dwt_readrxdata((uint8_t *)MHR_802_15_4_PTR(mac_frame_ptr), aes_job->header_len, 0); 170 | 171 | /* Place a breakpoint here to see an unencrypted header */ 172 | 173 | get_src_and_dst_frame_addr(mac_frame_ptr,&src_addr,&dst_addr); 174 | security_state = get_security_state(mac_frame_ptr); 175 | //Check if we got a secure frame with the right destination and source addresses 176 | if ((security_state != SECURITY_STATE_SECURE)||(exp_src_addr != src_addr)||(exp_dst_addr != dst_addr)) 177 | return AES_RES_ERROR_IGNORE_FRAME; // This is not for us 178 | 179 | /* next get the MIC size */ 180 | aes_job->mic_size = mac_frame_get_aux_mic_size(mac_frame_ptr); 181 | if(aes_job->mic_size == MIC_ERROR) 182 | return AES_RES_ERROR_FRAME; 183 | 184 | payload_len = frame_length - (aes_job->header_len + aes_job->mic_size + FCS_LEN); /* to get unencrypted payload length subtract MIC, FCS and MHR lengths */ 185 | /* Check if payload_len is valid */ 186 | if ((payload_len < 0) || (payload_len > max_payload)) 187 | return AES_RES_ERROR_FRAME; 188 | 189 | /* next get the nonce (SS-TWR AES example uses 13-byte nonce*/ 190 | mac_frame_get_nonce(mac_frame_ptr, nonce); 191 | 192 | /* Fill AES job to decrypt the received packet */ 193 | aes_job->nonce = nonce; 194 | aes_job->payload_len = payload_len; 195 | aes_job->header = NULL; /* not used for decryption*/ 196 | aes_config->mic = dwt_mic_size_from_bytes(aes_job->mic_size); 197 | //aes_config->aes_core_type=AES_core_type_CCM; 198 | dwt_configure_aes(aes_config); 199 | 200 | /* program the correct 128-bit key into DW3000 AES block*/ 201 | dwt_set_keyreg_128(&aes_key_ptr[MAC_FRAME_AUX_KEY_IDENTIFY_802_15_4(mac_frame_ptr)-1]); 202 | 203 | /* perform the decryption job, the unencrypted payload will be stored in aes_job->payload */ 204 | status = dwt_do_aes(aes_job,aes_config->aes_core_type); 205 | 206 | /* "status" represents a last read of AES_STS_ID register. 207 | * See DW3000 User Manual for details. 208 | * */ 209 | if (status<0) 210 | {//Problem with Header/Payload length or mode selection 211 | return AES_RES_ERROR_LENGTH; 212 | } 213 | else 214 | { 215 | if (status & AES_ERRORS) 216 | {//One of the error status bits were raised 217 | return AES_RES_ERROR; 218 | } 219 | else 220 | { 221 | return AES_RES_OK; 222 | } 223 | } 224 | } 225 | else 226 | { 227 | return AES_RES_ERROR_FRAME; 228 | } 229 | } 230 | 231 | /* @fn get_security_state 232 | * @brief This function checks if the security bit is set in the frame header corresponding security_state_e value. 233 | * 234 | * @param frame pointer 235 | * @return security_state_e according to the state 236 | */ 237 | security_state_e get_security_state(mac_frame_802_15_4_format_t *mac_frame_ptr) 238 | { 239 | if(MAC_FRAME_FRAME_CTRL_802_15_4(mac_frame_ptr,0) & SECURITY_ENABLE_BIT_MASK) 240 | return SECURITY_STATE_SECURE;//Protected 241 | else 242 | return SECURITY_STATE_NOT_SECURE;//Not protected 243 | } 244 | 245 | 246 | /* @fn get_src_and_dst_frame_addr 247 | * @brief Copy the source and destination data from the frame header into given destination and source buffers. 248 | * 249 | * @param mac_frame_ptr - pointer to MAC frame 250 | * @param src - pointer to 64-bit integer where the src address will be stored 251 | * @param dst - pointer to 64-bit integer where the dst address will be stored 252 | * @return None 253 | */ 254 | void get_src_and_dst_frame_addr(mac_frame_802_15_4_format_t *mac_frame_ptr, uint64_t *src, uint64_t *dst) 255 | { 256 | uint8_t cnt1, *src_ptr, *dst_ptr; 257 | 258 | *src=*dst=0; 259 | src_ptr=&MAC_FRAME_SRC_ADDR_802_15_4(mac_frame_ptr,0); 260 | dst_ptr=&MAC_FRAME_DEST_ADDR_ID_802_15_4(mac_frame_ptr,0); 261 | 262 | for (cnt1=0;cnt1 127 89 | 90 | #define LOGGER_MEM_ID 0x180000 91 | 92 | #define PANADR_PAN_ID_BYTE_OFFSET 2 93 | #define PMSC_CTRL0_PLL2_SEQ_EN 0x01000000UL /* Enable PLL2 on/off sequencing by SNIFF mode */ 94 | #define RX_BUFFER_MAX_LEN (1023) 95 | #define TX_BUFFER_MAX_LEN (1024) 96 | #define RX_FINFO_STD_RXFLEN_MASK 0x0000007FUL /* Receive Frame Length (0 to 127) */ 97 | #define RX_TIME_RX_STAMP_LEN (5) /* read only 5 bytes (the adjusted timestamp (40:0)) */ 98 | #define TX_TIME_TX_STAMP_LEN (5) /* 40-bits = 5 bytes */ 99 | #define SCRATCH_BUFFER_MAX_LEN (127) /* AES scratch memory */ 100 | #define STD_FRAME_LEN (127) 101 | 102 | 103 | /* RX events mask relating to reception into RX buffer 0, when double buffer is used */ 104 | #define RDB_STATUS_CLEAR_BUFF0_EVENTS (RDB_STATUS_CP_ERR0_BIT_MASK | RDB_STATUS_CIADONE0_BIT_MASK | RDB_STATUS_RXFR0_BIT_MASK | RDB_STATUS_RXFCG0_BIT_MASK) 105 | /* RX events mask relating to reception into RX buffer 1, when double buffer is used */ 106 | #define RDB_STATUS_CLEAR_BUFF1_EVENTS (RDB_STATUS_CP_ERR1_BIT_MASK | RDB_STATUS_CIADONE1_BIT_MASK | RDB_STATUS_RXFR1_BIT_MASK | RDB_STATUS_RXFCG1_BIT_MASK) 107 | 108 | /* User defined RX timeouts (frame wait timeout and preamble detect timeout) mask. */ 109 | #define SYS_STATUS_ALL_RX_TO (SYS_STATUS_RXFTO_BIT_MASK | SYS_STATUS_RXPTO_BIT_MASK) 110 | 111 | /* All RX errors mask. */ 112 | #define SYS_STATUS_ALL_RX_ERR (SYS_STATUS_RXPHE_BIT_MASK | SYS_STATUS_RXFCE_BIT_MASK | SYS_STATUS_RXFSL_BIT_MASK | SYS_STATUS_RXSTO_BIT_MASK \ 113 | | SYS_STATUS_ARFE_BIT_MASK | SYS_STATUS_CIAERR_BIT_MASK) 114 | 115 | /* All STS Mode 3 RX errors mask. */ 116 | #define SYS_STATUS_ALL_ND_RX_ERR (SYS_STATUS_CIAERR_BIT_MASK | SYS_STATUS_RXSTO_BIT_MASK) 117 | 118 | /* All RX events after a correct packet reception mask. */ 119 | #define SYS_STATUS_ALL_RX_GOOD (SYS_STATUS_RXFR_BIT_MASK | SYS_STATUS_RXFCG_BIT_MASK | SYS_STATUS_RXPRD_BIT_MASK | \ 120 | SYS_STATUS_RXSFDD_BIT_MASK | SYS_STATUS_RXPHD_BIT_MASK | SYS_STATUS_CIADONE_BIT_MASK) 121 | 122 | /* All TX events mask. */ 123 | #define SYS_STATUS_ALL_TX (SYS_STATUS_AAT_BIT_MASK | SYS_STATUS_TXFRB_BIT_MASK | SYS_STATUS_TXPRS_BIT_MASK | \ 124 | SYS_STATUS_TXPHS_BIT_MASK | SYS_STATUS_TXFRS_BIT_MASK ) 125 | 126 | #define SYS_STATUS_RXOK (SYS_STATUS_RXFCG_BIT_MASK | SYS_STATUS_CIA_DONE_BIT_MASK) 127 | 128 | #define AES_ERRORS (AES_STS_AUTH_ERR_BIT_MASK|AES_STS_TRANS_ERR_BIT_MASK|AES_STS_MEM_CONF_BIT_MASK) 129 | 130 | #define MAX_OFFSET_ALLOWED (0xFFF) 131 | #define MIN_INDERECT_ADDR (0x1000) 132 | 133 | #define BUF0_RX_FINFO 0x180000 //part of min set 134 | #define BUF0_RX_TIME 0x180004 //part of min set (RX time ~ RX_TIME_O) 135 | #define BUF0_RX_TIME1 0x180008 //part of min set 136 | #define BUF0_CIA_DIAG_0 0x18000C //part of min set 137 | #define BUF0_TDOA 0x180010 //part of min set 138 | #define BUF0_PDOA 0x180014 //part of min set 139 | #define BUF0_RES1 0x180018 //part of min set (---) 140 | #define BUF0_IP_DIAG_12 0x18001C //part of min set 141 | #define BUF0_IP_TS 0x180020 //part of mid set 142 | #define BUF0_RES2 0x180024 //part of mid set 143 | #define BUF0_STS_TS 0x180028 //part of mid set 144 | #define BUF0_STS_STAT 0x18002C //part of mid set 145 | #define BUF0_STS1_TS 0x180030 //part of mid set 146 | #define BUF0_STS1_STAT 0x180034 //part of mid set 147 | #define BUF0_CIA_DIAG_1 0x180038 //part of max set 148 | #define BUF0_IP_DIAG_0 0x18003C //part of max set 149 | #define BUF0_IP_DIAG_1 0x180040 //part of max set 150 | #define BUF0_IP_DIAG_2 0x180044 //... 151 | #define BUF0_IP_DIAG_3 0x180048 152 | #define BUF0_IP_DIAG_4 0x18004C 153 | #define BUF0_IP_DIAG_5 0x180050 154 | #define BUF0_IP_DIAG_6 0x180054 155 | #define BUF0_IP_DIAG_7 0x180058 156 | #define BUF0_IP_DIAG_8 0x18005C 157 | #define BUF0_IP_DIAG_9 0x180060 158 | #define BUF0_IP_DIAG_10 0x180064 159 | #define BUF0_IP_DIAG_11 0x180068 160 | #define BUF0_STS_DIAG_0 0x18006C 161 | #define BUF0_STS_DIAG_1 0x180070 162 | #define BUF0_STS_DIAG_2 0x180074 163 | #define BUF0_STS_DIAG_3 0x180078 164 | #define BUF0_STS_DIAG_4 0x18007C 165 | #define BUF0_STS_DIAG_5 0x180080 166 | #define BUF0_STS_DIAG_6 0x180084 167 | #define BUF0_STS_DIAG_7 0x180088 168 | #define BUF0_STS_DIAG_8 0x18008C 169 | #define BUF0_STS_DIAG_9 0x180090 170 | #define BUF0_STS_DIAG_10 0x180094 171 | #define BUF0_STS_DIAG_11 0x180098 172 | #define BUF0_STS_DIAG_12 0x18009C 173 | #define BUF0_STS_DIAG_13 0x1800A0 174 | #define BUF0_STS_DIAG_14 0x1800A4 175 | #define BUF0_STS_DIAG_15 0x1800A8 176 | #define BUF0_STS_DIAG_16 0x1800AC 177 | #define BUF0_STS_DIAG_17 0x1800B0 178 | #define BUF0_STS1_DIAG_0 0x1800B4 179 | #define BUF0_STS1_DIAG_1 0x1800B8 180 | #define BUF0_STS1_DIAG_2 0x1800BC 181 | #define BUF0_STS1_DIAG_3 0x1800C0 182 | #define BUF0_STS1_DIAG_4 0x1800C4 183 | #define BUF0_STS1_DIAG_5 0x1800C8 184 | #define BUF0_STS1_DIAG_6 0x1800CC 185 | #define BUF0_STS1_DIAG_7 0x1800D0 186 | #define BUF0_STS1_DIAG_8 0x1800D4 187 | #define BUF0_STS1_DIAG_9 0x1800D8 188 | #define BUF0_STS1_DIAG_10 0x1800DC 189 | #define BUF0_STS1_DIAG_11 0x1800E0 190 | #define BUF0_STS1_DIAG_12 0x1800E4 191 | 192 | #define BUF1_RX_FINFO 0x1800E8 //part of min set 193 | #define BUF1_RX_TIME 0x1800EC //part of min set (RX time ~ RX_TIME_O) 194 | #define BUF1_RX_TIME1 0x1800F0 //part of min set 195 | #define BUF1_CIA_DIAG_0 0x1800F4 //part of min set 196 | #define BUF1_TDOA 0x1800F8 //part of min set 197 | #define BUF1_PDOA 0x1800FC //part of min set 198 | #define BUF1_RES1 0x180100 //part of min set (---) 199 | #define BUF1_IP_DIAG_12 0x180104 //part of min set 200 | #define BUF1_IP_TS 0x180108 //part of mid set 201 | #define BUF1_RES2 0x18010C //part of mid set 202 | #define BUF1_STS_TS 0x180110 //part of mid set 203 | #define BUF1_RES3 0x180114 //part of mid set 204 | #define BUF1_STS1_TS 0x180118 //part of mid set 205 | #define BUF1_RES4 0x18011C //part of mid set 206 | #define BUF1_CIA_DIAG_1 0x180120 //part of max set 207 | #define BUF1_IP_DIAG_0 0x180124 //part of max set 208 | #define BUF1_IP_DIAG_1 0x180128 //part of max set 209 | #define BUF1_IP_DIAG_2 0x18012C //... 210 | #define BUF1_IP_DIAG_3 0x180130 211 | #define BUF1_IP_DIAG_4 0x180134 212 | #define BUF1_IP_DIAG_5 0x180138 213 | #define BUF1_IP_DIAG_6 0x18013C 214 | #define BUF1_IP_DIAG_7 0x180140 215 | #define BUF1_IP_DIAG_8 0x180144 216 | #define BUF1_IP_DIAG_9 0x180148 217 | #define BUF1_IP_DIAG_10 0x18014C 218 | #define BUF1_IP_DIAG_11 0x180150 219 | #define BUF1_STS_DIAG_0 0x180154 220 | #define BUF1_STS_DIAG_1 0x180158 221 | #define BUF1_STS_DIAG_2 0x18015C 222 | #define BUF1_STS_DIAG_3 0x180160 223 | #define BUF1_STS_DIAG_4 0x180164 224 | #define BUF1_STS_DIAG_5 0x180168 225 | #define BUF1_STS_DIAG_6 0x18016C 226 | #define BUF1_STS_DIAG_7 0x180170 227 | #define BUF1_STS_DIAG_8 0x180174 228 | #define BUF1_STS_DIAG_9 0x180178 229 | #define BUF1_STS_DIAG_10 0x18017C 230 | #define BUF1_STS_DIAG_11 0x180180 231 | #define BUF1_STS_DIAG_12 0x180184 232 | #define BUF1_STS_DIAG_13 0x180188 233 | #define BUF1_STS_DIAG_14 0x18018C 234 | #define BUF1_STS_DIAG_15 0x180190 235 | #define BUF1_STS_DIAG_16 0x180194 236 | #define BUF1_STS_DIAG_17 0x180198 237 | #define BUF1_STS1_DIAG_0 0x18019C 238 | #define BUF1_STS1_DIAG_1 0x1801A0 239 | #define BUF1_STS1_DIAG_2 0x1801A4 240 | #define BUF1_STS1_DIAG_3 0x1801A8 241 | #define BUF1_STS1_DIAG_4 0x1801AC 242 | #define BUF1_STS1_DIAG_5 0x1801B0 243 | #define BUF1_STS1_DIAG_6 0x1801B4 244 | #define BUF1_STS1_DIAG_7 0x1801B8 245 | #define BUF1_STS1_DIAG_8 0x1801BC 246 | #define BUF1_STS1_DIAG_9 0x1801C0 247 | #define BUF1_STS1_DIAG_10 0x1801C4 248 | #define BUF1_STS1_DIAG_11 0x1801C8 249 | #define BUF1_STS1_DIAG_12 0x1801CC 250 | 251 | 252 | #ifdef __cplusplus 253 | } 254 | #endif 255 | 256 | #endif 257 | -------------------------------------------------------------------------------- /src/dw3000_shared_functions.cpp: -------------------------------------------------------------------------------- 1 | /*! ---------------------------------------------------------------------------- 2 | * @file shared_functions.h 3 | * @brief Global functions are found here 4 | * 5 | * @attention 6 | * 7 | * Copyright 2013-2020 (c) Decawave Ltd, Dublin, Ireland. 8 | * 9 | * All rights reserved. 10 | * 11 | */ 12 | 13 | #include "dw3000_shared_functions.h" 14 | 15 | /*! ------------------------------------------------------------------------------------------------------------------ 16 | * @fn check_for_status_errors() 17 | * 18 | * @brief This function is used to get a value to increase the delay timer by dependent on the current TX preamble length set. 19 | * 20 | * @param reg: uint32_t value representing the current status register value. 21 | * @param errors: pointer to a uint32_t buffer that contains the sum of different errors logged during program operation. 22 | * 23 | * @return none 24 | */ 25 | void check_for_status_errors(uint32_t reg, uint32_t * errors) 26 | { 27 | uint16_t stsStatus = 0; 28 | 29 | if (!(reg & SYS_STATUS_RXFCG_BIT_MASK)) 30 | { 31 | errors[BAD_FRAME_ERR_IDX] += 1; 32 | } 33 | 34 | if (reg & SYS_STATUS_RXFSL_BIT_MASK) 35 | { 36 | errors[RSE_ERR_IDX] += 1; 37 | } 38 | 39 | if (reg & SYS_STATUS_RXPHE_BIT_MASK) 40 | { 41 | errors[PHE_ERR_IDX] += 1; 42 | } 43 | 44 | if (reg & SYS_STATUS_RXPTO_BIT_MASK) 45 | { 46 | errors[PTO_ERR_IDX] += 1; 47 | } 48 | 49 | if (reg & SYS_STATUS_ARFE_BIT_MASK) 50 | { 51 | errors[ARFE_ERR_IDX] += 1; 52 | } 53 | 54 | if ((reg & SYS_STATUS_RXFR_BIT_MASK) && !(reg & SYS_STATUS_RXFCG_BIT_MASK)) 55 | { 56 | errors[CRC_ERR_IDX] += 1; 57 | } 58 | 59 | if ((reg & SYS_STATUS_RXFTO_BIT_MASK) || (reg & SYS_STATUS_ALL_RX_TO)) 60 | { 61 | errors[RTO_ERR_IDX] += 1; 62 | } 63 | 64 | if (reg & SYS_STATUS_RXSTO_BIT_MASK) 65 | { 66 | errors[SFDTO_ERR_IDX] += 1; 67 | } 68 | 69 | if (reg & SYS_STATUS_CPERR_BIT_MASK) 70 | { 71 | // There is a general STS error 72 | errors[STS_PREAMBLE_ERR] += 1; 73 | 74 | // Get the status for a more detailed error reading of what went wrong with the STS 75 | dwt_readstsstatus(&stsStatus, 0); 76 | if (stsStatus & 0x100) 77 | { 78 | // Peak growth rate warning 79 | errors[STS_PEAK_GROWTH_RATE_ERR] += 1; 80 | } 81 | if (stsStatus & 0x080) 82 | { 83 | // ADC count warning 84 | errors[STS_ADC_COUNT_ERR] += 1; 85 | } 86 | if (stsStatus & 0x040) 87 | { 88 | // SFD count warning 89 | errors[STS_SFD_COUNT_ERR] += 1; 90 | } 91 | if (stsStatus & 0x020) 92 | { 93 | // Late first path estimation 94 | errors[STS_LATE_FIRST_PATH_ERR] += 1; 95 | } 96 | if (stsStatus & 0x010) 97 | { 98 | // Late coarse estimation 99 | errors[STS_LATE_COARSE_EST_ERR] += 1; 100 | } 101 | if (stsStatus & 0x008) 102 | { 103 | // Coarse estimation empty 104 | errors[STS_COARSE_EST_EMPTY_ERR] += 1; 105 | } 106 | if (stsStatus & 0x004) 107 | { 108 | // High noise threshold 109 | errors[STS_HIGH_NOISE_THREASH_ERR] += 1; 110 | } 111 | if (stsStatus & 0x002) 112 | { 113 | // Non-triangle 114 | errors[STS_NON_TRIANGLE_ERR] += 1; 115 | } 116 | if (stsStatus & 0x001) 117 | { 118 | // Logistic regression failed 119 | errors[STS_LOG_REG_FAILED_ERR] += 1; 120 | } 121 | } 122 | } 123 | 124 | /*! ------------------------------------------------------------------------------------------------------------------ 125 | * @fn get_rx_delay_time_txpreamble() 126 | * 127 | * @brief This function is used to get a value to increase the delay timer by dependent on the current TX preamble length set. 128 | * 129 | * @param None 130 | * 131 | * @return delay_time - a uint32_t value indicating the required increase needed to delay the time by. 132 | */ 133 | uint32_t get_rx_delay_time_txpreamble(void) 134 | { 135 | uint32_t delay_time = 0; 136 | /* Standard delay values for preamble lengths of 32, 64, 72 & 128 should be adequate. 137 | * Additional time delay will be needed for larger preamble lengths. 138 | * Delay required is dependent on the preamble length as it increases the frame length. */ 139 | switch (config_options.txPreambLength) 140 | { 141 | case DWT_PLEN_256: 142 | delay_time += 128; /* 256 - 128 */ 143 | break; 144 | case DWT_PLEN_512: 145 | delay_time += 384; /* 512 - 128 */ 146 | break; 147 | case DWT_PLEN_1024: 148 | delay_time += 896; /* 1024 - 128 */ 149 | break; 150 | case DWT_PLEN_1536: 151 | delay_time += 1408; /* 1536 - 128 */ 152 | break; 153 | case DWT_PLEN_2048: 154 | delay_time += 1920; /* 2048 - 128 */ 155 | break; 156 | case DWT_PLEN_4096: 157 | delay_time += 3968; /* 4096 - 128 */ 158 | break; 159 | case DWT_PLEN_32: 160 | case DWT_PLEN_64: 161 | case DWT_PLEN_72: 162 | case DWT_PLEN_128: 163 | default: 164 | break; 165 | } 166 | 167 | return delay_time; 168 | } 169 | /*! ------------------------------------------------------------------------------------------------------------------ 170 | * @fn get_rx_delay_time_data_rate() 171 | * 172 | * @brief This function is used to get a value to increase the delay timer by dependent on the current data rate set. 173 | * 174 | * @param None 175 | * 176 | * @return delay_time - a uint32_t value indicating the required increase needed to delay the time by. 177 | */ 178 | uint32_t get_rx_delay_time_data_rate(void) 179 | { 180 | uint32_t delay_time = 0; 181 | /* 182 | * If data rate is set to 850k (slower rate), 183 | * increase the delay time 184 | */ 185 | switch (config_options.dataRate) 186 | { 187 | case DWT_BR_850K: 188 | delay_time += 200; 189 | break; 190 | case DWT_BR_6M8: 191 | default: 192 | break; 193 | } 194 | 195 | return delay_time; 196 | } 197 | 198 | /*! ------------------------------------------------------------------------------------------------------------------ 199 | * @fn set_delayed_rx_time() 200 | * 201 | * @brief This function is used to set the delayed RX time before running dwt_rxenable() 202 | * 203 | * @param delay - This is a defined delay value (usually POLL_TX_TO_RESP_RX_DLY_UUS) 204 | * @param config_options - pointer to dwt_config_t configuration structure that is in use at the time this function 205 | * is called. 206 | * 207 | * @return None 208 | */ 209 | void set_delayed_rx_time(uint32_t delay, dwt_config_t *config_options) 210 | { 211 | uint32_t delay_time = delay; 212 | 213 | switch (config_options->txPreambLength) 214 | { 215 | case DWT_PLEN_32: 216 | delay_time -= 32; 217 | break; 218 | case DWT_PLEN_64: 219 | delay_time -= 64; 220 | break; 221 | case DWT_PLEN_72: 222 | delay_time -= 72; 223 | break; 224 | case DWT_PLEN_128: 225 | delay_time -= 128; 226 | break; 227 | case DWT_PLEN_256: 228 | delay_time -= 256; 229 | break; 230 | case DWT_PLEN_512: 231 | delay_time -= 512; 232 | break; 233 | case DWT_PLEN_1024: 234 | delay_time -= 1024; 235 | break; 236 | case DWT_PLEN_1536: 237 | delay_time -= 1536; 238 | break; 239 | case DWT_PLEN_2048: 240 | case DWT_PLEN_4096: 241 | delay_time -= 2048; 242 | break; 243 | default: 244 | break; 245 | } 246 | 247 | /* Length of the STS effects the size of the frame also. 248 | * This means the delay required is greater for larger STS lengths. */ 249 | delay_time += ((1<<(config_options->stsLength+2))*8); 250 | 251 | dwt_setdelayedtrxtime((uint32_t)((delay_time * UUS_TO_DWT_TIME) >> 8)); 252 | } 253 | 254 | /*! ------------------------------------------------------------------------------------------------------------------ 255 | * @fn set_resp_rx_timeout() 256 | * 257 | * @brief This function is used to set the RX timeout value 258 | * 259 | * @param delay - This is a defined delay value (usually RESP_RX_TIMEOUT_UUS) 260 | * @param config_options - pointer to dwt_config_t configuration structure that is in use at the time this function 261 | * is called. 262 | * 263 | * @return None 264 | */ 265 | void set_resp_rx_timeout(uint32_t delay, dwt_config_t *config_options) 266 | { 267 | /* 268 | * The program will need to adjust the timeout value depending on the size of the frame 269 | * Different sized frames require different time delays. 270 | */ 271 | uint32_t delay_time = delay + get_rx_delay_time_data_rate() + get_rx_delay_time_txpreamble() + 500; 272 | 273 | /* Length of the STS effects the size of the frame also. 274 | * This means the delay required is greater for larger STS lengths. */ 275 | switch (config_options->stsLength) 276 | { 277 | case DWT_STS_LEN_256: 278 | case DWT_STS_LEN_512: 279 | case DWT_STS_LEN_1024: 280 | case DWT_STS_LEN_2048: 281 | delay_time += ((1<<(config_options->stsLength+2))*8); 282 | break; 283 | case DWT_STS_LEN_32: 284 | case DWT_STS_LEN_64: 285 | case DWT_STS_LEN_128: 286 | default: 287 | break; 288 | } 289 | 290 | dwt_setrxtimeout(delay_time); 291 | } 292 | 293 | /*! ------------------------------------------------------------------------------------------------------------------ 294 | * @fn resync_sts() 295 | * 296 | * @brief This function is used to resync the counter values used by the STS. 297 | * The counter value is sent over via the TX device during a "poll" message. 298 | * This counter value is used to make the RX device align with the same counter value 299 | * so that the STS aligns again. 300 | * 301 | * @param newCount - The 32 bit value to set the STS to. 302 | * 303 | * @return None 304 | */ 305 | void resync_sts(uint32_t newCount) 306 | { 307 | // New IV value to use is the original IV0 value plus the count value sent over from the RX, 308 | // plus half the STS length. This is because the TX device would have read it's current 309 | // STS count value and then transmitted it. By transmitting, it would have increased it's 310 | // STS count value by half of the configured STS length. 311 | // It is important to note that the STS counter will increment by 32 whenever there is a 312 | // receiver or SFD timeout. This value is consistent regardless of the STS preamble length 313 | // that is set. 314 | uint32_t iv_value = newCount; 315 | 316 | iv_value += ((1<<(config_options.stsLength+2))*8)/2; 317 | 318 | /* Write the new STS count value to the appropriate register and reload the value into the counter */ 319 | dwt_write32bitreg(STS_IV0_ID, iv_value); 320 | dwt_configurestsloadiv(); 321 | } 322 | 323 | /*! ------------------------------------------------------------------------------------------------------------------ 324 | * @fn resp_msg_get_ts() 325 | * 326 | * @brief Read a given timestamp value from the response message. In the timestamp fields of the response message, the 327 | * least significant byte is at the lower address. 328 | * 329 | * @param ts_field pointer on the first byte of the timestamp field to get 330 | * ts timestamp value 331 | * 332 | * @return none 333 | */ 334 | void resp_msg_get_ts(uint8_t *ts_field, uint32_t *ts) 335 | { 336 | int i; 337 | *ts = 0; 338 | for (i = 0; i < RESP_MSG_TS_LEN; i++) 339 | { 340 | *ts += (uint32_t)ts_field[i] << (i * 8); 341 | } 342 | } 343 | 344 | /*! ------------------------------------------------------------------------------------------------------------------ 345 | * @fn get_tx_timestamp_u64() 346 | * 347 | * @brief Get the TX time-stamp in a 64-bit variable. 348 | * /!\ This function assumes that length of time-stamps is 40 bits, for both TX and RX! 349 | * 350 | * @param none 351 | * 352 | * @return 64-bit value of the read time-stamp. 353 | */ 354 | uint64_t get_tx_timestamp_u64(void) 355 | { 356 | uint8_t ts_tab[5]; 357 | uint64_t ts = 0; 358 | int8_t i; 359 | dwt_readtxtimestamp(ts_tab); 360 | for (i = 4; i >= 0; i--) 361 | { 362 | ts <<= 8; 363 | ts |= ts_tab[i]; 364 | } 365 | return ts; 366 | } 367 | 368 | /*! ------------------------------------------------------------------------------------------------------------------ 369 | * @fn get_rx_timestamp_u64() 370 | * 371 | * @brief Get the RX time-stamp in a 64-bit variable. 372 | * /!\ This function assumes that length of time-stamps is 40 bits, for both TX and RX! 373 | * 374 | * @param none 375 | * 376 | * @return 64-bit value of the read time-stamp. 377 | */ 378 | uint64_t get_rx_timestamp_u64(void) 379 | { 380 | uint8_t ts_tab[5]; 381 | uint64_t ts = 0; 382 | int8_t i; 383 | dwt_readrxtimestamp(ts_tab); 384 | for (i = 4; i >= 0; i--) 385 | { 386 | ts <<= 8; 387 | ts |= ts_tab[i]; 388 | } 389 | return ts; 390 | } 391 | 392 | /*! ------------------------------------------------------------------------------------------------------------------ 393 | * @fn final_msg_get_ts() 394 | * 395 | * @brief Read a given timestamp value from the final message. In the timestamp fields of the final message, the least 396 | * significant byte is at the lower address. 397 | * 398 | * @param ts_field pointer on the first byte of the timestamp field to read 399 | * ts timestamp value 400 | * 401 | * @return none 402 | */ 403 | void final_msg_get_ts(const uint8_t *ts_field, uint32_t *ts) 404 | { 405 | uint8_t i; 406 | *ts = 0; 407 | for (i = 0; i < FINAL_MSG_TS_LEN; i++) 408 | { 409 | *ts += ((uint32_t)ts_field[i] << (i * 8)); 410 | } 411 | } 412 | 413 | /*! ------------------------------------------------------------------------------------------------------------------ 414 | * @fn final_msg_set_ts() 415 | * 416 | * @brief Fill a given timestamp field in the final message with the given value. In the timestamp fields of the final 417 | * message, the least significant byte is at the lower address. 418 | * 419 | * @param ts_field pointer on the first byte of the timestamp field to fill 420 | * ts timestamp value 421 | * 422 | * @return none 423 | */ 424 | void final_msg_set_ts(uint8_t *ts_field, uint64_t ts) 425 | { 426 | uint8_t i; 427 | for (i = 0; i < FINAL_MSG_TS_LEN; i++) 428 | { 429 | ts_field[i] = (uint8_t)ts; 430 | ts >>= 8; 431 | } 432 | } 433 | 434 | /*! ------------------------------------------------------------------------------------------------------------------ 435 | * @fn resp_msg_set_ts() 436 | * 437 | * @brief Fill a given timestamp field in the response message with the given value. In the timestamp fields of the 438 | * response message, the least significant byte is at the lower address. 439 | * 440 | * @param ts_field pointer on the first byte of the timestamp field to fill 441 | * ts timestamp value 442 | * 443 | * @return none 444 | */ 445 | void resp_msg_set_ts(uint8_t *ts_field, const uint64_t ts) 446 | { 447 | uint8_t i; 448 | for (i = 0; i < RESP_MSG_TS_LEN; i++) 449 | { 450 | ts_field[i] = (uint8_t)(ts >> (i * 8)); 451 | } 452 | } 453 | -------------------------------------------------------------------------------- /examples/ex_06b_ss_twr_responder/ex_06b_ss_twr_responder.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * _ _ _ 4 | * (_) | | | 5 | * _| | __ _| |__ ___ 6 | * | | | / _` | '_ \/ __| 7 | * | | |___| (_| | |_) \__ \ 8 | * |_|______\__,_|_.__/|___/ 9 | * 10 | * ---------------------------------------------------------------------------- 11 | * "THE BEER-WARE LICENSE" (Revision 42): 12 | * wrote this file. As long as you retain this notice you 13 | * can do whatever you want with this stuff. If we meet some day, and you think 14 | * this stuff is worth it, you can buy me a beer in return - Pontus Oldberg 15 | * ---------------------------------------------------------------------------- 16 | */ 17 | 18 | #include "dw3000.h" 19 | 20 | #define APP_NAME "SS TWR RESP v1.0" 21 | 22 | /* Default communication configuration. We use default non-STS DW mode. */ 23 | static dwt_config_t config = { 24 | 5, /* Channel number. */ 25 | DWT_PLEN_128, /* Preamble length. Used in TX only. */ 26 | DWT_PAC8, /* Preamble acquisition chunk size. Used in RX only. */ 27 | 9, /* TX preamble code. Used in TX only. */ 28 | 9, /* RX preamble code. Used in RX only. */ 29 | 1, /* 0 to use standard 8 symbol SFD, 1 to use non-standard 8 symbol, 2 for non-standard 16 symbol SFD and 3 for 4z 8 symbol SDF type */ 30 | DWT_BR_6M8, /* Data rate. */ 31 | DWT_PHRMODE_STD, /* PHY header mode. */ 32 | DWT_PHRRATE_STD, /* PHY header rate. */ 33 | (129 + 8 - 8), /* SFD timeout (preamble length + 1 + SFD length - PAC size). Used in RX only. */ 34 | DWT_STS_MODE_OFF, /* STS disabled */ 35 | DWT_STS_LEN_64,/* STS length see allowed values in Enum dwt_sts_lengths_e */ 36 | DWT_PDOA_M0 /* PDOA mode off */ 37 | }; 38 | 39 | /* Default antenna delay values for 64 MHz PRF. See NOTE 2 below. */ 40 | #define TX_ANT_DLY 16385 41 | #define RX_ANT_DLY 16385 42 | 43 | /* Frames used in the ranging process. See NOTE 3 below. */ 44 | static uint8_t rx_poll_msg[] = {0x41, 0x88, 0, 0xCA, 0xDE, 'W', 'A', 'V', 'E', 0xE0, 0, 0}; 45 | static uint8_t tx_resp_msg[] = {0x41, 0x88, 0, 0xCA, 0xDE, 'V', 'E', 'W', 'A', 0xE1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 46 | /* Length of the common part of the message (up to and including the function code, see NOTE 3 below). */ 47 | #define ALL_MSG_COMMON_LEN 10 48 | /* Index to access some of the fields in the frames involved in the process. */ 49 | #define ALL_MSG_SN_IDX 2 50 | #define RESP_MSG_POLL_RX_TS_IDX 10 51 | #define RESP_MSG_RESP_TX_TS_IDX 14 52 | #define RESP_MSG_TS_LEN 4 53 | /* Frame sequence number, incremented after each transmission. */ 54 | static uint8_t frame_seq_nb = 0; 55 | 56 | /* Buffer to store received messages. 57 | * Its size is adjusted to longest frame that this example code is supposed to handle. */ 58 | #define RX_BUF_LEN 12//Must be less than FRAME_LEN_MAX_EX 59 | static uint8_t rx_buffer[RX_BUF_LEN]; 60 | 61 | /* Hold copy of status register state here for reference so that it can be examined at a debug breakpoint. */ 62 | static uint32_t status_reg = 0; 63 | 64 | /* Delay between frames, in UWB microseconds. See NOTE 1 below. */ 65 | #ifdef RPI_BUILD 66 | #define POLL_RX_TO_RESP_TX_DLY_UUS 550 67 | #endif //RPI_BUILD 68 | #ifdef STM32F429xx 69 | #define POLL_RX_TO_RESP_TX_DLY_UUS 450 70 | #endif //STM32F429xx 71 | #ifdef NRF52840_XXAA 72 | #define POLL_RX_TO_RESP_TX_DLY_UUS 650 73 | #endif //NRF52840_XXAA 74 | 75 | #define POLL_RX_TO_RESP_TX_DLY_UUS 450 76 | 77 | /* Timestamps of frames transmission/reception. */ 78 | static uint64_t poll_rx_ts; 79 | static uint64_t resp_tx_ts; 80 | 81 | /* Values for the PG_DELAY and TX_POWER registers reflect the bandwidth and power of the spectrum at the current 82 | * temperature. These values can be calibrated prior to taking reference measurements. See NOTE 5 below. */ 83 | extern dwt_txconfig_t txconfig_options; 84 | 85 | void setup() { 86 | // while (!Serial) 87 | delay(100); 88 | 89 | Serial.begin(115200); 90 | Serial.println(APP_NAME); 91 | 92 | /* Start SPI and get stuff going*/ 93 | spiBegin(); 94 | spiSelect(); 95 | 96 | delay(200); // Time needed for DW3000 to start up (transition from INIT_RC to IDLE_RC, or could wait for SPIRDY event) 97 | 98 | while (!dwt_checkidlerc()) // Need to make sure DW IC is in IDLE_RC before proceeding 99 | { 100 | Serial.print("IDLE FAILED\r\n"); 101 | while (1) ; 102 | } 103 | 104 | dwt_softreset(); 105 | delay(200); 106 | 107 | while (!dwt_checkidlerc()) // Need to make sure DW IC is in IDLE_RC before proceeding 108 | { 109 | Serial.print("IDLE FAILED\r\n"); 110 | while (1); 111 | } 112 | 113 | if (dwt_initialise(DWT_DW_INIT) == DWT_ERROR) 114 | { 115 | Serial.print("INIT FAILED\r\n"); 116 | while (1) ; 117 | } 118 | 119 | // Enabling LEDs here for debug so that for each TX the D1 LED will flash on DW3000 red eval-shield boards. 120 | dwt_setleds(DWT_LEDS_ENABLE | DWT_LEDS_INIT_BLINK); 121 | 122 | /* Configure DW IC. See NOTE 6 below. */ 123 | if(dwt_configure(&config)) // if the dwt_configure returns DWT_ERROR either the PLL or RX calibration has failed the host should reset the device 124 | { 125 | Serial.print("CONFIG FAILED\r\n"); 126 | while (1) ; 127 | } 128 | 129 | /* Configure the TX spectrum parameters (power, PG delay and PG count) */ 130 | dwt_configuretxrf(&txconfig_options); 131 | 132 | /* Apply default antenna delay value. See NOTE 2 below. */ 133 | dwt_setrxantennadelay(RX_ANT_DLY); 134 | dwt_settxantennadelay(TX_ANT_DLY); 135 | 136 | /* Next can enable TX/RX states output on GPIOs 5 and 6 to help debug, and also TX/RX LEDs 137 | * Note, in real low power applications the LEDs should not be used. */ 138 | dwt_setlnapamode(DWT_LNA_ENABLE | DWT_PA_ENABLE); 139 | } 140 | 141 | void loop() { 142 | /* Activate reception immediately. */ 143 | dwt_rxenable(DWT_START_RX_IMMEDIATE); 144 | 145 | /* Poll for reception of a frame or error/timeout. See NOTE 6 below. */ 146 | while (!((status_reg = dwt_read32bitreg(SYS_STATUS_ID)) & (SYS_STATUS_RXFCG_BIT_MASK | SYS_STATUS_ALL_RX_ERR))) 147 | { }; 148 | 149 | if (status_reg & SYS_STATUS_RXFCG_BIT_MASK) 150 | { 151 | uint32_t frame_len; 152 | 153 | /* Clear good RX frame event in the DW IC status register. */ 154 | dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_RXFCG_BIT_MASK); 155 | 156 | /* A frame has been received, read it into the local buffer. */ 157 | frame_len = dwt_read32bitreg(RX_FINFO_ID) & RXFLEN_MASK; 158 | if (frame_len <= sizeof(rx_buffer)) 159 | { 160 | dwt_readrxdata(rx_buffer, frame_len, 0); 161 | 162 | /* Check that the frame is a poll sent by "SS TWR initiator" example. 163 | * As the sequence number field of the frame is not relevant, it is cleared to simplify the validation of the frame. */ 164 | rx_buffer[ALL_MSG_SN_IDX] = 0; 165 | if (memcmp(rx_buffer, rx_poll_msg, ALL_MSG_COMMON_LEN) == 0) 166 | { 167 | uint32_t resp_tx_time; 168 | int ret; 169 | 170 | /* Retrieve poll reception timestamp. */ 171 | poll_rx_ts = get_rx_timestamp_u64(); 172 | 173 | /* Compute response message transmission time. See NOTE 7 below. */ 174 | resp_tx_time = (poll_rx_ts + (POLL_RX_TO_RESP_TX_DLY_UUS * UUS_TO_DWT_TIME)) >> 8; 175 | dwt_setdelayedtrxtime(resp_tx_time); 176 | 177 | /* Response TX timestamp is the transmission time we programmed plus the antenna delay. */ 178 | resp_tx_ts = (((uint64_t)(resp_tx_time & 0xFFFFFFFEUL)) << 8) + TX_ANT_DLY; 179 | 180 | /* Write all timestamps in the final message. See NOTE 8 below. */ 181 | resp_msg_set_ts(&tx_resp_msg[RESP_MSG_POLL_RX_TS_IDX], poll_rx_ts); 182 | resp_msg_set_ts(&tx_resp_msg[RESP_MSG_RESP_TX_TS_IDX], resp_tx_ts); 183 | 184 | /* Write and send the response message. See NOTE 9 below. */ 185 | tx_resp_msg[ALL_MSG_SN_IDX] = frame_seq_nb; 186 | dwt_writetxdata(sizeof(tx_resp_msg), tx_resp_msg, 0); /* Zero offset in TX buffer. */ 187 | dwt_writetxfctrl(sizeof(tx_resp_msg), 0, 1); /* Zero offset in TX buffer, ranging. */ 188 | ret = dwt_starttx(DWT_START_TX_DELAYED); 189 | 190 | /* If dwt_starttx() returns an error, abandon this ranging exchange and proceed to the next one. See NOTE 10 below. */ 191 | if (ret == DWT_SUCCESS) 192 | { 193 | /* Poll DW IC until TX frame sent event set. See NOTE 6 below. */ 194 | while (!(dwt_read32bitreg(SYS_STATUS_ID) & SYS_STATUS_TXFRS_BIT_MASK)) 195 | { }; 196 | 197 | /* Clear TXFRS event. */ 198 | dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_TXFRS_BIT_MASK); 199 | 200 | /* Increment frame sequence number after transmission of the poll message (modulo 256). */ 201 | frame_seq_nb++; 202 | } 203 | } 204 | } 205 | } 206 | else 207 | { 208 | /* Clear RX error events in the DW IC status register. */ 209 | dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_ALL_RX_ERR); 210 | } 211 | } 212 | 213 | /***************************************************************************************************************************************************** 214 | * NOTES: 215 | * 216 | * 1. The single-sided two-way ranging scheme implemented here has to be considered carefully as the accuracy of the distance measured is highly 217 | * sensitive to the clock offset error between the devices and the length of the response delay between frames. To achieve the best possible 218 | * accuracy, this response delay must be kept as low as possible. In order to do so, 6.8 Mbps data rate is used in this example and the response 219 | * delay between frames is defined as low as possible. The user is referred to User Manual for more details about the single-sided two-way ranging 220 | * process. 221 | * 222 | * Initiator: |Poll TX| ..... |Resp RX| 223 | * Responder: |Poll RX| ..... |Resp TX| 224 | * ^|P RMARKER| - time of Poll TX/RX 225 | * ^|R RMARKER| - time of Resp TX/RX 226 | * 227 | * <--TDLY-> - POLL_TX_TO_RESP_RX_DLY_UUS (RDLY-RLEN) 228 | * <-RLEN-> - RESP_RX_TIMEOUT_UUS (length of response frame) 229 | * <----RDLY------> - POLL_RX_TO_RESP_TX_DLY_UUS (depends on how quickly responder can turn around and reply) 230 | * 231 | * 232 | * 2. The sum of the values is the TX to RX antenna delay, experimentally determined by a calibration process. Here we use a hard coded typical value 233 | * but, in a real application, each device should have its own antenna delay properly calibrated to get the best possible precision when performing 234 | * range measurements. 235 | * 3. The frames used here are Decawave specific ranging frames, complying with the IEEE 802.15.4 standard data frame encoding. The frames are the 236 | * following: 237 | * - a poll message sent by the initiator to trigger the ranging exchange. 238 | * - a response message sent by the responder to complete the exchange and provide all information needed by the initiator to compute the 239 | * time-of-flight (distance) estimate. 240 | * The first 10 bytes of those frame are common and are composed of the following fields: 241 | * - byte 0/1: frame control (0x8841 to indicate a data frame using 16-bit addressing). 242 | * - byte 2: sequence number, incremented for each new frame. 243 | * - byte 3/4: PAN ID (0xDECA). 244 | * - byte 5/6: destination address, see NOTE 4 below. 245 | * - byte 7/8: source address, see NOTE 4 below. 246 | * - byte 9: function code (specific values to indicate which message it is in the ranging process). 247 | * The remaining bytes are specific to each message as follows: 248 | * Poll message: 249 | * - no more data 250 | * Response message: 251 | * - byte 10 -> 13: poll message reception timestamp. 252 | * - byte 14 -> 17: response message transmission timestamp. 253 | * All messages end with a 2-byte checksum automatically set by DW IC. 254 | * 4. Source and destination addresses are hard coded constants in this example to keep it simple but for a real product every device should have a 255 | * unique ID. Here, 16-bit addressing is used to keep the messages as short as possible but, in an actual application, this should be done only 256 | * after an exchange of specific messages used to define those short addresses for each device participating to the ranging exchange. 257 | * 5. In a real application, for optimum performance within regulatory limits, it may be necessary to set TX pulse bandwidth and TX power, (using 258 | * the dwt_configuretxrf API call) to per device calibrated values saved in the target system or the DW IC OTP memory. 259 | * 6. We use polled mode of operation here to keep the example as simple as possible but all status events can be used to generate interrupts. Please 260 | * refer to DW IC User Manual for more details on "interrupts". It is also to be noted that STATUS register is 5 bytes long but, as the event we 261 | * use are all in the first bytes of the register, we can use the simple dwt_read32bitreg() API call to access it instead of reading the whole 5 262 | * bytes. 263 | * 7. As we want to send final TX timestamp in the final message, we have to compute it in advance instead of relying on the reading of DW IC 264 | * register. Timestamps and delayed transmission time are both expressed in device time units so we just have to add the desired response delay to 265 | * response RX timestamp to get final transmission time. The delayed transmission time resolution is 512 device time units which means that the 266 | * lower 9 bits of the obtained value must be zeroed. This also allows to encode the 40-bit value in a 32-bit words by shifting the all-zero lower 267 | * 8 bits. 268 | * 8. In this operation, the high order byte of each 40-bit timestamps is discarded. This is acceptable as those time-stamps are not separated by 269 | * more than 2**32 device time units (which is around 67 ms) which means that the calculation of the round-trip delays (needed in the 270 | * time-of-flight computation) can be handled by a 32-bit subtraction. 271 | * 9. dwt_writetxdata() takes the full size of the message as a parameter but only copies (size - 2) bytes as the check-sum at the end of the frame is 272 | * automatically appended by the DW IC. This means that our variable could be two bytes shorter without losing any data (but the sizeof would not 273 | * work anymore then as we would still have to indicate the full length of the frame to dwt_writetxdata()). 274 | * 10. When running this example on the DW3000 platform with the POLL_RX_TO_RESP_TX_DLY response delay provided, the dwt_starttx() is always 275 | * successful. However, in cases where the delay is too short (or something else interrupts the code flow), then the dwt_starttx() might be issued 276 | * too late for the configured start time. The code below provides an example of how to handle this condition: In this case it abandons the 277 | * ranging exchange and simply goes back to awaiting another poll message. If this error handling code was not here, a late dwt_starttx() would 278 | * result in the code flow getting stuck waiting subsequent RX event that will will never come. The companion "initiator" example (ex_06a) should 279 | * timeout from awaiting the "response" and proceed to send another poll in due course to initiate another ranging exchange. 280 | * 11. The user is referred to DecaRanging ARM application (distributed with EVK1000 product) for additional practical example of usage, and to the 281 | * DW IC API Guide for more details on the DW IC driver functions. 282 | * 12. In this example, the DW IC is put into IDLE state after calling dwt_initialise(). This means that a fast SPI rate of up to 20 MHz can be used 283 | * thereafter. 284 | * 13. Desired configuration by user may be different to the current programmed configuration. dwt_configure is called to set desired 285 | * configuration. 286 | ****************************************************************************************************************************************************/ 287 | -------------------------------------------------------------------------------- /examples/ex_06a_ss_twr_initiator/ex_06a_ss_twr_initiator.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * _ _ _ 4 | * (_) | | | 5 | * _| | __ _| |__ ___ 6 | * | | | / _` | '_ \/ __| 7 | * | | |___| (_| | |_) \__ \ 8 | * |_|______\__,_|_.__/|___/ 9 | * 10 | * ---------------------------------------------------------------------------- 11 | * "THE BEER-WARE LICENSE" (Revision 42): 12 | * wrote this file. As long as you retain this notice you 13 | * can do whatever you want with this stuff. If we meet some day, and you think 14 | * this stuff is worth it, you can buy me a beer in return - Pontus Oldberg 15 | * ---------------------------------------------------------------------------- 16 | */ 17 | 18 | #include "dw3000.h" 19 | 20 | #define APP_NAME "SS TWR INIT v1.0" 21 | 22 | /* Default communication configuration. We use default non-STS DW mode. */ 23 | static dwt_config_t config = { 24 | 5, /* Channel number. */ 25 | DWT_PLEN_128, /* Preamble length. Used in TX only. */ 26 | DWT_PAC8, /* Preamble acquisition chunk size. Used in RX only. */ 27 | 9, /* TX preamble code. Used in TX only. */ 28 | 9, /* RX preamble code. Used in RX only. */ 29 | 1, /* 0 to use standard 8 symbol SFD, 1 to use non-standard 8 symbol, 2 for non-standard 16 symbol SFD and 3 for 4z 8 symbol SDF type */ 30 | DWT_BR_6M8, /* Data rate. */ 31 | DWT_PHRMODE_STD, /* PHY header mode. */ 32 | DWT_PHRRATE_STD, /* PHY header rate. */ 33 | (129 + 8 - 8), /* SFD timeout (preamble length + 1 + SFD length - PAC size). Used in RX only. */ 34 | DWT_STS_MODE_OFF, /* STS disabled */ 35 | DWT_STS_LEN_64,/* STS length see allowed values in Enum dwt_sts_lengths_e */ 36 | DWT_PDOA_M0 /* PDOA mode off */ 37 | }; 38 | 39 | /* Inter-ranging delay period, in milliseconds. */ 40 | #define RNG_DELAY_MS 1000 41 | 42 | /* Default antenna delay values for 64 MHz PRF. See NOTE 2 below. */ 43 | #define TX_ANT_DLY 16385 44 | #define RX_ANT_DLY 16385 45 | 46 | /* Frames used in the ranging process. See NOTE 3 below. */ 47 | static uint8_t tx_poll_msg[] = {0x41, 0x88, 0, 0xCA, 0xDE, 'W', 'A', 'V', 'E', 0xE0, 0, 0}; 48 | static uint8_t rx_resp_msg[] = {0x41, 0x88, 0, 0xCA, 0xDE, 'V', 'E', 'W', 'A', 0xE1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 49 | /* Length of the common part of the message (up to and including the function code, see NOTE 3 below). */ 50 | #define ALL_MSG_COMMON_LEN 10 51 | /* Indexes to access some of the fields in the frames defined above. */ 52 | #define ALL_MSG_SN_IDX 2 53 | #define RESP_MSG_POLL_RX_TS_IDX 10 54 | #define RESP_MSG_RESP_TX_TS_IDX 14 55 | #define RESP_MSG_TS_LEN 4 56 | /* Frame sequence number, incremented after each transmission. */ 57 | static uint8_t frame_seq_nb = 0; 58 | 59 | /* Buffer to store received response message. 60 | * Its size is adjusted to longest frame that this example code is supposed to handle. */ 61 | #define RX_BUF_LEN 20 62 | static uint8_t rx_buffer[RX_BUF_LEN]; 63 | 64 | /* Hold copy of status register state here for reference so that it can be examined at a debug breakpoint. */ 65 | static uint32_t status_reg = 0; 66 | 67 | /* Delay between frames, in UWB microseconds. See NOTE 1 below. */ 68 | #ifdef RPI_BUILD 69 | #define POLL_TX_TO_RESP_RX_DLY_UUS 240 70 | #endif //RPI_BUILD 71 | #ifdef STM32F429xx 72 | #define POLL_TX_TO_RESP_RX_DLY_UUS 240 73 | #endif //STM32F429xx 74 | #ifdef NRF52840_XXAA 75 | #define POLL_TX_TO_RESP_RX_DLY_UUS 240 76 | #endif //NRF52840_XXAA 77 | /* Receive response timeout. See NOTE 5 below. */ 78 | #ifdef RPI_BUILD 79 | #define RESP_RX_TIMEOUT_UUS 270 80 | #endif //RPI_BUILD 81 | #ifdef STM32F429xx 82 | #define RESP_RX_TIMEOUT_UUS 210 83 | #endif //STM32F429xx 84 | #ifdef NRF52840_XXAA 85 | #define RESP_RX_TIMEOUT_UUS 400 86 | #endif //NRF52840_XXAA 87 | 88 | #define POLL_TX_TO_RESP_RX_DLY_UUS 240 89 | #define RESP_RX_TIMEOUT_UUS 400 90 | 91 | 92 | /* Hold copies of computed time of flight and distance here for reference so that it can be examined at a debug breakpoint. */ 93 | static double tof; 94 | static double distance; 95 | 96 | /* Values for the PG_DELAY and TX_POWER registers reflect the bandwidth and power of the spectrum at the current 97 | * temperature. These values can be calibrated prior to taking reference measurements. See NOTE 2 below. */ 98 | extern dwt_txconfig_t txconfig_options; 99 | 100 | void setup() { 101 | while (!Serial) 102 | delay(100); 103 | 104 | Serial.begin(115200); 105 | Serial.println(APP_NAME); 106 | 107 | /* Start SPI and get stuff going*/ 108 | spiBegin(); 109 | spiSelect(); 110 | 111 | delay(200); // Time needed for DW3000 to start up (transition from INIT_RC to IDLE_RC, or could wait for SPIRDY event) 112 | 113 | while (!dwt_checkidlerc()) // Need to make sure DW IC is in IDLE_RC before proceeding 114 | { 115 | Serial.print("IDLE FAILED\r\n"); 116 | while (1); 117 | } 118 | 119 | dwt_softreset(); 120 | delay(200); 121 | 122 | while (!dwt_checkidlerc()) // Need to make sure DW IC is in IDLE_RC before proceeding 123 | { 124 | Serial.print("IDLE FAILED\r\n"); 125 | while (1); 126 | } 127 | 128 | if (dwt_initialise(DWT_DW_INIT) == DWT_ERROR) 129 | { 130 | Serial.print("INIT FAILED\r\n"); 131 | while (1); 132 | } 133 | 134 | /* Configure DW IC. See NOTE 6 below. */ 135 | if(dwt_configure(&config)) // if the dwt_configure returns DWT_ERROR either the PLL or RX calibration has failed the host should reset the device 136 | { 137 | Serial.print("CONFIG FAILED\r\n"); 138 | while (1); 139 | } 140 | 141 | /* Configure the TX spectrum parameters (power, PG delay and PG count) */ 142 | dwt_configuretxrf(&txconfig_options); 143 | 144 | /* Apply default antenna delay value. See NOTE 2 below. */ 145 | dwt_setrxantennadelay(RX_ANT_DLY); 146 | dwt_settxantennadelay(TX_ANT_DLY); 147 | 148 | /* Set expected response's delay and timeout. See NOTE 1 and 5 below. 149 | * As this example only handles one incoming frame with always the same delay and timeout, those values can be set here once for all. */ 150 | dwt_setrxaftertxdelay(POLL_TX_TO_RESP_RX_DLY_UUS); 151 | dwt_setrxtimeout(RESP_RX_TIMEOUT_UUS); 152 | 153 | /* Next can enable TX/RX states output on GPIOs 5 and 6 to help debug, and also TX/RX LEDs 154 | * Note, in real low power applications the LEDs should not be used. */ 155 | dwt_setlnapamode(DWT_LNA_ENABLE | DWT_PA_ENABLE); 156 | } 157 | 158 | void loop() { 159 | /* Write frame data to DW IC and prepare transmission. See NOTE 7 below. */ 160 | tx_poll_msg[ALL_MSG_SN_IDX] = frame_seq_nb; 161 | dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_TXFRS_BIT_MASK); 162 | dwt_writetxdata(sizeof(tx_poll_msg), tx_poll_msg, 0); /* Zero offset in TX buffer. */ 163 | dwt_writetxfctrl(sizeof(tx_poll_msg), 0, 1); /* Zero offset in TX buffer, ranging. */ 164 | 165 | /* Start transmission, indicating that a response is expected so that reception is enabled automatically after the frame is sent and the delay 166 | * set by dwt_setrxaftertxdelay() has elapsed. */ 167 | dwt_starttx(DWT_START_TX_IMMEDIATE | DWT_RESPONSE_EXPECTED); 168 | 169 | /* We assume that the transmission is achieved correctly, poll for reception of a frame or error/timeout. See NOTE 8 below. */ 170 | while (!((status_reg = dwt_read32bitreg(SYS_STATUS_ID)) & (SYS_STATUS_RXFCG_BIT_MASK | SYS_STATUS_ALL_RX_TO | SYS_STATUS_ALL_RX_ERR))) 171 | { }; 172 | 173 | /* Increment frame sequence number after transmission of the poll message (modulo 256). */ 174 | frame_seq_nb++; 175 | 176 | if (status_reg & SYS_STATUS_RXFCG_BIT_MASK) 177 | { 178 | uint32_t frame_len; 179 | 180 | /* Clear good RX frame event in the DW IC status register. */ 181 | dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_RXFCG_BIT_MASK); 182 | 183 | /* A frame has been received, read it into the local buffer. */ 184 | frame_len = dwt_read32bitreg(RX_FINFO_ID) & RXFLEN_MASK; 185 | if (frame_len <= sizeof(rx_buffer)) 186 | { 187 | dwt_readrxdata(rx_buffer, frame_len, 0); 188 | 189 | /* Check that the frame is the expected response from the companion "SS TWR responder" example. 190 | * As the sequence number field of the frame is not relevant, it is cleared to simplify the validation of the frame. */ 191 | rx_buffer[ALL_MSG_SN_IDX] = 0; 192 | if (memcmp(rx_buffer, rx_resp_msg, ALL_MSG_COMMON_LEN) == 0) 193 | { 194 | uint32_t poll_tx_ts, resp_rx_ts, poll_rx_ts, resp_tx_ts; 195 | int32_t rtd_init, rtd_resp; 196 | float clockOffsetRatio ; 197 | 198 | /* Retrieve poll transmission and response reception timestamps. See NOTE 9 below. */ 199 | poll_tx_ts = dwt_readtxtimestamplo32(); 200 | resp_rx_ts = dwt_readrxtimestamplo32(); 201 | 202 | /* Read carrier integrator value and calculate clock offset ratio. See NOTE 11 below. */ 203 | clockOffsetRatio = ((float)dwt_readclockoffset()) / (uint32_t)(1<<26); 204 | 205 | /* Get timestamps embedded in response message. */ 206 | resp_msg_get_ts(&rx_buffer[RESP_MSG_POLL_RX_TS_IDX], &poll_rx_ts); 207 | resp_msg_get_ts(&rx_buffer[RESP_MSG_RESP_TX_TS_IDX], &resp_tx_ts); 208 | 209 | /* Compute time of flight and distance, using clock offset ratio to correct for differing local and remote clock rates */ 210 | rtd_init = resp_rx_ts - poll_tx_ts; 211 | rtd_resp = resp_tx_ts - poll_rx_ts; 212 | 213 | tof = ((rtd_init - rtd_resp * (1 - clockOffsetRatio)) / 2.0) * DWT_TIME_UNITS; 214 | distance = tof * SPEED_OF_LIGHT; 215 | 216 | /* Display computed distance on LCD. */ 217 | snprintf(dist_str, sizeof(dist_str), "DIST: %3.2f m", distance); 218 | Serial.println(dist_str); 219 | } 220 | } 221 | } 222 | else 223 | { 224 | /* Clear RX error/timeout events in the DW IC status register. */ 225 | dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_ALL_RX_TO | SYS_STATUS_ALL_RX_ERR); 226 | } 227 | 228 | /* Execute a delay between ranging exchanges. */ 229 | Sleep(RNG_DELAY_MS); 230 | } 231 | 232 | /***************************************************************************************************************************************************** 233 | * NOTES: 234 | * 235 | * 1. The single-sided two-way ranging scheme implemented here has to be considered carefully as the accuracy of the distance measured is highly 236 | * sensitive to the clock offset error between the devices and the length of the response delay between frames. To achieve the best possible 237 | * accuracy, this response delay must be kept as low as possible. In order to do so, 6.8 Mbps data rate is used in this example and the response 238 | * delay between frames is defined as low as possible. The user is referred to User Manual for more details about the single-sided two-way ranging 239 | * process. NB:SEE ALSO NOTE 11. 240 | * 241 | * Initiator: |Poll TX| ..... |Resp RX| 242 | * Responder: |Poll RX| ..... |Resp TX| 243 | * ^|P RMARKER| - time of Poll TX/RX 244 | * ^|R RMARKER| - time of Resp TX/RX 245 | * 246 | * <--TDLY-> - POLL_TX_TO_RESP_RX_DLY_UUS (RDLY-RLEN) 247 | * <-RLEN-> - RESP_RX_TIMEOUT_UUS (length of response frame) 248 | * <----RDLY------> - POLL_RX_TO_RESP_TX_DLY_UUS (depends on how quickly responder can turn around and reply) 249 | * 250 | * 251 | * 2. The sum of the values is the TX to RX antenna delay, this should be experimentally determined by a calibration process. Here we use a hard coded 252 | * value (expected to be a little low so a positive error will be seen on the resultant distance estimate). For a real production application, each 253 | * device should have its own antenna delay properly calibrated to get good precision when performing range measurements. 254 | * 3. The frames used here are Decawave specific ranging frames, complying with the IEEE 802.15.4 standard data frame encoding. The frames are the 255 | * following: 256 | * - a poll message sent by the initiator to trigger the ranging exchange. 257 | * - a response message sent by the responder to complete the exchange and provide all information needed by the initiator to compute the 258 | * time-of-flight (distance) estimate. 259 | * The first 10 bytes of those frame are common and are composed of the following fields: 260 | * - byte 0/1: frame control (0x8841 to indicate a data frame using 16-bit addressing). 261 | * - byte 2: sequence number, incremented for each new frame. 262 | * - byte 3/4: PAN ID (0xDECA). 263 | * - byte 5/6: destination address, see NOTE 4 below. 264 | * - byte 7/8: source address, see NOTE 4 below. 265 | * - byte 9: function code (specific values to indicate which message it is in the ranging process). 266 | * The remaining bytes are specific to each message as follows: 267 | * Poll message: 268 | * - no more data 269 | * Response message: 270 | * - byte 10 -> 13: poll message reception timestamp. 271 | * - byte 14 -> 17: response message transmission timestamp. 272 | * All messages end with a 2-byte checksum automatically set by DW IC. 273 | * 4. Source and destination addresses are hard coded constants in this example to keep it simple but for a real product every device should have a 274 | * unique ID. Here, 16-bit addressing is used to keep the messages as short as possible but, in an actual application, this should be done only 275 | * after an exchange of specific messages used to define those short addresses for each device participating to the ranging exchange. 276 | * 5. This timeout is for complete reception of a frame, i.e. timeout duration must take into account the length of the expected frame. Here the value 277 | * is arbitrary but chosen large enough to make sure that there is enough time to receive the complete response frame sent by the responder at the 278 | * 6.8M data rate used (around 200 µs). 279 | * 6. In a real application, for optimum performance within regulatory limits, it may be necessary to set TX pulse bandwidth and TX power, (using 280 | * the dwt_configuretxrf API call) to per device calibrated values saved in the target system or the DW IC OTP memory. 281 | * 7. dwt_writetxdata() takes the full size of the message as a parameter but only copies (size - 2) bytes as the check-sum at the end of the frame is 282 | * automatically appended by the DW IC. This means that our variable could be two bytes shorter without losing any data (but the sizeof would not 283 | * work anymore then as we would still have to indicate the full length of the frame to dwt_writetxdata()). 284 | * 8. We use polled mode of operation here to keep the example as simple as possible but all status events can be used to generate interrupts. Please 285 | * refer to DW IC User Manual for more details on "interrupts". It is also to be noted that STATUS register is 5 bytes long but, as the event we 286 | * use are all in the first bytes of the register, we can use the simple dwt_read32bitreg() API call to access it instead of reading the whole 5 287 | * bytes. 288 | * 9. The high order byte of each 40-bit time-stamps is discarded here. This is acceptable as, on each device, those time-stamps are not separated by 289 | * more than 2**32 device time units (which is around 67 ms) which means that the calculation of the round-trip delays can be handled by a 32-bit 290 | * subtraction. 291 | * 10. The user is referred to DecaRanging ARM application (distributed with EVK1000 product) for additional practical example of usage, and to the 292 | * DW IC API Guide for more details on the DW IC driver functions. 293 | * 11. The use of the clock offset value to correct the TOF calculation, significantly improves the result of the SS-TWR where the remote 294 | * responder unit's clock is a number of PPM offset from the local initiator unit's clock. 295 | * As stated in NOTE 2 a fixed offset in range will be seen unless the antenna delay is calibrated and set correctly. 296 | * 12. In this example, the DW IC is put into IDLE state after calling dwt_initialise(). This means that a fast SPI rate of up to 20 MHz can be used 297 | * thereafter. 298 | * 13. Desired configuration by user may be different to the current programmed configuration. dwt_configure is called to set desired 299 | * configuration. 300 | ****************************************************************************************************************************************************/ 301 | -------------------------------------------------------------------------------- /src/dw3000_port.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * port.c 3 | * 4 | * Created: 9/10/2021 1:20:05 PM 5 | * Author: Emim Eminof 6 | */ 7 | 8 | #include "dw3000_port.h" 9 | #include "SPI.h" 10 | 11 | uint8_t _ss; 12 | uint8_t _rst; 13 | uint8_t _irq; 14 | uint8_t _wake; 15 | 16 | #ifdef ESP8266 17 | // default ESP8266 frequency is 80 Mhz, thus divide by 4 is 20 MHz 18 | const SPISettings _fastSPI = SPISettings(8000000L, MSBFIRST, SPI_MODE0); 19 | #else 20 | const SPISettings _fastSPI = SPISettings(8000000L, MSBFIRST, SPI_MODE0); 21 | #endif 22 | const SPISettings _slowSPI = SPISettings(2000000L, MSBFIRST, SPI_MODE0); 23 | const SPISettings* _currentSPI = &_fastSPI; 24 | 25 | boolean _debounceClockEnabled = false; 26 | 27 | /* register caches. */ 28 | byte _syscfg[LEN_SYS_CFG]; 29 | byte _sysctrl[LEN_SYS_CTRL]; 30 | byte _sysstatus[LEN_SYS_STATUS]; 31 | byte _txfctrl[LEN_TX_FCTRL]; 32 | byte _sysmask[LEN_SYS_MASK]; 33 | byte _chanctrl[LEN_CHAN_CTRL]; 34 | 35 | uint8_t _deviceMode; 36 | 37 | /* device status monitoring */ 38 | byte _vmeas3v3; 39 | byte _tmeas23C; 40 | 41 | /* PAN and short address. */ 42 | byte _networkAndAddress[LEN_PANADR]; 43 | 44 | void enableDebounceClock() { 45 | byte pmscctrl0[LEN_PMSC_CTRL0]; 46 | memset(pmscctrl0, 0, LEN_PMSC_CTRL0); 47 | readBytes(PMSC, PMSC_CTRL0_SUB, pmscctrl0, LEN_PMSC_CTRL0); 48 | setBit(pmscctrl0, LEN_PMSC_CTRL0, GPDCE_BIT, 1); 49 | setBit(pmscctrl0, LEN_PMSC_CTRL0, KHZCLKEN_BIT, 1); 50 | writeBytes(PMSC, PMSC_CTRL0_SUB, pmscctrl0, LEN_PMSC_CTRL0); 51 | _debounceClockEnabled = true; 52 | } 53 | 54 | void sleepms(uint32_t x) 55 | { 56 | //_delay_ms(x); // delay by milliseconds 57 | } 58 | 59 | int sleepus(uint32_t x) 60 | { 61 | //_delay_us(x); // delay by microseconds 62 | return 0; 63 | } 64 | 65 | void deca_sleep(uint8_t time_ms) // wrapper for decawave sleep function 66 | { 67 | sleepms(time_ms); 68 | } 69 | 70 | void deca_usleep(uint8_t time_us) // wrapper for decawave sleep function 71 | { 72 | sleepus(time_us); 73 | } 74 | 75 | 76 | void spiBegin(uint8_t irq, uint8_t rst, uint8_t wake) 77 | { 78 | /*DDR_SPI = _BV(DD_MOSI)|_BV(DD_SCK)|_BV(DD_SS); // Set MOSI, SCK and CS output 79 | DDR_SPI &= ~_BV(DD_MISO); // make sure MISO is an input 80 | SPCR0 = _BV(SPE)|_BV(MSTR); // Enable SPI functionality and Master SPI mode 81 | SPCR0 &= ~_BV(DORD); // set SPI most significant bit first (this is default on ATMEGA328pb) 82 | */ 83 | 84 | // Wakeup pin not used in library but needs to be set to high for operation. 85 | _wake = wake; 86 | pinMode(wake, OUTPUT); 87 | digitalWrite(wake, HIGH); 88 | 89 | // generous initial init/wake-up-idle delay 90 | delay(5); 91 | // Configure the IRQ pin as INPUT. Required for correct interrupt setting for ESP8266 92 | pinMode(irq, INPUT); 93 | // start SPI 94 | SPI1.begin(); 95 | #ifndef ESP8266 96 | // SPI1.usingInterrupt(digitalPinToInterrupt(irq)); // not every board support this, e.g. ESP8266 97 | #endif 98 | // pin and basic member setup 99 | _rst = rst; 100 | _irq = irq; 101 | //_deviceMode = IDLE_MODE; 102 | // attach interrupt 103 | //attachInterrupt(_irq, DW1000Class::handleInterrupt, CHANGE); // todo interrupt for ESP8266 104 | // TODO throw error if pin is not a interrupt pin 105 | //attachInterrupt(digitalPinToInterrupt(_irq), DW1000Class::handleInterrupt, RISING); // todo interrupt for ESP8266 106 | } 107 | 108 | void reselect(uint8_t ss) { 109 | _ss = ss; 110 | pinMode(_ss, OUTPUT); 111 | digitalWrite(_ss, HIGH); 112 | } 113 | 114 | void readBytes(byte cmd, uint16_t offset, byte data[], uint16_t n) { 115 | byte header[3]; 116 | uint8_t headerLen = 1; 117 | uint16_t i = 0; 118 | 119 | // build SPI header 120 | if(offset == NO_SUB) { 121 | header[0] = READ | cmd; 122 | } else { 123 | header[0] = READ_SUB | cmd; 124 | if(offset < 128) { 125 | header[1] = (byte)offset; 126 | headerLen++; 127 | } else { 128 | header[1] = RW_SUB_EXT | (byte)offset; 129 | header[2] = (byte)(offset >> 7); 130 | headerLen += 2; 131 | } 132 | } 133 | SPI1.beginTransaction(*_currentSPI); 134 | digitalWrite(_ss, LOW); 135 | for(i = 0; i < headerLen; i++) { 136 | SPI1.transfer(header[i]); // send header 137 | } 138 | for(i = 0; i < n; i++) { 139 | data[i] = SPI1.transfer(JUNK); // read values 140 | } 141 | delayMicroseconds(5); 142 | digitalWrite(_ss, HIGH); 143 | SPI1.endTransaction(); 144 | } 145 | 146 | // always 4 bytes 147 | // TODO why always 4 bytes? can be different, see p. 58 table 10 otp memory map 148 | void readBytesOTP(uint16_t address, byte data[]) { 149 | byte addressBytes[LEN_OTP_ADDR]; 150 | 151 | // p60 - 6.3.3 Reading a value from OTP memory 152 | // bytes of address 153 | addressBytes[0] = (address & 0xFF); 154 | addressBytes[1] = ((address >> 8) & 0xFF); 155 | // set address 156 | writeBytes(OTP_IF, OTP_ADDR_SUB, addressBytes, LEN_OTP_ADDR); 157 | // switch into read mode 158 | writeByte(OTP_IF, OTP_CTRL_SUB, 0x03); // OTPRDEN | OTPREAD 159 | writeByte(OTP_IF, OTP_CTRL_SUB, 0x01); // OTPRDEN 160 | // read value/block - 4 bytes 161 | readBytes(OTP_IF, OTP_RDAT_SUB, data, LEN_OTP_RDAT); 162 | // end read mode 163 | writeByte(OTP_IF, OTP_CTRL_SUB, 0x00); 164 | } 165 | 166 | // Helper to set a single register 167 | void writeByte(byte cmd, uint16_t offset, byte data) { 168 | writeBytes(cmd, offset, &data, 1); 169 | } 170 | 171 | /* 172 | * Write bytes to the DW1000. Single bytes can be written to registers via sub-addressing. 173 | * @param cmd 174 | * The register address (see Chapter 7 in the DW1000 user manual). 175 | * @param offset 176 | * The offset to select register sub-parts for writing, or 0x00 to disable 177 | * sub-adressing. 178 | * @param data 179 | * The data array to be written. 180 | * @param data_size 181 | * The number of bytes to be written (take care not to go out of bounds of 182 | * the register). 183 | */ 184 | // TODO offset really bigger than byte? 185 | void writeBytes(byte cmd, uint16_t offset, byte data[], uint16_t data_size) { 186 | byte header[3]; 187 | uint8_t headerLen = 1; 188 | uint16_t i = 0; 189 | 190 | // TODO proper error handling: address out of bounds 191 | // build SPI header 192 | if(offset == NO_SUB) { 193 | header[0] = WRITE | cmd; 194 | } else { 195 | header[0] = WRITE_SUB | cmd; 196 | if(offset < 128) { 197 | header[1] = (byte)offset; 198 | headerLen++; 199 | } else { 200 | header[1] = RW_SUB_EXT | (byte)offset; 201 | header[2] = (byte)(offset >> 7); 202 | headerLen += 2; 203 | } 204 | } 205 | SPI1.beginTransaction(*_currentSPI); 206 | digitalWrite(_ss, LOW); 207 | for(i = 0; i < headerLen; i++) { 208 | SPI1.transfer(header[i]); // send header 209 | } 210 | for(i = 0; i < data_size; i++) { 211 | SPI1.transfer(data[i]); // write values 212 | } 213 | delayMicroseconds(5); 214 | digitalWrite(_ss, HIGH); 215 | SPI1.endTransaction(); 216 | } 217 | 218 | void enableClock(byte clock) { 219 | byte pmscctrl0[LEN_PMSC_CTRL0]; 220 | memset(pmscctrl0, 0, LEN_PMSC_CTRL0); 221 | readBytes(PMSC, PMSC_CTRL0_SUB, pmscctrl0, LEN_PMSC_CTRL0); 222 | if(clock == AUTO_CLOCK) { 223 | _currentSPI = &_fastSPI; 224 | pmscctrl0[0] = AUTO_CLOCK; 225 | pmscctrl0[1] &= 0xFE; 226 | } else if(clock == XTI_CLOCK) { 227 | _currentSPI = &_slowSPI; 228 | pmscctrl0[0] &= 0xFC; 229 | pmscctrl0[0] |= XTI_CLOCK; 230 | } else if(clock == PLL_CLOCK) { 231 | _currentSPI = &_fastSPI; 232 | pmscctrl0[0] &= 0xFC; 233 | pmscctrl0[0] |= PLL_CLOCK; 234 | } else { 235 | // TODO deliver proper warning 236 | } 237 | writeBytes(PMSC, PMSC_CTRL0_SUB, pmscctrl0, 2); 238 | } 239 | 240 | void reset() { 241 | if(_rst == 0xff) { 242 | softReset(); 243 | } else { 244 | // dw1000 data sheet v2.08 §5.6.1 page 20, the RSTn pin should not be driven high but left floating. 245 | pinMode(_rst, OUTPUT); 246 | digitalWrite(_rst, LOW); 247 | delay(2); // dw1000 data sheet v2.08 §5.6.1 page 20: nominal 50ns, to be safe take more time 248 | pinMode(_rst, INPUT); 249 | delay(10); // dwm1000 data sheet v1.2 page 5: nominal 3 ms, to be safe take more time 250 | // force into idle mode (although it should be already after reset) 251 | idle(); 252 | } 253 | } 254 | 255 | void softReset() { 256 | byte pmscctrl0[LEN_PMSC_CTRL0]; 257 | readBytes(PMSC, PMSC_CTRL0_SUB, pmscctrl0, LEN_PMSC_CTRL0); 258 | pmscctrl0[0] = 0x01; 259 | writeBytes(PMSC, PMSC_CTRL0_SUB, pmscctrl0, LEN_PMSC_CTRL0); 260 | pmscctrl0[3] = 0x00; 261 | writeBytes(PMSC, PMSC_CTRL0_SUB, pmscctrl0, LEN_PMSC_CTRL0); 262 | delay(10); 263 | pmscctrl0[0] = 0x00; 264 | pmscctrl0[3] = 0xF0; 265 | writeBytes(PMSC, PMSC_CTRL0_SUB, pmscctrl0, LEN_PMSC_CTRL0); 266 | // force into idle mode 267 | idle(); 268 | } 269 | 270 | void setBit(byte data[], uint16_t n, uint16_t bit, boolean val) { 271 | uint16_t idx; 272 | uint8_t shift; 273 | 274 | idx = bit/8; 275 | if(idx >= n) { 276 | return; // TODO proper error handling: out of bounds 277 | } 278 | byte* targetByte = &data[idx]; 279 | shift = bit%8; 280 | if(val) { 281 | bitSet(*targetByte, shift); 282 | } else { 283 | bitClear(*targetByte, shift); 284 | } 285 | } 286 | 287 | /* 288 | * Check the value of a bit in an array of bytes that are considered 289 | * consecutive and stored from MSB to LSB. 290 | * @param data 291 | * The number as byte array. 292 | * @param n 293 | * The number of bytes in the array. 294 | * @param bit 295 | * The position of the bit to be checked. 296 | */ 297 | boolean getBit(byte data[], uint16_t n, uint16_t bit) { 298 | uint16_t idx; 299 | uint8_t shift; 300 | 301 | idx = bit/8; 302 | if(idx >= n) { 303 | return false; // TODO proper error handling: out of bounds 304 | } 305 | byte targetByte = data[idx]; 306 | shift = bit%8; 307 | 308 | return bitRead(targetByte, shift); // TODO wrong type returned byte instead of boolean 309 | } 310 | 311 | void writeValueToBytes(byte data[], int32_t val, uint16_t n) { 312 | uint16_t i; 313 | for(i = 0; i < n; i++) { 314 | data[i] = ((val >> (i*8)) & 0xFF); // TODO bad types - signed unsigned problem 315 | } 316 | } 317 | 318 | void readSystemConfigurationRegister() { 319 | readBytes(SYS_CFG, NO_SUB, _syscfg, LEN_SYS_CFG); 320 | } 321 | 322 | void writeSystemConfigurationRegister() { 323 | writeBytes(SYS_CFG, NO_SUB, _syscfg, LEN_SYS_CFG); 324 | } 325 | 326 | void readSystemEventStatusRegister() { 327 | readBytes(SYS_STATUS, NO_SUB, _sysstatus, LEN_SYS_STATUS); 328 | } 329 | 330 | void readNetworkIdAndDeviceAddress() { 331 | readBytes(PANADR, NO_SUB, _networkAndAddress, LEN_PANADR); 332 | } 333 | 334 | void writeNetworkIdAndDeviceAddress() { 335 | writeBytes(PANADR, NO_SUB, _networkAndAddress, LEN_PANADR); 336 | } 337 | 338 | void readSystemEventMaskRegister() { 339 | readBytes(SYS_MASK, NO_SUB, _sysmask, LEN_SYS_MASK); 340 | } 341 | 342 | void writeSystemEventMaskRegister() { 343 | writeBytes(SYS_MASK, NO_SUB, _sysmask, LEN_SYS_MASK); 344 | } 345 | 346 | void readChannelControlRegister() { 347 | readBytes(CHAN_CTRL, NO_SUB, _chanctrl, LEN_CHAN_CTRL); 348 | } 349 | 350 | void writeChannelControlRegister() { 351 | writeBytes(CHAN_CTRL, NO_SUB, _chanctrl, LEN_CHAN_CTRL); 352 | } 353 | 354 | void readTransmitFrameControlRegister() { 355 | readBytes(TX_FCTRL, NO_SUB, _txfctrl, LEN_TX_FCTRL); 356 | } 357 | 358 | void writeTransmitFrameControlRegister() { 359 | writeBytes(TX_FCTRL, NO_SUB, _txfctrl, LEN_TX_FCTRL); 360 | } 361 | 362 | void idle() { 363 | memset(_sysctrl, 0, LEN_SYS_CTRL); 364 | setBit(_sysctrl, LEN_SYS_CTRL, TRXOFF_BIT, true); 365 | _deviceMode = IDLE_MODE; 366 | writeBytes(SYS_CTRL, NO_SUB, _sysctrl, LEN_SYS_CTRL); 367 | } 368 | 369 | void setDoubleBuffering(boolean val) { 370 | setBit(_syscfg, LEN_SYS_CFG, DIS_DRXB_BIT, !val); 371 | } 372 | 373 | void setInterruptPolarity(boolean val) { 374 | setBit(_syscfg, LEN_SYS_CFG, HIRQ_POL_BIT, val); 375 | } 376 | 377 | void clearInterrupts() { 378 | memset(_sysmask, 0, LEN_SYS_MASK); 379 | } 380 | 381 | void manageLDE() { 382 | // transfer any ldo tune values 383 | byte ldoTune[LEN_OTP_RDAT]; 384 | readBytesOTP(0x04, ldoTune); // TODO #define 385 | if(ldoTune[0] != 0) { 386 | // TODO tuning available, copy over to RAM: use OTP_LDO bit 387 | } 388 | // tell the chip to load the LDE microcode 389 | // TODO remove clock-related code (PMSC_CTRL) as handled separately 390 | byte pmscctrl0[LEN_PMSC_CTRL0]; 391 | byte otpctrl[LEN_OTP_CTRL]; 392 | memset(pmscctrl0, 0, LEN_PMSC_CTRL0); 393 | memset(otpctrl, 0, LEN_OTP_CTRL); 394 | readBytes(PMSC, PMSC_CTRL0_SUB, pmscctrl0, LEN_PMSC_CTRL0); 395 | readBytes(OTP_IF, OTP_CTRL_SUB, otpctrl, LEN_OTP_CTRL); 396 | pmscctrl0[0] = 0x01; 397 | pmscctrl0[1] = 0x03; 398 | otpctrl[0] = 0x00; 399 | otpctrl[1] = 0x80; 400 | writeBytes(PMSC, PMSC_CTRL0_SUB, pmscctrl0, 2); 401 | writeBytes(OTP_IF, OTP_CTRL_SUB, otpctrl, 2); 402 | delay(5); 403 | pmscctrl0[0] = 0x00; 404 | pmscctrl0[1] &= 0x02; 405 | writeBytes(PMSC, PMSC_CTRL0_SUB, pmscctrl0, 2); 406 | } 407 | 408 | void Sleep(uint32_t d) { 409 | delay(d); 410 | } 411 | 412 | void spiSelect(uint8_t ss) { 413 | reselect(ss); 414 | // try locking clock at PLL speed (should be done already, 415 | // but just to be sure) 416 | enableClock(AUTO_CLOCK); 417 | delay(5); 418 | // reset chip (either soft or hard) 419 | if(_rst != 0xff) { 420 | // dw1000 data sheet v2.08 §5.6.1 page 20, the RSTn pin should not be driven high but left floating. 421 | pinMode(_rst, INPUT); 422 | } 423 | reset(); 424 | // default network and node id 425 | writeValueToBytes(_networkAndAddress, 0xFF, LEN_PANADR); 426 | writeNetworkIdAndDeviceAddress(); 427 | // default system configuration 428 | memset(_syscfg, 0, LEN_SYS_CFG); 429 | setDoubleBuffering(false); 430 | setInterruptPolarity(true); 431 | writeSystemConfigurationRegister(); 432 | // default interrupt mask, i.e. no interrupts 433 | clearInterrupts(); 434 | writeSystemEventMaskRegister(); 435 | // load LDE micro-code 436 | enableClock(XTI_CLOCK); 437 | delay(5); 438 | manageLDE(); 439 | delay(5); 440 | enableClock(AUTO_CLOCK); 441 | delay(5); 442 | 443 | // read the temp and vbat readings from OTP that were recorded during production test 444 | // see 6.3.1 OTP memory map 445 | byte buf_otp[4]; 446 | readBytesOTP(0x008, buf_otp); // the stored 3.3 V reading 447 | _vmeas3v3 = buf_otp[0]; 448 | readBytesOTP(0x009, buf_otp); // the stored 23C reading 449 | _tmeas23C = buf_otp[0]; 450 | } 451 | 452 | 453 | int readfromspi(uint16_t headerLength, uint8_t *headerBuffer, uint16_t readLength, uint8_t *readBuffer) 454 | { 455 | 456 | SPI1.beginTransaction(*_currentSPI); 457 | digitalWrite(_ss, LOW); 458 | for(int i = 0; i < headerLength; i++) { 459 | SPI1.transfer(headerBuffer[i]); // send header 460 | } 461 | for(int i = 0; i < readLength; i++) { 462 | readBuffer[i] = SPI1.transfer(JUNK); // read values 463 | } 464 | delayMicroseconds(5); 465 | digitalWrite(_ss, HIGH); 466 | SPI1.endTransaction(); 467 | 468 | /*open_spi(); // we first open the SPI line by setting it to low 469 | for(int i=0; i wrote this file. As long as you retain this notice you 13 | * can do whatever you want with this stuff. If we meet some day, and you think 14 | * this stuff is worth it, you can buy me a beer in return - Pontus Oldberg 15 | * ---------------------------------------------------------------------------- 16 | */ 17 | 18 | #include "dw3000.h" 19 | 20 | #define APP_NAME "SS TWR RESP STS NO DATA v1.0" 21 | 22 | /* Inter-ranging delay period, in milliseconds. */ 23 | #define RNG_DELAY_MS 1000 24 | 25 | /* Default antenna delay values for 64 MHz PRF. See NOTE 2 below. */ 26 | #define TX_ANT_DLY 16385 27 | #define RX_ANT_DLY 16385 28 | 29 | /* Frames used in the ranging process. See NOTE 3 below. */ 30 | static uint8_t tx_report_msg[] = {0x41, 0x88, 0, 0xCA, 0xDE, 'V', 'E', 'W', 'A', 0xE1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 31 | 32 | /* Length of the common part of the frame (up to and including the function code, see NOTE 3 below). */ 33 | #define ALL_MSG_COMMON_LEN 10 34 | /* Index to access some of the fields in the frames involved in the process. */ 35 | #define ALL_MSG_SN_IDX 2 36 | #define REPORT_MSG_POLL_RX_TS_IDX 10 37 | #define REPORT_MSG_RESP_TX_TS_IDX 14 38 | /* Frame sequence number, incremented after each transmission. */ 39 | static uint8_t frame_seq_nb = 0; 40 | 41 | /* Hold copy of status register state here for reference so that it can be examined at a debug breakpoint. */ 42 | static uint32_t status_reg = 0; 43 | 44 | /* Delay between frames, in UWB microseconds. See NOTE 1 below. */ 45 | #define POLL_RX_TO_RESP_TX_DLY_UUS (550 + CPU_COMP) 46 | 47 | /* Timestamps of frames transmission/reception. */ 48 | static uint64_t poll_rx_ts; 49 | static uint64_t resp_tx_ts; 50 | 51 | /* Hold the amount of errors that have occurred */ 52 | static uint32_t errors[23] = {0}; 53 | 54 | extern dwt_config_t config_option_sp3; 55 | extern dwt_config_t config_option_sp0; 56 | 57 | /* Externally declared structures for TX configuration. */ 58 | extern dwt_txconfig_t txconfig_options; 59 | extern dwt_txconfig_t txconfig_options_ch9; 60 | 61 | /* 62 | * 128-bit STS key to be programmed into CP_KEY register. 63 | * 64 | * This key needs to be known and programmed the same at both units performing the SS-TWR. 65 | * In a real application for security this would be private and unique to the two communicating units 66 | * and chosen/assigned in a secure manner lasting just for the period of their association. 67 | * 68 | * Here we use a default KEY as specified in the IEEE 802.15.4z annex 69 | */ 70 | static dwt_sts_cp_key_t cp_key = 71 | { 72 | 0x14EB220F,0xF86050A8,0xD1D336AA,0x14148674 73 | }; 74 | 75 | /* 76 | * 128-bit initial value for the nonce to be programmed into the CP_IV register. 77 | * 78 | * The IV, like the key, needs to be known and programmed the same at both units performing the SS-TWR. 79 | * It can be considered as an extension of the KEY. The low 32 bits of the IV is the counter. 80 | * In a real application for any particular key the value of the IV including the count should not be reused, 81 | * i.e. if the counter value wraps the upper 96-bits of the IV should be changed, e.g. incremented. 82 | * 83 | * Here we use a default IV as specified in the IEEE 802.15.4z annex 84 | */ 85 | static dwt_sts_cp_iv_t cp_iv = 86 | { 87 | 0x1F9A3DE4,0xD37EC3CA,0xC44FA8FB,0x362EEB34 88 | }; 89 | 90 | 91 | int16_t stsQual; /* This will contain STS quality index and status */ 92 | int goodSts = 0; /* Used for checking STS quality in received signal */ 93 | uint8_t firstLoopFlag = 0; 94 | 95 | 96 | void setup() { 97 | while (!Serial) 98 | delay(100); 99 | 100 | Serial.begin(115200); 101 | Serial.println(APP_NAME); 102 | 103 | /* Start SPI and get stuff going*/ 104 | spiBegin(); 105 | spiSelect(); 106 | 107 | delay(200); // Time needed for DW3000 to start up (transition from INIT_RC to IDLE_RC, or could wait for SPIRDY event) 108 | 109 | while (!dwt_checkidlerc()) // Need to make sure DW IC is in IDLE_RC before proceeding 110 | { 111 | Serial.print("IDLE FAILED\r\n"); 112 | while (1) ; 113 | } 114 | 115 | if (dwt_initialise(DWT_DW_INIT) == DWT_ERROR) 116 | { 117 | Serial.print("INIT FAILED\r\n"); 118 | while (1) ; 119 | } 120 | 121 | /* Enabling LEDs here for debug so that for each TX the D1 LED will flash on DW3000 red eval-shield boards. 122 | * Note, in real low power applications the LEDs should not be used. */ 123 | dwt_setleds(DWT_LEDS_ENABLE | DWT_LEDS_INIT_BLINK) ; 124 | 125 | /* Apply default antenna delay value. See NOTE 2 below. */ 126 | dwt_setrxantennadelay(RX_ANT_DLY); 127 | dwt_settxantennadelay(TX_ANT_DLY); 128 | 129 | /* Next can enable TX/RX states output on GPIOs 5 and 6 to help diagnostics, and also TX/RX LEDs */ 130 | dwt_setlnapamode(DWT_LNA_ENABLE | DWT_PA_ENABLE); 131 | 132 | /* Configure DW IC. See NOTE 12 below. */ 133 | if(dwt_configure(&config_option_sp3)) /* if the dwt_configure returns DWT_ERROR either the PLL or RX calibration has failed the host should reset the device */ 134 | { 135 | Serial.println("CONFIG FAILED"); 136 | while (1) 137 | { }; 138 | } 139 | 140 | /* Configure the TX spectrum parameters (power, PG delay and PG count) */ 141 | if(config_option_sp3.chan == 5) 142 | { 143 | dwt_configuretxrf(&txconfig_options); 144 | } 145 | else 146 | { 147 | dwt_configuretxrf(&txconfig_options_ch9); 148 | } 149 | } 150 | 151 | void loop() { 152 | dwt_configurestsmode(DWT_STS_MODE_ND); 153 | /* 154 | * Set CP encryption key and IV (nonce). 155 | * See Note 11 below. 156 | */ 157 | if (!firstLoopFlag) 158 | { 159 | /* 160 | * On first loop, configure the STS key & IV, then load them. 161 | */ 162 | dwt_configurestskey(&cp_key); 163 | dwt_configurestsiv(&cp_iv); 164 | dwt_configurestsloadiv(); 165 | firstLoopFlag = 1; 166 | } 167 | else 168 | { 169 | /* 170 | * On subsequent loops, we only need to reload the lower 32 bits of STS IV. 171 | */ 172 | dwt_writetodevice(STS_IV0_ID, 0, 4, (uint8_t *)&cp_iv); 173 | dwt_configurestsloadiv(); 174 | } 175 | 176 | /* Activate reception immediately. */ 177 | dwt_rxenable(DWT_START_RX_IMMEDIATE); 178 | 179 | /* Poll for reception of a packet or error/timeout. See NOTE 5 below. */ 180 | /* STS Mode 3 packets are polled for differently than STS Mode 0 frames */ 181 | while (!((status_reg = dwt_read32bitreg(SYS_STATUS_ID)) & (SYS_STATUS_RXFR_BIT_MASK | SYS_STATUS_ALL_RX_TO | SYS_STATUS_ALL_ND_RX_ERR))) 182 | { }; 183 | 184 | /* 185 | * Need to check the STS has been received and is good. 186 | */ 187 | goodSts = dwt_readstsquality(&stsQual); 188 | 189 | /* 190 | * At this point of the program, we are expecting the POLL packet to be received. 191 | * Since the POLL packet will have no PHY payload (i.e. no data in the packet), we only check 192 | * to see if the packet has been received correctly and the quality of the STS is good. 193 | * When using No Data STS mode we do not get RXFCG but RXFR 194 | */ 195 | if (status_reg & SYS_STATUS_RXFR_BIT_MASK) 196 | { 197 | /* 198 | * Checking for the SP3 mode POLL packet 199 | */ 200 | if (goodSts >= 0) 201 | { 202 | uint32_t resp_tx_time, report_tx_time; 203 | int ret; 204 | 205 | /* Retrieve poll reception timestamp. */ 206 | poll_rx_ts = get_rx_timestamp_u64(); 207 | 208 | /* Calculate the required delay time before sending the RESP packet. */ 209 | resp_tx_time = (poll_rx_ts /* Received timestamp value */ 210 | + ((POLL_RX_TO_RESP_TX_DLY_UUS /* Set delay time */ 211 | + get_rx_delay_time_data_rate() /* Added delay time for data rate set */ 212 | + get_rx_delay_time_txpreamble() /* Added delay for TX preamble length */ 213 | + ((1<<(config_option_sp3.stsLength+2))*8)) /* Added delay for STS length */ 214 | * UUS_TO_DWT_TIME)) >> 8; /* Converted to time units for chip */ 215 | dwt_setdelayedtrxtime(resp_tx_time); 216 | 217 | /* Response TX timestamp is the transmission time we programmed plus the antenna delay. */ 218 | resp_tx_ts = (((uint64_t)(resp_tx_time & 0xFFFFFFFEUL)) << 8) + TX_ANT_DLY; 219 | 220 | /* Send the SP3 RESP packet. */ 221 | dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_TXFRS_BIT_MASK); 222 | dwt_writetxfctrl(0, 0, 1); /* Zero offset in TX buffer, ranging. */ 223 | ret = dwt_starttx(DWT_START_TX_DELAYED); 224 | 225 | /* If dwt_starttx() returns an error, abandon this ranging exchange and proceed to the next one. See NOTE 9 & 10 below. */ 226 | if (ret == DWT_SUCCESS) 227 | { 228 | /* Poll DW IC until TX packet sent event set. See NOTE 5 below. */ 229 | while (!(dwt_read32bitreg(SYS_STATUS_ID) & SYS_STATUS_TXFRS_BIT_MASK)) 230 | { }; 231 | 232 | /* Clear TXFRS event. */ 233 | dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_TXFRS_BIT_MASK); 234 | 235 | 236 | /* 237 | * Now reconfigure device to SP0 mode and send REPORT frame 238 | */ 239 | /* Configure DW IC. See NOTE 12 below. */ 240 | dwt_configurestsmode(DWT_STS_MODE_OFF); 241 | 242 | /* Set the delay to be twice the previous time period with respect to the RX timestamp of the POLL packet. */ 243 | report_tx_time = (poll_rx_ts /* Received timestamp value */ 244 | + ((((POLL_RX_TO_RESP_TX_DLY_UUS) * 2) /* Set delay time */ 245 | + (get_rx_delay_time_data_rate() * 2) /* Added delay time for data rate set */ 246 | + (get_rx_delay_time_txpreamble() * 2) /* Added delay for TX preamble length */ 247 | + (((1<<(config_option_sp3.stsLength+2))*8)) * 2) /* Added delay for STS length */ 248 | * UUS_TO_DWT_TIME)) >> 8; /* Converted to time units for chip */ 249 | dwt_setdelayedtrxtime(report_tx_time); 250 | 251 | /* Write all timestamps in the report frame. See NOTE 6 & 7 below. */ 252 | resp_msg_set_ts(&tx_report_msg[REPORT_MSG_POLL_RX_TS_IDX], poll_rx_ts); 253 | resp_msg_set_ts(&tx_report_msg[REPORT_MSG_RESP_TX_TS_IDX], resp_tx_ts); 254 | 255 | /* Write and send the response frame. See NOTE 8 below. */ 256 | tx_report_msg[ALL_MSG_SN_IDX] = frame_seq_nb; 257 | 258 | dwt_writetxdata(sizeof(tx_report_msg), tx_report_msg, 0); /* Zero offset in TX buffer. */ 259 | dwt_writetxfctrl(sizeof(tx_report_msg), 0, 0); /* Zero offset in TX buffer, not ranging. */ 260 | ret = dwt_starttx(DWT_START_TX_DELAYED); 261 | 262 | /* If dwt_starttx() returns an error, abandon this ranging exchange and proceed to the next one. See NOTE 9 & 10 below. */ 263 | if (ret == DWT_SUCCESS) 264 | { 265 | /* Poll DW IC until TX frame sent event set. See NOTE 5 below. */ 266 | while (!(dwt_read32bitreg(SYS_STATUS_ID) & SYS_STATUS_TXFRS_BIT_MASK)) 267 | { }; 268 | 269 | /* Clear TXFRS event. */ 270 | dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_TXFRS_BIT_MASK); 271 | 272 | /* Increment frame sequence number after transmission of the report frame (modulo 256). */ 273 | frame_seq_nb++; 274 | } 275 | } 276 | else 277 | { 278 | // Delayed TX has failed - too "late" 279 | } 280 | } 281 | else 282 | { 283 | errors[PREAMBLE_COUNT_ERR_IDX] += 1; 284 | /* Clear RX error events in the DW IC status register. */ 285 | dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_ALL_RX_ERR); 286 | } 287 | } 288 | else 289 | { 290 | check_for_status_errors(status_reg, errors); 291 | 292 | if (goodSts < 0) 293 | { 294 | errors[PREAMBLE_COUNT_ERR_IDX] += 1; 295 | } 296 | if (stsQual <= 0) 297 | { 298 | errors[CP_QUAL_ERR_IDX] += 1; 299 | } 300 | /* Clear RX error events in the DW IC status register. */ 301 | dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_ALL_RX_ERR); 302 | } 303 | } 304 | 305 | /***************************************************************************************************************************************************** 306 | * NOTES: 307 | * 308 | * 1. The single-sided two-way ranging scheme implemented here has to be considered carefully as the accuracy of the distance measured is highly 309 | * sensitive to the clock offset error between the devices and the length of the response delay between packets. To achieve the best possible 310 | * accuracy, this response delay must be kept as low as possible. In order to do so, 6.8 Mbps data rate is advised in this example and the response 311 | * delay between packets is defined as low as possible. The user is referred to User Manual for more details about the single-sided two-way ranging 312 | * process. 313 | * 314 | * Initiator: |Poll TX| ..... |Resp RX| 315 | * Responder: |Poll RX| ..... |Resp TX| 316 | * ^|P RMARKER| - time of Poll TX/RX 317 | * ^|R RMARKER| - time of Resp TX/RX 318 | * 319 | * <--TDLY-> - POLL_TX_TO_RESP_RX_DLY_UUS (RDLY-RLEN) 320 | * <-RLEN-> - RESP_RX_TIMEOUT_UUS (length of response packet) 321 | * <----RDLY------> - POLL_RX_TO_RESP_TX_DLY_UUS (depends on how quickly responder can turn around and reply) 322 | * 323 | * 324 | * 2. The sum of the values is the TX to RX antenna delay, experimentally determined by a calibration process. Here we use a hard coded typical value 325 | * but, in a real application, each device should have its own antenna delay properly calibrated to get the best possible precision when performing 326 | * range measurements. 327 | * 3. The frames used here are Decawave specific frames, complying with the IEEE 802.15.4 standard data frame encoding. The frames are the 328 | * following: 329 | * - a report frame sent by the responder to complete the exchange and provide all information needed by the initiator to compute the 330 | * time-of-flight (distance) estimate. 331 | * The first 10 bytes of those frames are common and are composed of the following fields: 332 | * - byte 0/1: frame control (0x8841 to indicate a data frame using 16-bit addressing). 333 | * - byte 2: sequence number, incremented for each new frame. 334 | * - byte 3/4: PAN ID (0xDECA). 335 | * - byte 5/6: destination address, see NOTE 4 below. 336 | * - byte 7/8: source address, see NOTE 4 below. 337 | * - byte 9: function code (specific values to indicate which frame it is in the ranging process). 338 | * The remaining bytes are specific to each frame as follows: 339 | * Report frame: 340 | * - byte 10 -> 13: poll frame reception timestamp. 341 | * - byte 14 -> 17: response frame transmission timestamp. 342 | * All frames (apart from the STS Mode 3 packets) end with a 2-byte checksum automatically set by DW IC. 343 | * 4. Source and destination addresses are hard coded constants in this example to keep it simple but for a real product every device should have a 344 | * unique ID. Here, 16-bit addressing is used to keep the frames as short as possible but, in an actual application, this should be done only 345 | * after an exchange of specific frames used to define those short addresses for each device participating to the ranging exchange. 346 | * 5. We use polled mode of operation here to keep the example as simple as possible but all status events can be used to generate interrupts. Please 347 | * refer to DW IC User Manual for more details on "interrupts". It is also to be noted that STATUS register is 5 bytes long but, as the event we 348 | * use are all in the first bytes of the register, we can use the simple dwt_read32bitreg() API call to access it instead of reading the whole 5 349 | * bytes. 350 | * 6. As we want to send final TX timestamp in the final frame, we have to compute it in advance instead of relying on the reading of DW IC 351 | * register. Timestamps and delayed transmission time are both expressed in device time units so we just have to add the desired response delay to 352 | * response RX timestamp to get final transmission time. The delayed transmission time resolution is 512 device time units which means that the 353 | * lower 9 bits of the obtained value must be zeroed. This also allows to encode the 40-bit value in a 32-bit words by shifting the all-zero lower 354 | * 8 bits. 355 | * 7. In this operation, the high order byte of each 40-bit timestamps is discarded. This is acceptable as those time-stamps are not separated by 356 | * more than 2**32 device time units (which is around 67 ms) which means that the calculation of the round-trip delays (needed in the 357 | * time-of-flight computation) can be handled by a 32-bit subtraction. 358 | * 8. dwt_writetxdata() takes the full size of the frame as a parameter but only copies (size - 2) bytes as the check-sum at the end of the frame is 359 | * automatically appended by the DW IC. This means that our variable could be two bytes shorter without losing any data (but the sizeof would not 360 | * work anymore then as we would still have to indicate the full length of the frame to dwt_writetxdata()). 361 | * 9. When running this example on the DW3000 platform with the POLL_RX_TO_RESP_TX_DLY response delay provided, the dwt_starttx() is always 362 | * successful. However, in cases where the delay is too short (or something else interrupts the code flow), then the dwt_starttx() might be issued 363 | * too late for the configured start time. The code below provides an example of how to handle this condition: In this case it abandons the 364 | * ranging exchange and simply goes back to awaiting another poll packet. If this error handling code was not here, a late dwt_starttx() would 365 | * result in the code flow getting stuck waiting subsequent RX event that will will never come. The companion "initiator" example (ex_06a) should 366 | * timeout from awaiting the "response" and proceed to send another poll in due course to initiate another ranging exchange. 367 | * 10. The user is referred to DecaRanging ARM application (distributed with DW3000 product) for additional practical example of usage, and to the 368 | * DW IC API Guide for more details on the DW IC driver functions. 369 | * 11. This example will set the STS key and IV upon each iteration of the main while loop. While this has the benefit of keeping the STS count in 370 | * sync with the responder device (which does the same), it should be noted that this is not a 'secure' implementation as the count is reset upon 371 | * each iteration of the loop. An attacker could potentially recognise this pattern if the signal was being monitored. While it serves it's 372 | * purpose in this simple example, it should not be utilised in any final solution. 373 | * 12. Desired configuration by user may be different to the current programmed configuration. dwt_configure is called to set desired 374 | * configuration. 375 | ****************************************************************************************************************************************************/ 376 | -------------------------------------------------------------------------------- /examples/ex_06b_ss_twr_responder_sts/ex_06b_ss_twr_responder_sts.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * _ _ _ 4 | * (_) | | | 5 | * _| | __ _| |__ ___ 6 | * | | | / _` | '_ \/ __| 7 | * | | |___| (_| | |_) \__ \ 8 | * |_|______\__,_|_.__/|___/ 9 | * 10 | * ---------------------------------------------------------------------------- 11 | * "THE BEER-WARE LICENSE" (Revision 42): 12 | * wrote this file. As long as you retain this notice you 13 | * can do whatever you want with this stuff. If we meet some day, and you think 14 | * this stuff is worth it, you can buy me a beer in return - Pontus Oldberg 15 | * ---------------------------------------------------------------------------- 16 | */ 17 | 18 | #include "dw3000.h" 19 | 20 | #define APP_NAME "SS TWR RESP STS v1.0" 21 | 22 | /* Inter-ranging delay period, in milliseconds. */ 23 | #define RNG_DELAY_MS 1000 24 | 25 | /* Default antenna delay values for 64 MHz PRF. See NOTE 2 below. */ 26 | #define TX_ANT_DLY 16385 27 | #define RX_ANT_DLY 16385 28 | 29 | /* Frames used in the ranging process. See NOTE 3 below. */ 30 | static uint8_t rx_poll_msg[] = {0x41, 0x88, 0, 0xCA, 0xDE, 'W', 'A', 'V', 'E', 0xE0, 0, 0}; 31 | static uint8_t tx_resp_msg[] = {0x41, 0x88, 0, 0xCA, 0xDE, 'V', 'E', 'W', 'A', 0xE1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 32 | 33 | /* Length of the common part of the message (up to and including the function code, see NOTE 3 below). */ 34 | #define ALL_MSG_COMMON_LEN 10 35 | /* Index to access some of the fields in the frames involved in the process. */ 36 | #define ALL_MSG_SN_IDX 2 37 | #define RESP_MSG_POLL_RX_TS_IDX 10 38 | #define RESP_MSG_RESP_TX_TS_IDX 14 39 | #define RESP_MSG_STS_COUNT_IDX 18 40 | /* Frame sequence number, incremented after each transmission. */ 41 | static uint8_t frame_seq_nb = 0; 42 | 43 | /* Buffer to store received messages. 44 | * Its size is adjusted to longest frame that this example code is supposed to handle. */ 45 | #define RX_BUF_LEN 24//Must be less than FRAME_LEN_MAX_EX 46 | static uint8_t rx_buffer[RX_BUF_LEN]; 47 | 48 | /* Hold copy of status register state here for reference so that it can be examined at a debug breakpoint. */ 49 | static uint32_t status_reg = 0; 50 | 51 | /* Delay between frames, in UWB microseconds. See NOTE 1 below. */ 52 | #define POLL_RX_TO_RESP_TX_DLY_UUS (450 + CPU_COMP) 53 | 54 | /* Timestamps of frames transmission/reception. */ 55 | static uint64_t poll_rx_ts; 56 | static uint64_t resp_tx_ts; 57 | 58 | /* Hold the amount of errors that have occurred */ 59 | static uint32_t errors[23] = {0}; 60 | 61 | extern dwt_config_t config_options; 62 | extern dwt_txconfig_t txconfig_options; 63 | extern dwt_txconfig_t txconfig_options_ch9; 64 | 65 | /* 66 | * 128-bit STS key to be programmed into CP_KEY register. 67 | * 68 | * This key needs to be known and programmed the same at both units performing the SS-TWR. 69 | * In a real application for security this would be private and unique to the two communicating units 70 | * and chosen/assigned in a secure manner lasting just for the period of their association. 71 | * 72 | * Here we use a default KEY as specified in the IEEE 802.15.4z annex 73 | */ 74 | static dwt_sts_cp_key_t cp_key = 75 | { 76 | 0x14EB220F,0xF86050A8,0xD1D336AA,0x14148674 77 | }; 78 | 79 | /* 80 | * 128-bit initial value for the nonce to be programmed into the CP_IV register. 81 | * 82 | * The IV, like the key, needs to be known and programmed the same at both units performing the SS-TWR. 83 | * It can be considered as an extension of the KEY. The low 32 bits of the IV is the counter. 84 | * In a real application for any particular key the value of the IV including the count should not be reused, 85 | * i.e. if the counter value wraps the upper 96-bits of the IV should be changed, e.g. incremented. 86 | * 87 | * Here we use a default IV as specified in the IEEE 802.15.4z annex 88 | */ 89 | static dwt_sts_cp_iv_t cp_iv = 90 | { 91 | 0x1F9A3DE4,0xD37EC3CA,0xC44FA8FB,0x362EEB34 92 | }; 93 | 94 | 95 | int16_t stsQual; /* This will contain STS quality index and status */ 96 | int goodSts = 0; /* Used for checking STS quality in received signal */ 97 | uint8_t firstLoopFlag = 0; /* Used to track if the program has gone through the first loop or not. */ 98 | 99 | 100 | void setup() { 101 | while (!Serial) 102 | delay(100); 103 | 104 | Serial.begin(115200); 105 | Serial.println(APP_NAME); 106 | 107 | /* Start SPI and get stuff going*/ 108 | spiBegin(); 109 | spiSelect(); 110 | 111 | delay(200); // Time needed for DW3000 to start up (transition from INIT_RC to IDLE_RC, or could wait for SPIRDY event) 112 | 113 | while (!dwt_checkidlerc()) // Need to make sure DW IC is in IDLE_RC before proceeding 114 | { 115 | Serial.print("IDLE FAILED\r\n"); 116 | while (1) ; 117 | } 118 | 119 | if (dwt_initialise(DWT_DW_INIT) == DWT_ERROR) 120 | { 121 | Serial.print("INIT FAILED\r\n"); 122 | while (1) ; 123 | } 124 | 125 | // Enabling LEDs here for debug so that for each TX the D1 LED will flash on DW3000 red eval-shield boards. 126 | dwt_setleds(DWT_LEDS_ENABLE | DWT_LEDS_INIT_BLINK); 127 | 128 | /* Configure DW IC. See NOTE 14 below. */ 129 | if(dwt_configure(&config_options)) /* if the dwt_configure returns DWT_ERROR either the PLL or RX calibration has failed the host should reset the device */ 130 | { 131 | Serial.println("CONFIG FAILED"); 132 | while (1) 133 | { }; 134 | } 135 | 136 | /* Configure the TX spectrum parameters (power, PG delay and PG count) */ 137 | if(config_options.chan == 5) 138 | { 139 | dwt_configuretxrf(&txconfig_options); 140 | } 141 | else 142 | { 143 | dwt_configuretxrf(&txconfig_options_ch9); 144 | } 145 | 146 | /* Apply default antenna delay value. See NOTE 2 below. */ 147 | dwt_setrxantennadelay(RX_ANT_DLY); 148 | dwt_settxantennadelay(TX_ANT_DLY); 149 | 150 | /* Next can enable TX/RX states output on GPIOs 5 and 6 to help diagnostics, and also TX/RX LEDs */ 151 | dwt_setlnapamode(DWT_LNA_ENABLE | DWT_PA_ENABLE); 152 | } 153 | 154 | void loop() { 155 | /* 156 | * Set STS encryption key and IV (nonce). 157 | * See NOTE 15 below. 158 | */ 159 | if (!firstLoopFlag) 160 | { 161 | /* 162 | * On first loop, configure the STS key & IV, then load them. 163 | */ 164 | dwt_configurestskey(&cp_key); 165 | dwt_configurestsiv(&cp_iv); 166 | dwt_configurestsloadiv(); 167 | firstLoopFlag = 1; 168 | } 169 | else 170 | { 171 | /* 172 | * On subsequent loops, we only need to reload the lower 32 bits of STS IV. 173 | */ 174 | dwt_writetodevice(STS_IV0_ID, 0, 4, (uint8_t *)&cp_iv); 175 | dwt_configurestsloadiv(); 176 | } 177 | 178 | /* Activate reception immediately. */ 179 | dwt_rxenable(DWT_START_RX_IMMEDIATE); 180 | 181 | /* Poll for reception of a frame or error/timeout. See NOTE 6 below. */ 182 | while (!((status_reg = dwt_read32bitreg(SYS_STATUS_ID)) & (SYS_STATUS_RXFCG_BIT_MASK | SYS_STATUS_ALL_RX_TO | SYS_STATUS_ALL_RX_ERR))) 183 | { }; 184 | 185 | /* 186 | * Need to check the STS has been received and is good. 187 | */ 188 | goodSts = dwt_readstsquality(&stsQual); 189 | 190 | /* 191 | * Check for a good frame with good STS count. 192 | */ 193 | if ((status_reg & SYS_STATUS_RXFCG_BIT_MASK) && (goodSts >= 0)) 194 | { 195 | uint32_t frame_len; 196 | 197 | /* Clear good RX frame event in the DW IC status register. */ 198 | dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_RXFCG_BIT_MASK); 199 | 200 | /* A frame has been received, read it into the local buffer. */ 201 | frame_len = dwt_read32bitreg(RX_FINFO_ID) & RXFLEN_MASK; 202 | if (frame_len <= sizeof(rx_buffer)) 203 | { 204 | dwt_readrxdata(rx_buffer, frame_len, 0); 205 | 206 | /* Check that the frame is a poll sent by "SS TWR initiator STS" example. 207 | * As the sequence number field of the frame is not relevant, it is cleared to simplify the validation of the frame. */ 208 | rx_buffer[ALL_MSG_SN_IDX] = 0; 209 | if (memcmp(rx_buffer, rx_poll_msg, ALL_MSG_COMMON_LEN) == 0) 210 | { 211 | uint32_t resp_tx_time; 212 | int ret; 213 | 214 | /* Retrieve poll reception timestamp. */ 215 | poll_rx_ts = get_rx_timestamp_u64(); 216 | 217 | resp_tx_time = (poll_rx_ts /* Received timestamp value */ 218 | + ((POLL_RX_TO_RESP_TX_DLY_UUS /* Set delay time */ 219 | + get_rx_delay_time_data_rate() /* Added delay time for data rate set */ 220 | + get_rx_delay_time_txpreamble() /* Added delay for TX preamble length */ 221 | + ((1<<(config_options.stsLength+2))*8)) /* Added delay for STS length */ 222 | * UUS_TO_DWT_TIME)) >> 8; /* Converted to time units for chip */ 223 | dwt_setdelayedtrxtime(resp_tx_time); 224 | 225 | /* Response TX timestamp is the transmission time we programmed plus the antenna delay. */ 226 | resp_tx_ts = (((uint64_t)(resp_tx_time & 0xFFFFFFFEUL)) << 8) + TX_ANT_DLY; 227 | 228 | /* Write all timestamps in the final message. See NOTE 8 below. */ 229 | resp_msg_set_ts(&tx_resp_msg[RESP_MSG_POLL_RX_TS_IDX], poll_rx_ts); 230 | resp_msg_set_ts(&tx_resp_msg[RESP_MSG_RESP_TX_TS_IDX], resp_tx_ts); 231 | 232 | /* Write and send the response message. See NOTE 9 below. */ 233 | tx_resp_msg[ALL_MSG_SN_IDX] = frame_seq_nb; 234 | dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_TXFRS_BIT_MASK); 235 | dwt_writetxdata(sizeof(tx_resp_msg), tx_resp_msg, 0); /* Zero offset in TX buffer. */ 236 | dwt_writetxfctrl(sizeof(tx_resp_msg), 0, 1); /* Zero offset in TX buffer, ranging. */ 237 | ret = dwt_starttx(DWT_START_TX_DELAYED); 238 | 239 | /* If dwt_starttx() returns an error, abandon this ranging exchange and proceed to the next one. See NOTE 10 below. */ 240 | if (ret == DWT_SUCCESS) 241 | { 242 | /* Poll DW IC until TX frame sent event set. See NOTE 6 below. */ 243 | while (!(dwt_read32bitreg(SYS_STATUS_ID) & SYS_STATUS_TXFRS_BIT_MASK)) 244 | { }; 245 | 246 | /* Clear TXFRS event. */ 247 | dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_TXFRS_BIT_MASK); 248 | 249 | /* Increment frame sequence number after transmission of the poll message (modulo 256). */ 250 | frame_seq_nb++; 251 | } 252 | } 253 | } 254 | else 255 | { 256 | errors[RTO_ERR_IDX] += 1; 257 | } 258 | } 259 | else 260 | { 261 | check_for_status_errors(status_reg, errors); 262 | 263 | if (!(status_reg & SYS_STATUS_RXFCG_BIT_MASK)) 264 | { 265 | errors[BAD_FRAME_ERR_IDX] += 1; 266 | } 267 | if (goodSts < 0) 268 | { 269 | errors[PREAMBLE_COUNT_ERR_IDX] += 1; 270 | } 271 | if (stsQual <= 0) 272 | { 273 | errors[CP_QUAL_ERR_IDX] += 1; 274 | } 275 | /* Clear RX error events in the DW IC status register. */ 276 | dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_ALL_RX_ERR); 277 | } 278 | } 279 | 280 | /***************************************************************************************************************************************************** 281 | * NOTES: 282 | * 283 | * 1. The double-sided two-way ranging scheme implemented here has to be considered carefully as the accuracy of the distance measured is highly 284 | * sensitive to the clock offset error between the devices and the length of the response delay between frames. To achieve the best possible 285 | * accuracy, this response delay must be kept as low as possible. In order to do so, 6.8 Mbps data rate is advised in this example and the response 286 | * delay between frames is defined as low as possible. The user is referred to User Manual for more details about the double-sided two-way ranging 287 | * process. 288 | * 289 | * Initiator: |Poll TX| ..... |Resp RX| 290 | * Responder: |Poll RX| ..... |Resp TX| 291 | * ^|P RMARKER| - time of Poll TX/RX 292 | * ^|R RMARKER| - time of Resp TX/RX 293 | * 294 | * <--TDLY-> - POLL_TX_TO_RESP_RX_DLY_UUS (RDLY-RLEN) 295 | * <-RLEN-> - RESP_RX_TIMEOUT_UUS (length of response frame) 296 | * <----RDLY------> - POLL_RX_TO_RESP_TX_DLY_UUS (depends on how quickly responder can turn around and reply) 297 | * 298 | * 299 | * 2. The sum of the values is the TX to RX antenna delay, experimentally determined by a calibration process. Here we use a hard coded typical value 300 | * but, in a real application, each device should have its own antenna delay properly calibrated to get the best possible precision when performing 301 | * range measurements. 302 | * 3. The frames used here are Decawave specific ranging frames, complying with the IEEE 802.15.4z standard data frame encoding. The frames are the 303 | * following: 304 | * - a poll message sent by the initiator to trigger the ranging exchange. 305 | * - a response message sent by the responder to complete the exchange and provide all information needed by the initiator to compute the 306 | * time-of-flight (distance) estimate. 307 | * The first 10 bytes of those frame are common and are composed of the following fields: 308 | * - byte 0/1: frame control (0x8841 to indicate a data frame using 16-bit addressing). 309 | * - byte 2: sequence number, incremented for each new frame. 310 | * - byte 3/4: PAN ID (0xDECA). 311 | * - byte 5/6: destination address, see NOTE 4 below. 312 | * - byte 7/8: source address, see NOTE 4 below. 313 | * - byte 9: function code (specific values to indicate which message it is in the ranging process). 314 | * The remaining bytes are specific to each message as follows: 315 | * Poll message: 316 | * - no more data 317 | * Response message: 318 | * - byte 10 -> 13: poll message reception timestamp. 319 | * - byte 14 -> 17: response message transmission timestamp. 320 | * All messages end with a 2-byte checksum automatically set by DW IC. 321 | * 4. Source and destination addresses are hard coded constants in this example to keep it simple but for a real product every device should have a 322 | * unique ID. Here, 16-bit addressing is used to keep the messages as short as possible but, in an actual application, this should be done only 323 | * after an exchange of specific messages used to define those short addresses for each device participating to the ranging exchange. 324 | * 5. In a real application, for optimum performance within regulatory limits, it may be necessary to set TX pulse bandwidth and TX power, (using 325 | * the dwt_configuretxrf API call) to per device calibrated values saved in the target system or the DW IC OTP memory. 326 | * 6. We use polled mode of operation here to keep the example as simple as possible but all status events can be used to generate interrupts. Please 327 | * refer to DW IC User Manual for more details on "interrupts". It is also to be noted that STATUS register is 5 bytes long but, as the event we 328 | * use are all in the first bytes of the register, we can use the simple dwt_read32bitreg() API call to access it instead of reading the whole 5 329 | * bytes. 330 | * 7. As we want to send final TX timestamp in the final message, we have to compute it in advance instead of relying on the reading of DW IC 331 | * register. Timestamps and delayed transmission time are both expressed in device time units so we just have to add the desired response delay to 332 | * response RX timestamp to get final transmission time. The delayed transmission time resolution is 512 device time units which means that the 333 | * lower 9 bits of the obtained value must be zeroed. This also allows to encode the 40-bit value in a 32-bit words by shifting the all-zero lower 334 | * 8 bits. 335 | * 8. In this operation, the high order byte of each 40-bit timestamps is discarded. This is acceptable as those time-stamps are not separated by 336 | * more than 2**32 device time units (which is around 67 ms) which means that the calculation of the round-trip delays (needed in the 337 | * time-of-flight computation) can be handled by a 32-bit subtraction. 338 | * 9. dwt_writetxdata() takes the full size of the message as a parameter but only copies (size - 2) bytes as the check-sum at the end of the frame is 339 | * automatically appended by the DW IC. This means that our variable could be two bytes shorter without losing any data (but the sizeof would not 340 | * work anymore then as we would still have to indicate the full length of the frame to dwt_writetxdata()). 341 | * 10. When running this example on the DW3000 platform with the POLL_RX_TO_RESP_TX_DLY response delay provided, the dwt_starttx() is always 342 | * successful. However, in cases where the delay is too short (or something else interrupts the code flow), then the dwt_starttx() might be issued 343 | * too late for the configured start time. The code below provides an example of how to handle this condition: In this case it abandons the 344 | * ranging exchange and simply goes back to awaiting another poll message. If this error handling code was not here, a late dwt_starttx() would 345 | * result in the code flow getting stuck waiting subsequent RX event that will will never come. The companion "initiator" example (ex_06a) should 346 | * timeout from awaiting the "response" and proceed to send another poll in due course to initiate another ranging exchange. 347 | * 11. The user is referred to DecaRanging ARM application (distributed with EVK1000 product) for additional practical example of usage, and to the 348 | * DW IC API Guide for more details on the DW IC driver functions. 349 | * 12. In this example, the DW IC is put into IDLE state after calling dwt_initialise(). This means that a fast SPI rate of up to 20 MHz can be used 350 | * thereafter. 351 | * 13. This example uses STS with a packet configuration of mode 1 which looks like so: 352 | * --------------------------------------------------- 353 | * | Ipatov Preamble | SFD | STS | PHR | PHY Payload | 354 | * --------------------------------------------------- 355 | * There is a possibility that the TX and RX units in this example will go out of sync as their STS IV values may be misaligned. The STS IV value 356 | * changes upon each receiving and transmitting event by the chip. While the TX and RX devices in this example start at the same STS IV values, it 357 | * is possible that they can go out sync if a signal is not received correctly, devices are out of range, etc. To combat this, the 'poll message' 358 | * that the initiator sends to the responder contains a plain-text STS counter value. The responder receives this message and first checks if 359 | * the received frame is out of sync with it's own counter. If so, it will use this received counter value to update it's own counter. When out 360 | * of sync with each other, the STS will not align correctly - thus we get no secure timestamp values. 361 | * 14. Desired configuration by user may be different to the current programmed configuration. dwt_configure is called to set desired 362 | * configuration. 363 | * 15. This example will set the STS key and IV upon each iteration of the main while loop. While this has the benefit of keeping the STS count in 364 | * sync with the responder device (which does the same), it should be noted that this is not a 'secure' implementation as the count is reset upon 365 | * each iteration of the loop. An attacker could potentially recognise this pattern if the signal was being monitored. While it serves it's 366 | * purpose in this simple example, it should not be utilised in any final solution. 367 | ****************************************************************************************************************************************************/ 368 | --------------------------------------------------------------------------------