diff --git a/apps/decawave-range/dw-range-anchor.c b/apps/decawave-range/dw-range-anchor.c new file mode 100644 index 0000000000000000000000000000000000000000..687b0dc0cf379a42b37cbb15f7be019ec8d4777e --- /dev/null +++ b/apps/decawave-range/dw-range-anchor.c @@ -0,0 +1,350 @@ +/** + * \file Decawace uwb demo application + * \author Kim Albertsson + * + * \note If you get a HPDWARN in status reg you are probably taking to long + * time to create a delayed send. Increase MESSAGE_DELAY_MS or optimise + * critical path for creating packet. + */ + +/*===========================================================================*/ +/*================================ Includes =================================*/ + +#include <stdio.h> /* For printf() */ +#include <stdint.h> +#include "string.h" +#include <stddef.h> + +#include "udelay.h" + +#include "dw1000-base.h" +#include "dwFrameTypes.h" +#include "dw-range.h" + +#include "contiki.h" +// #include "contiki-net.h" +// #include "rest-engine.h" + +/*===========================================================================*/ +/*================================ Defines ==================================*/ + +#define MESSAGE_DELAY_MS 10.0f +#define DEVICE_TIME_UNITS (1.0/499.2e6/128.0) +#define ANTENNA_DELAY ((515.0 / 2.0) * 1e-9 / (1.0/499.2e6/128.0)) + +#define MASK_40_BIT 0x000000FFFFFFFFFFULL + +/*===========================================================================*/ +/*========================== Public Declarations ============================*/ + +/** + * \brief Keeps track of all variables needed for a distance measurement. + */ +typedef struct +{ + uint64_t tsp; /**< Poll sent time */ + uint64_t trp; /**< Poll received time */ + uint64_t tsr; /**< Response sent time */ + uint64_t trr; /**< Response received time */ + uint64_t tsf; /**< Final sent time */ + uint64_t trf; /**< Final received time */ + + int64_t ttrt; /**< Round trip time as seen by tag. */ + int64_t tart; /**< Round trip time as seen by anchor. */ + int64_t trt; /**< Estimated round trip time. */ + int64_t tof; /**< Estimated Time of Flight. [~15.65ps per tick] */ + double s; /**< Estimated distance */ + +} distance_meas_t; + +typedef struct +{ + uint32_t num_meas; + uint32_t num_errors; + + // Measurements + float accumulated_distance; + float max; + float min; + float stddev; + + // Quality + float rx_power; + float fp_power; + float noise_level; + float fp_ampl; + + // Sensors + float temperature; + float voltage; +} statistics_t; + +extern dw1000_base_driver dw1000; +extern struct process * interrupt_handler_callback; + +static distance_meas_t dist_meas; +static statistics_t stats; + +// For coap service +float lastMeasuredDistance = 0.f; +float accumulated_distance = 0.f; + +// static void res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +// RESOURCE(res_dw_range, "title=\"Distance: ?len=0..\";rt=\"Text\"", res_get_handler, NULL, NULL, NULL); + +/*---------------------------------------------------------------------------*/ +PROCESS(dw_main_process , "Main process"); +PROCESS(dw_anchor_process , "Anchor process (dw1000)"); +AUTOSTART_PROCESSES(&dw_main_process); +/*---------------------------------------------------------------------------*/ + +/*===========================================================================*/ +/*============================ Public Functions =============================*/ + +/** + * \brief Used to convert from raw measurements to real world distances. + * + * \details + * + * \todo Present error bounds on this function. + * + * @param distance raw measurement + * @return estimated distance + */ +static float distance_correction( float measurement ) +{ + // return distance*0.8719 - 32.8600; + // return distance*0.9876 - 37.0932; + // return distance*0.9430 - 72.4511; + return measurement; +} + +void print_statistics( statistics_t * stats ) +{ + float avg = stats->accumulated_distance/stats->num_meas; + printf("========================================\n"); + printf("Measurement no. %i\n", stats->num_meas); + printf("--- Data -------------------------------\n"); + printf("Avg: %f\n", avg); + printf("Max: %f\n", stats->max); + printf("Min: %f\n", stats->min); + printf("Std dev: %f\n", stats->stddev); + printf("--- Quality ----------------------------\n"); + stats->rx_power = dw_get_rx_power(); + stats->fp_power = dw_get_fp_power(); + stats->noise_level = dw_get_noise_level(); + stats->fp_ampl = dw_get_fp_ampl(); + printf("rx_power : %f\n", stats->rx_power); + printf("fp_power : %f\n", stats->fp_power); + printf("noise_level: %f\n", stats->noise_level); + printf("fp_ampl : %f\n", stats->fp_ampl); + printf("--- Sensors ----------------------------\n"); + stats->temperature = dw_get_temperature(DW_ADC_SRC_LATEST); + stats->voltage = dw_get_voltage(DW_ADC_SRC_LATEST); + printf("temperature: %f\n", stats->temperature); + printf("voltage : %f\n", stats->voltage); + printf("--- Diagnostics ------------------------\n"); + printf("num_packets_rx : %i\n", packet_stats.num_packets_rx); + printf("num_packets_tx : %i\n", packet_stats.num_packets_tx); + printf("num_packet_errors: %i\n", packet_stats.num_errors); + printf("========================================\n"); +} + +void reset_statistics( statistics_t * stats ) +{ + stats->num_meas = 0; + stats->accumulated_distance = 0.f; + stats->max = -1e9; + stats->min = 1e9; + stats->stddev = 0.f; + stats->num_errors = 0; +} + + +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(dw_main_process, ev, data) +{ + PROCESS_BEGIN(); + + // Init coap + // rest_init_engine(); + // rest_activate_resource(&res_dw_range, "test/distance"); + + // Init dw1000 + process_start(&dw_interrupt_callback_proc, NULL); + + dw_init(); + dw_conf_print(); + interrupt_handler_callback = &dw_anchor_process; + reset_statistics( &stats ); + process_start(&dw_anchor_process, NULL); + + // Start code proper + while(1) + { + PROCESS_WAIT_EVENT(); + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(dw_anchor_process, ev, data) +{ + PROCESS_BEGIN(); + + printf("Starting Anchor\n"); + // For precise measurements this should be calibrated per device + dw_set_antenna_delay( ANTENNA_DELAY ); + + static ranging_state_t ranging_state = IDLE; + static uint64_t destAddr = 0ULL; + + dw_frame_blink_t frameBlink; + dw_frame_range_t frameRangePoll; + dw_message_poll_t msgPoll; + dw_frame_range_t frameRangeFinal; + dw_message_final_t msgFinal; + while( 1 ) + { + if (ranging_state == IDLE) + { + // This would be in the main switch as + // case IDLE: + // if contiki multithreading would have allowed it. + dw1000_rx_conf_t rx_conf; + rx_conf.is_delayed = 0; + rx_conf.timeout = 0xFFFF; + dw_conf_rx( &rx_conf ); + dw_receive( DW_TRANCEIVE_ASYNC ); + PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_CONTINUE); + ranging_state = *(ranging_state_t *)data; + + // printf("State: %i\n", ranging_state); + // printf("ranging_state: %i\n", ranging_state); + } + + uint32_t msgLen; + uint64_t dx_timestamp; + switch (ranging_state) + { + case MEASUREMENT_ADDED: + ranging_state = IDLE; + + if (stats.num_meas % 100 != 0) { break; } + print_statistics(&stats); + if (stats.num_meas != 1000) { break; } + + // For easy calibration of distance_correction(). + // Now you can take one sample and then reset device. + // Remove loop when calibration is done. + while(1){}; + + // Reset statistics. + reset_statistics( &stats ); + printf("Reset.\n"); + + break; + + case BLINK_RECEIVED: + + parseFrameBlink(dw1000.p_receive_buffer, dw1000.receive_buffer_len, &frameBlink); + destAddr = frameBlink.tag_id; + + dx_timestamp = dw_get_rx_timestamp() + dw_ms_to_device_time( MESSAGE_DELAY_MS ); + + sendRangeInit( destAddr, (uint16_t)MESSAGE_DELAY_MS, dx_timestamp ); + printf("Sent ranging init\n"); + ranging_state = IDLE; + break; + + case POLL_RECEIVED: + dist_meas.trp = dw_get_rx_timestamp(); + dx_timestamp = dist_meas.trp + dw_ms_to_device_time( MESSAGE_DELAY_MS ); + //printArray(dw1000.p_receive_buffer, dw1000.receive_buffer_len); + + msgLen = dw1000.receive_buffer_len - DW_FRAME_RANGE_LEN - DW_FRAME_FCS_LEN; + parseFrameRange( dw1000.p_receive_buffer, dw1000.receive_buffer_len, &frameRangePoll ); + parseMessagePoll( frameRangePoll.pPayload, msgLen, &msgPoll ); + + // TODO: Keep track of paired tags + if (destAddr == 0x0ULL) + { + destAddr = frameRangePoll.src_addr; + } + + sendResponse( destAddr, &dist_meas.tsr, dx_timestamp ); + // printArray( dw1000.p_receive_buffer, dw1000.receive_buffer_len ); + ranging_state = IDLE; + break; + + case FINAL_RECEIVED: + dist_meas.trf = dw_get_rx_timestamp(); + + msgLen = dw1000.receive_buffer_len - DW_FRAME_RANGE_LEN - DW_FRAME_FCS_LEN; + parseFrameRange( dw1000.p_receive_buffer, dw1000.receive_buffer_len, &frameRangeFinal ); + parseMessageFinal( frameRangeFinal.pPayload, msgLen, &msgFinal ); + + memcpy( &dist_meas.tsp, msgFinal.poll_msg_tx_timestamp , 5 ); + memcpy( &dist_meas.trr, msgFinal.resp_msg_rx_timestamp , 5 ); + memcpy( &dist_meas.tsf, msgFinal.final_msg_tx_timestamp, 5 ); + + uint64_t tsp = dist_meas.tsp; + uint64_t trp = dist_meas.trp; + uint64_t tsr = dist_meas.tsr; + uint64_t trr = dist_meas.trr; + uint64_t tsf = dist_meas.tsf; + uint64_t trf = dist_meas.trf; + dist_meas.ttrt = ((trr - tsp) & MASK_40_BIT) - ((tsr - trp) & MASK_40_BIT); + dist_meas.tart = ((trf - tsr) & MASK_40_BIT) - ((tsf - trr) & MASK_40_BIT); + dist_meas.trt = ((dist_meas.tart & MASK_40_BIT) + (dist_meas.ttrt & MASK_40_BIT)) >> 1; + dist_meas.tof = dist_meas.trt >> 1; + dist_meas.s = 3e8 * 15.65e-12 * (double)dist_meas.tof; + dist_meas.s = distance_correction(dist_meas.s); + if (dist_meas.s > 200.0f) + { + /* + BUG: sometimes we get a really large value... + This is possibly fixed now... (has to do with delayed + send ignoring lowest 9 bits.) + */ + ++stats.num_errors; + break; + } + + stats.accumulated_distance += dist_meas.s; + stats.max = (dist_meas.s > stats.max) ? dist_meas.s : stats.max; + stats.min = (dist_meas.s < stats.min) ? dist_meas.s : stats.min; + ++stats.num_meas; + ranging_state = MEASUREMENT_ADDED; + break; + + case ERROR: + default : + ++packet_stats.num_errors; // TODO: bad encapsulation, change to software errors. + ranging_state = IDLE; + break; + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +// static void +// res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +// { +// /** +// * \note This should be working... But it was a long time ago I tested it +// * so it probably won't. +// */ + +// // Set up response payload. +// static const uint32_t length = 21; +// static char message[128]; +// sprintf( message, "Distance to tag: %4f", lastMeasuredDistance ); +// memcpy(buffer, message, length); + +// // Set up response packet +// REST.set_header_content_type(response, REST.type.TEXT_PLAIN); /* text/plain is the default, hence this option could be omitted. */ +// REST.set_header_etag(response, (uint8_t *) &length, 1); +// REST.set_response_payload(response, buffer, length); +// } \ No newline at end of file diff --git a/apps/decawave-range/dw-range-tag.c b/apps/decawave-range/dw-range-tag.c new file mode 100644 index 0000000000000000000000000000000000000000..28e41f0fc6fb2f5e043f7e222d116eed418f30ee --- /dev/null +++ b/apps/decawave-range/dw-range-tag.c @@ -0,0 +1,176 @@ +/** +* \file + * Decawace uwb demo application + * \author + * Kim Albertsson + */ + +// Tested with mulle board 145 + +#include "contiki.h" + +#include <stdio.h> /* For printf() */ +#include <stdint.h> +#include <stddef.h> + +#include "udelay.h" + +#include "dw1000-base.h" +#include "dwFrameTypes.h" +#include "dw-range.h" + +#define DEVICE_TIME_UNITS (1.0/499.2e6/128.0) +#define ANTENNA_DELAY ((515.0 / 2.0) * 1e-9 / (1.0/499.2e6/128.0)) + +typedef enum +{ + UNPAIRED = 0, + PAIRED +} tag_state_t; + +extern struct process * interrupt_handler_callback; + +int error; + +/*---------------------------------------------------------------------------*/ +PROCESS(dw_main_process , "Main process"); +PROCESS(dw_tag_process , "Tag process (dw1000)"); +AUTOSTART_PROCESSES(&dw_main_process); +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(dw_main_process, ev, data) +{ + PROCESS_BEGIN(); + + // Init dw1000 + process_start(&dw_interrupt_callback_proc, NULL); + + dw_init(); + dw_conf_print(); + interrupt_handler_callback = &dw_tag_process; + process_start(&dw_tag_process, NULL); + + // Start code proper + while(1) + { + PROCESS_WAIT_EVENT(); + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(dw_tag_process, ev, data) +{ + PROCESS_BEGIN(); + + static uint64_t dest_addr = 0ULL; + static uint16_t responseDelay; + + static tag_state_t tag_state = UNPAIRED; + static ranging_state_t ranging_state = IDLE; + + printf("Starting Tag\n"); + // Setting antenna delay + dw_set_antenna_delay( ANTENNA_DELAY ); + + // Enable rx timeout + dw_set_rx_timeout( 0xFFFF ); + printf("Timeout: %f ms.\n", (float)dw_get_rx_timeout()/1000.0f); + dw_enable_rx_timeout(); + + // Configure rx + static dw1000_rx_conf_t rx_conf; + rx_conf.is_delayed = 0; + rx_conf.timeout = 0xFFFF; + dw_conf_rx( &rx_conf ); + dw_receive( DW_TRANCEIVE_ASYNC ); + + static uint64_t tsp; + static uint64_t trr; + static uint64_t tsf; + static uint64_t dx_timestamp; + static uint32_t msgLen; + static dw_frame_range_t frameRange; + static dw_message_range_init_t msgRangeInit; + static dw_message_response_t msgResponse; + // static struct etimer et; + // etimer_set(&et, CLOCK_SECOND); + while (1) + { + PROCESS_WAIT_EVENT(); + // printf("Received Event. %i.\n", ev); + // printf("Receive state. %i.\n", ranging_state); + //else + { + ranging_state = *(ranging_state_t *)data; + switch (ranging_state) + { + case RANGE_INIT_RECEIVED: + // printf("Range init received.\n"); + msgLen = dw1000.receive_buffer_len - DW_FRAME_RANGE_LEN - DW_FRAME_FCS_LEN; + parseFrameRange(dw1000.p_receive_buffer, dw1000.receive_buffer_len, &frameRange); + parseMessageRangeInit(frameRange.pPayload, msgLen, &msgRangeInit); + + dest_addr = frameRange.dest_addr; + responseDelay = msgRangeInit.response_delay_ms; + + tag_state = PAIRED; + break; + + case RESPONSE_RECEIVED: + //printf("Response Received.\n"); + trr = dw_get_rx_timestamp(); + dx_timestamp = trr + dw_ms_to_device_time( (float)responseDelay ); + + msgLen = dw1000.receive_buffer_len - DW_FRAME_RANGE_LEN - DW_FRAME_FCS_LEN; + parseFrameRange(dw1000.p_receive_buffer, dw1000.receive_buffer_len, &frameRange); + parseMessageResponse(frameRange.pPayload, msgLen, &msgResponse); + + // send final + sendFinal( dest_addr, tsp, trr, &tsf, dx_timestamp ); + printf("Final sent.\n"); + break; + + case ERROR: + default: + //printf("Error.\n"); + break; + } + + ranging_state = IDLE; + } + + if ( ranging_state == IDLE /*ev == PROCESS_EVENT_TIMER*/ ) + { + // send either poll or blink + if (tag_state == UNPAIRED && ranging_state == IDLE) + { + // send blink + //printf("Sending Blink.\n"); + sendBlink(); + // Listen for answer + ranging_state = RECEIVING; + //rx_conf.is_delayed = 1; + //rx_conf.dx_timestamp = dw_get_tx_timestamp() + dw_ms_to_device_time(4.8f); + dw_conf_rx( &rx_conf ); + dw_receive( DW_TRANCEIVE_ASYNC ); + } + else if (tag_state == PAIRED && ranging_state == IDLE) + { + // send poll + printf("Sending Poll.\n"); + sendPoll( dest_addr, &tsp ); + + // Listen for answer + ranging_state = RECEIVING; + //rx_conf.is_delayed = 1; + //rx_conf.dx_timestamp = dw_get_tx_timestamp() + dw_ms_to_device_time(responseDelay-0.2); + dw_conf_rx( &rx_conf ); + dw_receive( DW_TRANCEIVE_ASYNC ); + } + // etimer_reset(&et); + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ \ No newline at end of file