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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
|
#ifndef INCLUDED_UHD_USRP_UBLOX_CONTROL_IMPL_HPP
#define INCLUDED_UHD_USRP_UBLOX_CONTROL_IMPL_HPP
#include <boost/cstdint.hpp>
#include <boost/noncopyable.hpp>
#include <boost/asio.hpp>
#include <uhd/config.hpp>
#include <uhd/usrp/gps_ctrl.hpp>
#include <uhd/types/sensors.hpp>
#include "e300_async_serial.hpp"
namespace uhd { namespace usrp { namespace gps {
namespace ublox { namespace ubx {
// ublox binary sync words
static const boost::uint8_t SYNC1 = 0xB5;
static const boost::uint8_t SYNC2 = 0x62;
// message classes
static const boost::uint8_t CLASS_NAV = 0x01;
static const boost::uint8_t CLASS_ACK = 0x05;
static const boost::uint8_t CLASS_CFG = 0x06;
static const boost::uint8_t CLASS_MON = 0x0a;
static const boost::uint8_t CLASS_NMEA = 0xf0;
// Message IDs
static const boost::uint8_t ID_NAV_POSLLH = 0x02;
static const boost::uint8_t ID_NAV_SOL = 0x06;
static const boost::uint8_t ID_NAV_PVT = 0x07;
static const boost::uint8_t ID_NAV_VELNED = 0x12;
static const boost::uint8_t ID_NAV_TIMEUTC = 0x21;
static const boost::uint8_t ID_NAV_SVINFO = 0x30;
static const boost::uint8_t ID_ACK_NAK = 0x00;
static const boost::uint8_t ID_ACK_ACK = 0x01;
static const boost::uint8_t ID_CFG_PRT = 0x00;
static const boost::uint8_t ID_CFG_ANT = 0x13;
static const boost::uint8_t ID_CFG_TP = 0x07;
static const boost::uint8_t ID_CFG_MSG = 0x01;
static const boost::uint8_t ID_CFG_RATE = 0x08;
static const boost::uint8_t ID_CFG_NAV5 = 0x24;
static const boost::uint8_t ID_MON_VER = 0x04;
static const boost::uint8_t ID_MON_HW = 0x09;
static const boost::uint8_t ID_GGA = 0x00;
static const boost::uint8_t ID_GLL = 0x01;
static const boost::uint8_t ID_GSA = 0x02;
static const boost::uint8_t ID_GSV = 0x03;
static const boost::uint8_t ID_RMC = 0x04;
static const boost::uint8_t ID_VTG = 0x05;
static const boost::uint8_t ID_GST = 0x07;
// Message Classes & IDs //
static const boost::uint16_t MSG_NAV_POSLLH
= CLASS_NAV | (ID_NAV_POSLLH << 8);
static const boost::uint16_t MSG_NAV_SOL
= CLASS_NAV | (ID_NAV_SOL << 8);
static const boost::uint16_t MSG_NAV_PVT
= CLASS_NAV | (ID_NAV_PVT << 8);
static const boost::uint16_t MSG_NAV_VELNED
= CLASS_NAV | (ID_NAV_VELNED << 8);
static const boost::uint16_t MSG_NAV_TIMEUTC
= CLASS_NAV | (ID_NAV_TIMEUTC << 8);
static const boost::uint16_t MSG_NAV_SVINFO
= CLASS_NAV | (ID_NAV_SVINFO << 8);
static const boost::uint16_t MSG_ACK_NAK
= CLASS_ACK | (ID_ACK_NAK << 8);
static const boost::uint16_t MSG_ACK_ACK
= CLASS_ACK | (ID_ACK_ACK << 8);
static const boost::uint16_t MSG_CFG_PRT
= CLASS_CFG | (ID_CFG_PRT << 8);
static const boost::uint16_t MSG_CFG_ANT
= CLASS_CFG | (ID_CFG_ANT << 8);
static const boost::uint16_t MSG_CFG_TP
= CLASS_CFG | (ID_CFG_TP << 8);
static const boost::uint16_t MSG_CFG_MSG
= CLASS_CFG | (ID_CFG_MSG << 8);
static const boost::uint16_t MSG_CFG_RATE
= CLASS_CFG | (ID_CFG_RATE << 8);
static const boost::uint16_t MSG_CFG_NAV5
= CLASS_CFG | (ID_CFG_NAV5 << 8);
static const boost::uint16_t MSG_MON_HW
= CLASS_MON | (ID_MON_HW << 8);
static const boost::uint16_t MSG_MON_VER
= CLASS_MON | (ID_MON_VER << 8);
// NMEA ones
static const boost::uint16_t MSG_GGA
= CLASS_NMEA | (ID_GGA << 8);
static const boost::uint16_t MSG_GLL
= CLASS_NMEA | (ID_GLL << 8);
static const boost::uint16_t MSG_GSA
= CLASS_NMEA | (ID_GSA << 8);
static const boost::uint16_t MSG_GSV
= CLASS_NMEA | (ID_GSV << 8);
static const boost::uint16_t MSG_RMC
= CLASS_NMEA | (ID_RMC << 8);
static const boost::uint16_t MSG_VTG
= CLASS_NMEA | (ID_VTG << 8);
// header
struct header_t
{
boost::uint8_t sync1;
boost::uint8_t sync2;
boost::uint16_t msg;
boost::uint16_t length;
};
// checksum
struct checksum_t
{
boost::uint8_t ck_a;
boost::uint8_t ck_b;
};
// rx rx mon-hw (ubx6)
struct payload_rx_mon_hw_t
{
boost::uint32_t pin_sel;
boost::uint32_t pin_bank;
boost::uint32_t pin_dir;
boost::uint32_t pin_val;
boost::uint16_t noise_per_ms;
boost::uint16_t agc_cnt;
boost::uint8_t a_status;
boost::uint8_t a_power;
boost::uint8_t flags;
boost::uint8_t reserved1;
boost::uint32_t used_mask;
boost::uint8_t vp[25];
boost::uint8_t jam_ind;
boost::uint16_t reserved3;
boost::uint32_t pin_irq;
boost::uint32_t pullh;
boost::uint32_t pulll;
};
// rx mon-ver
struct payload_rx_mon_ver_part1_t
{
char sw_version[30];
char hw_version[10];
};
struct payload_rx_mon_ver_part2_t
{
boost::uint8_t extension[30];
};
// rx ack-ack
typedef union {
boost::uint16_t msg;
struct {
boost::uint8_t cls_id;
boost::uint8_t msg_id;
};
} payload_rx_ack_ack_t;
// rx ack-nak
typedef union {
boost::uint16_t msg;
struct {
boost::uint8_t cls_id;
boost::uint8_t msg_id;
};
} payload_rx_ack_nak_t;
// tx cfg-prt (uart)
struct payload_tx_cfg_prt_t
{
boost::uint8_t port_id;
boost::uint8_t reserved0;
boost::uint16_t tx_ready;
boost::uint32_t mode;
boost::uint32_t baud_rate;
boost::uint16_t in_proto_mask;
boost::uint16_t out_proto_mask;
boost::uint16_t flags;
boost::uint16_t reserved5;
};
// tx cfg-rate
struct payload_tx_cfg_rate_t
{
boost::uint16_t meas_rate;
boost::uint16_t nav_rate;
boost::uint16_t time_ref;
};
// tx cfg-msg
struct payload_tx_cfg_msg_t
{
boost::uint16_t msg;
boost::uint8_t rate[6];
};
// tx cfg-ant
struct payload_tx_cfg_ant_t
{
boost::uint16_t flags;
boost::uint16_t pins;
};
// tx cfg-tp
struct payload_tx_cfg_tp_t
{
boost::uint32_t interval;
boost::uint32_t length;
boost::int8_t status;
boost::uint8_t time_ref;
boost::uint8_t flags;
boost::uint8_t reserved1;
boost::int16_t antenna_delay;
boost::int16_t rf_group_delay;
boost::int32_t user_delay;
};
struct payload_rx_nav_sol_t
{
boost::uint32_t i_tow;
boost::int32_t f_tow;
boost::int16_t week;
boost::uint8_t gps_fix;
boost::uint8_t flags;
boost::int32_t ecef_x;
boost::int32_t ecef_y;
boost::int32_t ecef_z;
boost::uint32_t p_acc;
boost::int32_t ecef_vx;
boost::int32_t ecef_vy;
boost::int32_t ecef_vz;
boost::uint32_t s_acc;
boost::uint16_t p_dop;
boost::uint8_t reserved1;
boost::uint8_t num_sv;
boost::uint32_t reserved2;
};
struct payload_rx_nav_timeutc_t
{
boost::uint32_t i_tow;
boost::uint32_t t_acc;
boost::int32_t nano;
boost::uint16_t year;
boost::uint8_t month;
boost::uint8_t day;
boost::uint8_t hour;
boost::uint8_t min;
boost::uint8_t sec;
boost::uint8_t valid;
};
typedef union {
payload_rx_mon_hw_t payload_rx_mon_hw;
payload_rx_mon_ver_part1_t payload_rx_mon_ver_part1;
payload_rx_mon_ver_part2_t payload_rx_mon_ver_part2;
payload_rx_ack_ack_t payload_rx_ack_ack;
payload_rx_ack_nak_t payload_rx_ack_nak;
payload_tx_cfg_prt_t payload_tx_cfg_prt;
payload_tx_cfg_ant_t payload_tx_cfg_ant;
payload_tx_cfg_rate_t payload_tx_cfg_rate;
payload_tx_cfg_msg_t payload_tx_cfg_msg;
payload_rx_nav_timeutc_t payload_rx_nav_timeutc;
payload_rx_nav_sol_t payload_rx_nav_sol;
boost::uint8_t raw[];
} buf_t;
template <typename T>
class sensor_entry
{
public:
sensor_entry() : _seen(false)
{
}
void update(const T &val)
{
boost::mutex::scoped_lock l(_mutex);
_value = val;
_seen = false;
l.unlock();
_cond.notify_one();
}
bool seen() const
{
boost::mutex::scoped_lock l(_mutex);
return _seen;
}
bool try_and_see(T &val)
{
boost::mutex::scoped_lock l(_mutex);
if (_seen)
return false;
val = _value;
_seen = true;
return true;
}
void wait_and_see(T &val)
{
boost::mutex::scoped_lock l(_mutex);
while(_seen)
{
_cond.wait(l);
//std::cout << "Already seen ... " << std::endl;
}
val = _value;
_seen = true;
}
private: // members
T _value;
boost::mutex _mutex;
boost::condition_variable _cond;
bool _seen;
};
class control_impl : public control
{
public:
control_impl(const std::string &node, const size_t baud_rate);
virtual ~control_impl(void);
void configure_message_rate(
const boost::uint16_t msg,
const boost::uint8_t rate);
void configure_antenna(
const boost::uint16_t flags,
const boost::uint16_t pins);
void configure_pps(
const boost::uint32_t interval,
const boost::uint32_t length,
const boost::int8_t status,
const boost::uint8_t time_ref,
const boost::uint8_t flags,
const boost::int16_t antenna_delay,
const boost::int16_t rf_group_delay,
const boost::int32_t user_delay);
void configure_rates(
boost::uint16_t meas_rate,
boost::uint16_t nav_rate,
boost::uint16_t time_ref);
// gps_ctrl interface
bool gps_detected(void);
std::vector<std::string> get_sensors(void);
uhd::sensor_value_t get_sensor(std::string key);
private: // types
enum decoder_state_t {
DECODE_SYNC1 = 0,
DECODE_SYNC2,
DECODE_CLASS,
DECODE_ID,
DECODE_LENGTH1,
DECODE_LENGTH2,
DECODE_PAYLOAD,
DECODE_CHKSUM1,
DECODE_CHKSUM2,
};
enum rxmsg_state_t {
RXMSG_IGNORE = 0,
RXMSG_HANDLE,
RXMSG_DISABLE,
RXMSG_ERROR_LENGTH
};
enum ack_state_t {
ACK_IDLE = 0,
ACK_WAITING,
ACK_GOT_ACK,
ACK_GOT_NAK
};
private: // methods
std::time_t _get_epoch_time(void);
void _decode_init(void);
void _add_byte_to_checksum(const boost::uint8_t b);
void _detect(void);
void _send_message(
const boost::uint16_t msg,
const boost::uint8_t *payload,
const boost::uint16_t len);
int _wait_for_ack(
const boost::uint16_t msg,
const double timeout);
void _calc_checksum(
const boost::uint8_t *buffer,
const boost::uint16_t length,
checksum_t &checksum);
void _rx_callback(const char *data, unsigned len);
void _parse_char(const boost::uint8_t b);
int _payload_rx_init(void);
int _payload_rx_add(const boost::uint8_t b);
int _payload_rx_done(void);
private: // members
// gps_ctrl stuff
bool _detected;
std::vector<std::string> _sensors;
sensor_entry<bool> _locked;
sensor_entry<boost::posix_time::ptime> _ptime;
// decoder state
decoder_state_t _decode_state;
rxmsg_state_t _rxmsg_state;
ack_state_t _ack_state;
boost::uint16_t _ack_waiting_msg;
boost::uint8_t _rx_ck_a;
boost::uint8_t _rx_ck_b;
boost::uint16_t _rx_payload_length;
size_t _rx_payload_index;
boost::uint16_t _rx_msg;
rxmsg_state_t _rx_state;
boost::shared_ptr<async_serial> _serial;
// this has to be at the end of the
// class to be valid C++
buf_t _buf;
};
}} // namespace ublox::ubx
}}} // namespace
#endif // INCLUDED_UHD_USRP_UBLOX_CONTROL_IMPL_HPP
|