mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2025-04-11 03:02:20 +02:00
Merged in TheOtherCliff/librepilot/theothercliff/LP-212_Support_DJI_GPS_mag_combo (pull request #173)
LP-212 DJI GPSMag support
This commit is contained in:
commit
a4830a576d
@ -2,7 +2,8 @@
|
|||||||
******************************************************************************
|
******************************************************************************
|
||||||
*
|
*
|
||||||
* @file auxmagsupport.c
|
* @file auxmagsupport.c
|
||||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2014.
|
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015-2016.
|
||||||
|
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2014.
|
||||||
* @brief Functions to handle aux mag data and calibration.
|
* @brief Functions to handle aux mag data and calibration.
|
||||||
* --
|
* --
|
||||||
* @see The GNU Public License (GPL) Version 3
|
* @see The GNU Public License (GPL) Version 3
|
||||||
@ -57,6 +58,10 @@ void auxmagsupport_reload_settings()
|
|||||||
|
|
||||||
// GPSV9, Ext (unused), and Flexi
|
// GPSV9, Ext (unused), and Flexi
|
||||||
AuxMagSettingsTypeGet(&option);
|
AuxMagSettingsTypeGet(&option);
|
||||||
|
|
||||||
|
const uint8_t status = AUXMAGSENSOR_STATUS_NONE;
|
||||||
|
// next sample from other external mags will provide the right status if present
|
||||||
|
AuxMagSensorStatusSet((uint8_t *)&status);
|
||||||
}
|
}
|
||||||
|
|
||||||
void auxmagsupport_publish_samples(float mags[3], uint8_t status)
|
void auxmagsupport_publish_samples(float mags[3], uint8_t status)
|
||||||
|
408
flight/modules/GPS/DJI.c
Normal file
408
flight/modules/GPS/DJI.c
Normal file
@ -0,0 +1,408 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @addtogroup OpenPilotModules OpenPilot Modules
|
||||||
|
* @{
|
||||||
|
* @addtogroup GSPModule GPS Module
|
||||||
|
* @brief Process GPS information (DJI-Naza binary format)
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file DJI.c
|
||||||
|
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016.
|
||||||
|
* @brief GPS module, handles DJI stream
|
||||||
|
* @see The GNU Public License (GPL) Version 3
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
/*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "openpilot.h"
|
||||||
|
#include "pios.h"
|
||||||
|
#include "pios_math.h"
|
||||||
|
#include <pios_helpers.h>
|
||||||
|
#include <pios_delay.h>
|
||||||
|
|
||||||
|
#if defined(PIOS_INCLUDE_GPS_DJI_PARSER)
|
||||||
|
|
||||||
|
#include "inc/DJI.h"
|
||||||
|
#include "inc/GPS.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <auxmagsupport.h>
|
||||||
|
|
||||||
|
// parsing functions
|
||||||
|
static void parse_dji_gps(struct DJIPacket *dji, GPSPositionSensorData *gpsPosition);
|
||||||
|
#if !defined(PIOS_GPS_MINIMAL)
|
||||||
|
static void parse_dji_mag(struct DJIPacket *dji, GPSPositionSensorData *gpsPosition);
|
||||||
|
static void parse_dji_ver(struct DJIPacket *dji, GPSPositionSensorData *gpsPosition);
|
||||||
|
#endif /* !defined(PIOS_GPS_MINIMAL) */
|
||||||
|
|
||||||
|
static bool checksum_dji_message(struct DJIPacket *dji);
|
||||||
|
static uint32_t parse_dji_message(struct DJIPacket *dji, GPSPositionSensorData *gpsPosition);
|
||||||
|
|
||||||
|
// parse table item
|
||||||
|
typedef struct {
|
||||||
|
uint8_t msgId;
|
||||||
|
void (*handler)(struct DJIPacket *dji, GPSPositionSensorData *gpsPosition);
|
||||||
|
} djiMessageHandler;
|
||||||
|
|
||||||
|
const djiMessageHandler djiHandlerTable[] = {
|
||||||
|
{ .msgId = DJI_ID_GPS, .handler = &parse_dji_gps },
|
||||||
|
#if !defined(PIOS_GPS_MINIMAL)
|
||||||
|
{ .msgId = DJI_ID_MAG, .handler = &parse_dji_mag },
|
||||||
|
{ .msgId = DJI_ID_VER, .handler = &parse_dji_ver },
|
||||||
|
#endif /* !defined(PIOS_GPS_MINIMAL) */
|
||||||
|
};
|
||||||
|
#define DJI_HANDLER_TABLE_SIZE NELEMENTS(djiHandlerTable)
|
||||||
|
|
||||||
|
#if !defined(PIOS_GPS_MINIMAL)
|
||||||
|
static bool useMag = false;
|
||||||
|
|
||||||
|
// detected hw version
|
||||||
|
uint32_t djiHwVersion = -1;
|
||||||
|
uint32_t djiSwVersion = -1;
|
||||||
|
#endif /* !defined(PIOS_GPS_MINIMAL) */
|
||||||
|
|
||||||
|
|
||||||
|
// parse incoming character stream for messages in DJI binary format
|
||||||
|
#define djiPacket ((struct DJIPacket *)parsedDjiStruct)
|
||||||
|
int parse_dji_stream(uint8_t *inputBuffer, uint16_t inputBufferLength, char *parsedDjiStruct, GPSPositionSensorData *gpsPosition, struct GPS_RX_STATS *gpsRxStats)
|
||||||
|
{
|
||||||
|
enum ProtocolStates {
|
||||||
|
START,
|
||||||
|
DJI_SY2,
|
||||||
|
DJI_ID,
|
||||||
|
DJI_LEN,
|
||||||
|
DJI_PAYLOAD,
|
||||||
|
DJI_CHK1,
|
||||||
|
DJI_CHK2,
|
||||||
|
FINISHED
|
||||||
|
};
|
||||||
|
enum RestartStates {
|
||||||
|
RESTART_WITH_ERROR,
|
||||||
|
RESTART_NO_ERROR
|
||||||
|
};
|
||||||
|
static uint16_t payloadCount = 0;
|
||||||
|
static enum ProtocolStates protocolState = START;
|
||||||
|
static bool previousPacketGood = true;
|
||||||
|
int ret = PARSER_INCOMPLETE; // message not (yet) complete
|
||||||
|
uint16_t inputBufferIndex = 0;
|
||||||
|
uint16_t restartIndex = 0; // input buffer location to restart from
|
||||||
|
enum RestartStates restartState;
|
||||||
|
uint8_t inputByte;
|
||||||
|
bool currentPacketGood;
|
||||||
|
|
||||||
|
// switch continue is the normal condition and comes back to here for another byte
|
||||||
|
// switch break is the error state that branches to the end and restarts the scan at the byte after the first sync byte
|
||||||
|
while (inputBufferIndex < inputBufferLength) {
|
||||||
|
inputByte = inputBuffer[inputBufferIndex++];
|
||||||
|
switch (protocolState) {
|
||||||
|
case START: // detect protocol
|
||||||
|
if (inputByte == DJI_SYNC1) { // first DJI sync char found
|
||||||
|
protocolState = DJI_SY2;
|
||||||
|
// restart here, at byte after SYNC1, if we fail to parse
|
||||||
|
restartIndex = inputBufferIndex;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
case DJI_SY2:
|
||||||
|
if (inputByte == DJI_SYNC2) { // second DJI sync char found
|
||||||
|
protocolState = DJI_ID;
|
||||||
|
} else {
|
||||||
|
restartState = RESTART_NO_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
case DJI_ID:
|
||||||
|
djiPacket->header.id = inputByte;
|
||||||
|
protocolState = DJI_LEN;
|
||||||
|
continue;
|
||||||
|
case DJI_LEN:
|
||||||
|
if (inputByte > sizeof(DJIPayload)) {
|
||||||
|
gpsRxStats->gpsRxOverflow++;
|
||||||
|
restartState = RESTART_WITH_ERROR;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
djiPacket->header.len = inputByte;
|
||||||
|
if (inputByte == 0) {
|
||||||
|
protocolState = DJI_CHK1;
|
||||||
|
} else {
|
||||||
|
payloadCount = 0;
|
||||||
|
protocolState = DJI_PAYLOAD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
case DJI_PAYLOAD:
|
||||||
|
if (payloadCount < djiPacket->header.len) {
|
||||||
|
djiPacket->payload.payload[payloadCount] = inputByte;
|
||||||
|
if (++payloadCount == djiPacket->header.len) {
|
||||||
|
protocolState = DJI_CHK1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
case DJI_CHK1:
|
||||||
|
djiPacket->header.checksumA = inputByte;
|
||||||
|
protocolState = DJI_CHK2;
|
||||||
|
continue;
|
||||||
|
case DJI_CHK2:
|
||||||
|
djiPacket->header.checksumB = inputByte;
|
||||||
|
// ignore checksum errors on correct mag packets that nonetheless have checksum errors
|
||||||
|
// these checksum errors happen very often on clone DJI GPS (never on real DJI GPS)
|
||||||
|
// and are caused by a clone DJI GPS firmware error
|
||||||
|
// the errors happen when it is time to send a non-mag packet (4 or 5 per second)
|
||||||
|
// instead of a mag packet (30 per second)
|
||||||
|
currentPacketGood = checksum_dji_message(djiPacket);
|
||||||
|
// message complete and valid or (it's a mag packet and the previous "any" packet was good)
|
||||||
|
if (currentPacketGood || (djiPacket->header.id == DJI_ID_MAG && previousPacketGood)) {
|
||||||
|
parse_dji_message(djiPacket, gpsPosition);
|
||||||
|
gpsRxStats->gpsRxReceived++;
|
||||||
|
protocolState = START;
|
||||||
|
// overwrite PARSER_INCOMPLETE with PARSER_COMPLETE
|
||||||
|
// but don't overwrite PARSER_ERROR with PARSER_COMPLETE
|
||||||
|
// pass PARSER_ERROR to caller if it happens even once
|
||||||
|
// only pass PARSER_COMPLETE back to caller if we parsed a full set of GPS data
|
||||||
|
// that allows the caller to know if we are parsing GPS data
|
||||||
|
// or just other packets for some reason (DJI clone firmware bug that happens sometimes)
|
||||||
|
if (djiPacket->header.id == DJI_ID_GPS && ret == PARSER_INCOMPLETE) {
|
||||||
|
ret = PARSER_COMPLETE; // message complete & processed
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
gpsRxStats->gpsRxChkSumError++;
|
||||||
|
restartState = RESTART_WITH_ERROR;
|
||||||
|
previousPacketGood = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
previousPacketGood = currentPacketGood;
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this simple restart doesn't work across calls
|
||||||
|
// but it does work within a single call
|
||||||
|
// and it does the expected thing across calls
|
||||||
|
// if restarting due to error detected in 2nd call to this function (on split packet)
|
||||||
|
// then we just restart at index 0, which is mid-packet, not the second byte
|
||||||
|
if (restartState == RESTART_WITH_ERROR) {
|
||||||
|
ret = PARSER_ERROR; // inform caller that we found at least one error (along with 0 or more good packets)
|
||||||
|
}
|
||||||
|
inputBuffer += restartIndex; // restart parsing just past the most recent SYNC1
|
||||||
|
inputBufferLength -= restartIndex;
|
||||||
|
inputBufferIndex = 0;
|
||||||
|
protocolState = START;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool checksum_dji_message(struct DJIPacket *dji)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint8_t checksumA, checksumB;
|
||||||
|
|
||||||
|
checksumA = dji->header.id;
|
||||||
|
checksumB = checksumA;
|
||||||
|
|
||||||
|
checksumA += dji->header.len;
|
||||||
|
checksumB += checksumA;
|
||||||
|
|
||||||
|
for (i = 0; i < dji->header.len; i++) {
|
||||||
|
checksumA += dji->payload.payload[i];
|
||||||
|
checksumB += checksumA;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dji->header.checksumA == checksumA &&
|
||||||
|
dji->header.checksumB == checksumB) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void parse_dji_gps(struct DJIPacket *dji, GPSPositionSensorData *gpsPosition)
|
||||||
|
{
|
||||||
|
GPSVelocitySensorData gpsVelocity;
|
||||||
|
struct DjiGps *djiGps = &dji->payload.gps;
|
||||||
|
|
||||||
|
// decode with xor mask
|
||||||
|
uint8_t mask = djiGps->unused5;
|
||||||
|
|
||||||
|
// some bytes at the end are not xored
|
||||||
|
// some bytes in the middle are not xored
|
||||||
|
for (uint8_t i = 0; i < GPS_DECODED_LENGTH; ++i) {
|
||||||
|
if (i != GPS_NOT_XORED_BYTE_1 && i != GPS_NOT_XORED_BYTE_2) {
|
||||||
|
dji->payload.payload[i] ^= mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gpsVelocity.North = (float)djiGps->velN * 0.01f;
|
||||||
|
gpsVelocity.East = (float)djiGps->velE * 0.01f;
|
||||||
|
gpsVelocity.Down = (float)djiGps->velD * 0.01f;
|
||||||
|
GPSVelocitySensorSet(&gpsVelocity);
|
||||||
|
|
||||||
|
#if !defined(PIOS_GPS_MINIMAL)
|
||||||
|
gpsPosition->Groundspeed = sqrtf(gpsVelocity.North * gpsVelocity.North + gpsVelocity.East * gpsVelocity.East);
|
||||||
|
#else
|
||||||
|
gpsPosition->Groundspeed = fmaxf(gpsVelocity.North, gpsVelocity.East) * 1.2f; // within 20% or so
|
||||||
|
#endif /* !defined(PIOS_GPS_MINIMAL) */
|
||||||
|
// don't allow a funny number like 4.87416e-06 to show up in Uavo Browser for Heading
|
||||||
|
// smallest groundspeed is 0.01f from (int)1 * (float)0.01
|
||||||
|
// so this is saying if groundspeed is zero
|
||||||
|
if (gpsPosition->Groundspeed < 0.009f) {
|
||||||
|
gpsPosition->Heading = 0.0f;
|
||||||
|
} else {
|
||||||
|
gpsPosition->Heading = RAD2DEG(atan2f(-gpsVelocity.East, -gpsVelocity.North)) + 180.0f;
|
||||||
|
}
|
||||||
|
gpsPosition->Altitude = (float)djiGps->hMSL * 0.001f;
|
||||||
|
// there is no source of geoid separation data in the DJI protocol
|
||||||
|
// Is there a reasonable world model calculation we can do to get a value for geoid separation?
|
||||||
|
gpsPosition->GeoidSeparation = 0.0f;
|
||||||
|
gpsPosition->Latitude = djiGps->lat;
|
||||||
|
gpsPosition->Longitude = djiGps->lon;
|
||||||
|
gpsPosition->Satellites = djiGps->numSV;
|
||||||
|
gpsPosition->PDOP = djiGps->pDOP * 0.01f;
|
||||||
|
#if !defined(PIOS_GPS_MINIMAL)
|
||||||
|
gpsPosition->HDOP = sqrtf((float)djiGps->nDOP * (float)djiGps->nDOP + (float)djiGps->eDOP * (float)djiGps->eDOP) * 0.01f;
|
||||||
|
if (gpsPosition->HDOP > 99.99f) {
|
||||||
|
gpsPosition->HDOP = 99.99f;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
gpsPosition->HDOP = MAX(djiGps->nDOP, djiGps->eDOP) * 0.01f;
|
||||||
|
#endif
|
||||||
|
gpsPosition->VDOP = djiGps->vDOP * 0.01f;
|
||||||
|
if (djiGps->flags & FLAGS_GPSFIX_OK) {
|
||||||
|
gpsPosition->Status = djiGps->fixType == FIXTYPE_3D ?
|
||||||
|
GPSPOSITIONSENSOR_STATUS_FIX3D : GPSPOSITIONSENSOR_STATUS_FIX2D;
|
||||||
|
} else {
|
||||||
|
gpsPosition->Status = GPSPOSITIONSENSOR_STATUS_NOFIX;
|
||||||
|
}
|
||||||
|
gpsPosition->SensorType = GPSPOSITIONSENSOR_SENSORTYPE_DJI;
|
||||||
|
gpsPosition->AutoConfigStatus = GPSPOSITIONSENSOR_AUTOCONFIGSTATUS_DISABLED;
|
||||||
|
GPSPositionSensorSet(gpsPosition);
|
||||||
|
|
||||||
|
#if !defined(PIOS_GPS_MINIMAL)
|
||||||
|
// Time is valid, set GpsTime
|
||||||
|
GPSTimeData gpsTime;
|
||||||
|
// the lowest bit of day and the highest bit of hour overlap (xored? no, stranger than that)
|
||||||
|
// this causes strange day/hour changes
|
||||||
|
// we could track it here and even if we guess wrong initially
|
||||||
|
// we can massage the data so that time doesn't jump at least
|
||||||
|
// and maybe make the assumption that most people will fly at 5pm, not 1am
|
||||||
|
// this is part of the DJI protocol
|
||||||
|
// see DJI.h for further info
|
||||||
|
gpsTime.Year = (int16_t)djiGps->year + 2000;
|
||||||
|
gpsTime.Month = djiGps->month;
|
||||||
|
gpsTime.Day = djiGps->day;
|
||||||
|
gpsTime.Hour = djiGps->hour;
|
||||||
|
gpsTime.Minute = djiGps->min;
|
||||||
|
gpsTime.Second = djiGps->sec;
|
||||||
|
GPSTimeSet(&gpsTime);
|
||||||
|
#endif /* !defined(PIOS_GPS_MINIMAL) */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(PIOS_GPS_MINIMAL)
|
||||||
|
void dji_load_mag_settings()
|
||||||
|
{
|
||||||
|
if (auxmagsupport_get_type() == AUXMAGSETTINGS_TYPE_DJI) {
|
||||||
|
useMag = true;
|
||||||
|
} else {
|
||||||
|
useMag = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void parse_dji_mag(struct DJIPacket *dji, __attribute__((unused)) GPSPositionSensorData *gpsPosition)
|
||||||
|
{
|
||||||
|
if (!useMag) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct DjiMag *mag = &dji->payload.mag;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
int8_t mask;
|
||||||
|
int8_t mask2;
|
||||||
|
};
|
||||||
|
int16_t maskmask;
|
||||||
|
} u;
|
||||||
|
u.mask = (int8_t)(dji->payload.payload[4]);
|
||||||
|
u.mask = u.mask2 = (((u.mask ^ (u.mask >> 4)) & 0x0F) | ((u.mask << 3) & 0xF0)) ^ (((u.mask & 0x01) << 3) | ((u.mask & 0x01) << 7));
|
||||||
|
// yes, z is only xored by mask<<8, not maskmask
|
||||||
|
float mags[3] = { mag->x ^ u.maskmask, mag->y ^ u.maskmask, mag->z ^ ((int16_t)u.mask << 8) };
|
||||||
|
auxmagsupport_publish_samples(mags, AUXMAGSENSOR_STATUS_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void parse_dji_ver(struct DJIPacket *dji, __attribute__((unused)) GPSPositionSensorData *gpsPosition)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
struct DjiVer *ver = &dji->payload.ver;
|
||||||
|
// decode with xor mask
|
||||||
|
uint8_t mask = (uint8_t)(ver->unused1);
|
||||||
|
|
||||||
|
// first 4 bytes are unused and 0 before the encryption
|
||||||
|
// so any one of them can be used for the decrypting xor mask
|
||||||
|
for (uint8_t i = VER_FIRST_DECODED_BYTE; i < sizeof(struct DjiVer); ++i) {
|
||||||
|
dji->payload.payload[i] ^= mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
djiHwVersion = ver->hwVersion;
|
||||||
|
djiSwVersion = ver->swVersion;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
GPSPositionSensorSensorTypeOptions sensorType;
|
||||||
|
sensorType = GPSPOSITIONSENSOR_SENSORTYPE_DJI;
|
||||||
|
GPSPositionSensorSensorTypeSet((uint8_t *)&sensorType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* !defined(PIOS_GPS_MINIMAL) */
|
||||||
|
|
||||||
|
|
||||||
|
// DJI message parser
|
||||||
|
// returns UAVObjectID if a UAVObject structure is ready for further processing
|
||||||
|
uint32_t parse_dji_message(struct DJIPacket *dji, GPSPositionSensorData *gpsPosition)
|
||||||
|
{
|
||||||
|
static bool djiInitialized = false;
|
||||||
|
uint32_t id = 0;
|
||||||
|
|
||||||
|
if (!djiInitialized) {
|
||||||
|
// initialize dop values. If no DOP sentence is received it is safer to initialize them to a high value rather than 0.
|
||||||
|
gpsPosition->HDOP = 99.99f;
|
||||||
|
gpsPosition->PDOP = 99.99f;
|
||||||
|
gpsPosition->VDOP = 99.99f;
|
||||||
|
djiInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < DJI_HANDLER_TABLE_SIZE; i++) {
|
||||||
|
const djiMessageHandler *handler = &djiHandlerTable[i];
|
||||||
|
if (handler->msgId == dji->header.id) {
|
||||||
|
handler->handler(dji, gpsPosition);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
uint8_t status;
|
||||||
|
GPSPositionSensorStatusGet(&status);
|
||||||
|
if (status == GPSPOSITIONSENSOR_STATUS_NOGPS) {
|
||||||
|
// Some dji thing has been received so GPS is there
|
||||||
|
status = GPSPOSITIONSENSOR_STATUS_NOFIX;
|
||||||
|
GPSPositionSensorStatusSet(&status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
#endif // PIOS_INCLUDE_GPS_DJI_PARSER
|
@ -7,7 +7,8 @@
|
|||||||
* @{
|
* @{
|
||||||
*
|
*
|
||||||
* @file GPS.c
|
* @file GPS.c
|
||||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016.
|
||||||
|
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||||
* @brief GPS module, handles GPS and NMEA stream
|
* @brief GPS module, handles GPS and NMEA stream
|
||||||
* @see The GNU Public License (GPL) Version 3
|
* @see The GNU Public License (GPL) Version 3
|
||||||
*
|
*
|
||||||
@ -48,30 +49,48 @@
|
|||||||
#include "GPS.h"
|
#include "GPS.h"
|
||||||
#include "NMEA.h"
|
#include "NMEA.h"
|
||||||
#include "UBX.h"
|
#include "UBX.h"
|
||||||
|
#include "DJI.h"
|
||||||
#if defined(PIOS_INCLUDE_GPS_UBX_PARSER) && !defined(PIOS_GPS_MINIMAL)
|
#if defined(PIOS_INCLUDE_GPS_UBX_PARSER) && !defined(PIOS_GPS_MINIMAL)
|
||||||
#include "inc/ubx_autoconfig.h"
|
#include "inc/ubx_autoconfig.h"
|
||||||
|
#define FULL_UBX_PARSER
|
||||||
#endif
|
#endif
|
||||||
|
#include <auxmagsupport.h>
|
||||||
|
|
||||||
#include <pios_instrumentation_helper.h>
|
#include <pios_instrumentation_helper.h>
|
||||||
PERF_DEFINE_COUNTER(counterBytesIn);
|
PERF_DEFINE_COUNTER(counterBytesIn);
|
||||||
PERF_DEFINE_COUNTER(counterRate);
|
PERF_DEFINE_COUNTER(counterRate);
|
||||||
PERF_DEFINE_COUNTER(counterParse);
|
PERF_DEFINE_COUNTER(counterParse);
|
||||||
|
|
||||||
|
#if defined(ANY_GPS_PARSER) || defined(ANY_FULL_GPS_PARSER) || defined(ANY_FULL_MAG_PARSER)
|
||||||
|
#error ANY_GPS_PARSER ANY_FULL_GPS_PARSER and ANY_FULL_MAG_PARSER should all be undefined at this point.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PIOS_INCLUDE_GPS_NMEA_PARSER) || defined(PIOS_INCLUDE_GPS_UBX_PARSER) || defined(PIOS_INCLUDE_GPS_DJI_PARSER)
|
||||||
|
#define ANY_GPS_PARSER
|
||||||
|
#endif
|
||||||
|
#if defined(ANY_GPS_PARSER) && !defined(PIOS_GPS_MINIMAL)
|
||||||
|
#define ANY_FULL_GPS_PARSER
|
||||||
|
#endif
|
||||||
|
#if (defined(PIOS_INCLUDE_HMC5X83) || defined(PIOS_INCLUDE_GPS_UBX_PARSER) || defined(PIOS_INCLUDE_GPS_DJI_PARSER)) && !defined(PIOS_GPS_MINIMAL)
|
||||||
|
#define ANY_FULL_MAG_PARSER
|
||||||
|
#endif
|
||||||
|
|
||||||
// ****************
|
// ****************
|
||||||
// Private functions
|
// Private functions
|
||||||
|
|
||||||
static void gpsTask(__attribute__((unused)) void *parameters);
|
static void gpsTask(__attribute__((unused)) void *parameters);
|
||||||
static void updateHwSettings(__attribute__((unused)) UAVObjEvent *ev);
|
static void updateHwSettings(__attribute__((unused)) UAVObjEvent *ev);
|
||||||
|
|
||||||
#ifdef PIOS_GPS_SETS_HOMELOCATION
|
#if defined(PIOS_GPS_SETS_HOMELOCATION)
|
||||||
static void setHomeLocation(GPSPositionSensorData *gpsData);
|
static void setHomeLocation(GPSPositionSensorData *gpsData);
|
||||||
static float GravityAccel(float latitude, float longitude, float altitude);
|
static float GravityAccel(float latitude, float longitude, float altitude);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef PIOS_INCLUDE_GPS_UBX_PARSER
|
#if defined(ANY_FULL_MAG_PARSER)
|
||||||
void AuxMagSettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev);
|
void AuxMagSettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev);
|
||||||
#ifndef PIOS_GPS_MINIMAL
|
|
||||||
void updateGpsSettings(__attribute__((unused)) UAVObjEvent *ev);
|
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(ANY_FULL_GPS_PARSER)
|
||||||
|
void updateGpsSettings(__attribute__((unused)) UAVObjEvent *ev);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ****************
|
// ****************
|
||||||
@ -124,7 +143,7 @@ static char *gps_rx_buffer;
|
|||||||
|
|
||||||
static uint32_t timeOfLastUpdateMs;
|
static uint32_t timeOfLastUpdateMs;
|
||||||
|
|
||||||
#if defined(PIOS_INCLUDE_GPS_NMEA_PARSER) || defined(PIOS_INCLUDE_GPS_UBX_PARSER)
|
#if defined(ANY_GPS_PARSER)
|
||||||
static struct GPS_RX_STATS gpsRxStats;
|
static struct GPS_RX_STATS gpsRxStats;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -178,7 +197,7 @@ int32_t GPSInitialize(void)
|
|||||||
GPSTimeInitialize();
|
GPSTimeInitialize();
|
||||||
GPSSatellitesInitialize();
|
GPSSatellitesInitialize();
|
||||||
HomeLocationInitialize();
|
HomeLocationInitialize();
|
||||||
#ifdef PIOS_INCLUDE_GPS_UBX_PARSER
|
#if defined(ANY_FULL_MAG_PARSER)
|
||||||
AuxMagSensorInitialize();
|
AuxMagSensorInitialize();
|
||||||
AuxMagSettingsInitialize();
|
AuxMagSettingsInitialize();
|
||||||
GPSExtendedStatusInitialize();
|
GPSExtendedStatusInitialize();
|
||||||
@ -212,19 +231,40 @@ int32_t GPSInitialize(void)
|
|||||||
#endif /* if defined(REVOLUTION) */
|
#endif /* if defined(REVOLUTION) */
|
||||||
|
|
||||||
if (gpsEnabled) {
|
if (gpsEnabled) {
|
||||||
#if defined(PIOS_INCLUDE_GPS_NMEA_PARSER) && defined(PIOS_INCLUDE_GPS_UBX_PARSER)
|
#if defined(PIOS_GPS_MINIMAL)
|
||||||
gps_rx_buffer = pios_malloc((sizeof(struct UBXPacket) > NMEA_MAX_PACKET_LENGTH) ? sizeof(struct UBXPacket) : NMEA_MAX_PACKET_LENGTH);
|
#if defined(PIOS_INCLUDE_GPS_UBX_PARSER)
|
||||||
#elif defined(PIOS_INCLUDE_GPS_UBX_PARSER)
|
|
||||||
gps_rx_buffer = pios_malloc(sizeof(struct UBXPacket));
|
gps_rx_buffer = pios_malloc(sizeof(struct UBXPacket));
|
||||||
#elif defined(PIOS_INCLUDE_GPS_NMEA_PARSER)
|
#elif defined(PIOS_INCLUDE_GPS_DJI_PARSER)
|
||||||
gps_rx_buffer = pios_malloc(NMEA_MAX_PACKET_LENGTH);
|
gps_rx_buffer = pios_malloc(sizeof(struct DJIPacket));
|
||||||
#else
|
#else
|
||||||
gps_rx_buffer = NULL;
|
gps_rx_buffer = NULL;
|
||||||
#endif
|
#endif
|
||||||
#if defined(PIOS_INCLUDE_GPS_NMEA_PARSER) || defined(PIOS_INCLUDE_GPS_UBX_PARSER)
|
#else /* defined(PIOS_GPS_MINIMAL) */
|
||||||
|
#if defined(ANY_GPS_PARSER)
|
||||||
|
#if defined(PIOS_INCLUDE_GPS_NMEA_PARSER)
|
||||||
|
size_t bufSize = NMEA_MAX_PACKET_LENGTH;
|
||||||
|
#else
|
||||||
|
size_t bufSize = 0;
|
||||||
|
#endif
|
||||||
|
#if defined(PIOS_INCLUDE_GPS_UBX_PARSER)
|
||||||
|
if (bufSize < sizeof(struct UBXPacket)) {
|
||||||
|
bufSize = sizeof(struct UBXPacket);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(PIOS_INCLUDE_GPS_DJI_PARSER)
|
||||||
|
if (bufSize < sizeof(struct DJIPacket)) {
|
||||||
|
bufSize = sizeof(struct DJIPacket);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
gps_rx_buffer = pios_malloc(bufSize);
|
||||||
|
#else /* defined(ANY_GPS_PARSER) */
|
||||||
|
gps_rx_buffer = NULL;
|
||||||
|
#endif /* defined(ANY_GPS_PARSER) */
|
||||||
|
#endif /* defined(PIOS_GPS_MINIMAL) */
|
||||||
|
#if defined(ANY_GPS_PARSER)
|
||||||
PIOS_Assert(gps_rx_buffer);
|
PIOS_Assert(gps_rx_buffer);
|
||||||
#endif
|
#endif
|
||||||
#if defined(PIOS_INCLUDE_GPS_UBX_PARSER) && !defined(PIOS_GPS_MINIMAL)
|
#if defined(ANY_FULL_GPS_PARSER)
|
||||||
HwSettingsConnectCallback(updateHwSettings); // allow changing baud rate even after startup
|
HwSettingsConnectCallback(updateHwSettings); // allow changing baud rate even after startup
|
||||||
GPSSettingsConnectCallback(updateGpsSettings);
|
GPSSettingsConnectCallback(updateGpsSettings);
|
||||||
#endif
|
#endif
|
||||||
@ -258,10 +298,9 @@ static void gpsTask(__attribute__((unused)) void *parameters)
|
|||||||
GPSPositionSensorData gpspositionsensor;
|
GPSPositionSensorData gpspositionsensor;
|
||||||
|
|
||||||
timeOfLastUpdateMs = timeNowMs;
|
timeOfLastUpdateMs = timeNowMs;
|
||||||
|
|
||||||
GPSPositionSensorGet(&gpspositionsensor);
|
GPSPositionSensorGet(&gpspositionsensor);
|
||||||
#if defined(PIOS_INCLUDE_GPS_UBX_PARSER) && !defined(PIOS_GPS_MINIMAL)
|
#if defined(ANY_FULL_GPS_PARSER)
|
||||||
// this should be done in the task because it calls out to actually start the GPS serial reads
|
// this should be done in the task because it calls out to actually start the ubx GPS serial reads
|
||||||
updateGpsSettings(0);
|
updateGpsSettings(0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -275,7 +314,7 @@ static void gpsTask(__attribute__((unused)) void *parameters)
|
|||||||
// Loop forever
|
// Loop forever
|
||||||
while (1) {
|
while (1) {
|
||||||
if (gpsPort) {
|
if (gpsPort) {
|
||||||
#if defined(PIOS_INCLUDE_GPS_UBX_PARSER) && !defined(PIOS_GPS_MINIMAL)
|
#if defined(FULL_UBX_PARSER)
|
||||||
// do autoconfig stuff for UBX GPS's
|
// do autoconfig stuff for UBX GPS's
|
||||||
if (gpsSettings.DataProtocol == GPSSETTINGS_DATAPROTOCOL_UBX) {
|
if (gpsSettings.DataProtocol == GPSSETTINGS_DATAPROTOCOL_UBX) {
|
||||||
char *buffer = 0;
|
char *buffer = 0;
|
||||||
@ -309,7 +348,7 @@ static void gpsTask(__attribute__((unused)) void *parameters)
|
|||||||
GPSPositionSensorAutoConfigStatusSet(&gpspositionsensor.AutoConfigStatus);
|
GPSPositionSensorAutoConfigStatusSet(&gpspositionsensor.AutoConfigStatus);
|
||||||
lastStatus = gpspositionsensor.AutoConfigStatus;
|
lastStatus = gpspositionsensor.AutoConfigStatus;
|
||||||
}
|
}
|
||||||
#endif /* if defined(PIOS_INCLUDE_GPS_UBX_PARSER) && !defined(PIOS_GPS_MINIMAL) */
|
#endif /* if defined(FULL_UBX_PARSER) */
|
||||||
|
|
||||||
uint16_t cnt;
|
uint16_t cnt;
|
||||||
int res;
|
int res;
|
||||||
@ -330,6 +369,11 @@ static void gpsTask(__attribute__((unused)) void *parameters)
|
|||||||
case GPSSETTINGS_DATAPROTOCOL_UBX:
|
case GPSSETTINGS_DATAPROTOCOL_UBX:
|
||||||
res = parse_ubx_stream(c, cnt, gps_rx_buffer, &gpspositionsensor, &gpsRxStats);
|
res = parse_ubx_stream(c, cnt, gps_rx_buffer, &gpspositionsensor, &gpsRxStats);
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
#if defined(PIOS_INCLUDE_GPS_DJI_PARSER)
|
||||||
|
case GPSSETTINGS_DATAPROTOCOL_DJI:
|
||||||
|
res = parse_dji_stream(c, cnt, gps_rx_buffer, &gpspositionsensor, &gpsRxStats);
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
res = NO_PARSER; // this should not happen
|
res = NO_PARSER; // this should not happen
|
||||||
@ -343,8 +387,13 @@ static void gpsTask(__attribute__((unused)) void *parameters)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there is any error at all, set status to NOGPS
|
// if there is a protocol error or communication error, or timeout error,
|
||||||
// Check for GPS timeout
|
// generally, if there is an error that is due to configuration or bad hardware, set status to NOGPS
|
||||||
|
// poor GPS signal gets a different error/alarm (below)
|
||||||
|
//
|
||||||
|
// should this be expanded to include aux mag status as well? currently the aux mag
|
||||||
|
// attached to a GPS protocol (OPV9 and DJI) still says OK after the GPS/mag goes down
|
||||||
|
// (data cable unplugged or flight battery removed with USB still powering the FC)
|
||||||
timeNowMs = xTaskGetTickCount() * portTICK_RATE_MS;
|
timeNowMs = xTaskGetTickCount() * portTICK_RATE_MS;
|
||||||
if ((res == PARSER_ERROR) ||
|
if ((res == PARSER_ERROR) ||
|
||||||
(timeNowMs - timeOfLastUpdateMs) >= GPS_TIMEOUT_MS ||
|
(timeNowMs - timeOfLastUpdateMs) >= GPS_TIMEOUT_MS ||
|
||||||
@ -356,10 +405,15 @@ static void gpsTask(__attribute__((unused)) void *parameters)
|
|||||||
AlarmsSet(SYSTEMALARMS_ALARM_GPS, SYSTEMALARMS_ALARM_ERROR);
|
AlarmsSet(SYSTEMALARMS_ALARM_GPS, SYSTEMALARMS_ALARM_ERROR);
|
||||||
}
|
}
|
||||||
// if we parsed at least one packet successfully
|
// if we parsed at least one packet successfully
|
||||||
|
// we aren't offline, but we still may not have a good enough fix to fly
|
||||||
|
// or we might not even be receiving all necessary GPS packets (NMEA)
|
||||||
else if (res == PARSER_COMPLETE) {
|
else if (res == PARSER_COMPLETE) {
|
||||||
// we appear to be receiving GPS sentences OK, we've had an update
|
// we appear to be receiving packets OK
|
||||||
// criteria for GPS-OK taken from this post...
|
// criteria for GPS-OK taken from this post...
|
||||||
// http://forums.openpilot.org/topic/1523-professors-insgps-in-svn/page__view__findpost__p__5220
|
// http://forums.openpilot.org/topic/1523-professors-insgps-in-svn/page__view__findpost__p__5220
|
||||||
|
// NMEA doesn't verify that all necessary packet types for an update have been received
|
||||||
|
//
|
||||||
|
// if (the fix is good) {
|
||||||
if ((gpspositionsensor.PDOP < gpsSettings.MaxPDOP) && (gpspositionsensor.Satellites >= gpsSettings.MinSatellites) &&
|
if ((gpspositionsensor.PDOP < gpsSettings.MaxPDOP) && (gpspositionsensor.Satellites >= gpsSettings.MinSatellites) &&
|
||||||
(gpspositionsensor.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) &&
|
(gpspositionsensor.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) &&
|
||||||
(gpspositionsensor.Latitude != 0 || gpspositionsensor.Longitude != 0)) {
|
(gpspositionsensor.Latitude != 0 || gpspositionsensor.Longitude != 0)) {
|
||||||
@ -380,9 +434,11 @@ static void gpsTask(__attribute__((unused)) void *parameters)
|
|||||||
homelocationSetDelay = 0;
|
homelocationSetDelay = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
// else if (we are at least getting what might be usable GPS data to finish a flight with) {
|
||||||
} else if ((gpspositionsensor.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) &&
|
} else if ((gpspositionsensor.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) &&
|
||||||
(gpspositionsensor.Latitude != 0 || gpspositionsensor.Longitude != 0)) {
|
(gpspositionsensor.Latitude != 0 || gpspositionsensor.Longitude != 0)) {
|
||||||
AlarmsSet(SYSTEMALARMS_ALARM_GPS, SYSTEMALARMS_ALARM_WARNING);
|
AlarmsSet(SYSTEMALARMS_ALARM_GPS, SYSTEMALARMS_ALARM_WARNING);
|
||||||
|
// else data is probably not good enough to fly
|
||||||
} else {
|
} else {
|
||||||
AlarmsSet(SYSTEMALARMS_ALARM_GPS, SYSTEMALARMS_ALARM_CRITICAL);
|
AlarmsSet(SYSTEMALARMS_ALARM_GPS, SYSTEMALARMS_ALARM_CRITICAL);
|
||||||
}
|
}
|
||||||
@ -498,72 +554,120 @@ void gps_set_fc_baud_from_arg(uint8_t baud)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// set the FC port baud rate
|
||||||
|
// from HwSettings or override with 115200 if DJI
|
||||||
|
static void gps_set_fc_baud_from_settings()
|
||||||
|
{
|
||||||
|
uint8_t speed;
|
||||||
|
|
||||||
|
// Retrieve settings
|
||||||
|
#if defined(PIOS_INCLUDE_GPS_DJI_PARSER) && !defined(PIOS_GPS_MINIMAL)
|
||||||
|
if (gpsSettings.DataProtocol == GPSSETTINGS_DATAPROTOCOL_DJI) {
|
||||||
|
speed = HWSETTINGS_GPSSPEED_115200;
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
HwSettingsGPSSpeedGet(&speed);
|
||||||
|
#if defined(PIOS_INCLUDE_GPS_DJI_PARSER) && !defined(PIOS_GPS_MINIMAL)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// set fc baud
|
||||||
|
gps_set_fc_baud_from_arg(speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the GPS settings, called on startup.
|
* HwSettings callback
|
||||||
* FIXME: This should be in the GPSSettings object. But objects have
|
* Generally speaking, set the FC baud rate
|
||||||
* too much overhead yet. Also the GPS has no any specific settings
|
* and for UBX, if it is safe, start the auto config process
|
||||||
* like protocol, etc. Thus the HwSettings object which contains the
|
* this allows the user to change the baud rate and see if it works without rebooting
|
||||||
* GPS port speed is used for now.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// must updateHwSettings() before updateGpsSettings() so baud rate is set before GPS serial code starts running
|
// must updateHwSettings() before updateGpsSettings() so baud rate is set before GPS serial code starts running
|
||||||
static void updateHwSettings(UAVObjEvent __attribute__((unused)) *ev)
|
static void updateHwSettings(UAVObjEvent __attribute__((unused)) *ev)
|
||||||
{
|
{
|
||||||
#if defined(PIOS_INCLUDE_GPS_UBX_PARSER) && !defined(PIOS_GPS_MINIMAL)
|
#if defined(ANY_FULL_GPS_PARSER)
|
||||||
static uint32_t previousGpsPort = 0xf0f0f0f0; // = doesn't match gpsport
|
static uint32_t previousGpsPort = 0xf0f0f0f0; // = doesn't match gpsport
|
||||||
#endif
|
#endif
|
||||||
// if GPS (UBX or NMEA) is enabled at all
|
// if GPS (UBX or NMEA) is enabled at all
|
||||||
if (gpsPort && gpsEnabled) {
|
if (gpsPort && gpsEnabled) {
|
||||||
|
// if we have ubx auto config then sometimes we don't set the baud rate
|
||||||
|
#if defined(FULL_UBX_PARSER)
|
||||||
|
// just for UBX, because it has autoconfig
|
||||||
|
// if in startup, or not configured to do ubx and ubx auto config
|
||||||
|
//
|
||||||
// on first use of this port (previousGpsPort != gpsPort) we must set the Revo port baud rate
|
// on first use of this port (previousGpsPort != gpsPort) we must set the Revo port baud rate
|
||||||
// after startup (previousGpsPort == gpsPort) we must set the Revo port baud rate only if autoconfig is disabled
|
// after startup (previousGpsPort == gpsPort) we must set the Revo port baud rate only if autoconfig is disabled
|
||||||
// always we must set the Revo port baud rate if not using UBX
|
// always we must set the Revo port baud rate if not using UBX
|
||||||
#if defined(PIOS_INCLUDE_GPS_UBX_PARSER) && !defined(PIOS_GPS_MINIMAL)
|
|
||||||
if (ev == NULL
|
if (ev == NULL
|
||||||
|| previousGpsPort != gpsPort
|
|| previousGpsPort != gpsPort
|
||||||
|| gpsSettings.UbxAutoConfig == GPSSETTINGS_UBXAUTOCONFIG_DISABLED
|
|| gpsSettings.UbxAutoConfig == GPSSETTINGS_UBXAUTOCONFIG_DISABLED
|
||||||
|| gpsSettings.DataProtocol != GPSSETTINGS_DATAPROTOCOL_UBX)
|
|| gpsSettings.DataProtocol != GPSSETTINGS_DATAPROTOCOL_UBX)
|
||||||
#endif
|
#endif /* defined(FULL_UBX_PARSER) */
|
||||||
{
|
{
|
||||||
uint8_t speed;
|
// always set the baud rate
|
||||||
// Retrieve settings
|
gps_set_fc_baud_from_settings();
|
||||||
HwSettingsGPSSpeedGet(&speed);
|
#if defined(FULL_UBX_PARSER)
|
||||||
// set fc baud
|
// just for UBX, because it has subtypes UBX(6), UBX7 and UBX8
|
||||||
gps_set_fc_baud_from_arg(speed);
|
// changing anything in HwSettings will make it re-verify the sensor type (including auto-baud if not completely disabled)
|
||||||
#if defined(PIOS_INCLUDE_GPS_UBX_PARSER) && !defined(PIOS_GPS_MINIMAL)
|
// for auto baud disabled, the user can just try some baud rates and when the baud rate is correct, the sensor type becomes valid
|
||||||
// even changing the baud rate will make it re-verify the sensor type
|
|
||||||
// that way the user can just try some baud rates and when the sensor type is valid, the baud rate is correct
|
|
||||||
gps_ubx_reset_sensor_type();
|
gps_ubx_reset_sensor_type();
|
||||||
#endif
|
#endif /* defined(FULL_UBX_PARSER) */
|
||||||
}
|
}
|
||||||
#if defined(PIOS_INCLUDE_GPS_UBX_PARSER) && !defined(PIOS_GPS_MINIMAL)
|
#if defined(FULL_UBX_PARSER)
|
||||||
else {
|
else {
|
||||||
// it will never do this during startup because ev == NULL
|
// else:
|
||||||
|
// - we are past startup
|
||||||
|
// - we are running uxb protocol
|
||||||
|
// - and some form of ubx auto config is enabled
|
||||||
|
//
|
||||||
|
// it will never do this during startup because ev == NULL during startup
|
||||||
|
//
|
||||||
|
// this is here so that runtime (not startup) user changes to HwSettings will restart auto-config
|
||||||
gps_ubx_autoconfig_set(NULL);
|
gps_ubx_autoconfig_set(NULL);
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* defined(FULL_UBX_PARSER) */
|
||||||
}
|
}
|
||||||
#if defined(PIOS_INCLUDE_GPS_UBX_PARSER) && !defined(PIOS_GPS_MINIMAL)
|
#if defined(ANY_FULL_GPS_PARSER)
|
||||||
previousGpsPort = gpsPort;
|
previousGpsPort = gpsPort;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if defined(PIOS_INCLUDE_GPS_UBX_PARSER) && !defined(PIOS_GPS_MINIMAL)
|
#if defined(ANY_FULL_MAG_PARSER)
|
||||||
void AuxMagSettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev)
|
void AuxMagSettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev)
|
||||||
{
|
{
|
||||||
|
auxmagsupport_reload_settings();
|
||||||
|
#if defined(PIOS_INCLUDE_GPS_UBX_PARSER)
|
||||||
op_gpsv9_load_mag_settings();
|
op_gpsv9_load_mag_settings();
|
||||||
|
#endif
|
||||||
|
#if defined(PIOS_INCLUDE_GPS_DJI_PARSER)
|
||||||
|
dji_load_mag_settings();
|
||||||
|
#endif
|
||||||
|
#if defined(PIOS_INCLUDE_HMC5X83)
|
||||||
|
aux_hmc5x83_load_mag_settings();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
#endif /* defined(ANY_FULL_MAG_PARSER) */
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(ANY_FULL_GPS_PARSER)
|
||||||
void updateGpsSettings(__attribute__((unused)) UAVObjEvent *ev)
|
void updateGpsSettings(__attribute__((unused)) UAVObjEvent *ev)
|
||||||
{
|
{
|
||||||
ubx_autoconfig_settings_t newconfig;
|
ubx_autoconfig_settings_t newconfig;
|
||||||
|
|
||||||
GPSSettingsGet(&gpsSettings);
|
GPSSettingsGet(&gpsSettings);
|
||||||
|
|
||||||
// it's OK that ubx auto config is inited and ready to go, when GPS is disabled or running NMEA
|
#if defined(PIOS_INCLUDE_GPS_DJI_PARSER)
|
||||||
|
// each time there is a protocol change, set the baud rate
|
||||||
|
// so that DJI can be forced to 115200, but changing to another protocol will change the baud rate to the user specified value
|
||||||
|
// note that changes to HwSettings GPS baud rate are detected in the HwSettings callback,
|
||||||
|
// but changing to/from DJI is effectively a baud rate change because DJI is forced to be 115200
|
||||||
|
gps_set_fc_baud_from_settings(); // knows to force 115200 for DJI
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// it's OK that ubx auto config is inited and ready to go, when GPS is disabled or running another protocol
|
||||||
// because ubx auto config never gets called
|
// because ubx auto config never gets called
|
||||||
// setting it up completely means that if we switch from initial NMEA to UBX or disabled to enabled, that it will start normally
|
// setting it up completely means that if we switch from the other protocol to UBX or disabled to enabled, that it will start normally
|
||||||
newconfig.UbxAutoConfig = gpsSettings.UbxAutoConfig;
|
newconfig.UbxAutoConfig = gpsSettings.UbxAutoConfig;
|
||||||
newconfig.navRate = gpsSettings.UbxRate;
|
newconfig.navRate = gpsSettings.UbxRate;
|
||||||
newconfig.dynamicModel = gpsSettings.UbxDynamicModel == GPSSETTINGS_UBXDYNAMICMODEL_PORTABLE ? UBX_DYNMODEL_PORTABLE :
|
newconfig.dynamicModel = gpsSettings.UbxDynamicModel == GPSSETTINGS_UBXDYNAMICMODEL_PORTABLE ? UBX_DYNMODEL_PORTABLE :
|
||||||
@ -650,9 +754,22 @@ void updateGpsSettings(__attribute__((unused)) UAVObjEvent *ev)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
gps_ubx_autoconfig_set(&newconfig);
|
// handle protocol changes and devices that have just been powered up
|
||||||
|
#if defined(PIOS_INCLUDE_GPS_UBX_PARSER)
|
||||||
|
if (gpsSettings.DataProtocol == GPSSETTINGS_DATAPROTOCOL_UBX) {
|
||||||
|
// do whatever the user has configured for power on startup
|
||||||
|
// even autoconfig disabled still gets the ubx version
|
||||||
|
gps_ubx_autoconfig_set(&newconfig);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(PIOS_INCLUDE_GPS_DJI_PARSER)
|
||||||
|
if (gpsSettings.DataProtocol == GPSSETTINGS_DATAPROTOCOL_DJI) {
|
||||||
|
// clear out satellite data because DJI doesn't provide it
|
||||||
|
GPSSatellitesSetDefaults(GPSSatellitesHandle(), 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif /* if defined(PIOS_INCLUDE_GPS_UBX_PARSER) && !defined(PIOS_GPS_MINIMAL) */
|
#endif /* defined(ANY_FULL_GPS_PARSER) */
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
* @}
|
* @}
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
* @{
|
* @{
|
||||||
*
|
*
|
||||||
* @file NMEA.c
|
* @file NMEA.c
|
||||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016.
|
||||||
|
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||||
* @brief GPS module, handles GPS and NMEA stream
|
* @brief GPS module, handles GPS and NMEA stream
|
||||||
* @see The GNU Public License (GPL) Version 3
|
* @see The GNU Public License (GPL) Version 3
|
||||||
*
|
*
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
* @{
|
* @{
|
||||||
*
|
*
|
||||||
* @file UBX.c
|
* @file UBX.c
|
||||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015-2016.
|
||||||
|
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
|
||||||
* @brief GPS module, handles GPS and NMEA stream
|
* @brief GPS module, handles GPS and NMEA stream
|
||||||
* @see The GNU Public License (GPL) Version 3
|
* @see The GNU Public License (GPL) Version 3
|
||||||
*
|
*
|
||||||
@ -33,22 +34,25 @@
|
|||||||
#include "pios_math.h"
|
#include "pios_math.h"
|
||||||
#include <pios_helpers.h>
|
#include <pios_helpers.h>
|
||||||
#include <pios_delay.h>
|
#include <pios_delay.h>
|
||||||
|
|
||||||
#if defined(PIOS_INCLUDE_GPS_UBX_PARSER)
|
#if defined(PIOS_INCLUDE_GPS_UBX_PARSER)
|
||||||
|
|
||||||
#include "inc/UBX.h"
|
#include "inc/UBX.h"
|
||||||
#include "inc/GPS.h"
|
#include "inc/GPS.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#ifndef PIOS_GPS_MINIMAL
|
#if !defined(PIOS_GPS_MINIMAL)
|
||||||
#include <auxmagsupport.h>
|
#include <auxmagsupport.h>
|
||||||
|
|
||||||
static bool useMag = false;
|
static bool useMag = false;
|
||||||
#endif
|
#endif /* !defined(PIOS_GPS_MINIMAL) */
|
||||||
GPSPositionSensorSensorTypeOptions sensorType = GPSPOSITIONSENSOR_SENSORTYPE_UNKNOWN;
|
|
||||||
|
// this is set and used by this low level ubx code
|
||||||
|
// it is also reset by the ubx configuration code (UBX6 vs. UBX7) in ubx_autoconfig.c
|
||||||
|
GPSPositionSensorSensorTypeOptions ubxSensorType = GPSPOSITIONSENSOR_SENSORTYPE_UNKNOWN;
|
||||||
|
|
||||||
static bool usePvt = false;
|
static bool usePvt = false;
|
||||||
static uint32_t lastPvtTime = 0;
|
static uint32_t lastPvtTime = 0;
|
||||||
|
|
||||||
|
|
||||||
// parse table item
|
// parse table item
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t msgClass;
|
uint8_t msgClass;
|
||||||
@ -57,31 +61,27 @@ typedef struct {
|
|||||||
} ubx_message_handler;
|
} ubx_message_handler;
|
||||||
|
|
||||||
// parsing functions, roughly ordered by reception rate (higher rate messages on top)
|
// parsing functions, roughly ordered by reception rate (higher rate messages on top)
|
||||||
|
|
||||||
static void parse_ubx_nav_posllh(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition);
|
static void parse_ubx_nav_posllh(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition);
|
||||||
static void parse_ubx_nav_velned(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition);
|
static void parse_ubx_nav_velned(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition);
|
||||||
static void parse_ubx_nav_sol(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition);
|
static void parse_ubx_nav_sol(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition);
|
||||||
static void parse_ubx_nav_dop(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition);
|
static void parse_ubx_nav_dop(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition);
|
||||||
#ifndef PIOS_GPS_MINIMAL
|
#if !defined(PIOS_GPS_MINIMAL)
|
||||||
static void parse_ubx_nav_pvt(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition);
|
static void parse_ubx_nav_pvt(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition);
|
||||||
static void parse_ubx_nav_timeutc(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition);
|
static void parse_ubx_nav_timeutc(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition);
|
||||||
static void parse_ubx_nav_svinfo(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition);
|
static void parse_ubx_nav_svinfo(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition);
|
||||||
|
|
||||||
static void parse_ubx_op_sys(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition);
|
static void parse_ubx_op_sys(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition);
|
||||||
static void parse_ubx_op_mag(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition);
|
static void parse_ubx_op_mag(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition);
|
||||||
|
|
||||||
static void parse_ubx_ack_ack(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition);
|
static void parse_ubx_ack_ack(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition);
|
||||||
static void parse_ubx_ack_nak(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition);
|
static void parse_ubx_ack_nak(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition);
|
||||||
|
|
||||||
static void parse_ubx_mon_ver(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition);
|
static void parse_ubx_mon_ver(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition);
|
||||||
#endif
|
#endif /* !defined(PIOS_GPS_MINIMAL) */
|
||||||
|
|
||||||
const ubx_message_handler ubx_handler_table[] = {
|
const ubx_message_handler ubx_handler_table[] = {
|
||||||
{ .msgClass = UBX_CLASS_NAV, .msgID = UBX_ID_NAV_POSLLH, .handler = &parse_ubx_nav_posllh },
|
{ .msgClass = UBX_CLASS_NAV, .msgID = UBX_ID_NAV_POSLLH, .handler = &parse_ubx_nav_posllh },
|
||||||
{ .msgClass = UBX_CLASS_NAV, .msgID = UBX_ID_NAV_VELNED, .handler = &parse_ubx_nav_velned },
|
{ .msgClass = UBX_CLASS_NAV, .msgID = UBX_ID_NAV_VELNED, .handler = &parse_ubx_nav_velned },
|
||||||
{ .msgClass = UBX_CLASS_NAV, .msgID = UBX_ID_NAV_SOL, .handler = &parse_ubx_nav_sol },
|
{ .msgClass = UBX_CLASS_NAV, .msgID = UBX_ID_NAV_SOL, .handler = &parse_ubx_nav_sol },
|
||||||
{ .msgClass = UBX_CLASS_NAV, .msgID = UBX_ID_NAV_DOP, .handler = &parse_ubx_nav_dop },
|
{ .msgClass = UBX_CLASS_NAV, .msgID = UBX_ID_NAV_DOP, .handler = &parse_ubx_nav_dop },
|
||||||
#ifndef PIOS_GPS_MINIMAL
|
#if !defined(PIOS_GPS_MINIMAL)
|
||||||
{ .msgClass = UBX_CLASS_NAV, .msgID = UBX_ID_NAV_PVT, .handler = &parse_ubx_nav_pvt },
|
{ .msgClass = UBX_CLASS_NAV, .msgID = UBX_ID_NAV_PVT, .handler = &parse_ubx_nav_pvt },
|
||||||
{ .msgClass = UBX_CLASS_OP_CUST, .msgID = UBX_ID_OP_MAG, .handler = &parse_ubx_op_mag },
|
{ .msgClass = UBX_CLASS_OP_CUST, .msgID = UBX_ID_OP_MAG, .handler = &parse_ubx_op_mag },
|
||||||
{ .msgClass = UBX_CLASS_NAV, .msgID = UBX_ID_NAV_SVINFO, .handler = &parse_ubx_nav_svinfo },
|
{ .msgClass = UBX_CLASS_NAV, .msgID = UBX_ID_NAV_SVINFO, .handler = &parse_ubx_nav_svinfo },
|
||||||
@ -92,7 +92,7 @@ const ubx_message_handler ubx_handler_table[] = {
|
|||||||
{ .msgClass = UBX_CLASS_ACK, .msgID = UBX_ID_ACK_NAK, .handler = &parse_ubx_ack_nak },
|
{ .msgClass = UBX_CLASS_ACK, .msgID = UBX_ID_ACK_NAK, .handler = &parse_ubx_ack_nak },
|
||||||
|
|
||||||
{ .msgClass = UBX_CLASS_MON, .msgID = UBX_ID_MON_VER, .handler = &parse_ubx_mon_ver },
|
{ .msgClass = UBX_CLASS_MON, .msgID = UBX_ID_MON_VER, .handler = &parse_ubx_mon_ver },
|
||||||
#endif
|
#endif /* !defined(PIOS_GPS_MINIMAL) */
|
||||||
};
|
};
|
||||||
#define UBX_HANDLER_TABLE_SIZE NELEMENTS(ubx_handler_table)
|
#define UBX_HANDLER_TABLE_SIZE NELEMENTS(ubx_handler_table)
|
||||||
|
|
||||||
@ -105,11 +105,10 @@ struct UBX_ACK_NAK ubxLastNak;
|
|||||||
|
|
||||||
// If a PVT sentence is received in the last UBX_PVT_TIMEOUT (ms) timeframe it disables VELNED/POSLLH/SOL/TIMEUTC
|
// If a PVT sentence is received in the last UBX_PVT_TIMEOUT (ms) timeframe it disables VELNED/POSLLH/SOL/TIMEUTC
|
||||||
#define UBX_PVT_TIMEOUT (1000)
|
#define UBX_PVT_TIMEOUT (1000)
|
||||||
// parse incoming character stream for messages in UBX binary format
|
|
||||||
|
|
||||||
|
// parse incoming character stream for messages in UBX binary format
|
||||||
int parse_ubx_stream(uint8_t *rx, uint16_t len, char *gps_rx_buffer, GPSPositionSensorData *GpsData, struct GPS_RX_STATS *gpsRxStats)
|
int parse_ubx_stream(uint8_t *rx, uint16_t len, char *gps_rx_buffer, GPSPositionSensorData *GpsData, struct GPS_RX_STATS *gpsRxStats)
|
||||||
{
|
{
|
||||||
int ret = PARSER_INCOMPLETE; // message not (yet) complete
|
|
||||||
enum proto_states {
|
enum proto_states {
|
||||||
START,
|
START,
|
||||||
UBX_SY2,
|
UBX_SY2,
|
||||||
@ -126,13 +125,14 @@ int parse_ubx_stream(uint8_t *rx, uint16_t len, char *gps_rx_buffer, GPSPosition
|
|||||||
RESTART_WITH_ERROR,
|
RESTART_WITH_ERROR,
|
||||||
RESTART_NO_ERROR
|
RESTART_NO_ERROR
|
||||||
};
|
};
|
||||||
uint8_t c;
|
|
||||||
static enum proto_states proto_state = START;
|
|
||||||
static uint16_t rx_count = 0;
|
static uint16_t rx_count = 0;
|
||||||
|
static enum proto_states proto_state = START;
|
||||||
struct UBXPacket *ubx = (struct UBXPacket *)gps_rx_buffer;
|
struct UBXPacket *ubx = (struct UBXPacket *)gps_rx_buffer;
|
||||||
|
int ret = PARSER_INCOMPLETE; // message not (yet) complete
|
||||||
uint16_t i = 0;
|
uint16_t i = 0;
|
||||||
uint16_t restart_index = 0;
|
uint16_t restart_index = 0;
|
||||||
enum restart_states restart_state;
|
enum restart_states restart_state;
|
||||||
|
uint8_t c;
|
||||||
|
|
||||||
// switch continue is the normal condition and comes back to here for another byte
|
// switch continue is the normal condition and comes back to here for another byte
|
||||||
// switch break is the error state that branches to the end and restarts the scan at the byte after the first sync byte
|
// switch break is the error state that branches to the end and restarts the scan at the byte after the first sync byte
|
||||||
@ -172,11 +172,10 @@ int parse_ubx_stream(uint8_t *rx, uint16_t len, char *gps_rx_buffer, GPSPosition
|
|||||||
gpsRxStats->gpsRxOverflow++;
|
gpsRxStats->gpsRxOverflow++;
|
||||||
#if defined(PIOS_GPS_MINIMAL)
|
#if defined(PIOS_GPS_MINIMAL)
|
||||||
restart_state = RESTART_NO_ERROR;
|
restart_state = RESTART_NO_ERROR;
|
||||||
break;
|
|
||||||
#else
|
#else
|
||||||
restart_state = RESTART_WITH_ERROR;
|
restart_state = RESTART_WITH_ERROR;
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
|
break;
|
||||||
} else {
|
} else {
|
||||||
if (ubx->header.len == 0) {
|
if (ubx->header.len == 0) {
|
||||||
proto_state = UBX_CHK1;
|
proto_state = UBX_CHK1;
|
||||||
@ -204,15 +203,20 @@ int parse_ubx_stream(uint8_t *rx, uint16_t len, char *gps_rx_buffer, GPSPosition
|
|||||||
// this has been proven by running it without autoconfig and testing:
|
// this has been proven by running it without autoconfig and testing:
|
||||||
// data coming from OPV9 "GPS+MCU" port the checksum errors happen roughly every 5 to 30 seconds
|
// data coming from OPV9 "GPS+MCU" port the checksum errors happen roughly every 5 to 30 seconds
|
||||||
// same data coming from OPV9 "GPS Only" port the checksums are always good
|
// same data coming from OPV9 "GPS Only" port the checksums are always good
|
||||||
// this also ocassionally causes parse_ubx_message() to issue alarms because not all the messages were received
|
// this also occasionally causes parse_ubx_message() to issue alarms because not all the messages were received
|
||||||
// see OP GPSV9 comment in parse_ubx_message() for further information
|
// see OP GPSV9 comment in parse_ubx_message() for further information
|
||||||
if (checksum_ubx_message(ubx)) { // message complete and valid
|
if (checksum_ubx_message(ubx)) {
|
||||||
parse_ubx_message(ubx, GpsData);
|
|
||||||
gpsRxStats->gpsRxReceived++;
|
gpsRxStats->gpsRxReceived++;
|
||||||
proto_state = START;
|
proto_state = START;
|
||||||
// pass PARSER_ERROR to be to caller if it happens even once
|
// overwrite PARSER_INCOMPLETE with PARSER_COMPLETE
|
||||||
if (ret == PARSER_INCOMPLETE) {
|
// but don't overwrite PARSER_ERROR with PARSER_COMPLETE
|
||||||
ret = PARSER_COMPLETE; // message complete & processed
|
// pass PARSER_ERROR to caller if it happens even once
|
||||||
|
// only pass PARSER_COMPLETE back to caller if we parsed a full set of GPS data
|
||||||
|
// that allows the caller to know if we are parsing GPS data
|
||||||
|
// or just other packets for some reason (mis-configuration)
|
||||||
|
if (parse_ubx_message(ubx, GpsData) == GPSPOSITIONSENSOR_OBJID
|
||||||
|
&& ret == PARSER_INCOMPLETE) {
|
||||||
|
ret = PARSER_COMPLETE;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
gpsRxStats->gpsRxChkSumError++;
|
gpsRxStats->gpsRxChkSumError++;
|
||||||
@ -232,7 +236,6 @@ int parse_ubx_stream(uint8_t *rx, uint16_t len, char *gps_rx_buffer, GPSPosition
|
|||||||
if (restart_state == RESTART_WITH_ERROR) {
|
if (restart_state == RESTART_WITH_ERROR) {
|
||||||
ret = PARSER_ERROR; // inform caller that we found at least one error (along with 0 or more good packets)
|
ret = PARSER_ERROR; // inform caller that we found at least one error (along with 0 or more good packets)
|
||||||
}
|
}
|
||||||
// else restart with no error
|
|
||||||
rx += restart_index; // restart parsing just past the most recent SYNC1
|
rx += restart_index; // restart parsing just past the most recent SYNC1
|
||||||
len -= restart_index;
|
len -= restart_index;
|
||||||
i = 0;
|
i = 0;
|
||||||
@ -242,10 +245,8 @@ int parse_ubx_stream(uint8_t *rx, uint16_t len, char *gps_rx_buffer, GPSPosition
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Keep track of various GPS messages needed to make up a single UAVO update
|
// Keep track of various GPS messages needed to make up a single UAVO update
|
||||||
// time-of-week timestamp is used to correlate matching messages
|
// time-of-week timestamp is used to correlate matching messages
|
||||||
|
|
||||||
#define POSLLH_RECEIVED (1 << 0)
|
#define POSLLH_RECEIVED (1 << 0)
|
||||||
#define STATUS_RECEIVED (1 << 1)
|
#define STATUS_RECEIVED (1 << 1)
|
||||||
#define DOP_RECEIVED (1 << 2)
|
#define DOP_RECEIVED (1 << 2)
|
||||||
@ -375,6 +376,7 @@ static void parse_ubx_nav_velned(struct UBXPacket *ubx, GPSPositionSensorData *G
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(PIOS_GPS_MINIMAL)
|
#if !defined(PIOS_GPS_MINIMAL)
|
||||||
static void parse_ubx_nav_pvt(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition)
|
static void parse_ubx_nav_pvt(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition)
|
||||||
{
|
{
|
||||||
@ -504,12 +506,12 @@ static void parse_ubx_mon_ver(struct UBXPacket *ubx, __attribute__((unused)) GPS
|
|||||||
{
|
{
|
||||||
struct UBX_MON_VER *mon_ver = &ubx->payload.mon_ver;
|
struct UBX_MON_VER *mon_ver = &ubx->payload.mon_ver;
|
||||||
|
|
||||||
ubxHwVersion = atoi(mon_ver->hwVersion);
|
ubxHwVersion = atoi(mon_ver->hwVersion);
|
||||||
sensorType = (ubxHwVersion >= 80000) ? GPSPOSITIONSENSOR_SENSORTYPE_UBX8 :
|
ubxSensorType = (ubxHwVersion >= UBX_HW_VERSION_8) ? GPSPOSITIONSENSOR_SENSORTYPE_UBX8 :
|
||||||
((ubxHwVersion >= 70000) ? GPSPOSITIONSENSOR_SENSORTYPE_UBX7 : GPSPOSITIONSENSOR_SENSORTYPE_UBX);
|
((ubxHwVersion >= UBX_HW_VERSION_7) ? GPSPOSITIONSENSOR_SENSORTYPE_UBX7 : GPSPOSITIONSENSOR_SENSORTYPE_UBX);
|
||||||
// send sensor type right now because on UBX NEMA we don't get a full set of messages
|
// send sensor type right now because on UBX NEMA we don't get a full set of messages
|
||||||
// and we want to be able to see sensor type even on UBX NEMA GPS's
|
// and we want to be able to see sensor type even on UBX NEMA GPS's
|
||||||
GPSPositionSensorSensorTypeSet((uint8_t *)&sensorType);
|
GPSPositionSensorSensorTypeSet((uint8_t *)&ubxSensorType);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_ubx_op_sys(struct UBXPacket *ubx, __attribute__((unused)) GPSPositionSensorData *GpsPosition)
|
static void parse_ubx_op_sys(struct UBXPacket *ubx, __attribute__((unused)) GPSPositionSensorData *GpsPosition)
|
||||||
@ -538,10 +540,8 @@ static void parse_ubx_op_mag(struct UBXPacket *ubx, __attribute__((unused)) GPSP
|
|||||||
}
|
}
|
||||||
#endif /* if !defined(PIOS_GPS_MINIMAL) */
|
#endif /* if !defined(PIOS_GPS_MINIMAL) */
|
||||||
|
|
||||||
|
|
||||||
// UBX message parser
|
// UBX message parser
|
||||||
// returns UAVObjectID if a UAVObject structure is ready for further processing
|
// returns UAVObjectID if a UAVObject structure is ready for further processing
|
||||||
|
|
||||||
uint32_t parse_ubx_message(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition)
|
uint32_t parse_ubx_message(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosition)
|
||||||
{
|
{
|
||||||
uint32_t id = 0;
|
uint32_t id = 0;
|
||||||
@ -564,7 +564,7 @@ uint32_t parse_ubx_message(struct UBXPacket *ubx, GPSPositionSensorData *GpsPosi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GpsPosition->SensorType = sensorType;
|
GpsPosition->SensorType = ubxSensorType;
|
||||||
|
|
||||||
if (msgtracker.msg_received == ALL_RECEIVED) {
|
if (msgtracker.msg_received == ALL_RECEIVED) {
|
||||||
// leave BaudRate field alone!
|
// leave BaudRate field alone!
|
||||||
@ -597,5 +597,5 @@ void op_gpsv9_load_mag_settings()
|
|||||||
useMag = false;
|
useMag = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif // !defined(PIOS_GPS_MINIMAL)
|
||||||
#endif // PIOS_INCLUDE_GPS_UBX_PARSER
|
#endif // defined(PIOS_INCLUDE_GPS_UBX_PARSER)
|
||||||
|
332
flight/modules/GPS/inc/DJI.h
Normal file
332
flight/modules/GPS/inc/DJI.h
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @addtogroup OpenPilotModules OpenPilot Modules
|
||||||
|
* @{
|
||||||
|
* @addtogroup GSPModule GPS Module
|
||||||
|
* @brief Process GPS information
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file DJI.h
|
||||||
|
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016.
|
||||||
|
* @brief GPS module, handles DJI stream
|
||||||
|
* @see The GNU Public License (GPL) Version 3
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
/*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DJI_H
|
||||||
|
#define DJI_H
|
||||||
|
#include "openpilot.h"
|
||||||
|
#include "gpspositionsensor.h"
|
||||||
|
#include "gpsextendedstatus.h"
|
||||||
|
#ifndef PIOS_GPS_MINIMAL
|
||||||
|
#include "auxmagsensor.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "GPS.h"
|
||||||
|
|
||||||
|
#define DJI_SYNC1 0x55 // DJI protocol synchronization characters
|
||||||
|
#define DJI_SYNC2 0xaa
|
||||||
|
|
||||||
|
// Message IDs
|
||||||
|
typedef enum {
|
||||||
|
DJI_ID_GPS = 0x10,
|
||||||
|
DJI_ID_MAG = 0x20,
|
||||||
|
DJI_ID_VER = 0x30,
|
||||||
|
} dji_msg_id;
|
||||||
|
|
||||||
|
// private structures
|
||||||
|
|
||||||
|
/*
|
||||||
|
GPS protocol info from
|
||||||
|
http://www.rcgroups.com/forums/showpost.php?p=26210591&postcount=15
|
||||||
|
|
||||||
|
The 0x10 message contains GPS data. Here is the structure of the message,
|
||||||
|
fields marked with XX I'm not sure about yet. The others will be described below.
|
||||||
|
|
||||||
|
55 AA 10 3A DT DT DT DT LO LO LO LO LA LA LA LA AL AL AL AL HA HA HA HA VA VA VA VA XX XX XX XX
|
||||||
|
NV NV NV NV EV EV EV EV DV DV DV DV PD PD VD VD ND ND ED ED NS XX FT XX SF XX XX XM SN SN CS CS
|
||||||
|
|
||||||
|
The payload is XORed with a mask that changes over time (see below for more details).
|
||||||
|
|
||||||
|
Values in the message are stored in little endian.
|
||||||
|
|
||||||
|
HEADER
|
||||||
|
-------------
|
||||||
|
BYTE 1-2: message header - always 55 AA
|
||||||
|
BYTE 3: message id (0x10 for GPS message)
|
||||||
|
BYTE 4: lenght of the payload (0x3A or 58 decimal for 0x10 message)
|
||||||
|
|
||||||
|
PAYLOAD
|
||||||
|
--------------
|
||||||
|
BYTE 5-8 (DT) : date and time, see details below
|
||||||
|
BYTE 9-12 (LO) : longitude (x10^7, degree decimal)
|
||||||
|
BYTE 13-16 (LA): latitude (x10^7, degree decimal)
|
||||||
|
BYTE 17-20 (AL): altitude (in milimeters)
|
||||||
|
BYTE 21-24 (HA): horizontal accuracy estimate (see uBlox NAV-POSLLH message for details)
|
||||||
|
BYTE 25-28 (VA): vertical accuracy estimate (see uBlox NAV-POSLLH message for details)
|
||||||
|
BYTE 29-32 : ??? (seems to be always 0)
|
||||||
|
BYTE 33-36 (NV): NED north velocity (see uBlox NAV-VELNED message for details)
|
||||||
|
BYTE 37-40 (EV): NED east velocity (see uBlox NAV-VELNED message for details)
|
||||||
|
BYTE 41-44 (DV): NED down velocity (see uBlox NAV-VELNED message for details)
|
||||||
|
BYTE 45-46 (PD): position DOP (see uBlox NAV-DOP message for details)
|
||||||
|
BYTE 47-48 (VD): vertical DOP (see uBlox NAV-DOP message for details)
|
||||||
|
BYTE 49-50 (ND): northing DOP (see uBlox NAV-DOP message for details)
|
||||||
|
BYTE 51-52 (ED): easting DOP (see uBlox NAV-DOP message for details)
|
||||||
|
BYTE 53 (NS) : number of satellites (not XORed)
|
||||||
|
BYTE 54 : ??? (not XORed, seems to be always 0)
|
||||||
|
BYTE 55 (FT) : fix type (0 - no lock, 2 - 2D lock, 3 - 3D lock, not sure if other values can be expected
|
||||||
|
: see uBlox NAV-SOL message for details)
|
||||||
|
BYTE 56 : ??? (seems to be always 0)
|
||||||
|
BYTE 57 (SF) : fix status flags (see uBlox NAV-SOL message for details)
|
||||||
|
BYTE 58-59 : ??? (seems to be always 0)
|
||||||
|
BYTE 60 (XM) : not sure yet, but I use it as the XOR mask
|
||||||
|
BYTE 61-62 (SN): sequence number (not XORed), once there is a lock - increases with every message.
|
||||||
|
When the lock is lost later LSB and MSB are swapped with every message.
|
||||||
|
|
||||||
|
CHECKSUM
|
||||||
|
-----------------
|
||||||
|
BYTE 63-64 (CS): checksum, calculated the same way as for uBlox binary messages
|
||||||
|
|
||||||
|
|
||||||
|
XOR mask
|
||||||
|
---------------
|
||||||
|
All bytes of the payload except 53rd (NS), 54th, 61st (SN LSB) and 62nd (SN MSB) are XORed with a mask.
|
||||||
|
Mask is calculated based on the value of byte 53rd (NS) and 61st (SN LSB).
|
||||||
|
|
||||||
|
If we index bits from LSB to MSB as 0-7 we have:
|
||||||
|
mask[0] = 53rdByte[0] xor 61stByte[4]
|
||||||
|
mask[1] = 53rdByte[1] xor 61stByte[5]
|
||||||
|
mask[2] = 53rdByte[2] xor 61stByte[6]
|
||||||
|
mask[3] = 53rdByte[3] xor 61stByte[7] xor 53rdByte[0];
|
||||||
|
mask[4] = 53rdByte[1];
|
||||||
|
mask[5] = 53rdByte[2];
|
||||||
|
mask[6] = 53rdByte[3];
|
||||||
|
mask[7] = 53rdByte[0] xor 61stByte[4];
|
||||||
|
|
||||||
|
To simplify calculations any of the unknown bytes that when XORer seem to be always 0 (29-32, 56, 58-60)
|
||||||
|
can be used as XOR mask (based on the fact that 0 XOR mask == mask). In the library I use byte 60.
|
||||||
|
|
||||||
|
Date and time format
|
||||||
|
----------------------------
|
||||||
|
Date (Year, Month, Day) and time (Hour, Minute, Second) are stored as little endian 32bit unsigned integer,
|
||||||
|
the meaning of particular bits is as follows:
|
||||||
|
|
||||||
|
YYYYYYYMMMMDDDDDHHHHMMMMMMSSSSSS
|
||||||
|
|
||||||
|
NOTE 1: to get the day value correct you must add 1 when hour is > 7
|
||||||
|
NOTE 2: for the time between 16:00 and 23:59 the hour will be returned as 0-7
|
||||||
|
and there seems to be no way to differentiate between 00:00 - 07:59 and 16:00 - 23:59.
|
||||||
|
|
||||||
|
From further discussion in the thread, it sounds like the day is written into the buffer
|
||||||
|
(buffer initially zero bits) and then the hour is xored into the buffer
|
||||||
|
with the bottom bit of day and top bit of hour mapped to the same buffer bit?
|
||||||
|
Is that even correct? Or could we have a correct hour and the day is just wrong?
|
||||||
|
|
||||||
|
http://www.rcgroups.com/forums/showpost.php?p=28158918&postcount=180
|
||||||
|
Midnight between 13th and 14th of March
|
||||||
|
0001110 0011 01110 0000 000000 000000 -> 14.3.14 00:00:00 -> 0
|
||||||
|
identical with
|
||||||
|
4PM, 14th of March
|
||||||
|
0001110 0011 01110 0000 000000 000000 -> 14.3.14 00:00:00 -> 0
|
||||||
|
|
||||||
|
Midnight between 14th and 15th of March
|
||||||
|
0001110 0011 01111 0000 000000 000000 -> 14.3.15 00:00:00 -> 16
|
||||||
|
identical with
|
||||||
|
4PM, 15th of March
|
||||||
|
0001110 0011 01111 0000 000000 000000 -> 14.3.15 00:00:00 -> 16
|
||||||
|
|
||||||
|
So as you can see even if we take 5 bits the hour is not correct either
|
||||||
|
Are they are xored? If we knew the date from a different source we would know the time.
|
||||||
|
Maybe the xor mask itself contains the bit. Does the mask change? and how? across the transitions.
|
||||||
|
|
||||||
|
http://www.rcgroups.com/forums/showpost.php?p=28168741&postcount=182
|
||||||
|
Originally Posted by gwouite View Post
|
||||||
|
Question, are you sure that at 4PM, you're day value doesn't increase of 1 ?
|
||||||
|
It does, but it also does decrease by 1 at 8am so you have:
|
||||||
|
00:00 - 07:59 => day = X, hour = 0 - 7
|
||||||
|
08:00 - 15:59 => day = X - 1, hour = 8 - 15
|
||||||
|
16:00 - 23:59 => day = X, hour = 0 - 7
|
||||||
|
|
||||||
|
http://www.rcgroups.com/forums/showpost.php?p=28782603&postcount=218
|
||||||
|
Here is the SBAS config from the Naza GPS
|
||||||
|
CFG-SBAS - 06 16 08 00 01 03 03 00 51 62 06 00
|
||||||
|
If I read it correctly EGNOS (PRN 124/124/126), MSAS (PRN 129/137) and WAAS (PRN 133/134/135/138) are enabled.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// DJI GPS packet
|
||||||
|
struct DjiGps { // byte offset from beginning of packet, subtract 5 for struct offset
|
||||||
|
struct { // YYYYYYYMMMMDDDDDHHHHMMMMMMSSSSSS
|
||||||
|
uint32_t sec : 6;
|
||||||
|
uint32_t min : 6;
|
||||||
|
uint32_t hour : 4;
|
||||||
|
uint32_t day : 5;
|
||||||
|
uint32_t month : 4;
|
||||||
|
uint32_t year : 7;
|
||||||
|
}; // BYTE 5-8 (DT): date and time, see details above
|
||||||
|
int32_t lon; // BYTE 9-12 (LO): longitude (x10^7, degree decimal)
|
||||||
|
int32_t lat; // BYTE 13-16 (LA): latitude (x10^7, degree decimal)
|
||||||
|
int32_t hMSL; // BYTE 17-20 (AL): altitude (in millimeters) (is this MSL or geoid?)
|
||||||
|
uint32_t hAcc; // BYTE 21-24 (HA): horizontal accuracy estimate (see uBlox NAV-POSLLH message for details)
|
||||||
|
uint32_t vAcc; // BYTE 25-28 (VA): vertical accuracy estimate (see uBlox NAV-POSLLH message for details)
|
||||||
|
uint32_t unused1; // BYTE 29-32: ??? (seems to be always 0)
|
||||||
|
int32_t velN; // BYTE 33-36 (NV): NED north velocity (see uBlox NAV-VELNED message for details)
|
||||||
|
int32_t velE; // BYTE 37-40 (EV): NED east velocity (see uBlox NAV-VELNED message for details)
|
||||||
|
int32_t velD; // BYTE 41-44 (DV): NED down velocity (see uBlox NAV-VELNED message for details)
|
||||||
|
uint16_t pDOP; // BYTE 45-46 (PD): position DOP (see uBlox NAV-DOP message for details)
|
||||||
|
uint16_t vDOP; // BYTE 47-48 (VD): vertical DOP (see uBlox NAV-DOP message for details)
|
||||||
|
uint16_t nDOP; // BYTE 49-50 (ND): northing DOP (see uBlox NAV-DOP message for details)
|
||||||
|
uint16_t eDOP; // BYTE 51-52 (ED): easting DOP (see uBlox NAV-DOP message for details)
|
||||||
|
uint8_t numSV; // BYTE 53 (NS): number of satellites (not XORed)
|
||||||
|
uint8_t unused2; // BYTE 54: ??? (not XORed, seems to be always 0)
|
||||||
|
uint8_t fixType; // BYTE 55 (FT): fix type (0 - no lock, 2 - 2D lock, 3 - 3D lock, not sure if other values can be expected
|
||||||
|
// see uBlox NAV-SOL message for details)
|
||||||
|
uint8_t unused3; // BYTE 56: ??? (seems to be always 0)
|
||||||
|
uint8_t flags; // BYTE 57 (SF): fix status flags (see uBlox NAV-SOL message for details)
|
||||||
|
uint16_t unused4; // BYTE 58-59: ??? (seems to be always 0)
|
||||||
|
uint8_t unused5; // BYTE 60 (XM): not sure yet, but I use it as the XOR mask
|
||||||
|
uint16_t seqNo; // BYTE 61-62 (SN): sequence number (not XORed), once there is a lock
|
||||||
|
// increases with every message. When the lock is lost later LSB and MSB are swapped (in all messages where lock is lost).
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#define FLAGS_GPSFIX_OK (1 << 0)
|
||||||
|
#define FLAGS_DIFFSOLN (1 << 1)
|
||||||
|
#define FLAGS_WKNSET (1 << 2)
|
||||||
|
#define FLAGS_TOWSET (1 << 3)
|
||||||
|
|
||||||
|
#define FIXTYPE_NO_FIX 0x00 /* No Fix */
|
||||||
|
#define FIXTYPE_DEAD_RECKON 0x01 /* Dead Reckoning only */
|
||||||
|
#define FIXTYPE_2D 0x02 /* 2D-Fix */
|
||||||
|
#define FIXTYPE_3D 0x03 /* 3D-Fix */
|
||||||
|
#define FIXTYPE_GNSS_DEAD_RECKON 0x04 /* GNSS + dead reckoning combined */
|
||||||
|
#define FIXTYPE_TIME_ONLY 0x05 /* Time only fix */
|
||||||
|
|
||||||
|
#define GPS_DECODED_LENGTH offsetof(struct DjiGps, seqNo)
|
||||||
|
#define GPS_NOT_XORED_BYTE_1 offsetof(struct DjiGps, numSV)
|
||||||
|
#define GPS_NOT_XORED_BYTE_2 offsetof(struct DjiGps, unused2)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
mag protocol info from
|
||||||
|
http://www.rcgroups.com/forums/showpost.php?p=26248426&postcount=62
|
||||||
|
|
||||||
|
The 0x20 message contains compass data. Here is the structure of the message,
|
||||||
|
fields marked with XX I'm not sure about yet. The others will be described below.
|
||||||
|
|
||||||
|
55 AA 20 06 CX CX CY CY CZ CZ CS CS
|
||||||
|
|
||||||
|
Values in the message are stored in little endian.
|
||||||
|
|
||||||
|
HEADER
|
||||||
|
-------------
|
||||||
|
BYTE 1-2: message header - always 55 AA
|
||||||
|
BYTE 3: message id (0x20 for compass message)
|
||||||
|
BYTE 4: length of the payload (0x06 or 6 decimal for 0x20 message)
|
||||||
|
|
||||||
|
PAYLOAD
|
||||||
|
--------------
|
||||||
|
BYTE 5-6 (CX): compass X axis data (signed) - see comments below
|
||||||
|
BYTE 7-8 (CY): compass Y axis data (signed) - see comments below
|
||||||
|
BYTE 9-10 (CZ): compass Z axis data (signed) - see comments below
|
||||||
|
|
||||||
|
CHECKSUM
|
||||||
|
-----------------
|
||||||
|
BYTE 11-12 (CS): checksum, calculated the same way as for uBlox binary messages
|
||||||
|
|
||||||
|
All the bytes of the payload except 9th are XORed with a mask.
|
||||||
|
Mask is calculated based on the value of the 9th byte.
|
||||||
|
|
||||||
|
If we index bits from LSB to MSB as 0-7 we have:
|
||||||
|
mask[0] = 9thByte[0] xor 9thByte[4]
|
||||||
|
mask[1] = 9thByte[1] xor 9thByte[5]
|
||||||
|
mask[2] = 9thByte[2] xor 9thByte[6]
|
||||||
|
mask[3] = 9thByte[3] xor 9thByte[7] xor 9thByte[0];
|
||||||
|
mask[4] = 9thByte[1];
|
||||||
|
mask[5] = 9thByte[2];
|
||||||
|
mask[6] = 9thByte[3];
|
||||||
|
mask[7] = 9thByte[4] xor 9thByte[0];
|
||||||
|
|
||||||
|
To calculate the heading (not tilt compensated) you need to do atan2 on the resulting
|
||||||
|
y any a (y and x?) values, convert radians to degrees and add 360 if the result is negative.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct DjiMag { // byte offset from beginning of packet, subtract 5 for struct offset
|
||||||
|
int16_t x; // BYTE 5-6 (CX): compass X axis data (signed) - see comments below
|
||||||
|
int16_t y; // BYTE 7-8 (CY): compass Y axis data (signed) - see comments below
|
||||||
|
int16_t z; // BYTE 9-10 (CZ): compass Z axis data (signed) - see comments below
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
version info from
|
||||||
|
http://www.rcgroups.com/forums/showpost.php?p=27058649&postcount=120
|
||||||
|
|
||||||
|
This is still to be confirmed but I believe the 0x30 message carries the GPS module hardware id and firmware version.
|
||||||
|
|
||||||
|
55 AA 30 0C XX XX XX XX FW FW FW FW HW HW HW HW CS CS
|
||||||
|
|
||||||
|
Note that you need to read version numbers backwards (02 01 00 06 means v6.0.1.2)
|
||||||
|
|
||||||
|
HEADER
|
||||||
|
-------------
|
||||||
|
BYTE 1-2: message header - always 55 AA
|
||||||
|
BYTE 3: message id (0x30 for GPS module versions message)
|
||||||
|
BYTE 4: length of the payload (0x0C or 12 decimal for 0x30 message)
|
||||||
|
|
||||||
|
PAYLOAD
|
||||||
|
--------------
|
||||||
|
BYTE 5-8" ??? (seems to be always 0)
|
||||||
|
BYTE 9-12 (FW): firmware version
|
||||||
|
BYTE 13-16 (HW): hardware id
|
||||||
|
|
||||||
|
CHECKSUM
|
||||||
|
-----------------
|
||||||
|
BYTE 17-18 (CS): checksum, calculated the same way as for uBlox binary messages
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct DjiVer { // byte offset from beginning of packet, subtract 5 for struct offset
|
||||||
|
uint32_t unused1; // BYTE 5-8" ??? (seems to be always 0)
|
||||||
|
uint32_t swVersion; // BYTE 9-12 (FW): firmware version
|
||||||
|
uint32_t hwVersion; // BYTE 13-16 (HW): hardware id
|
||||||
|
} __attribute__((packed));
|
||||||
|
#define VER_FIRST_DECODED_BYTE offsetof(struct DjiVer, swVersion)
|
||||||
|
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
uint8_t payload[0];
|
||||||
|
// Nav Class
|
||||||
|
struct DjiGps gps;
|
||||||
|
struct DjiMag mag;
|
||||||
|
struct DjiVer ver;
|
||||||
|
} DJIPayload;
|
||||||
|
|
||||||
|
struct DJIHeader {
|
||||||
|
uint8_t id;
|
||||||
|
uint8_t len;
|
||||||
|
uint8_t checksumA; // these are not part of the dji header, they are actually in the trailer
|
||||||
|
uint8_t checksumB; // but they are kept here for parsing ease
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct DJIPacket {
|
||||||
|
struct DJIHeader header;
|
||||||
|
DJIPayload payload;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
int parse_dji_stream(uint8_t *inputBuffer, uint16_t inputBufferLength, char *parsedDjiStruct, GPSPositionSensorData *GpsData, struct GPS_RX_STATS *GpsRxStats);
|
||||||
|
void dji_load_mag_settings();
|
||||||
|
|
||||||
|
#endif /* DJI_H */
|
@ -7,7 +7,8 @@
|
|||||||
* @{
|
* @{
|
||||||
*
|
*
|
||||||
* @file UBX.h
|
* @file UBX.h
|
||||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015-2016.
|
||||||
|
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||||
* @brief GPS module, handles GPS and NMEA stream
|
* @brief GPS module, handles GPS and NMEA stream
|
||||||
* @see The GNU Public License (GPL) Version 3
|
* @see The GNU Public License (GPL) Version 3
|
||||||
*
|
*
|
||||||
@ -612,7 +613,7 @@ union UBXSENTPACKET {
|
|||||||
|
|
||||||
// Used by AutoConfig code
|
// Used by AutoConfig code
|
||||||
extern int32_t ubxHwVersion;
|
extern int32_t ubxHwVersion;
|
||||||
extern GPSPositionSensorSensorTypeOptions sensorType;
|
extern GPSPositionSensorSensorTypeOptions ubxSensorType;
|
||||||
extern struct UBX_ACK_ACK ubxLastAck;
|
extern struct UBX_ACK_ACK ubxLastAck;
|
||||||
extern struct UBX_ACK_NAK ubxLastNak;
|
extern struct UBX_ACK_NAK ubxLastNak;
|
||||||
|
|
||||||
@ -621,5 +622,6 @@ uint32_t parse_ubx_message(struct UBXPacket *, GPSPositionSensorData *);
|
|||||||
|
|
||||||
int parse_ubx_stream(uint8_t *rx, uint16_t len, char *, GPSPositionSensorData *, struct GPS_RX_STATS *);
|
int parse_ubx_stream(uint8_t *rx, uint16_t len, char *, GPSPositionSensorData *, struct GPS_RX_STATS *);
|
||||||
void op_gpsv9_load_mag_settings();
|
void op_gpsv9_load_mag_settings();
|
||||||
|
void aux_hmc5x83_load_mag_settings();
|
||||||
|
|
||||||
#endif /* UBX_H */
|
#endif /* UBX_H */
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
* @{
|
* @{
|
||||||
*
|
*
|
||||||
* @file ubx_autoconfig.c
|
* @file ubx_autoconfig.c
|
||||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2014.
|
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015-2016.
|
||||||
|
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2014.
|
||||||
* @brief Support code for UBX AutoConfig
|
* @brief Support code for UBX AutoConfig
|
||||||
* @see The GNU Public License (GPL) Version 3
|
* @see The GNU Public License (GPL) Version 3
|
||||||
*
|
*
|
||||||
@ -238,10 +239,10 @@ void gps_ubx_reset_sensor_type()
|
|||||||
// is this needed?
|
// is this needed?
|
||||||
// what happens if two tasks / threads try to do an XyzSet() at the same time?
|
// what happens if two tasks / threads try to do an XyzSet() at the same time?
|
||||||
if (__sync_fetch_and_add(&mutex, 1) == 0) {
|
if (__sync_fetch_and_add(&mutex, 1) == 0) {
|
||||||
ubxHwVersion = -1;
|
ubxHwVersion = -1;
|
||||||
baud_to_try_index -= 1; // undo postincrement and start with the one that was most recently successful
|
baud_to_try_index -= 1; // undo postincrement and start with the one that was most recently successful
|
||||||
sensorType = GPSPOSITIONSENSOR_SENSORTYPE_UNKNOWN;
|
ubxSensorType = GPSPOSITIONSENSOR_SENSORTYPE_UNKNOWN;
|
||||||
GPSPositionSensorSensorTypeSet(&sensorType);
|
GPSPositionSensorSensorTypeSet(&ubxSensorType);
|
||||||
// make the sensor type / autobaud code time out immediately to send the request immediately
|
// make the sensor type / autobaud code time out immediately to send the request immediately
|
||||||
status->lastStepTimestampRaw += 0x8000000UL;
|
status->lastStepTimestampRaw += 0x8000000UL;
|
||||||
}
|
}
|
||||||
@ -849,6 +850,8 @@ void gps_ubx_autoconfig_run(char * *buffer, uint16_t *bytes_to_send)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// (re)init the autoconfig stuff so that it will run if called
|
||||||
|
//
|
||||||
// this can be called from a different thread
|
// this can be called from a different thread
|
||||||
// so everything it touches must be declared volatile
|
// so everything it touches must be declared volatile
|
||||||
void gps_ubx_autoconfig_set(ubx_autoconfig_settings_t *config)
|
void gps_ubx_autoconfig_set(ubx_autoconfig_settings_t *config)
|
||||||
@ -883,17 +886,17 @@ void gps_ubx_autoconfig_set(ubx_autoconfig_settings_t *config)
|
|||||||
status->currentStep = new_step;
|
status->currentStep = new_step;
|
||||||
status->currentStepSave = new_step;
|
status->currentStepSave = new_step;
|
||||||
|
|
||||||
|
// this forces the sensor type detection to occur outside the FSM
|
||||||
|
// and _can_ also engage the autobaud detection that is outside the FSM
|
||||||
|
// don't do it if FSM is enabled as FSM can change the baud itself
|
||||||
|
// (don't do it because the baud rates are already in sync)
|
||||||
|
gps_ubx_reset_sensor_type();
|
||||||
|
|
||||||
if (status->currentSettings.UbxAutoConfig >= GPSSETTINGS_UBXAUTOCONFIG_AUTOBAUDANDCONFIGURE) {
|
if (status->currentSettings.UbxAutoConfig >= GPSSETTINGS_UBXAUTOCONFIG_AUTOBAUDANDCONFIGURE) {
|
||||||
// enabled refers to autoconfigure
|
// enabled refers to autoconfigure
|
||||||
// note that sensor type (gps type) detection happens even if completely disabled
|
// note that sensor type (gps type) detection happens even if completely disabled
|
||||||
// also note that AutoBaud is less than Configure
|
// also note that AutoBaud is less than AutoBaudAndConfigure
|
||||||
enabled = true;
|
enabled = true;
|
||||||
} else {
|
|
||||||
// this forces the sensor type detection to occur outside the FSM
|
|
||||||
// and _can_ also engage the autobaud detection that is outside the FSM
|
|
||||||
// don't do it if FSM is enabled as FSM can change the baud itself
|
|
||||||
// (don't do it because the baud rates are already in sync)
|
|
||||||
gps_ubx_reset_sensor_type();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
* @{
|
* @{
|
||||||
*
|
*
|
||||||
* @file sensors.c
|
* @file sensors.c
|
||||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2015.
|
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015-2016.
|
||||||
|
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2015.
|
||||||
* @brief Module to handle fetch and preprocessing of sensor data
|
* @brief Module to handle fetch and preprocessing of sensor data
|
||||||
*
|
*
|
||||||
* @see The GNU Public License (GPL) Version 3
|
* @see The GNU Public License (GPL) Version 3
|
||||||
@ -62,6 +63,7 @@
|
|||||||
#include <auxmagsupport.h>
|
#include <auxmagsupport.h>
|
||||||
#include <accelgyrosettings.h>
|
#include <accelgyrosettings.h>
|
||||||
#include <revosettings.h>
|
#include <revosettings.h>
|
||||||
|
#include <UBX.h>
|
||||||
|
|
||||||
#include <mathmisc.h>
|
#include <mathmisc.h>
|
||||||
#include <taskinfo.h>
|
#include <taskinfo.h>
|
||||||
@ -128,6 +130,10 @@ PERF_DEFINE_COUNTER(counterBaroPeriod);
|
|||||||
PERF_DEFINE_COUNTER(counterSensorPeriod);
|
PERF_DEFINE_COUNTER(counterSensorPeriod);
|
||||||
PERF_DEFINE_COUNTER(counterSensorResets);
|
PERF_DEFINE_COUNTER(counterSensorResets);
|
||||||
|
|
||||||
|
#if defined(PIOS_INCLUDE_HMC5X83)
|
||||||
|
void aux_hmc5x83_load_settings();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Private functions
|
// Private functions
|
||||||
static void SensorsTask(void *parameters);
|
static void SensorsTask(void *parameters);
|
||||||
static void settingsUpdatedCb(UAVObjEvent *objEv);
|
static void settingsUpdatedCb(UAVObjEvent *objEv);
|
||||||
@ -141,7 +147,9 @@ static void clearContext(sensor_fetch_context *sensor_context);
|
|||||||
static void handleAccel(float *samples, float temperature);
|
static void handleAccel(float *samples, float temperature);
|
||||||
static void handleGyro(float *samples, float temperature);
|
static void handleGyro(float *samples, float temperature);
|
||||||
static void handleMag(float *samples, float temperature);
|
static void handleMag(float *samples, float temperature);
|
||||||
|
#if defined(PIOS_INCLUDE_HMC5X83)
|
||||||
static void handleAuxMag(float *samples);
|
static void handleAuxMag(float *samples);
|
||||||
|
#endif
|
||||||
static void handleBaro(float sample, float temperature);
|
static void handleBaro(float sample, float temperature);
|
||||||
|
|
||||||
static void updateAccelTempBias(float temperature);
|
static void updateAccelTempBias(float temperature);
|
||||||
@ -184,6 +192,12 @@ static float baro_temp_bias = 0;
|
|||||||
static float baro_temperature = NAN;
|
static float baro_temperature = NAN;
|
||||||
static uint8_t baro_temp_calibration_count = 0;
|
static uint8_t baro_temp_calibration_count = 0;
|
||||||
|
|
||||||
|
#if defined(PIOS_INCLUDE_HMC5X83)
|
||||||
|
// Allow AuxMag to be disabled without reboot
|
||||||
|
// because the other mags are that way
|
||||||
|
static bool useAuxMag = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialise the module. Called before the start function
|
* Initialise the module. Called before the start function
|
||||||
* \returns 0 on success or -1 if initialisation failed
|
* \returns 0 on success or -1 if initialisation failed
|
||||||
@ -200,9 +214,11 @@ int32_t SensorsInitialize(void)
|
|||||||
AttitudeSettingsInitialize();
|
AttitudeSettingsInitialize();
|
||||||
AccelGyroSettingsInitialize();
|
AccelGyroSettingsInitialize();
|
||||||
|
|
||||||
|
#if defined(PIOS_INCLUDE_HMC5X83)
|
||||||
// for auxmagsupport.c helpers
|
// for auxmagsupport.c helpers
|
||||||
AuxMagSettingsInitialize();
|
AuxMagSettingsInitialize();
|
||||||
AuxMagSensorInitialize();
|
AuxMagSensorInitialize();
|
||||||
|
#endif
|
||||||
|
|
||||||
RevoSettingsConnectCallback(&settingsUpdatedCb);
|
RevoSettingsConnectCallback(&settingsUpdatedCb);
|
||||||
RevoCalibrationConnectCallback(&settingsUpdatedCb);
|
RevoCalibrationConnectCallback(&settingsUpdatedCb);
|
||||||
@ -366,9 +382,12 @@ static void processSamples3d(sensor_fetch_context *sensor_context, const PIOS_SE
|
|||||||
|
|
||||||
PIOS_SENSORS_GetScales(sensor, scales, MAX_SENSORS_PER_INSTANCE);
|
PIOS_SENSORS_GetScales(sensor, scales, MAX_SENSORS_PER_INSTANCE);
|
||||||
float inv_count = 1.0f / (float)sensor_context->count;
|
float inv_count = 1.0f / (float)sensor_context->count;
|
||||||
if ((sensor->type & PIOS_SENSORS_TYPE_3AXIS_ACCEL) ||
|
if ((sensor->type & PIOS_SENSORS_TYPE_3AXIS_ACCEL)
|
||||||
(sensor->type == PIOS_SENSORS_TYPE_3AXIS_MAG) ||
|
|| (sensor->type == PIOS_SENSORS_TYPE_3AXIS_MAG)
|
||||||
(sensor->type == PIOS_SENSORS_TYPE_3AXIS_AUXMAG)) {
|
#if defined(PIOS_INCLUDE_HMC5X83)
|
||||||
|
|| (sensor->type == PIOS_SENSORS_TYPE_3AXIS_AUXMAG)
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
float t = inv_count * scales[0];
|
float t = inv_count * scales[0];
|
||||||
samples[0] = ((float)sensor_context->accum[0].x * t);
|
samples[0] = ((float)sensor_context->accum[0].x * t);
|
||||||
samples[1] = ((float)sensor_context->accum[0].y * t);
|
samples[1] = ((float)sensor_context->accum[0].y * t);
|
||||||
@ -380,11 +399,13 @@ static void processSamples3d(sensor_fetch_context *sensor_context, const PIOS_SE
|
|||||||
PERF_MEASURE_PERIOD(counterMagPeriod);
|
PERF_MEASURE_PERIOD(counterMagPeriod);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#if defined(PIOS_INCLUDE_HMC5X83)
|
||||||
case PIOS_SENSORS_TYPE_3AXIS_AUXMAG:
|
case PIOS_SENSORS_TYPE_3AXIS_AUXMAG:
|
||||||
handleAuxMag(samples);
|
handleAuxMag(samples);
|
||||||
PERF_MEASURE_PERIOD(counterMagPeriod);
|
PERF_MEASURE_PERIOD(counterMagPeriod);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
PERF_TRACK_VALUE(counterAccelSamples, sensor_context->count);
|
PERF_TRACK_VALUE(counterAccelSamples, sensor_context->count);
|
||||||
PERF_MEASURE_PERIOD(counterAccelPeriod);
|
PERF_MEASURE_PERIOD(counterAccelPeriod);
|
||||||
@ -473,10 +494,14 @@ static void handleMag(float *samples, float temperature)
|
|||||||
MagSensorSet(&mag);
|
MagSensorSet(&mag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(PIOS_INCLUDE_HMC5X83)
|
||||||
static void handleAuxMag(float *samples)
|
static void handleAuxMag(float *samples)
|
||||||
{
|
{
|
||||||
auxmagsupport_publish_samples(samples, AUXMAGSENSOR_STATUS_OK);
|
if (useAuxMag) {
|
||||||
|
auxmagsupport_publish_samples(samples, AUXMAGSENSOR_STATUS_OK);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void handleBaro(float sample, float temperature)
|
static void handleBaro(float sample, float temperature)
|
||||||
{
|
{
|
||||||
@ -607,6 +632,19 @@ static void settingsUpdatedCb(__attribute__((unused)) UAVObjEvent *objEv)
|
|||||||
fabsf(baroCorrection.c) > 1e-9f ||
|
fabsf(baroCorrection.c) > 1e-9f ||
|
||||||
fabsf(baroCorrection.d) > 1e-9f));
|
fabsf(baroCorrection.d) > 1e-9f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(PIOS_INCLUDE_HMC5X83)
|
||||||
|
void aux_hmc5x83_load_mag_settings()
|
||||||
|
{
|
||||||
|
uint8_t magType = auxmagsupport_get_type();
|
||||||
|
|
||||||
|
if (magType == AUXMAGSETTINGS_TYPE_I2C || magType == AUXMAGSETTINGS_TYPE_FLEXI) {
|
||||||
|
useAuxMag = true;
|
||||||
|
} else {
|
||||||
|
useAuxMag = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
* @}
|
* @}
|
||||||
|
@ -148,6 +148,7 @@
|
|||||||
#define PIOS_GPS_MINIMAL
|
#define PIOS_GPS_MINIMAL
|
||||||
/* #define PIOS_INCLUDE_GPS_NMEA_PARSER */
|
/* #define PIOS_INCLUDE_GPS_NMEA_PARSER */
|
||||||
#define PIOS_INCLUDE_GPS_UBX_PARSER
|
#define PIOS_INCLUDE_GPS_UBX_PARSER
|
||||||
|
/* #define PIOS_INCLUDE_GPS_DJI_PARSER */
|
||||||
/* #define PIOS_GPS_SETS_HOMELOCATION */
|
/* #define PIOS_GPS_SETS_HOMELOCATION */
|
||||||
|
|
||||||
/* Stabilization options */
|
/* Stabilization options */
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2015, The LibrePilot Project, http://www.librepilot.org
|
# Copyright (c) 2015-2016, The LibrePilot Project, http://www.librepilot.org
|
||||||
# Copyright (c) 2009-2013, The OpenPilot Team, http://www.openpilot.org
|
# Copyright (c) 2009-2013, The OpenPilot Team, http://www.openpilot.org
|
||||||
# Copyright (c) 2012, PhoenixPilot, http://github.com/PhoenixPilot
|
# Copyright (c) 2012, PhoenixPilot, http://github.com/PhoenixPilot
|
||||||
#
|
#
|
||||||
@ -32,7 +32,7 @@ USE_CXX = YES
|
|||||||
USE_DSP_LIB ?= NO
|
USE_DSP_LIB ?= NO
|
||||||
|
|
||||||
# List of mandatory modules to include
|
# List of mandatory modules to include
|
||||||
#MODULES += Sensors
|
MODULES += Sensors
|
||||||
#MODULES += Attitude/revolution
|
#MODULES += Attitude/revolution
|
||||||
#MODULES += StateEstimation # use instead of Attitude
|
#MODULES += StateEstimation # use instead of Attitude
|
||||||
#MODULES += Altitude/revolution
|
#MODULES += Altitude/revolution
|
||||||
|
@ -5,7 +5,8 @@
|
|||||||
* @addtogroup OpenPilotCore OpenPilot Core
|
* @addtogroup OpenPilotCore OpenPilot Core
|
||||||
* @{
|
* @{
|
||||||
* @file pios_config.h
|
* @file pios_config.h
|
||||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2013.
|
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015-2016.
|
||||||
|
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2013.
|
||||||
* @brief PiOS configuration header, the compile time config file for the PIOS.
|
* @brief PiOS configuration header, the compile time config file for the PIOS.
|
||||||
* Defines which PiOS libraries and features are included in the firmware.
|
* Defines which PiOS libraries and features are included in the firmware.
|
||||||
* @see The GNU Public License (GPL) Version 3
|
* @see The GNU Public License (GPL) Version 3
|
||||||
@ -149,6 +150,7 @@
|
|||||||
/* #define PIOS_GPS_MINIMAL */
|
/* #define PIOS_GPS_MINIMAL */
|
||||||
#define PIOS_INCLUDE_GPS_NMEA_PARSER
|
#define PIOS_INCLUDE_GPS_NMEA_PARSER
|
||||||
#define PIOS_INCLUDE_GPS_UBX_PARSER
|
#define PIOS_INCLUDE_GPS_UBX_PARSER
|
||||||
|
#define PIOS_INCLUDE_GPS_DJI_PARSER
|
||||||
#define PIOS_GPS_SETS_HOMELOCATION
|
#define PIOS_GPS_SETS_HOMELOCATION
|
||||||
|
|
||||||
/* Stabilization options */
|
/* Stabilization options */
|
||||||
|
@ -141,6 +141,7 @@
|
|||||||
/* #define PIOS_GPS_MINIMAL */
|
/* #define PIOS_GPS_MINIMAL */
|
||||||
#define PIOS_INCLUDE_GPS_NMEA_PARSER
|
#define PIOS_INCLUDE_GPS_NMEA_PARSER
|
||||||
#define PIOS_INCLUDE_GPS_UBX_PARSER
|
#define PIOS_INCLUDE_GPS_UBX_PARSER
|
||||||
|
#define PIOS_INCLUDE_GPS_DJI_PARSER
|
||||||
#define PIOS_GPS_SETS_HOMELOCATION
|
#define PIOS_GPS_SETS_HOMELOCATION
|
||||||
|
|
||||||
/* Stabilization options */
|
/* Stabilization options */
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* @addtogroup OpenPilotCore OpenPilot Core
|
* @addtogroup OpenPilotCore OpenPilot Core
|
||||||
* @{
|
* @{
|
||||||
* @file pios_config.h
|
* @file pios_config.h
|
||||||
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015.
|
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015-2016.
|
||||||
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2013.
|
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2013.
|
||||||
* @brief PiOS configuration header, the compile time config file for the PIOS.
|
* @brief PiOS configuration header, the compile time config file for the PIOS.
|
||||||
* Defines which PiOS libraries and features are included in the firmware.
|
* Defines which PiOS libraries and features are included in the firmware.
|
||||||
@ -153,6 +153,7 @@
|
|||||||
/* #define PIOS_GPS_MINIMAL */
|
/* #define PIOS_GPS_MINIMAL */
|
||||||
#define PIOS_INCLUDE_GPS_NMEA_PARSER
|
#define PIOS_INCLUDE_GPS_NMEA_PARSER
|
||||||
#define PIOS_INCLUDE_GPS_UBX_PARSER
|
#define PIOS_INCLUDE_GPS_UBX_PARSER
|
||||||
|
#define PIOS_INCLUDE_GPS_DJI_PARSER
|
||||||
#define PIOS_GPS_SETS_HOMELOCATION
|
#define PIOS_GPS_SETS_HOMELOCATION
|
||||||
|
|
||||||
/* Stabilization options */
|
/* Stabilization options */
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* @addtogroup OpenPilotCore OpenPilot Core
|
* @addtogroup OpenPilotCore OpenPilot Core
|
||||||
* @{
|
* @{
|
||||||
* @file pios_config.h
|
* @file pios_config.h
|
||||||
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015.
|
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015-2016.
|
||||||
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2013.
|
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2013.
|
||||||
* @brief PiOS configuration header, the compile time config file for the PIOS.
|
* @brief PiOS configuration header, the compile time config file for the PIOS.
|
||||||
* Defines which PiOS libraries and features are included in the firmware.
|
* Defines which PiOS libraries and features are included in the firmware.
|
||||||
@ -157,6 +157,7 @@
|
|||||||
/* #define PIOS_GPS_MINIMAL */
|
/* #define PIOS_GPS_MINIMAL */
|
||||||
#define PIOS_INCLUDE_GPS_NMEA_PARSER
|
#define PIOS_INCLUDE_GPS_NMEA_PARSER
|
||||||
#define PIOS_INCLUDE_GPS_UBX_PARSER
|
#define PIOS_INCLUDE_GPS_UBX_PARSER
|
||||||
|
#define PIOS_INCLUDE_GPS_DJI_PARSER
|
||||||
#define PIOS_GPS_SETS_HOMELOCATION
|
#define PIOS_GPS_SETS_HOMELOCATION
|
||||||
|
|
||||||
/* Stabilization options */
|
/* Stabilization options */
|
||||||
|
@ -5,7 +5,8 @@
|
|||||||
* @addtogroup OpenPilotCore OpenPilot Core
|
* @addtogroup OpenPilotCore OpenPilot Core
|
||||||
* @{
|
* @{
|
||||||
* @file pios_config.h
|
* @file pios_config.h
|
||||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2013.
|
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015-2016.
|
||||||
|
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2013.
|
||||||
* @brief PiOS configuration header, the compile time config file for the PIOS.
|
* @brief PiOS configuration header, the compile time config file for the PIOS.
|
||||||
* Defines which PiOS libraries and features are included in the firmware.
|
* Defines which PiOS libraries and features are included in the firmware.
|
||||||
* @see The GNU Public License (GPL) Version 3
|
* @see The GNU Public License (GPL) Version 3
|
||||||
@ -141,6 +142,7 @@
|
|||||||
/* #define PIOS_GPS_MINIMAL */
|
/* #define PIOS_GPS_MINIMAL */
|
||||||
#define PIOS_INCLUDE_GPS_NMEA_PARSER
|
#define PIOS_INCLUDE_GPS_NMEA_PARSER
|
||||||
#define PIOS_INCLUDE_GPS_UBX_PARSER
|
#define PIOS_INCLUDE_GPS_UBX_PARSER
|
||||||
|
#define PIOS_INCLUDE_GPS_DJI_PARSER
|
||||||
#define PIOS_GPS_SETS_HOMELOCATION
|
#define PIOS_GPS_SETS_HOMELOCATION
|
||||||
|
|
||||||
/* Stabilization options */
|
/* Stabilization options */
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
defaultvalue="1,0,0,0,1,0,0,0,1"/>
|
defaultvalue="1,0,0,0,1,0,0,0,1"/>
|
||||||
<field name="MagBiasNullingRate" units="" type="float" elements="1" defaultvalue="0"/>
|
<field name="MagBiasNullingRate" units="" type="float" elements="1" defaultvalue="0"/>
|
||||||
<field name="BoardRotation" units="deg" type="int16" elementnames="Roll,Pitch,Yaw" defaultvalue="0,0,0"/>
|
<field name="BoardRotation" units="deg" type="int16" elementnames="Roll,Pitch,Yaw" defaultvalue="0,0,0"/>
|
||||||
<field name="Type" units="" type="enum" elements="1" options="GPSV9,Ext,Flexi" defaultvalue="GPSV9"/>
|
<field name="Type" units="" type="enum" elements="1" options="GPSV9,Flexi,I2C,DJI" defaultvalue="GPSV9"/>
|
||||||
<field name="Usage" units="" type="enum" elements="1" options="Both,OnboardOnly,AuxOnly" defaultvalue="Both"/>
|
<field name="Usage" units="" type="enum" elements="1" options="Both,OnboardOnly,AuxOnly" defaultvalue="Both"/>
|
||||||
<access gcs="readwrite" flight="readwrite"/>
|
<access gcs="readwrite" flight="readwrite"/>
|
||||||
<telemetrygcs acked="true" updatemode="onchange" period="0"/>
|
<telemetrygcs acked="true" updatemode="onchange" period="0"/>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<field name="PDOP" units="" type="float" elements="1"/>
|
<field name="PDOP" units="" type="float" elements="1"/>
|
||||||
<field name="HDOP" units="" type="float" elements="1"/>
|
<field name="HDOP" units="" type="float" elements="1"/>
|
||||||
<field name="VDOP" units="" type="float" elements="1"/>
|
<field name="VDOP" units="" type="float" elements="1"/>
|
||||||
<field name="SensorType" units="" type="enum" elements="1" options="Unknown,NMEA,UBX,UBX7,UBX8" defaultvalue="Unknown" />
|
<field name="SensorType" units="" type="enum" elements="1" options="Unknown,NMEA,UBX,UBX7,UBX8,DJI" defaultvalue="Unknown" />
|
||||||
<field name="AutoConfigStatus" units="" type="enum" elements="1" options="Disabled,Running,Done,Error" defaultvalue="Disabled" />
|
<field name="AutoConfigStatus" units="" type="enum" elements="1" options="Disabled,Running,Done,Error" defaultvalue="Disabled" />
|
||||||
<field name="BaudRate" units="" type="enum" elements="1" options="2400,4800,9600,19200,38400,57600,115200,230400,Unknown" defaultvalue="Unknown" />
|
<field name="BaudRate" units="" type="enum" elements="1" options="2400,4800,9600,19200,38400,57600,115200,230400,Unknown" defaultvalue="Unknown" />
|
||||||
<access gcs="readwrite" flight="readwrite"/>
|
<access gcs="readwrite" flight="readwrite"/>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<object name="GPSSettings" singleinstance="true" settings="true" category="Sensors">
|
<object name="GPSSettings" singleinstance="true" settings="true" category="Sensors">
|
||||||
<description>GPS Module specific settings</description>
|
<description>GPS Module specific settings</description>
|
||||||
<field name="DataProtocol" units="" type="enum" elements="1" options="NMEA,UBX" defaultvalue="UBX"/>
|
<field name="DataProtocol" units="" type="enum" elements="1" options="NMEA,UBX,DJI" defaultvalue="UBX"/>
|
||||||
<field name="MinSatellites" units="" type="uint8" elements="1" defaultvalue="7"/>
|
<field name="MinSatellites" units="" type="uint8" elements="1" defaultvalue="7"/>
|
||||||
<field name="MaxPDOP" units="" type="float" elements="1" defaultvalue="3.5"/>
|
<field name="MaxPDOP" units="" type="float" elements="1" defaultvalue="3.5"/>
|
||||||
<!-- Ubx self configuration. Enable to allow the flight board to auto configure ubx GPS options,
|
<!-- Ubx self configuration. Enable to allow the flight board to auto configure ubx GPS options,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user