Line data Source code
1 : /*
2 : This program is free software: you can redistribute it and/or modify
3 : it under the terms of the GNU General Public License as published by
4 : the Free Software Foundation, either version 3 of the License, or
5 : (at your option) any later version.
6 :
7 : This program is distributed in the hope that it will be useful,
8 : but WITHOUT ANY WARRANTY; without even the implied warranty of
9 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 : GNU General Public License for more details.
11 :
12 : You should have received a copy of the GNU General Public License
13 : along with this program. If not, see <http://www.gnu.org/licenses/>.
14 : */
15 : /*
16 : support for serial connected InertialLabs INS
17 : */
18 :
19 : #include "AP_ExternalAHRS_config.h"
20 :
21 : #if AP_EXTERNAL_AHRS_INERTIALLABS_ENABLED
22 :
23 : #include "AP_ExternalAHRS_InertialLabs.h"
24 : #include <AP_Math/AP_Math.h>
25 : #include <AP_Math/crc.h>
26 : #include <AP_Baro/AP_Baro.h>
27 : #include <AP_Compass/AP_Compass.h>
28 : #include <AP_GPS/AP_GPS.h>
29 : #include <AP_Airspeed/AP_Airspeed.h>
30 : #include <AP_InertialSensor/AP_InertialSensor.h>
31 : #include <GCS_MAVLink/GCS.h>
32 : #include <AP_Logger/AP_Logger.h>
33 : #include <AP_SerialManager/AP_SerialManager.h>
34 : #include <AP_HAL/utility/sparse-endian.h>
35 : #include <AP_Common/Bitmask.h>
36 : #include <AP_Vehicle/AP_Vehicle_Type.h>
37 :
38 : extern const AP_HAL::HAL &hal;
39 :
40 : // unit status bits
41 : #define ILABS_UNIT_STATUS_ALIGNMENT_FAIL 0x0001
42 : #define ILABS_UNIT_STATUS_OPERATION_FAIL 0x0002
43 : #define ILABS_UNIT_STATUS_GYRO_FAIL 0x0004
44 : #define ILABS_UNIT_STATUS_ACCEL_FAIL 0x0008
45 : #define ILABS_UNIT_STATUS_MAG_FAIL 0x0010
46 : #define ILABS_UNIT_STATUS_ELECTRONICS_FAIL 0x0020
47 : #define ILABS_UNIT_STATUS_GNSS_FAIL 0x0040
48 : #define ILABS_UNIT_STATUS_RUNTIME_CAL 0x0080
49 : #define ILABS_UNIT_STATUS_VOLTAGE_LOW 0x0100
50 : #define ILABS_UNIT_STATUS_VOLTAGE_HIGH 0x0200
51 : #define ILABS_UNIT_STATUS_X_RATE_HIGH 0x0400
52 : #define ILABS_UNIT_STATUS_Y_RATE_HIGH 0x0800
53 : #define ILABS_UNIT_STATUS_Z_RATE_HIGH 0x1000
54 : #define ILABS_UNIT_STATUS_MAG_FIELD_HIGH 0x2000
55 : #define ILABS_UNIT_STATUS_TEMP_RANGE_ERR 0x4000
56 : #define ILABS_UNIT_STATUS_RUNTIME_CAL2 0x8000
57 :
58 : // unit status2 bits
59 : #define ILABS_UNIT_STATUS2_ACCEL_X_HIGH 0x0001
60 : #define ILABS_UNIT_STATUS2_ACCEL_Y_HIGH 0x0002
61 : #define ILABS_UNIT_STATUS2_ACCEL_Z_HIGH 0x0004
62 : #define ILABS_UNIT_STATUS2_BARO_FAIL 0x0008
63 : #define ILABS_UNIT_STATUS2_DIFF_PRESS_FAIL 0x0010
64 : #define ILABS_UNIT_STATUS2_MAGCAL_2D_ACT 0x0020
65 : #define ILABS_UNIT_STATUS2_MAGCAL_3D_ACT 0x0040
66 : #define ILABS_UNIT_STATUS2_GNSS_FUSION_OFF 0x0080
67 : #define ILABS_UNIT_STATUS2_DIFF_PRESS_FUSION_OFF 0x0100
68 : #define ILABS_UNIT_STATUS2_MAG_FUSION_OFF 0x0200
69 : #define ILABS_UNIT_STATUS2_GNSS_POS_VALID 0x0400
70 :
71 : // air data status bits
72 : #define ILABS_AIRDATA_INIT_FAIL 0x0001
73 : #define ILABS_AIRDATA_DIFF_PRESS_INIT_FAIL 0x0002
74 : #define ILABS_AIRDATA_STATIC_PRESS_FAIL 0x0004
75 : #define ILABS_AIRDATA_DIFF_PRESS_FAIL 0x0008
76 : #define ILABS_AIRDATA_STATIC_PRESS_RANGE_ERR 0x0010
77 : #define ILABS_AIRDATA_DIFF_PRESS_RANGE_ERR 0x0020
78 : #define ILABS_AIRDATA_PRESS_ALT_FAIL 0x0100
79 : #define ILABS_AIRDATA_AIRSPEED_FAIL 0x0200
80 : #define ILABS_AIRDATA_BELOW_THRESHOLD 0x0400
81 :
82 :
83 : // constructor
84 11 : AP_ExternalAHRS_InertialLabs::AP_ExternalAHRS_InertialLabs(AP_ExternalAHRS *_frontend,
85 11 : AP_ExternalAHRS::state_t &_state) :
86 11 : AP_ExternalAHRS_backend(_frontend, _state)
87 : {
88 11 : auto &sm = AP::serialmanager();
89 11 : uart = sm.find_serial(AP_SerialManager::SerialProtocol_AHRS, 0);
90 11 : if (!uart) {
91 0 : GCS_SEND_TEXT(MAV_SEVERITY_ERROR, "InertialLabs ExternalAHRS no UART");
92 0 : return;
93 : }
94 11 : baudrate = sm.find_baudrate(AP_SerialManager::SerialProtocol_AHRS, 0);
95 11 : port_num = sm.find_portnum(AP_SerialManager::SerialProtocol_AHRS, 0);
96 :
97 : // don't offer IMU by default, at 200Hz it is too slow for many aircraft
98 11 : set_default_sensors(uint16_t(AP_ExternalAHRS::AvailableSensor::GPS) |
99 : uint16_t(AP_ExternalAHRS::AvailableSensor::BARO) |
100 : uint16_t(AP_ExternalAHRS::AvailableSensor::COMPASS));
101 :
102 11 : if (!hal.scheduler->thread_create(FUNCTOR_BIND_MEMBER(&AP_ExternalAHRS_InertialLabs::update_thread, void), "ILabs", 2048, AP_HAL::Scheduler::PRIORITY_SPI, 0)) {
103 0 : AP_HAL::panic("InertialLabs Failed to start ExternalAHRS update thread");
104 : }
105 11 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "InertialLabs ExternalAHRS initialised");
106 : }
107 :
108 : /*
109 : re-sync buffer on parse failure
110 : */
111 0 : void AP_ExternalAHRS_InertialLabs::re_sync(void)
112 : {
113 0 : if (buffer_ofs > 3) {
114 : /*
115 : look for the 2 byte header and try to sync to that
116 : */
117 0 : const uint16_t header = 0x55AA;
118 0 : const uint8_t *p = (const uint8_t *)memmem(&buffer[1], buffer_ofs-3, &header, sizeof(header));
119 0 : if (p != nullptr) {
120 0 : const uint16_t n = p - &buffer[0];
121 0 : memmove(&buffer[0], p, buffer_ofs - n);
122 0 : buffer_ofs -= n;
123 : } else {
124 0 : buffer_ofs = 0;
125 : }
126 : } else {
127 0 : buffer_ofs = 0;
128 : }
129 0 : }
130 :
131 : // macro for checking we don't run past end of message buffer
132 : #define CHECK_SIZE(d) need_re_sync = (message_ofs + (msg_len=sizeof(d)) > buffer_end); if (need_re_sync) break
133 :
134 : // lookup a message in the msg_types bitmask to see if we received it in this packet
135 : #define GOT_MSG(mtype) msg_types.get(unsigned(MessageType::mtype))
136 :
137 : /*
138 : check header is valid
139 : */
140 35334 : bool AP_ExternalAHRS_InertialLabs::check_header(const ILabsHeader *h) const
141 : {
142 70668 : return h->magic == 0x55AA &&
143 35334 : h->msg_type == 1 &&
144 106002 : h->msg_id == 0x95 &&
145 70668 : h->msg_len <= sizeof(buffer)-2;
146 : }
147 :
148 : /*
149 : check the UART for more data
150 : returns true if we have consumed potentially valid bytes
151 : */
152 85088 : bool AP_ExternalAHRS_InertialLabs::check_uart()
153 : {
154 85088 : WITH_SEMAPHORE(state.sem);
155 :
156 85089 : if (!setup_complete) {
157 0 : return false;
158 : }
159 : // ensure we own the uart
160 85089 : uart->begin(0);
161 85089 : uint32_t n = uart->available();
162 85089 : if (n == 0) {
163 49755 : return false;
164 : }
165 35334 : if (n + buffer_ofs > sizeof(buffer)) {
166 265 : n = sizeof(buffer) - buffer_ofs;
167 : }
168 35334 : const ILabsHeader *h = (ILabsHeader *)&buffer[0];
169 :
170 35334 : if (buffer_ofs < sizeof(ILabsHeader)) {
171 35334 : n = MIN(n, sizeof(ILabsHeader)-buffer_ofs);
172 : } else {
173 0 : if (!check_header(h)) {
174 0 : re_sync();
175 0 : return false;
176 : }
177 0 : if (buffer_ofs > h->msg_len+8) {
178 0 : re_sync();
179 0 : return false;
180 : }
181 0 : n = MIN(n, uint32_t(h->msg_len + 2 - buffer_ofs));
182 : }
183 :
184 35334 : const ssize_t nread = uart->read(&buffer[buffer_ofs], n);
185 35334 : if (nread != ssize_t(n)) {
186 0 : re_sync();
187 0 : return false;
188 : }
189 35334 : buffer_ofs += n;
190 :
191 35334 : if (buffer_ofs < sizeof(ILabsHeader)) {
192 0 : return true;
193 : }
194 :
195 35334 : if (!check_header(h)) {
196 0 : re_sync();
197 0 : return false;
198 : }
199 :
200 35334 : if (buffer_ofs < h->msg_len+2) {
201 : /*
202 : see if we can read the rest immediately
203 : */
204 35334 : const uint16_t needed = h->msg_len+2 - buffer_ofs;
205 35334 : if (uart->available() < needed) {
206 : // need more data
207 0 : return true;
208 : }
209 35334 : const ssize_t nread2 = uart->read(&buffer[buffer_ofs], needed);
210 35334 : if (nread2 != needed) {
211 0 : re_sync();
212 0 : return false;
213 : }
214 35334 : buffer_ofs += nread2;
215 : }
216 :
217 : // check checksum
218 35334 : const uint16_t crc1 = crc_sum_of_bytes_16(&buffer[2], buffer_ofs-4);
219 35334 : const uint16_t crc2 = le16toh_ptr(&buffer[buffer_ofs-2]);
220 35334 : if (crc1 != crc2) {
221 0 : re_sync();
222 0 : return false;
223 : }
224 :
225 35334 : const uint8_t *buffer_end = &buffer[buffer_ofs];
226 35334 : const uint16_t payload_size = h->msg_len - 6;
227 35334 : const uint8_t *payload = &buffer[6];
228 35334 : if (payload_size < 3) {
229 0 : re_sync();
230 0 : return false;
231 : }
232 35334 : const uint8_t num_messages = payload[0];
233 35334 : if (num_messages == 0 ||
234 35334 : num_messages > payload_size-1) {
235 0 : re_sync();
236 0 : return false;
237 : }
238 35334 : const uint8_t *message_ofs = &payload[num_messages+1];
239 35334 : bool need_re_sync = false;
240 :
241 : // bitmask for what types we get
242 35334 : Bitmask<256> msg_types;
243 35334 : uint32_t now_ms = AP_HAL::millis();
244 :
245 1166022 : for (uint8_t i=0; i<num_messages; i++) {
246 1130688 : if (message_ofs >= buffer_end) {
247 0 : re_sync();
248 0 : return false;
249 : }
250 1130688 : MessageType mtype = (MessageType)payload[1+i];
251 1130688 : ILabsData &u = *(ILabsData*)message_ofs;
252 1130688 : uint8_t msg_len = 0;
253 :
254 1130688 : msg_types.set(unsigned(mtype));
255 :
256 1130688 : switch (mtype) {
257 35334 : case MessageType::GPS_INS_TIME_MS: {
258 : // this is the GPS tow timestamp in ms for when the IMU data was sampled
259 35334 : CHECK_SIZE(u.gnss_time_ms);
260 35334 : gps_data.ms_tow = u.gnss_time_ms;
261 35334 : break;
262 : }
263 35334 : case MessageType::GPS_WEEK: {
264 35334 : CHECK_SIZE(u.gnss_week);
265 35334 : gps_data.gps_week = u.gnss_week;
266 35334 : break;
267 : }
268 35334 : case MessageType::ACCEL_DATA_HR: {
269 35334 : CHECK_SIZE(u.accel_data_hr);
270 : // should use 9.8106 instead of GRAVITY_MSS-constant in accordance with the device-documentation
271 35334 : ins_data.accel = u.accel_data_hr.tofloat().rfu_to_frd()*9.8106f*1.0e-6; // m/s^2
272 35334 : break;
273 : }
274 35334 : case MessageType::GYRO_DATA_HR: {
275 35334 : CHECK_SIZE(u.gyro_data_hr);
276 35334 : ins_data.gyro = u.gyro_data_hr.tofloat().rfu_to_frd()*DEG_TO_RAD*1.0e-5; // rad/s
277 35334 : break;
278 : }
279 35334 : case MessageType::BARO_DATA: {
280 35334 : CHECK_SIZE(u.baro_data);
281 35334 : baro_data.pressure_pa = u.baro_data.pressure_pa2*2; // Pa
282 35334 : state2.baro_alt = u.baro_data.baro_alt*0.01; // m
283 35334 : break;
284 : }
285 35334 : case MessageType::MAG_DATA: {
286 35334 : CHECK_SIZE(u.mag_data);
287 35334 : mag_data.field = u.mag_data.tofloat().rfu_to_frd()*(10*NTESLA_TO_MGAUSS); // milligauss
288 35334 : break;
289 : }
290 35334 : case MessageType::ORIENTATION_ANGLES: {
291 35334 : CHECK_SIZE(u.orientation_angles);
292 35334 : state.quat.from_euler(radians(u.orientation_angles.roll*0.01),
293 35334 : radians(u.orientation_angles.pitch*0.01),
294 35334 : radians(u.orientation_angles.yaw*0.01));
295 35334 : state.have_quaternion = true;
296 35334 : if (last_att_ms == 0) {
297 11 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "InertialLabs: got link");
298 : }
299 35334 : last_att_ms = now_ms;
300 35334 : break;
301 : }
302 35334 : case MessageType::VELOCITIES: {
303 35334 : CHECK_SIZE(u.velocity);
304 35334 : state.velocity = u.velocity.tofloat().rfu_to_frd()*0.01;
305 35334 : gps_data.ned_vel_north = state.velocity.x; // m/s
306 35334 : gps_data.ned_vel_east = state.velocity.y; // m/s
307 35334 : gps_data.ned_vel_down = state.velocity.z; // m/s
308 35334 : state.have_velocity = true;
309 35334 : last_vel_ms = now_ms;
310 35334 : break;
311 : }
312 35334 : case MessageType::POSITION: {
313 35334 : CHECK_SIZE(u.position);
314 35334 : state.location.lat = u.position.lat; // deg*1.0e7
315 35334 : state.location.lng = u.position.lon; // deg*1.0e7
316 35334 : state.location.alt = u.position.alt; // m*100
317 :
318 35334 : gps_data.latitude = u.position.lat; // deg*1.0e7
319 35334 : gps_data.longitude = u.position.lon; // deg*1.0e7
320 35334 : gps_data.msl_altitude = u.position.alt; // m*100
321 :
322 35334 : state.have_location = true;
323 35334 : state.last_location_update_us = AP_HAL::micros();
324 35334 : last_pos_ms = now_ms;
325 35334 : break;
326 : }
327 35334 : case MessageType::KF_VEL_COVARIANCE: {
328 35334 : CHECK_SIZE(u.kf_vel_covariance);
329 35334 : state2.kf_vel_covariance = u.kf_vel_covariance.tofloat().rfu_to_frd(); // mm/s
330 35334 : break;
331 : }
332 35334 : case MessageType::KF_POS_COVARIANCE: {
333 35334 : CHECK_SIZE(u.kf_pos_covariance);
334 35334 : state2.kf_pos_covariance = u.kf_pos_covariance.tofloat(); // mm
335 35334 : break;
336 : }
337 35334 : case MessageType::UNIT_STATUS: {
338 35334 : CHECK_SIZE(u.unit_status);
339 35334 : state2.unit_status = u.unit_status;
340 35334 : break;
341 : }
342 35334 : case MessageType::GNSS_EXTENDED_INFO: {
343 35334 : CHECK_SIZE(u.gnss_extended_info);
344 35334 : gps_data.fix_type = AP_GPS_FixType(u.gnss_extended_info.fix_type+1);
345 35334 : gnss_data.spoof_status = u.gnss_extended_info.spoofing_status;
346 35334 : break;
347 : }
348 35334 : case MessageType::NUM_SATS: {
349 35334 : CHECK_SIZE(u.num_sats);
350 35334 : gps_data.satellites_in_view = u.num_sats;
351 35334 : break;
352 : }
353 35334 : case MessageType::GNSS_POSITION: {
354 35334 : CHECK_SIZE(u.gnss_position);
355 35334 : gnss_data.lat = u.gnss_position.lat; // deg*1.0e7
356 35334 : gnss_data.lng = u.gnss_position.lon; // deg*1.0e7
357 35334 : gnss_data.alt = u.gnss_position.alt; // mm
358 35334 : break;
359 : }
360 35334 : case MessageType::GNSS_VEL_TRACK: {
361 35334 : CHECK_SIZE(u.gnss_vel_track);
362 35334 : gnss_data.hor_speed = u.gnss_vel_track.hor_speed*0.01; // m/s
363 35334 : gnss_data.ver_speed = u.gnss_vel_track.ver_speed*0.01; // m/s
364 35334 : gnss_data.track_over_ground = u.gnss_vel_track.track_over_ground*0.01; // deg
365 35334 : break;
366 : }
367 35334 : case MessageType::GNSS_POS_TIMESTAMP: {
368 35334 : CHECK_SIZE(u.gnss_pos_timestamp);
369 35334 : gnss_data.pos_timestamp = u.gnss_pos_timestamp;
370 35334 : break;
371 : }
372 35334 : case MessageType::GNSS_INFO_SHORT: {
373 35334 : CHECK_SIZE(u.gnss_info_short);
374 35334 : gnss_data.info_short = u.gnss_info_short;
375 35334 : break;
376 : }
377 35334 : case MessageType::GNSS_NEW_DATA: {
378 35334 : CHECK_SIZE(u.gnss_new_data);
379 35334 : gnss_data.new_data = u.gnss_new_data;
380 35334 : break;
381 : }
382 35334 : case MessageType::GNSS_JAM_STATUS: {
383 35334 : CHECK_SIZE(u.gnss_jam_status);
384 35334 : gnss_data.jam_status = u.gnss_jam_status;
385 35334 : break;
386 : }
387 35334 : case MessageType::DIFFERENTIAL_PRESSURE: {
388 35334 : CHECK_SIZE(u.differential_pressure);
389 35334 : airspeed_data.differential_pressure = u.differential_pressure*1.0e-4*100; // 100: mbar to Pa
390 35334 : break;
391 : }
392 35334 : case MessageType::TRUE_AIRSPEED: {
393 35334 : CHECK_SIZE(u.true_airspeed);
394 35334 : state2.true_airspeed = u.true_airspeed*0.01; // m/s
395 35334 : break;
396 : }
397 35334 : case MessageType::WIND_SPEED: {
398 35334 : CHECK_SIZE(u.wind_speed);
399 35334 : state2.wind_speed = u.wind_speed.tofloat().rfu_to_frd()*0.01; // m/s
400 35334 : break;
401 : }
402 35334 : case MessageType::AIR_DATA_STATUS: {
403 35334 : CHECK_SIZE(u.air_data_status);
404 35334 : state2.air_data_status = u.air_data_status;
405 35334 : break;
406 : }
407 35334 : case MessageType::SUPPLY_VOLTAGE: {
408 35334 : CHECK_SIZE(u.supply_voltage);
409 35334 : state2.supply_voltage = u.supply_voltage*0.01; // V
410 35334 : break;
411 : }
412 35334 : case MessageType::TEMPERATURE: {
413 35334 : CHECK_SIZE(u.temperature);
414 : // assume same temperature for baro and airspeed
415 35334 : baro_data.temperature = u.temperature*0.1; // degC
416 35334 : airspeed_data.temperature = u.temperature*0.1; // degC
417 35334 : ins_data.temperature = u.temperature*0.1;
418 35334 : break;
419 : }
420 35334 : case MessageType::UNIT_STATUS2: {
421 35334 : CHECK_SIZE(u.unit_status2);
422 35334 : state2.unit_status2 = u.unit_status2;
423 35334 : break;
424 : }
425 35334 : case MessageType::GNSS_ANGLES: {
426 35334 : CHECK_SIZE(u.gnss_angles);
427 35334 : gnss_data.heading = u.gnss_angles.heading*0.01; // deg
428 35334 : gnss_data.pitch = u.gnss_angles.pitch*0.01; // deg
429 35334 : break;
430 : }
431 35334 : case MessageType::GNSS_ANGLE_POS_TYPE: {
432 35334 : CHECK_SIZE(u.gnss_angle_pos_type);
433 35334 : gnss_data.angle_pos_type = u.gnss_angle_pos_type;
434 35334 : break;
435 : }
436 35334 : case MessageType::GNSS_HEADING_TIMESTAMP: {
437 35334 : CHECK_SIZE(u.gnss_heading_timestamp);
438 35334 : gnss_data.heading_timestamp = u.gnss_heading_timestamp;
439 35334 : break;
440 : }
441 35334 : case MessageType::GNSS_DOP: {
442 35334 : CHECK_SIZE(u.gnss_dop);
443 35334 : gnss_data.gdop = u.gnss_dop.gdop*0.1;
444 35334 : gnss_data.pdop = u.gnss_dop.pdop*0.1;
445 35334 : gnss_data.tdop = u.gnss_dop.tdop*0.1;
446 :
447 35334 : gps_data.hdop = u.gnss_dop.hdop*0.1;
448 35334 : gps_data.vdop = u.gnss_dop.vdop*0.1;
449 35334 : break;
450 : }
451 35334 : case MessageType::INS_SOLUTION_STATUS: {
452 35334 : CHECK_SIZE(u.ins_sol_status);
453 35334 : state2.ins_sol_status = u.ins_sol_status;
454 35334 : break;
455 : }
456 : }
457 :
458 1130688 : if (msg_len == 0) {
459 : // got an unknown message
460 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "InertialLabs: unknown msg 0x%02x", unsigned(mtype));
461 0 : buffer_ofs = 0;
462 0 : return false;
463 : }
464 1130688 : message_ofs += msg_len;
465 :
466 1130688 : if (msg_len == 0 || need_re_sync) {
467 0 : re_sync();
468 0 : return false;
469 : }
470 : }
471 :
472 35334 : if (h->msg_len != message_ofs-buffer) {
473 : // we had stray bytes at the end of the message
474 0 : re_sync();
475 0 : return false;
476 : }
477 :
478 70668 : if (GOT_MSG(ACCEL_DATA_HR) &&
479 35334 : GOT_MSG(GYRO_DATA_HR)) {
480 35334 : AP::ins().handle_external(ins_data);
481 35334 : state.accel = ins_data.accel;
482 35334 : state.gyro = ins_data.gyro;
483 :
484 : #if HAL_LOGGING_ENABLED
485 35334 : uint64_t now_us = AP_HAL::micros64();
486 :
487 : // @LoggerMessage: ILB1
488 : // @Description: InertialLabs AHRS data1
489 : // @Field: TimeUS: Time since system startup
490 : // @Field: GMS: GPS INS time (round)
491 : // @Field: GyrX: Gyro X
492 : // @Field: GyrY: Gyro Y
493 : // @Field: GyrZ: Gyro z
494 : // @Field: AccX: Accelerometer X
495 : // @Field: AccY: Accelerometer Y
496 : // @Field: AccZ: Accelerometer Z
497 :
498 35334 : AP::logger().WriteStreaming("ILB1", "TimeUS,GMS,GyrX,GyrY,GyrZ,AccX,AccY,AccZ",
499 : "s-kkkooo",
500 : "F-------",
501 : "QIffffff",
502 : now_us, gps_data.ms_tow,
503 35334 : ins_data.gyro.x, ins_data.gyro.y, ins_data.gyro.z,
504 35334 : ins_data.accel.x, ins_data.accel.y, ins_data.accel.z);
505 : #endif // HAL_LOGGING_ENABLED
506 : }
507 :
508 70668 : if (GOT_MSG(GPS_INS_TIME_MS) &&
509 70668 : GOT_MSG(NUM_SATS) &&
510 70668 : GOT_MSG(GNSS_POSITION) &&
511 70668 : GOT_MSG(GNSS_NEW_DATA) &&
512 106002 : GOT_MSG(GNSS_EXTENDED_INFO) &&
513 35334 : gnss_data.new_data != 0) {
514 : uint8_t instance;
515 1763 : if (AP::gps().get_first_external_instance(instance)) {
516 1458 : AP::gps().handle_external(gps_data, instance);
517 : }
518 1763 : if (gps_data.satellites_in_view > 3) {
519 1763 : if (last_gps_ms == 0) {
520 11 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "InertialLabs: got GPS lock");
521 11 : if (!state.have_origin) {
522 11 : state.origin = Location{
523 : gps_data.latitude,
524 : gps_data.longitude,
525 : gps_data.msl_altitude,
526 : Location::AltFrame::ABSOLUTE};
527 11 : state.have_origin = true;
528 : }
529 : }
530 1763 : last_gps_ms = now_ms;
531 : }
532 :
533 : #if HAL_LOGGING_ENABLED
534 1763 : uint64_t now_us = AP_HAL::micros64();
535 :
536 : // @LoggerMessage: ILB4
537 : // @Description: InertialLabs AHRS data4
538 : // @Field: TimeUS: Time since system startup
539 : // @Field: GMS: GNSS Position timestamp
540 : // @Field: GWk: GPS Week
541 : // @Field: NSat: Number of satellites
542 : // @Field: NewGPS: Indicator of new update of GPS data
543 : // @Field: Lat: GNSS Latitude
544 : // @Field: Lng: GNSS Longitude
545 : // @Field: Alt: GNSS Altitude
546 : // @Field: GCrs: GNSS Track over ground
547 : // @Field: Spd: GNSS Horizontal speed
548 : // @Field: VZ: GNSS Vertical speed
549 :
550 1763 : AP::logger().WriteStreaming("ILB4", "TimeUS,GMS,GWk,NSat,NewGPS,Lat,Lng,Alt,GCrs,Spd,VZ",
551 : "s----DUmhnn",
552 : "F----------",
553 : "QIHBBffffff",
554 1763 : now_us, gnss_data.pos_timestamp, gps_data.gps_week,
555 1763 : gps_data.satellites_in_view, gnss_data.new_data,
556 1763 : gnss_data.lat*1.0e-7, gnss_data.lng*1.0e-7, gnss_data.alt*0.01,
557 1763 : gnss_data.track_over_ground, gnss_data.hor_speed, gnss_data.ver_speed
558 : );
559 :
560 : // @LoggerMessage: ILB5
561 : // @Description: InertialLabs AHRS data5
562 : // @Field: TimeUS: Time since system startup
563 : // @Field: GMS: GNSS Position timestamp
564 : // @Field: FType: fix type
565 : // @Field: GSS: GNSS spoofing status
566 : // @Field: GJS: GNSS jamming status
567 : // @Field: GI1: GNSS Info1
568 : // @Field: GI2: GNSS Info2
569 : // @Field: GAPS: GNSS Angles position type
570 :
571 1763 : AP::logger().WriteStreaming("ILB5", "TimeUS,GMS,FType,GSS,GJS,GI1,GI2,GAPS",
572 : "s-------",
573 : "F-------",
574 : "QIBBBBBB",
575 : now_us, gnss_data.pos_timestamp, gps_data.fix_type,
576 1763 : gnss_data.spoof_status, gnss_data.jam_status,
577 1763 : gnss_data.info_short.info1, gnss_data.info_short.info2,
578 1763 : gnss_data.angle_pos_type);
579 :
580 : // @LoggerMessage: ILB6
581 : // @Description: InertialLabs AHRS data6
582 : // @Field: TimeUS: Time since system startup
583 : // @Field: GMS: GNSS Position timestamp
584 : // @Field: GpsHTS: GNSS Heading timestamp
585 : // @Field: GpsYaw: GNSS Heading
586 : // @Field: GpsPitch: GNSS Pitch
587 : // @Field: GDOP: GNSS GDOP
588 : // @Field: PDOP: GNSS PDOP
589 : // @Field: HDOP: GNSS HDOP
590 : // @Field: VDOP: GNSS VDOP
591 : // @Field: TDOP: GNSS TDOP
592 :
593 1763 : AP::logger().WriteStreaming("ILB6", "TimeUS,GMS,GpsHTS,GpsYaw,GpsPitch,GDOP,PDOP,HDOP,VDOP,TDOP",
594 : "s--hd-----",
595 : "F---------",
596 : "QIIfffffff",
597 : now_us, gnss_data.pos_timestamp, gnss_data.heading_timestamp,
598 1763 : gnss_data.heading, gnss_data.pitch, gnss_data.gdop, gnss_data.pdop,
599 1763 : gps_data.hdop, gps_data.vdop, gnss_data.tdop);
600 : #endif // HAL_LOGGING_ENABLED
601 : }
602 :
603 : #if AP_BARO_EXTERNALAHRS_ENABLED
604 70668 : if (GOT_MSG(BARO_DATA) &&
605 35334 : GOT_MSG(TEMPERATURE)) {
606 35334 : AP::baro().handle_external(baro_data);
607 :
608 : #if HAL_LOGGING_ENABLED
609 35334 : uint64_t now_us = AP_HAL::micros64();
610 :
611 : // @LoggerMessage: ILB3
612 : // @Description: InertialLabs AHRS data3
613 : // @Field: TimeUS: Time since system startup
614 : // @Field: GMS: GPS INS time (round)
615 : // @Field: Press: Static pressure
616 : // @Field: Diff: Differential pressure
617 : // @Field: Temp: Temperature
618 : // @Field: Alt: Baro altitude
619 : // @Field: TAS: true airspeed
620 : // @Field: VWN: Wind velocity north
621 : // @Field: VWE: Wind velocity east
622 : // @Field: VWD: Wind velocity down
623 : // @Field: ADU: Air Data Unit status
624 :
625 35334 : AP::logger().WriteStreaming("ILB3", "TimeUS,GMS,Press,Diff,Temp,Alt,TAS,VWN,VWE,VWD,ADU",
626 : "s-PPOmnnnn-",
627 : "F----------",
628 : "QIffffffffH",
629 : now_us, gps_data.ms_tow,
630 35334 : baro_data.pressure_pa, airspeed_data.differential_pressure, baro_data.temperature,
631 35334 : state2.baro_alt, state2.true_airspeed,
632 35334 : state2.wind_speed.x, state2.wind_speed.y, state2.wind_speed.z,
633 35334 : state2.air_data_status);
634 : #endif // HAL_LOGGING_ENABLED
635 : }
636 : #endif // AP_BARO_EXTERNALAHRS_ENABLED
637 :
638 : #if AP_COMPASS_EXTERNALAHRS_ENABLED
639 35334 : if (GOT_MSG(MAG_DATA)) {
640 35334 : AP::compass().handle_external(mag_data);
641 :
642 : #if HAL_LOGGING_ENABLED
643 35334 : uint64_t now_us = AP_HAL::micros64();
644 :
645 : // @LoggerMessage: ILB2
646 : // @Description: InertialLabs AHRS data2
647 : // @Field: TimeUS: Time since system startup
648 : // @Field: GMS: GPS INS time (round)
649 : // @Field: MagX: Magnetometer X
650 : // @Field: MagY: Magnetometer Y
651 : // @Field: MagZ: Magnetometer Z
652 :
653 35334 : AP::logger().WriteStreaming("ILB2", "TimeUS,GMS,MagX,MagY,MagZ",
654 : "s----",
655 : "F----",
656 : "QIfff",
657 : now_us, gps_data.ms_tow,
658 35334 : mag_data.field.x, mag_data.field.y, mag_data.field.z);
659 : #endif // HAL_LOGGING_ENABLED
660 : }
661 : #endif // AP_COMPASS_EXTERNALAHRS_ENABLED
662 :
663 : #if AP_AIRSPEED_EXTERNAL_ENABLED && (APM_BUILD_COPTER_OR_HELI || APM_BUILD_TYPE(APM_BUILD_ArduPlane))
664 : // only on plane and copter as others do not link AP_Airspeed
665 70668 : if (GOT_MSG(DIFFERENTIAL_PRESSURE) &&
666 35334 : GOT_MSG(TEMPERATURE)) {
667 35334 : auto *arsp = AP::airspeed();
668 35334 : if (arsp != nullptr) {
669 35334 : arsp->handle_external(airspeed_data);
670 : }
671 : }
672 :
673 : #endif // AP_AIRSPEED_EXTERNAL_ENABLED
674 :
675 35334 : buffer_ofs = 0;
676 :
677 70668 : if (GOT_MSG(POSITION) &&
678 70668 : GOT_MSG(ORIENTATION_ANGLES) &&
679 35334 : GOT_MSG(VELOCITIES)) {
680 :
681 : float roll, pitch, yaw_deg;
682 35334 : state.quat.to_euler(roll, pitch, yaw_deg);
683 :
684 35334 : yaw_deg = fmodf(degrees(yaw_deg), 360.0f);
685 35334 : if (yaw_deg < 0.0f) {
686 30912 : yaw_deg += 360.0f;
687 : }
688 :
689 : #if HAL_LOGGING_ENABLED
690 35334 : uint64_t now_us = AP_HAL::micros64();
691 :
692 : // @LoggerMessage: ILB7
693 : // @Description: InertialLabs AHRS data7
694 : // @Field: TimeUS: Time since system startup
695 : // @Field: GMS: GPS INS time (round)
696 : // @Field: Roll: euler roll
697 : // @Field: Pitch: euler pitch
698 : // @Field: Yaw: euler yaw
699 : // @Field: VN: velocity north
700 : // @Field: VE: velocity east
701 : // @Field: VD: velocity down
702 : // @Field: Lat: latitude
703 : // @Field: Lng: longitude
704 : // @Field: Alt: altitude MSL
705 : // @Field: USW: USW1
706 : // @Field: USW2: USW2
707 : // @Field: Vdc: Supply voltage
708 :
709 70668 : AP::logger().WriteStreaming("ILB7", "TimeUS,GMS,Roll,Pitch,Yaw,VN,VE,VD,Lat,Lng,Alt,USW,USW2,Vdc",
710 : "s-dddnnnDUm--v",
711 : "F-------------",
712 : "QIfffffffffHHf",
713 : now_us, gps_data.ms_tow,
714 35334 : degrees(roll), degrees(pitch), yaw_deg,
715 35334 : state.velocity.x, state.velocity.y, state.velocity.z,
716 35334 : state.location.lat*1.0e-7, state.location.lng*1.0e-7, state.location.alt*0.01,
717 35334 : state2.unit_status, state2.unit_status2,
718 35334 : state2.supply_voltage);
719 :
720 : // @LoggerMessage: ILB8
721 : // @Description: InertialLabs AHRS data8
722 : // @Field: TimeUS: Time since system startup
723 : // @Field: GMS: GPS INS time (round)
724 : // @Field: PVN: position variance north
725 : // @Field: PVE: position variance east
726 : // @Field: PVD: position variance down
727 : // @Field: VVN: velocity variance north
728 : // @Field: VVE: velocity variance east
729 : // @Field: VVD: velocity variance down
730 :
731 35334 : AP::logger().WriteStreaming("ILB8", "TimeUS,GMS,PVN,PVE,PVD,VVN,VVE,VVD",
732 : "s-mmmnnn",
733 : "F-------",
734 : "QIffffff",
735 : now_us, gps_data.ms_tow,
736 35334 : state2.kf_pos_covariance.x, state2.kf_pos_covariance.y, state2.kf_pos_covariance.z,
737 35334 : state2.kf_vel_covariance.x, state2.kf_vel_covariance.y, state2.kf_vel_covariance.z);
738 : #endif // HAL_LOGGING_ENABLED
739 : }
740 :
741 35334 : const uint32_t dt_critical_usw = 10000;
742 35334 : uint32_t now_usw = AP_HAL::millis();
743 :
744 : // InertialLabs critical messages to GCS (sending messages once every 10 seconds)
745 35334 : if ((last_unit_status != state2.unit_status) ||
746 35334 : (last_unit_status2 != state2.unit_status2) ||
747 35334 : (last_air_data_status != state2.air_data_status) ||
748 35334 : (now_usw - last_critical_msg_ms > dt_critical_usw)) {
749 :
750 : // Critical USW message
751 14 : if (state2.unit_status & ILABS_UNIT_STATUS_ALIGNMENT_FAIL) {
752 0 : GCS_SEND_TEXT(MAV_SEVERITY_CRITICAL, "ILAB: Unsuccessful initial alignment");
753 : }
754 14 : if (state2.unit_status & ILABS_UNIT_STATUS_OPERATION_FAIL) {
755 0 : GCS_SEND_TEXT(MAV_SEVERITY_CRITICAL, "ILAB: IMU data are incorrect");
756 : }
757 :
758 14 : if (state2.unit_status & ILABS_UNIT_STATUS_GYRO_FAIL) {
759 0 : GCS_SEND_TEXT(MAV_SEVERITY_CRITICAL, "ILAB: Gyros failure");
760 : }
761 :
762 14 : if (state2.unit_status & ILABS_UNIT_STATUS_ACCEL_FAIL) {
763 0 : GCS_SEND_TEXT(MAV_SEVERITY_CRITICAL, "ILAB: Accelerometers failure");
764 : }
765 :
766 14 : if (state2.unit_status & ILABS_UNIT_STATUS_MAG_FAIL) {
767 0 : GCS_SEND_TEXT(MAV_SEVERITY_CRITICAL, "ILAB: Magnetometers failure");
768 : }
769 :
770 14 : if (state2.unit_status & ILABS_UNIT_STATUS_ELECTRONICS_FAIL) {
771 0 : GCS_SEND_TEXT(MAV_SEVERITY_CRITICAL, "ILAB: Electronics failure");
772 : }
773 :
774 14 : if (state2.unit_status & ILABS_UNIT_STATUS_GNSS_FAIL) {
775 0 : GCS_SEND_TEXT(MAV_SEVERITY_CRITICAL, "ILAB: GNSS receiver failure");
776 : }
777 :
778 : // Critical USW2 message
779 14 : if (state2.unit_status2 & ILABS_UNIT_STATUS2_BARO_FAIL) {
780 0 : GCS_SEND_TEXT(MAV_SEVERITY_CRITICAL, "ILAB: Baro altimeter failure");
781 : }
782 :
783 14 : if (state2.unit_status2 & ILABS_UNIT_STATUS2_DIFF_PRESS_FAIL) {
784 0 : GCS_SEND_TEXT(MAV_SEVERITY_CRITICAL, "ILAB: Diff. pressure sensor failure");
785 : }
786 :
787 : // Critical ADU message
788 14 : if (state2.air_data_status & ILABS_AIRDATA_INIT_FAIL) {
789 0 : GCS_SEND_TEXT(MAV_SEVERITY_CRITICAL, "ILAB: Static pressure sensor unsuccessful initialization");
790 : }
791 :
792 14 : if (state2.air_data_status & ILABS_AIRDATA_DIFF_PRESS_INIT_FAIL) {
793 0 : GCS_SEND_TEXT(MAV_SEVERITY_CRITICAL, "ILAB: Diff. pressure sensor unsuccessful initialization");
794 : }
795 :
796 14 : if (state2.air_data_status & ILABS_AIRDATA_STATIC_PRESS_FAIL) {
797 0 : GCS_SEND_TEXT(MAV_SEVERITY_ERROR, "ILAB: Static pressure sensor failure is detect");
798 : }
799 :
800 14 : if (state2.air_data_status & ILABS_AIRDATA_DIFF_PRESS_FAIL) {
801 0 : GCS_SEND_TEXT(MAV_SEVERITY_ERROR, "ILAB: Diff. pressure sensor failure is detect");
802 : }
803 :
804 14 : last_critical_msg_ms = AP_HAL::millis();
805 : }
806 :
807 35334 : if (last_unit_status != state2.unit_status) {
808 0 : if (state2.unit_status & ILABS_UNIT_STATUS_RUNTIME_CAL) {
809 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: On-the-fly calibration is in progress");
810 : }
811 :
812 0 : if (state2.unit_status & ILABS_UNIT_STATUS_VOLTAGE_LOW) {
813 0 : GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "ILAB: Low input voltage");
814 : } else {
815 0 : if (last_unit_status & ILABS_UNIT_STATUS_VOLTAGE_LOW) {
816 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: Input voltage is in range");
817 : }
818 : }
819 :
820 0 : if (state2.unit_status & ILABS_UNIT_STATUS_VOLTAGE_HIGH) {
821 0 : GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "ILAB: High input voltage");
822 : } else {
823 0 : if (last_unit_status & ILABS_UNIT_STATUS_VOLTAGE_HIGH) {
824 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: Input voltage is in range");
825 : }
826 : }
827 :
828 0 : if (state2.unit_status & ILABS_UNIT_STATUS_X_RATE_HIGH) {
829 0 : GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "ILAB: Y-axis angular rate is exceeded");
830 : } else {
831 0 : if (last_unit_status & ILABS_UNIT_STATUS_X_RATE_HIGH) {
832 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: Y-axis angular rate is in range");
833 : }
834 : }
835 :
836 0 : if (state2.unit_status & ILABS_UNIT_STATUS_Y_RATE_HIGH) {
837 0 : GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "ILAB: X-axis angular rate is exceeded");
838 : } else {
839 0 : if (last_unit_status & ILABS_UNIT_STATUS_Y_RATE_HIGH) {
840 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: X-axis angular rate is in range");
841 : }
842 : }
843 :
844 0 : if (state2.unit_status & ILABS_UNIT_STATUS_Z_RATE_HIGH) {
845 0 : GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "ILAB: Z-axis angular rate is exceeded");
846 : } else {
847 0 : if (last_unit_status & ILABS_UNIT_STATUS_Z_RATE_HIGH) {
848 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: Z-axis angular rate is in range");
849 : }
850 : }
851 :
852 0 : if (state2.unit_status & ILABS_UNIT_STATUS_MAG_FIELD_HIGH) {
853 0 : GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "ILAB: Large total magnetic field");
854 : } else {
855 0 : if (last_unit_status & ILABS_UNIT_STATUS_MAG_FIELD_HIGH) {
856 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: Total magnetic field is in range");
857 : }
858 : }
859 :
860 0 : if (state2.unit_status & ILABS_UNIT_STATUS_TEMP_RANGE_ERR) {
861 0 : GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "ILAB: Temperature is out of range");
862 : } else {
863 0 : if (last_unit_status & ILABS_UNIT_STATUS_TEMP_RANGE_ERR) {
864 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: Temperature is in range");
865 : }
866 : }
867 :
868 0 : if (state2.unit_status & ILABS_UNIT_STATUS_RUNTIME_CAL2) {
869 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: On-the-fly calibration successful");
870 : }
871 :
872 0 : last_unit_status = state2.unit_status;
873 : }
874 :
875 : // InertialLabs INS Unit Status Word 2 (USW2) messages to GCS
876 35334 : if (last_unit_status2 != state2.unit_status2) {
877 0 : if (state2.unit_status2 & ILABS_UNIT_STATUS2_ACCEL_X_HIGH) {
878 0 : GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "ILAB: Y-acceleration is out of range");
879 : } else {
880 0 : if (last_unit_status2 & ILABS_UNIT_STATUS2_ACCEL_X_HIGH) {
881 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: Y-acceleration is in range");
882 : }
883 : }
884 :
885 0 : if (state2.unit_status2 & ILABS_UNIT_STATUS2_ACCEL_Y_HIGH) {
886 0 : GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "ILAB: X-acceleration is out of range");
887 : } else {
888 0 : if (last_unit_status2 & ILABS_UNIT_STATUS2_ACCEL_Y_HIGH) {
889 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: X-acceleration is in range");
890 : }
891 : }
892 :
893 0 : if (state2.unit_status2 & ILABS_UNIT_STATUS2_ACCEL_Z_HIGH) {
894 0 : GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "ILAB: Z-acceleration is out of range");
895 : } else {
896 0 : if (last_unit_status2 & ILABS_UNIT_STATUS2_ACCEL_Z_HIGH) {
897 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: Z-acceleration is in range");
898 : }
899 : }
900 :
901 0 : if (state2.unit_status2 & ILABS_UNIT_STATUS2_MAGCAL_2D_ACT) {
902 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: Automatic 2D calibration is in progress");
903 : }
904 :
905 0 : if (state2.unit_status2 & ILABS_UNIT_STATUS2_MAGCAL_3D_ACT) {
906 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: Automatic 3D calibration is in progress");
907 : }
908 :
909 0 : if (state2.unit_status2 & ILABS_UNIT_STATUS2_GNSS_FUSION_OFF) {
910 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: GNSS input switched off");
911 : } else {
912 0 : if (last_unit_status2 & ILABS_UNIT_STATUS2_GNSS_FUSION_OFF) {
913 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: GNSS input switched on");
914 : }
915 : }
916 :
917 0 : if (state2.unit_status2 & ILABS_UNIT_STATUS2_DIFF_PRESS_FUSION_OFF) {
918 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: Diff. pressure input switched off");
919 : } else {
920 0 : if (last_unit_status2 & ILABS_UNIT_STATUS2_DIFF_PRESS_FUSION_OFF) {
921 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: Diff. pressure input switched on");
922 : }
923 : }
924 :
925 0 : if (state2.unit_status2 & ILABS_UNIT_STATUS2_MAG_FUSION_OFF) {
926 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: Magnetometer input switched off");
927 : } else {
928 0 : if (last_unit_status2 & ILABS_UNIT_STATUS2_MAG_FUSION_OFF) {
929 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: Magnetometer input switched on");
930 : }
931 : }
932 :
933 0 : if (state2.unit_status2 & ILABS_UNIT_STATUS2_GNSS_POS_VALID) {
934 0 : GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "ILAB: Incorrect GNSS position");
935 : } else {
936 0 : if (last_unit_status2 & ILABS_UNIT_STATUS2_GNSS_POS_VALID) {
937 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: GNSS position is correct");
938 : }
939 : }
940 :
941 0 : last_unit_status2 = state2.unit_status2;
942 : }
943 :
944 : // InertialLabs INS Air Data Unit (ADU) status messages to GCS
945 35334 : if (last_air_data_status != state2.air_data_status) {
946 0 : if (state2.air_data_status & ILABS_AIRDATA_STATIC_PRESS_RANGE_ERR) {
947 0 : GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "ILAB: Static pressure is out of range");
948 : } else {
949 0 : if (last_air_data_status & ILABS_AIRDATA_STATIC_PRESS_RANGE_ERR) {
950 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: Static pressure is in range");
951 : }
952 : }
953 :
954 0 : if (state2.air_data_status & ILABS_AIRDATA_DIFF_PRESS_RANGE_ERR) {
955 0 : GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "ILAB: Diff. pressure is out of range");
956 : } else {
957 0 : if (last_air_data_status & ILABS_AIRDATA_DIFF_PRESS_RANGE_ERR) {
958 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: Diff. pressure is in range");
959 : }
960 : }
961 :
962 0 : if (state2.air_data_status & ILABS_AIRDATA_PRESS_ALT_FAIL) {
963 0 : GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "ILAB: Pressure altitude is incorrect");
964 : } else {
965 0 : if (last_air_data_status & ILABS_AIRDATA_PRESS_ALT_FAIL) {
966 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "Pressure altitude is correct");
967 : }
968 : }
969 :
970 0 : if (state2.air_data_status & ILABS_AIRDATA_AIRSPEED_FAIL) {
971 0 : GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "ILAB: Air speed is incorrect");
972 : } else {
973 0 : if (last_air_data_status & ILABS_AIRDATA_AIRSPEED_FAIL) {
974 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: Air speed is correct");
975 : }
976 : }
977 :
978 0 : if (state2.air_data_status & ILABS_AIRDATA_AIRSPEED_FAIL) {
979 0 : GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "ILAB: Air speed is below the threshold");
980 : } else {
981 0 : if (last_air_data_status & ILABS_AIRDATA_AIRSPEED_FAIL) {
982 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: Air speed is above the threshold");
983 : }
984 : }
985 :
986 0 : last_air_data_status = state2.air_data_status;
987 : }
988 :
989 : // InertialLabs INS spoofing detection messages to GCS
990 35334 : if (last_spoof_status != gnss_data.spoof_status) {
991 11 : if ((last_spoof_status == 2 || last_spoof_status == 3) && (gnss_data.spoof_status == 1)) {
992 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: GNSS no spoofing");
993 : }
994 :
995 11 : if (last_spoof_status == 2) {
996 0 : GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "ILAB: GNSS spoofing indicated");
997 : }
998 :
999 11 : if (last_spoof_status == 3) {
1000 0 : GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "ILAB: GNSS multiple spoofing indicated");
1001 : }
1002 :
1003 11 : last_spoof_status = gnss_data.spoof_status;
1004 : }
1005 :
1006 : // InertialLabs INS jamming detection messages to GCS
1007 35334 : if (last_jam_status != gnss_data.jam_status) {
1008 11 : if ((last_jam_status == 2 || last_jam_status == 3) && (gnss_data.jam_status == 1)) {
1009 0 : GCS_SEND_TEXT(MAV_SEVERITY_INFO, "ILAB: GNSS no jamming");
1010 : }
1011 :
1012 11 : if (gnss_data.jam_status == 3) {
1013 0 : GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "ILAB: GNSS jamming indicated and no fix");
1014 : }
1015 :
1016 11 : last_jam_status = gnss_data.jam_status;
1017 : }
1018 :
1019 35334 : return true;
1020 85089 : }
1021 :
1022 11 : void AP_ExternalAHRS_InertialLabs::update_thread()
1023 : {
1024 : // Open port in the thread
1025 11 : uart->begin(baudrate, 1024, 512);
1026 :
1027 : /*
1028 : we assume the user has already configured the device
1029 : */
1030 :
1031 11 : setup_complete = true;
1032 : while (true) {
1033 76926 : if (!check_uart()) {
1034 45538 : hal.scheduler->delay_microseconds(250);
1035 : }
1036 : }
1037 : }
1038 :
1039 : // get serial port number for the uart
1040 33 : int8_t AP_ExternalAHRS_InertialLabs::get_port(void) const
1041 : {
1042 33 : if (!uart) {
1043 0 : return -1;
1044 : }
1045 33 : return port_num;
1046 : };
1047 :
1048 : // accessors for AP_AHRS
1049 8209 : bool AP_ExternalAHRS_InertialLabs::healthy(void) const
1050 : {
1051 8209 : WITH_SEMAPHORE(state.sem);
1052 8209 : return AP_HAL::millis() - last_att_ms < 100;
1053 8209 : }
1054 :
1055 8163 : bool AP_ExternalAHRS_InertialLabs::initialised(void) const
1056 : {
1057 8163 : if (!setup_complete) {
1058 0 : return false;
1059 : }
1060 8163 : return true;
1061 : }
1062 :
1063 46 : bool AP_ExternalAHRS_InertialLabs::pre_arm_check(char *failure_msg, uint8_t failure_msg_len) const
1064 : {
1065 46 : if (!setup_complete) {
1066 0 : hal.util->snprintf(failure_msg, failure_msg_len, "InertialLabs setup failed");
1067 0 : return false;
1068 : }
1069 46 : if (!healthy()) {
1070 0 : hal.util->snprintf(failure_msg, failure_msg_len, "InertialLabs unhealthy");
1071 0 : return false;
1072 : }
1073 46 : WITH_SEMAPHORE(state.sem);
1074 46 : uint32_t now = AP_HAL::millis();
1075 46 : if (now - last_att_ms > 10 ||
1076 46 : now - last_pos_ms > 10 ||
1077 46 : now - last_vel_ms > 10) {
1078 0 : hal.util->snprintf(failure_msg, failure_msg_len, "InertialLabs not up to date");
1079 0 : return false;
1080 : }
1081 46 : return true;
1082 46 : }
1083 :
1084 : /*
1085 : get filter status. We don't know the meaning of the status bits yet,
1086 : so assume all OK if we have GPS lock
1087 : */
1088 9759 : void AP_ExternalAHRS_InertialLabs::get_filter_status(nav_filter_status &status) const
1089 : {
1090 9759 : WITH_SEMAPHORE(state.sem);
1091 9759 : uint32_t now = AP_HAL::millis();
1092 9759 : const uint32_t dt_limit = 200;
1093 9759 : const uint32_t dt_limit_gps = 500;
1094 9759 : memset(&status, 0, sizeof(status));
1095 9759 : const bool init_ok = (state2.unit_status & (ILABS_UNIT_STATUS_ALIGNMENT_FAIL|ILABS_UNIT_STATUS_OPERATION_FAIL))==0;
1096 9759 : status.flags.initalized = init_ok;
1097 9759 : status.flags.attitude = init_ok && (now - last_att_ms < dt_limit) && init_ok;
1098 9759 : status.flags.vert_vel = init_ok && (now - last_vel_ms < dt_limit);
1099 9759 : status.flags.vert_pos = init_ok && (now - last_pos_ms < dt_limit);
1100 9759 : status.flags.horiz_vel = status.flags.vert_vel;
1101 9759 : status.flags.horiz_pos_abs = status.flags.vert_pos;
1102 9759 : status.flags.horiz_pos_rel = status.flags.horiz_pos_abs;
1103 9759 : status.flags.pred_horiz_pos_rel = status.flags.horiz_pos_abs;
1104 9759 : status.flags.pred_horiz_pos_abs = status.flags.horiz_pos_abs;
1105 19518 : status.flags.using_gps = (now - last_gps_ms < dt_limit_gps) &&
1106 9759 : ((state2.unit_status & ILABS_UNIT_STATUS_GNSS_FAIL) | (state2.unit_status2 & ILABS_UNIT_STATUS2_GNSS_FUSION_OFF)) == 0;
1107 29277 : status.flags.gps_quality_good = (now - last_gps_ms < dt_limit_gps) &&
1108 9759 : (state2.unit_status2 & ILABS_UNIT_STATUS2_GNSS_POS_VALID) != 0 &&
1109 0 : (state2.unit_status & ILABS_UNIT_STATUS_GNSS_FAIL) == 0;
1110 9759 : status.flags.rejecting_airspeed = (state2.air_data_status & ILABS_AIRDATA_AIRSPEED_FAIL);
1111 9759 : }
1112 :
1113 : // get variances
1114 9759 : bool AP_ExternalAHRS_InertialLabs::get_variances(float &velVar, float &posVar, float &hgtVar, Vector3f &magVar, float &tasVar) const
1115 : {
1116 9759 : velVar = state2.kf_vel_covariance.length() * vel_gate_scale;
1117 9759 : posVar = state2.kf_pos_covariance.xy().length() * pos_gate_scale;
1118 9759 : hgtVar = state2.kf_pos_covariance.z * hgt_gate_scale;
1119 9759 : tasVar = 0;
1120 9759 : return true;
1121 : }
1122 :
1123 : #endif // AP_EXTERNAL_AHRS_INERTIALLABS_ENABLED
1124 :
|