-
Notifications
You must be signed in to change notification settings - Fork 289
/
Copy pathRangingTag.ino
201 lines (188 loc) · 6.11 KB
/
RangingTag.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/*
* Copyright (c) 2015 by Thomas Trojer <[email protected]>
* Decawave DW1000 library for arduino.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @file RangingTag.ino
* Use this to test two-way ranging functionality with two DW1000. This is
* the tag component's code which polls for range computation. Addressing and
* frame filtering is currently done in a custom way, as no MAC features are
* implemented yet.
*
* Complements the "RangingAnchor" example sketch.
*
* @todo
* - use enum instead of define
* - move strings to flash (less RAM consumption)
*/
#include <SPI.h>
#include <DW1000.h>
// connection pins
const uint8_t PIN_RST = 9; // reset pin
const uint8_t PIN_IRQ = 2; // irq pin
const uint8_t PIN_SS = SS; // spi select pin
// messages used in the ranging protocol
// TODO replace by enum
#define POLL 0
#define POLL_ACK 1
#define RANGE 2
#define RANGE_REPORT 3
#define RANGE_FAILED 255
// message flow state
volatile byte expectedMsgId = POLL_ACK;
// message sent/received state
volatile boolean sentAck = false;
volatile boolean receivedAck = false;
// timestamps to remember
DW1000Time timePollSent;
DW1000Time timePollAckReceived;
DW1000Time timeRangeSent;
// data buffer
#define LEN_DATA 16
byte data[LEN_DATA];
// watchdog and reset period
uint32_t lastActivity;
uint32_t resetPeriod = 250;
// reply times (same on both sides for symm. ranging)
uint16_t replyDelayTimeUS = 3000;
void setup() {
// DEBUG monitoring
Serial.begin(115200);
Serial.println(F("### DW1000-arduino-ranging-tag ###"));
// initialize the driver
DW1000.begin(PIN_IRQ, PIN_RST);
DW1000.select(PIN_SS);
Serial.println("DW1000 initialized ...");
// general configuration
DW1000.newConfiguration();
DW1000.setDefaults();
DW1000.setDeviceAddress(2);
DW1000.setNetworkId(10);
DW1000.enableMode(DW1000.MODE_LONGDATA_RANGE_LOWPOWER);
DW1000.commitConfiguration();
Serial.println(F("Committed configuration ..."));
// DEBUG chip info and registers pretty printed
char msg[128];
DW1000.getPrintableDeviceIdentifier(msg);
Serial.print("Device ID: "); Serial.println(msg);
DW1000.getPrintableExtendedUniqueIdentifier(msg);
Serial.print("Unique ID: "); Serial.println(msg);
DW1000.getPrintableNetworkIdAndShortAddress(msg);
Serial.print("Network ID & Device Address: "); Serial.println(msg);
DW1000.getPrintableDeviceMode(msg);
Serial.print("Device mode: "); Serial.println(msg);
// attach callback for (successfully) sent and received messages
DW1000.attachSentHandler(handleSent);
DW1000.attachReceivedHandler(handleReceived);
// anchor starts by transmitting a POLL message
receiver();
transmitPoll();
noteActivity();
}
void noteActivity() {
// update activity timestamp, so that we do not reach "resetPeriod"
lastActivity = millis();
}
void resetInactive() {
// tag sends POLL and listens for POLL_ACK
expectedMsgId = POLL_ACK;
transmitPoll();
noteActivity();
}
void handleSent() {
// status change on sent success
sentAck = true;
}
void handleReceived() {
// status change on received success
receivedAck = true;
}
void transmitPoll() {
DW1000.newTransmit();
DW1000.setDefaults();
data[0] = POLL;
DW1000.setData(data, LEN_DATA);
DW1000.startTransmit();
}
void transmitRange() {
DW1000.newTransmit();
DW1000.setDefaults();
data[0] = RANGE;
// delay sending the message and remember expected future sent timestamp
DW1000Time deltaTime = DW1000Time(replyDelayTimeUS, DW1000Time::MICROSECONDS);
timeRangeSent = DW1000.setDelay(deltaTime);
timePollSent.getTimestamp(data + 1);
timePollAckReceived.getTimestamp(data + 6);
timeRangeSent.getTimestamp(data + 11);
DW1000.setData(data, LEN_DATA);
DW1000.startTransmit();
//Serial.print("Expect RANGE to be sent @ "); Serial.println(timeRangeSent.getAsFloat());
}
void receiver() {
DW1000.newReceive();
DW1000.setDefaults();
// so we don't need to restart the receiver manually
DW1000.receivePermanently(true);
DW1000.startReceive();
}
void loop() {
if (!sentAck && !receivedAck) {
// check if inactive
if (millis() - lastActivity > resetPeriod) {
resetInactive();
}
return;
}
// continue on any success confirmation
if (sentAck) {
sentAck = false;
byte msgId = data[0];
if (msgId == POLL) {
DW1000.getTransmitTimestamp(timePollSent);
//Serial.print("Sent POLL @ "); Serial.println(timePollSent.getAsFloat());
} else if (msgId == RANGE) {
DW1000.getTransmitTimestamp(timeRangeSent);
noteActivity();
}
}
if (receivedAck) {
receivedAck = false;
// get message and parse
DW1000.getData(data, LEN_DATA);
byte msgId = data[0];
if (msgId != expectedMsgId) {
// unexpected message, start over again
//Serial.print("Received wrong message # "); Serial.println(msgId);
expectedMsgId = POLL_ACK;
transmitPoll();
return;
}
if (msgId == POLL_ACK) {
DW1000.getReceiveTimestamp(timePollAckReceived);
expectedMsgId = RANGE_REPORT;
transmitRange();
noteActivity();
} else if (msgId == RANGE_REPORT) {
expectedMsgId = POLL_ACK;
float curRange;
memcpy(&curRange, data + 1, 4);
transmitPoll();
noteActivity();
} else if (msgId == RANGE_FAILED) {
expectedMsgId = POLL_ACK;
transmitPoll();
noteActivity();
}
}
}