PX4 Firmware
PX4 Autopilot Software http://px4.io
emlid_reach.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2012-2019 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 /**
35  * @file emlid_reach.cpp
36  *
37  * @author Bastien Auneau <bastien.auneau@while-true.fr>
38  */
39 
40 
41 #include "emlid_reach.h"
42 
43 #include <stdio.h>
44 #include <math.h>
45 #include <string.h>
46 #include <ctime>
47 #include <cstring>
48 #include <errno.h>
49 
50 #include <stdlib.h>
51 
52 //// ERB
53 // 'E' Ox45 | 'R' Ox52 | ID | LENGTH (2 Bytes little endian) | payload | CHECKSUM (2B)
54 #define ERB_SYNC_1 0x45 // E
55 #define ERB_SYNC_2 0x52 // R
56 
57 #define ERB_ID_VERSION 0x01
58 #define ERB_ID_GEODIC_POSITION 0x02
59 #define ERB_ID_NAV_STATUS 0x03
60 #define ERB_ID_DOPS 0x04
61 #define ERB_ID_VELOCITY_NED 0x05
62 #define ERB_ID_SPACE_INFO 0x06 // not used, reduces stack usage
63 #define ERB_ID_RTK 0x07 // RTK, TODO
64 
65 
66 #define EMLID_UNUSED(x) (void)x;
67 
68 #define GPS_PI 3.141592653589793238462643383280f
69 
70 #define AUTO_DETECT_MAX_READ_SENTENCE 5 // if more detect succeed
71 
72 
74  struct vehicle_gps_position_s *gps_position, struct satellite_info_s *satellite_info) :
75  GPSHelper(callback, callback_user),
76  _gps_position(gps_position), _satellite_info(satellite_info)
77 {}
78 
79 
80 int
82 {
83  // TODO RTK
84  if (output_mode != OutputMode::GPS) {
85  GPS_WARN("EMLIDREACH: Unsupported Output Mode %i", (int)output_mode);
86  return -1;
87  }
88 
89  unsigned baud_allowed[] {57600, 115200, 230400};
90 
91  for (unsigned i = 0; i < sizeof(baud_allowed) / sizeof(baud_allowed[0]); i++) {
92  if (baudrate > 0 && baudrate != baud_allowed[i]) {
93  continue;
94  }
95 
96  _sentence_cnt = 0;
98  _erb_payload_len = 0;
99  _erb_buff_cnt = 0;
100 
101  if (GPSHelper::setBaudrate(baud_allowed[i]) != 0) {
102  continue;
103  }
104 
105  if (! testConnection()) {
106  continue;
107  }
108 
109  baudrate = baud_allowed[i];
110  return 0;
111  }
112 
113  return -1;
114 }
115 
116 
117 bool
119 {
120  _testing_connection = true;
121  receive(500);
122  _testing_connection = false;
124 }
125 
126 
127 int
129 {
130  uint8_t read_buff[GPS_READ_BUFFER_SIZE];
131  unsigned read_buff_len = 0;
132  uint8_t read_ind = 0;
133  int return_status = 0;
134 
135  gps_abstime time_started = gps_absolute_time();
136 
137  while (true) {
138  // read from serial, timeout may be truncated further in read()
139  read_buff_len = read(read_buff, sizeof(read_buff), timeout);
140 
141  if (read_buff_len > 0) {
142  read_ind = 0;
143  }
144 
145  // process data in buffer return by read()
146  while (read_ind < read_buff_len) {
147  int ret = 0;
148  ret = erbParseChar(read_buff[read_ind++]);
149 
150  if (ret > 0) {
151  _sentence_cnt ++;
152 
153  // when testig connection, we care about syntax not semantic
154  if (! _testing_connection) {
155  return_status = handleErbSentence();
156  }
157  }
158  }
159 
160  if (return_status > 0) {
161  return return_status;
162  }
163 
164  /* abort after timeout if no useful packets received */
165  if (time_started + timeout * 1000 < gps_absolute_time()) {
166  // device timed out
167  return -1;
168  }
169  }
170 
171  return -1;
172 }
173 
174 
175 //// ERB
176 
177 int
179 {
180  int ret = 0;
181  uint8_t *buff_ptr = (uint8_t *)&_erb_buff;
182 
183  switch (_erb_decode_state) {
184  case ERB_State::init:
185  if (b == ERB_SYNC_1) {
186  _erb_buff_cnt = 0;
187  buff_ptr[_erb_buff_cnt ++] = b;
189  }
190 
191  break;
192 
194  if (b == ERB_SYNC_2) {
195  buff_ptr[_erb_buff_cnt ++] = b;
197 
198  } else {
200  }
201 
202  break;
203 
205  if (b >= ERB_ID_VERSION && b <= ERB_ID_RTK) {
206  buff_ptr[_erb_buff_cnt ++] = b;
208 
209  if (b == ERB_ID_SPACE_INFO || b == ERB_ID_RTK) {
210  //ignore those
212  }
213 
214  } else {
216  }
217 
218  break;
219 
220  case ERB_State::got_id:
221  buff_ptr[_erb_buff_cnt ++] = b;
223  _erb_payload_len = b;
224  break;
225 
227  buff_ptr[_erb_buff_cnt ++] = b;
229  _erb_payload_len = (b << 8) | _erb_payload_len;
230  break;
231 
235 
236  } else {
237  buff_ptr[_erb_buff_cnt ++] = b;
238  }
239 
240  if (_erb_buff_cnt >= _erb_payload_len + static_cast<unsigned>(ERB_HEADER_LEN)) {
242  }
243 
244  break;
245 
247  _erb_checksum.ck_a = b;
249  break;
250 
251  case ERB_State::got_CK_A:
252  _erb_checksum.ck_b = b;
253 
254  uint8_t cka = 0, ckb = 0;
255 
256  for (unsigned i = 2; i < _erb_payload_len + static_cast<unsigned>(ERB_HEADER_LEN); i++) {
257  cka += buff_ptr[i];
258  ckb += cka;
259  }
260 
261  if (cka == _erb_checksum.ck_a && ckb == _erb_checksum.ck_b) {
262  ret = 1;
263 
264  } else {
265  ret = 0;
266  }
267 
269  break;
270  }
271 
272  return ret;
273 }
274 
275 int
277 {
278  int ret = 0;
279 
281  //GPS_INFO("EMLIDREACH: ERB version: %d.%d.%d", _buff[ERB_HEADER_LEN + 4], _buff[ERB_HEADER_LEN + 5], _buff[ERB_HEADER_LEN + 6]);
282 
283  } else if (_erb_buff.header.id == ERB_ID_GEODIC_POSITION) {
284 
286 
292 
294 
295  _gps_position->eph = static_cast<float>(_erb_buff.payload.geodic_position.accHorizontal) * 1e-3f;
296  _gps_position->epv = static_cast<float>(_erb_buff.payload.geodic_position.accVertical) * 1e-3f;
297 
298  _gps_position->vel_ned_valid = false;
303 
304  _POS_received = true;
305 
306  } else if (_erb_buff.header.id == ERB_ID_NAV_STATUS) {
307 
311 
312  if (_fix_type == 0) {
313  // no Fix
314  _fix_type = 0;
315 
316  } else if (_fix_type == 1) {
317  // Single
318  _fix_type = (_satellites_used > 4) ? 3 : 2;
319 
320  } else if (_fix_type == 2) {
321  // RTK Float
322  _fix_type = 5;
323 
324  } else if (_fix_type == 3) {
325  // RTK Fix
326  _fix_type = 6;
327 
328  } else {
329  _fix_type = 0;
330  }
331 
332 
333  } else if (_erb_buff.header.id == ERB_ID_DOPS) {
334 
335  _hdop = static_cast<float>(_erb_buff.payload.dop.dopHorizontal) / 100.0f;
336  _vdop = static_cast<float>(_erb_buff.payload.dop.dopVertical) / 100.0f;
337 
338  } else if (_erb_buff.header.id == ERB_ID_VELOCITY_NED) {
339 
341 
342  _gps_position->vel_n_m_s = static_cast<float>(_erb_buff.payload.ned_velocity.velN) / 100.0f;
343  _gps_position->vel_e_m_s = static_cast<float>(_erb_buff.payload.ned_velocity.velE) / 100.0f;
344  _gps_position->vel_d_m_s = static_cast<float>(_erb_buff.payload.ned_velocity.velD) / 100.0f;
345 
346  _gps_position->vel_m_s = static_cast<float>(_erb_buff.payload.ned_velocity.speed) / 100.0f;
347  _gps_position->cog_rad = (static_cast<float>(_erb_buff.payload.ned_velocity.heading) / 1e5f) * GPS_PI / 180.0f;
348 
350 
352  _rate_count_vel++;
353 
354  _VEL_received = true;
355 
356  } else if (_erb_buff.header.id == ERB_ID_SPACE_INFO) {
357 
358  } else if (_erb_buff.header.id == ERB_ID_RTK) {
359 
360  } else {
361  //GPS_WARN("EMLIDREACH: ERB ID not known: %d", _erb_buff.header.id);
362  }
363 
364  // Emlid doc: "If position and velocity are valid, it takes value 0x01, else it takes 0x00"
365  if (_fix_status == 1
368  ret = 1;
369  _POS_received = false;
370  _VEL_received = false;
371  }
372 
373  return ret;
374 }
375 
376 
erb_navigation_status_t navigation_status
Definition: emlid_reach.h:121
uint8_t id
Definition: emlid_reach.h:61
#define ERB_ID_SPACE_INFO
Definition: emlid_reach.cpp:62
uint16_t _erb_payload_len
Definition: emlid_reach.h:186
#define ERB_SENTENCE_MAX_LEN
Definition: emlid_reach.h:51
#define ERB_ID_DOPS
Definition: emlid_reach.cpp:60
#define GPS_PI
Definition: emlid_reach.cpp:68
#define GPS_WARN(...)
Definition: definitions.h:48
unsigned _sentence_cnt
counts decoded sentence when testing connection
Definition: emlid_reach.h:184
int setBaudrate(int baudrate)
set the Baudrate
Definition: gps_helper.h:228
#define ERB_ID_RTK
Definition: emlid_reach.cpp:63
uint16_t dopHorizontal
Definition: emlid_reach.h:103
GPSDriverEmlidReach(GPSCallbackPtr callback, void *callback_user, struct vehicle_gps_position_s *gps_position, struct satellite_info_s *satellite_info)
Definition: emlid_reach.cpp:73
struct vehicle_gps_position_s * _gps_position
Pointer provided by caller, ie gps.cpp.
Definition: emlid_reach.h:178
uint16_t dopVertical
Definition: emlid_reach.h:102
erb_geodic_position_t geodic_position
Definition: emlid_reach.h:120
ERB_State _erb_decode_state
NMEA parser state machine.
Definition: emlid_reach.h:167
int read(uint8_t *buf, int buf_length, int timeout)
read from device
Definition: gps_helper.h:206
hrt_abstime gps_abstime
Definition: definitions.h:58
uint8_t _satellites_used
Definition: emlid_reach.h:197
erb_checksum_t _erb_checksum
Buffer used by parser to build ERB checksum.
Definition: emlid_reach.h:174
uint8_t ck_a
Definition: emlid_reach.h:66
erb_message_t _erb_buff
Buffer used by parser to build ERB sentences.
Definition: emlid_reach.h:170
uint32_t _last_VEL_timeGPS
Definition: emlid_reach.h:189
uint32_t speedAccuracy
Definition: emlid_reach.h:114
uint8_t _rate_count_vel
Definition: gps_helper.h:265
int erbParseChar(uint8_t b)
Feed ERB parser with received bytes from serial.
uint16_t _erb_buff_cnt
Definition: emlid_reach.h:171
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
Definition: integration.cpp:8
int(* GPSCallbackPtr)(GPSCallbackType type, void *data1, int data2, void *user)
Callback function for platform-specific stuff.
Definition: gps_helper.h:132
#define AUTO_DETECT_MAX_READ_SENTENCE
Definition: emlid_reach.cpp:70
erb_header_t header
Definition: emlid_reach.h:127
#define GPS_READ_BUFFER_SIZE
buffer size for the read() call. Messages can be longer than that.
Definition: gps_helper.h:46
#define ERB_ID_VERSION
Definition: emlid_reach.cpp:57
#define ERB_SYNC_1
Definition: emlid_reach.cpp:54
uint32_t _last_POS_timeGPS
Definition: emlid_reach.h:188
#define ERB_ID_GEODIC_POSITION
Definition: emlid_reach.cpp:58
erb_dop_t dop
Definition: emlid_reach.h:122
erb_payload_t payload
Definition: emlid_reach.h:128
int handleErbSentence()
ERB sentence into vehicle_gps_position_s or satellite_info_s, to be used by GPSHelper.
uint8_t _rate_count_lat_lon
Definition: gps_helper.h:264
#define ERB_SYNC_2
Definition: emlid_reach.cpp:55
uint8_t ck_b
Definition: emlid_reach.h:67
erb_ned_velocity_t ned_velocity
Definition: emlid_reach.h:123
#define ERB_ID_NAV_STATUS
Definition: emlid_reach.cpp:59
#define gps_absolute_time
Get the current time in us.
Definition: definitions.h:57
normal GPS output
#define ERB_HEADER_LEN
Definition: emlid_reach.h:49
int configure(unsigned &baudrate, OutputMode output_mode) override
configure the device
Definition: emlid_reach.cpp:81
int receive(unsigned timeout) override
receive & handle new data from the device
#define ERB_ID_VELOCITY_NED
Definition: emlid_reach.cpp:61