mirror of
https://github.com/iNavFlight/inav.git
synced 2025-07-24 16:55:29 +03:00
GPS: Protocol-independent stack. UBLOX binary driver implementation. Autoconfig works. Autobaud works.
GPS: Native MAG support (for future NAZA GPS support), bugfixes GPS: Supported GPS protocols on a per-target basis
This commit is contained in:
parent
a5628cc4a8
commit
69cfbb04d2
38 changed files with 1491 additions and 1249 deletions
3
Makefile
3
Makefile
|
@ -275,6 +275,9 @@ HIGHEND_SRC = \
|
||||||
flight/gps_conversion.c \
|
flight/gps_conversion.c \
|
||||||
common/colorconversion.c \
|
common/colorconversion.c \
|
||||||
io/gps.c \
|
io/gps.c \
|
||||||
|
io/gps_ublox.c \
|
||||||
|
io/gps_nmea.c \
|
||||||
|
io/gps_i2cnav.c \
|
||||||
io/ledstrip.c \
|
io/ledstrip.c \
|
||||||
io/display.c \
|
io/display.c \
|
||||||
telemetry/telemetry.c \
|
telemetry/telemetry.c \
|
||||||
|
|
|
@ -968,16 +968,16 @@ static void writeGPSFrame()
|
||||||
blackboxWriteUnsignedVB(currentTime - blackboxHistory[1]->time);
|
blackboxWriteUnsignedVB(currentTime - blackboxHistory[1]->time);
|
||||||
}
|
}
|
||||||
|
|
||||||
blackboxWriteUnsignedVB(GPS_numSat);
|
blackboxWriteUnsignedVB(gpsSol.numSat);
|
||||||
blackboxWriteSignedVB(GPS_coord[0] - gpsHistory.GPS_home[0]);
|
blackboxWriteSignedVB(gpsSol.llh.lat - gpsHistory.GPS_home[0]);
|
||||||
blackboxWriteSignedVB(GPS_coord[1] - gpsHistory.GPS_home[1]);
|
blackboxWriteSignedVB(gpsSol.llh.lon - gpsHistory.GPS_home[1]);
|
||||||
blackboxWriteUnsignedVB(GPS_altitude);
|
blackboxWriteUnsignedVB(gpsSol.llh.alt);
|
||||||
blackboxWriteUnsignedVB(GPS_speed);
|
blackboxWriteUnsignedVB(gpsSol.groundSpeed);
|
||||||
blackboxWriteUnsignedVB(GPS_ground_course);
|
blackboxWriteUnsignedVB(gpsSol.groundCourse);
|
||||||
|
|
||||||
gpsHistory.GPS_numSat = GPS_numSat;
|
gpsHistory.GPS_numSat = gpsSol.numSat;
|
||||||
gpsHistory.GPS_coord[0] = GPS_coord[0];
|
gpsHistory.GPS_coord[0] = gpsSol.llh.lat;
|
||||||
gpsHistory.GPS_coord[1] = GPS_coord[1];
|
gpsHistory.GPS_coord[1] = gpsSol.llh.lon;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1371,8 +1371,8 @@ static void blackboxLogIteration()
|
||||||
|
|
||||||
writeGPSHomeFrame();
|
writeGPSHomeFrame();
|
||||||
writeGPSFrame();
|
writeGPSFrame();
|
||||||
} else if (GPS_numSat != gpsHistory.GPS_numSat || GPS_coord[0] != gpsHistory.GPS_coord[0]
|
} else if (gpsSol.numSat != gpsHistory.GPS_numSat || gpsSol.llh.lat != gpsHistory.GPS_coord[0]
|
||||||
|| GPS_coord[1] != gpsHistory.GPS_coord[1]) {
|
|| gpsSol.llh.lon != gpsHistory.GPS_coord[1]) {
|
||||||
//We could check for velocity changes as well but I doubt it changes independent of position
|
//We could check for velocity changes as well but I doubt it changes independent of position
|
||||||
writeGPSFrame();
|
writeGPSFrame();
|
||||||
}
|
}
|
||||||
|
|
|
@ -461,15 +461,15 @@ static void imuCalculateEstimatedAttitude(float dT)
|
||||||
useMag = true;
|
useMag = true;
|
||||||
}
|
}
|
||||||
#if defined(GPS)
|
#if defined(GPS)
|
||||||
else if (STATE(FIXED_WING) && sensors(SENSOR_GPS) && STATE(GPS_FIX) && GPS_numSat >= 5 && GPS_speed >= 300) {
|
else if (STATE(FIXED_WING) && sensors(SENSOR_GPS) && STATE(GPS_FIX) && gpsSol.numSat >= 5 && gpsSol.groundSpeed >= 300) {
|
||||||
// In case of a fixed-wing aircraft we can use GPS course over ground to correct heading
|
// In case of a fixed-wing aircraft we can use GPS course over ground to correct heading
|
||||||
if (gpsHeadingInitialized) {
|
if (gpsHeadingInitialized) {
|
||||||
courseOverGround = DECIDEGREES_TO_RADIANS(GPS_ground_course);
|
courseOverGround = DECIDEGREES_TO_RADIANS(gpsSol.groundCourse);
|
||||||
useCOG = true;
|
useCOG = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Re-initialize quaternion from known Roll, Pitch and GPS heading
|
// Re-initialize quaternion from known Roll, Pitch and GPS heading
|
||||||
imuComputeQuaternionFromRPY(attitude.values.roll, attitude.values.pitch, GPS_ground_course);
|
imuComputeQuaternionFromRPY(attitude.values.roll, attitude.values.pitch, gpsSol.groundCourse);
|
||||||
gpsHeadingInitialized = true;
|
gpsHeadingInitialized = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -514,9 +514,9 @@ static void imuUpdateMeasuredAcceleration(float dT)
|
||||||
* assumption: tangential velocity only along body x-axis
|
* assumption: tangential velocity only along body x-axis
|
||||||
* assumption: GPS velocity equal to body x-axis velocity
|
* assumption: GPS velocity equal to body x-axis velocity
|
||||||
*/
|
*/
|
||||||
if (STATE(FIXED_WING) && sensors(SENSOR_GPS) && STATE(GPS_FIX) && GPS_numSat >= 5) {
|
if (STATE(FIXED_WING) && sensors(SENSOR_GPS) && STATE(GPS_FIX) && gpsSol.numSat >= 5) {
|
||||||
imuMeasuredGravityBF.A[Y] -= GPS_speed * imuMeasuredRotationBF.A[Z];
|
imuMeasuredGravityBF.A[Y] -= gpsSol.groundSpeed * imuMeasuredRotationBF.A[Z];
|
||||||
imuMeasuredGravityBF.A[Z] += GPS_speed * imuMeasuredRotationBF.A[Y];
|
imuMeasuredGravityBF.A[Z] += gpsSol.groundSpeed * imuMeasuredRotationBF.A[Y];
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1886,7 +1886,7 @@ void applyWaypointNavigationAndAltitudeHold(void)
|
||||||
if (posControl.flags.hasValidAltitudeSensor) navFlags |= (1 << 0);
|
if (posControl.flags.hasValidAltitudeSensor) navFlags |= (1 << 0);
|
||||||
if (posControl.flags.hasValidSurfaceSensor) navFlags |= (1 << 1);
|
if (posControl.flags.hasValidSurfaceSensor) navFlags |= (1 << 1);
|
||||||
if (posControl.flags.hasValidPositionSensor) navFlags |= (1 << 2);
|
if (posControl.flags.hasValidPositionSensor) navFlags |= (1 << 2);
|
||||||
if ((STATE(GPS_FIX) && GPS_numSat >= posControl.navConfig->inav.gps_min_sats)) navFlags |= (1 << 3);
|
if ((STATE(GPS_FIX) && gpsSol.numSat >= posControl.navConfig->inav.gps_min_sats)) navFlags |= (1 << 3);
|
||||||
if (isGPSGlitchDetected()) navFlags |= (1 << 4);
|
if (isGPSGlitchDetected()) navFlags |= (1 << 4);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -2241,6 +2241,7 @@ rthState_e getStateOfForcedRTH(void)
|
||||||
|
|
||||||
#else // NAV
|
#else // NAV
|
||||||
|
|
||||||
|
#ifdef GPS
|
||||||
/* Fallback if navigation is not compiled in - handle GPS home coordinates */
|
/* Fallback if navigation is not compiled in - handle GPS home coordinates */
|
||||||
static float GPS_scaleLonDown;
|
static float GPS_scaleLonDown;
|
||||||
|
|
||||||
|
@ -2266,7 +2267,7 @@ void onNewGPSData(int32_t newLat, int32_t newLon, int32_t newAlt, int16_t velN,
|
||||||
UNUSED(velDValid);
|
UNUSED(velDValid);
|
||||||
UNUSED(hdop);
|
UNUSED(hdop);
|
||||||
|
|
||||||
if (!(sensors(SENSOR_GPS) && STATE(GPS_FIX) && GPS_numSat >= 5))
|
if (!(sensors(SENSOR_GPS) && STATE(GPS_FIX) && gpsSol.numSat >= 5))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ARMING_FLAG(ARMED)) {
|
if (ARMING_FLAG(ARMED)) {
|
||||||
|
@ -2292,5 +2293,6 @@ void onNewGPSData(int32_t newLat, int32_t newLon, int32_t newAlt, int16_t velN,
|
||||||
GPS_scaleLonDown = cos_approx((ABS((float)newLat) / 10000000.0f) * 0.0174532925f);
|
GPS_scaleLonDown = cos_approx((ABS((float)newLat) / 10000000.0f) * 0.0174532925f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // NAV
|
#endif // NAV
|
||||||
|
|
|
@ -22,17 +22,11 @@
|
||||||
|
|
||||||
#include "io/rc_controls.h"
|
#include "io/rc_controls.h"
|
||||||
#include "io/escservo.h"
|
#include "io/escservo.h"
|
||||||
|
#include "io/gps.h"
|
||||||
|
|
||||||
#include "flight/pid.h"
|
#include "flight/pid.h"
|
||||||
#include "flight/failsafe.h"
|
#include "flight/failsafe.h"
|
||||||
|
|
||||||
/* LLH Location in NEU axis system */
|
|
||||||
typedef struct gpsLocation_s {
|
|
||||||
int32_t lat; // Lattitude * 1e+7
|
|
||||||
int32_t lon; // Longitude * 1e+7
|
|
||||||
int32_t alt; // Altitude in centimeters (meters * 100)
|
|
||||||
} gpsLocation_t;
|
|
||||||
|
|
||||||
/* GPS Home location data */
|
/* GPS Home location data */
|
||||||
extern gpsLocation_t GPS_home;
|
extern gpsLocation_t GPS_home;
|
||||||
extern uint16_t GPS_distanceToHome; // distance to home point in meters
|
extern uint16_t GPS_distanceToHome; // distance to home point in meters
|
||||||
|
|
|
@ -244,7 +244,7 @@ void onNewGPSData(int32_t newLat, int32_t newLon, int32_t newAlt, int16_t velN,
|
||||||
velDValid = false;
|
velDValid = false;
|
||||||
|
|
||||||
if (sensors(SENSOR_GPS)) {
|
if (sensors(SENSOR_GPS)) {
|
||||||
if (!(STATE(GPS_FIX) && GPS_numSat >= posControl.navConfig->inav.gps_min_sats)) {
|
if (!(STATE(GPS_FIX) && gpsSol.numSat >= posControl.navConfig->inav.gps_min_sats)) {
|
||||||
isFirstGPSUpdate = true;
|
isFirstGPSUpdate = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -264,7 +264,7 @@ void onNewGPSData(int32_t newLat, int32_t newLon, int32_t newAlt, int16_t velN,
|
||||||
|
|
||||||
/* Process position update if GPS origin is already set, or precision is good enough */
|
/* Process position update if GPS origin is already set, or precision is good enough */
|
||||||
// FIXME: use HDOP here
|
// FIXME: use HDOP here
|
||||||
if ((posControl.gpsOrigin.valid) || (GPS_numSat >= posControl.navConfig->inav.gps_min_sats)) {
|
if ((posControl.gpsOrigin.valid) || (gpsSol.numSat >= posControl.navConfig->inav.gps_min_sats)) {
|
||||||
/* Convert LLH position to local coordinates */
|
/* Convert LLH position to local coordinates */
|
||||||
t_fp_vector newLocalPos;
|
t_fp_vector newLocalPos;
|
||||||
geoConvertGeodeticToLocal(&posControl.gpsOrigin, &newLLH, &newLocalPos, GEO_ALT_ABSOLUTE);
|
geoConvertGeodeticToLocal(&posControl.gpsOrigin, &newLLH, &newLocalPos, GEO_ALT_ABSOLUTE);
|
||||||
|
|
|
@ -253,12 +253,12 @@ void beeperConfirmationBeeps(uint8_t beepCount)
|
||||||
void beeperGpsStatus(void)
|
void beeperGpsStatus(void)
|
||||||
{
|
{
|
||||||
// if GPS fix then beep out number of satellites
|
// if GPS fix then beep out number of satellites
|
||||||
if (STATE(GPS_FIX) && GPS_numSat >= 5) {
|
if (STATE(GPS_FIX) && gpsSol.numSat >= 5) {
|
||||||
uint8_t i = 0;
|
uint8_t i = 0;
|
||||||
do {
|
do {
|
||||||
beep_multiBeeps[i++] = 5;
|
beep_multiBeeps[i++] = 5;
|
||||||
beep_multiBeeps[i++] = 10;
|
beep_multiBeeps[i++] = 10;
|
||||||
} while (i < MAX_MULTI_BEEPS && GPS_numSat > i / 2);
|
} while (i < MAX_MULTI_BEEPS && gpsSol.numSat > i / 2);
|
||||||
|
|
||||||
beep_multiBeeps[i-1] = 50; // extend last pause
|
beep_multiBeeps[i-1] = 50; // extend last pause
|
||||||
beep_multiBeeps[i] = BEEPER_COMMAND_STOP;
|
beep_multiBeeps[i] = BEEPER_COMMAND_STOP;
|
||||||
|
|
|
@ -225,7 +225,7 @@ void updateFailsafeStatus(void)
|
||||||
case FAILSAFE_RX_LOSS_DETECTED:
|
case FAILSAFE_RX_LOSS_DETECTED:
|
||||||
failsafeIndicator = 'R';
|
failsafeIndicator = 'R';
|
||||||
break;
|
break;
|
||||||
#ifdef NAV
|
#if defined(NAV)
|
||||||
case FAILSAFE_RETURN_TO_HOME:
|
case FAILSAFE_RETURN_TO_HOME:
|
||||||
failsafeIndicator = 'H';
|
failsafeIndicator = 'H';
|
||||||
break;
|
break;
|
||||||
|
@ -338,7 +338,7 @@ void showProfilePage(void)
|
||||||
i2c_OLED_set_line(rowIndex++);
|
i2c_OLED_set_line(rowIndex++);
|
||||||
i2c_OLED_send_string(lineBuffer);
|
i2c_OLED_send_string(lineBuffer);
|
||||||
}
|
}
|
||||||
#define SATELLITE_COUNT (sizeof(GPS_svinfo_cno) / sizeof(GPS_svinfo_cno[0]))
|
#define SATELLITE_COUNT (sizeof(gpsSol.svInfo) / sizeof(gpsSol.svInfo[0]))
|
||||||
#define SATELLITE_GRAPH_LEFT_OFFSET ((SCREEN_CHARACTER_COLUMN_COUNT - SATELLITE_COUNT) / 2)
|
#define SATELLITE_GRAPH_LEFT_OFFSET ((SCREEN_CHARACTER_COLUMN_COUNT - SATELLITE_COUNT) / 2)
|
||||||
|
|
||||||
#ifdef GPS
|
#ifdef GPS
|
||||||
|
@ -346,9 +346,9 @@ void showGpsPage() {
|
||||||
uint8_t rowIndex = PAGE_TITLE_LINE_COUNT;
|
uint8_t rowIndex = PAGE_TITLE_LINE_COUNT;
|
||||||
|
|
||||||
static uint8_t gpsTicker = 0;
|
static uint8_t gpsTicker = 0;
|
||||||
static uint32_t lastGPSSvInfoReceivedCount = 0;
|
static uint8_t lastGPSHeartbeat = 0;
|
||||||
if (GPS_svInfoReceivedCount != lastGPSSvInfoReceivedCount) {
|
if (gpsSol.flags.gpsHeartbeat != lastGPSHeartbeat) {
|
||||||
lastGPSSvInfoReceivedCount = GPS_svInfoReceivedCount;
|
lastGPSHeartbeat = gpsSol.flags.gpsHeartbeat;
|
||||||
gpsTicker++;
|
gpsTicker++;
|
||||||
gpsTicker = gpsTicker % TICKER_CHARACTER_COUNT;
|
gpsTicker = gpsTicker % TICKER_CHARACTER_COUNT;
|
||||||
}
|
}
|
||||||
|
@ -360,58 +360,53 @@ void showGpsPage() {
|
||||||
|
|
||||||
uint32_t index;
|
uint32_t index;
|
||||||
for (index = 0; index < SATELLITE_COUNT && index < SCREEN_CHARACTER_COLUMN_COUNT; index++) {
|
for (index = 0; index < SATELLITE_COUNT && index < SCREEN_CHARACTER_COLUMN_COUNT; index++) {
|
||||||
uint8_t bargraphOffset = ((uint16_t) GPS_svinfo_cno[index] * VERTICAL_BARGRAPH_CHARACTER_COUNT) / (GPS_DBHZ_MAX - 1);
|
uint8_t bargraphOffset = ((uint16_t) gpsSol.svInfo[index].cno * VERTICAL_BARGRAPH_CHARACTER_COUNT) / (GPS_DBHZ_MAX - 1);
|
||||||
bargraphOffset = MIN(bargraphOffset, VERTICAL_BARGRAPH_CHARACTER_COUNT - 1);
|
bargraphOffset = MIN(bargraphOffset, VERTICAL_BARGRAPH_CHARACTER_COUNT - 1);
|
||||||
i2c_OLED_send_char(VERTICAL_BARGRAPH_ZERO_CHARACTER + bargraphOffset);
|
i2c_OLED_send_char(VERTICAL_BARGRAPH_ZERO_CHARACTER + bargraphOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char fixChar = STATE(GPS_FIX) ? 'Y' : 'N';
|
char fixChar = STATE(GPS_FIX) ? 'Y' : 'N';
|
||||||
tfp_sprintf(lineBuffer, "Sats: %d Fix: %c", GPS_numSat, fixChar);
|
tfp_sprintf(lineBuffer, "Sats: %d Fix: %c", gpsSol.numSat, fixChar);
|
||||||
padLineBuffer();
|
padLineBuffer();
|
||||||
i2c_OLED_set_line(rowIndex++);
|
i2c_OLED_set_line(rowIndex++);
|
||||||
i2c_OLED_send_string(lineBuffer);
|
i2c_OLED_send_string(lineBuffer);
|
||||||
|
|
||||||
tfp_sprintf(lineBuffer, "La/Lo: %d/%d", GPS_coord[LAT] / GPS_DEGREES_DIVIDER, GPS_coord[LON] / GPS_DEGREES_DIVIDER);
|
tfp_sprintf(lineBuffer, "La/Lo: %d/%d", gpsSol.llh.lat / GPS_DEGREES_DIVIDER, gpsSol.llh.lon / GPS_DEGREES_DIVIDER);
|
||||||
padLineBuffer();
|
padLineBuffer();
|
||||||
i2c_OLED_set_line(rowIndex++);
|
i2c_OLED_set_line(rowIndex++);
|
||||||
i2c_OLED_send_string(lineBuffer);
|
i2c_OLED_send_string(lineBuffer);
|
||||||
|
|
||||||
tfp_sprintf(lineBuffer, "Spd: %d", GPS_speed);
|
tfp_sprintf(lineBuffer, "Spd: %d", gpsSol.groundSpeed);
|
||||||
padHalfLineBuffer();
|
padHalfLineBuffer();
|
||||||
i2c_OLED_set_line(rowIndex);
|
i2c_OLED_set_line(rowIndex);
|
||||||
i2c_OLED_send_string(lineBuffer);
|
i2c_OLED_send_string(lineBuffer);
|
||||||
|
|
||||||
tfp_sprintf(lineBuffer, "GC: %d", GPS_ground_course);
|
tfp_sprintf(lineBuffer, "GC: %d", gpsSol.groundCourse);
|
||||||
padHalfLineBuffer();
|
padHalfLineBuffer();
|
||||||
i2c_OLED_set_xy(HALF_SCREEN_CHARACTER_COLUMN_COUNT, rowIndex++);
|
i2c_OLED_set_xy(HALF_SCREEN_CHARACTER_COLUMN_COUNT, rowIndex++);
|
||||||
i2c_OLED_send_string(lineBuffer);
|
i2c_OLED_send_string(lineBuffer);
|
||||||
|
|
||||||
tfp_sprintf(lineBuffer, "RX: %d", GPS_packetCount);
|
tfp_sprintf(lineBuffer, "RX: %d", gpsStats.packetCount);
|
||||||
padHalfLineBuffer();
|
padHalfLineBuffer();
|
||||||
i2c_OLED_set_line(rowIndex);
|
i2c_OLED_set_line(rowIndex);
|
||||||
i2c_OLED_send_string(lineBuffer);
|
i2c_OLED_send_string(lineBuffer);
|
||||||
|
|
||||||
tfp_sprintf(lineBuffer, "ERRs: %d", gpsData.errors, gpsData.timeouts);
|
tfp_sprintf(lineBuffer, "ERRs: %d", gpsStats.errors);
|
||||||
padHalfLineBuffer();
|
padHalfLineBuffer();
|
||||||
i2c_OLED_set_xy(HALF_SCREEN_CHARACTER_COLUMN_COUNT, rowIndex++);
|
i2c_OLED_set_xy(HALF_SCREEN_CHARACTER_COLUMN_COUNT, rowIndex++);
|
||||||
i2c_OLED_send_string(lineBuffer);
|
i2c_OLED_send_string(lineBuffer);
|
||||||
|
|
||||||
tfp_sprintf(lineBuffer, "Dt: %d", gpsData.lastMessage - gpsData.lastLastMessage);
|
tfp_sprintf(lineBuffer, "Dt: %d", gpsStats.lastMessageDt);
|
||||||
padHalfLineBuffer();
|
padHalfLineBuffer();
|
||||||
i2c_OLED_set_line(rowIndex);
|
i2c_OLED_set_line(rowIndex);
|
||||||
i2c_OLED_send_string(lineBuffer);
|
i2c_OLED_send_string(lineBuffer);
|
||||||
|
|
||||||
tfp_sprintf(lineBuffer, "TOs: %d", gpsData.timeouts);
|
tfp_sprintf(lineBuffer, "TOs: %d", gpsStats.timeouts);
|
||||||
padHalfLineBuffer();
|
padHalfLineBuffer();
|
||||||
i2c_OLED_set_xy(HALF_SCREEN_CHARACTER_COLUMN_COUNT, rowIndex++);
|
i2c_OLED_set_xy(HALF_SCREEN_CHARACTER_COLUMN_COUNT, rowIndex++);
|
||||||
i2c_OLED_send_string(lineBuffer);
|
i2c_OLED_send_string(lineBuffer);
|
||||||
|
|
||||||
strncpy(lineBuffer, gpsPacketLog, GPS_PACKET_LOG_ENTRY_COUNT);
|
|
||||||
padHalfLineBuffer();
|
|
||||||
i2c_OLED_set_line(rowIndex++);
|
|
||||||
i2c_OLED_send_string(lineBuffer);
|
|
||||||
|
|
||||||
#ifdef GPS_PH_DEBUG
|
#ifdef GPS_PH_DEBUG
|
||||||
tfp_sprintf(lineBuffer, "Angles: P:%d R:%d", GPS_angle[PITCH], GPS_angle[ROLL]);
|
tfp_sprintf(lineBuffer, "Angles: P:%d R:%d", GPS_angle[PITCH], GPS_angle[ROLL]);
|
||||||
padLineBuffer();
|
padLineBuffer();
|
||||||
|
|
1341
src/main/io/gps.c
1341
src/main/io/gps.c
File diff suppressed because it is too large
Load diff
|
@ -17,6 +17,11 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#define GPS_DBHZ_MIN 0
|
||||||
|
#define GPS_DBHZ_MAX 55
|
||||||
|
|
||||||
|
#define GPS_SV_MAXSATS 16
|
||||||
|
|
||||||
#define LAT 0
|
#define LAT 0
|
||||||
#define LON 1
|
#define LON 1
|
||||||
|
|
||||||
|
@ -25,11 +30,10 @@
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GPS_NMEA = 0,
|
GPS_NMEA = 0,
|
||||||
GPS_UBLOX,
|
GPS_UBLOX,
|
||||||
GPS_I2C
|
GPS_I2CNAV,
|
||||||
|
GPS_PROVIDER_COUNT
|
||||||
} gpsProvider_e;
|
} gpsProvider_e;
|
||||||
|
|
||||||
#define GPS_PROVIDER_MAX GPS_I2C
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SBAS_AUTO = 0,
|
SBAS_AUTO = 0,
|
||||||
SBAS_EGNOS,
|
SBAS_EGNOS,
|
||||||
|
@ -45,7 +49,8 @@ typedef enum {
|
||||||
GPS_BAUDRATE_57600,
|
GPS_BAUDRATE_57600,
|
||||||
GPS_BAUDRATE_38400,
|
GPS_BAUDRATE_38400,
|
||||||
GPS_BAUDRATE_19200,
|
GPS_BAUDRATE_19200,
|
||||||
GPS_BAUDRATE_9600
|
GPS_BAUDRATE_9600,
|
||||||
|
GPS_BAUDRATE_COUNT
|
||||||
} gpsBaudRate_e;
|
} gpsBaudRate_e;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -72,53 +77,54 @@ typedef struct gpsCoordinateDDDMMmmmm_s {
|
||||||
int16_t mmmm;
|
int16_t mmmm;
|
||||||
} gpsCoordinateDDDMMmmmm_t;
|
} gpsCoordinateDDDMMmmmm_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t chn; // Channel number
|
||||||
|
uint8_t svid; // Satellite ID
|
||||||
|
uint8_t quality; // Bitfield Qualtity
|
||||||
|
uint8_t cno; // Carrier to Noise Ratio (Signal Strength)
|
||||||
|
} gpsSVChannel_t;
|
||||||
|
|
||||||
typedef enum {
|
/* LLH Location in NEU axis system */
|
||||||
GPS_MESSAGE_STATE_IDLE = 0,
|
typedef struct gpsLocation_s {
|
||||||
GPS_MESSAGE_STATE_INIT,
|
int32_t lat; // Lattitude * 1e+7
|
||||||
GPS_MESSAGE_STATE_SBAS,
|
int32_t lon; // Longitude * 1e+7
|
||||||
GPS_MESSAGE_STATE_MAX = GPS_MESSAGE_STATE_SBAS
|
int32_t alt; // Altitude in centimeters (meters * 100)
|
||||||
} gpsMessageState_e;
|
} gpsLocation_t;
|
||||||
|
|
||||||
#define GPS_MESSAGE_STATE_ENTRY_COUNT (GPS_MESSAGE_STATE_MAX + 1)
|
typedef struct gpsSolutionData_s {
|
||||||
|
struct {
|
||||||
|
unsigned gpsHeartbeat : 1; // Toggle each update
|
||||||
|
unsigned fix3D : 1; // gps fix status
|
||||||
|
unsigned validVelNE : 1;
|
||||||
|
unsigned validVelD : 1;
|
||||||
|
unsigned validMag : 1;
|
||||||
|
} flags;
|
||||||
|
|
||||||
typedef struct gpsData_s {
|
uint8_t numSat;
|
||||||
uint8_t state; // GPS thread state. Used for detecting cable disconnects and configuring attached devices
|
|
||||||
uint8_t baudrateIndex; // index into auto-detecting or current baudrate
|
|
||||||
uint32_t errors; // gps error counter - crc error/lost of data/sync etc..
|
|
||||||
uint32_t timeouts;
|
|
||||||
uint32_t lastMessage; // last time valid GPS data was received (millis)
|
|
||||||
uint32_t lastLastMessage; // last-last valid GPS message. Used to calculate delta.
|
|
||||||
|
|
||||||
uint32_t state_position; // incremental variable for loops
|
uint8_t numCh;
|
||||||
uint32_t state_ts; // timestamp for last state_position increment
|
gpsSVChannel_t svInfo[GPS_SV_MAXSATS];
|
||||||
gpsMessageState_e messageState;
|
|
||||||
} gpsData_t;
|
|
||||||
|
|
||||||
#define GPS_PACKET_LOG_ENTRY_COUNT 21 // To make this useful we should log as many packets as we can fit characters a single line of a OLED display.
|
gpsLocation_t llh;
|
||||||
extern char gpsPacketLog[GPS_PACKET_LOG_ENTRY_COUNT];
|
int16_t magData[3];
|
||||||
|
int16_t velNED[3];
|
||||||
|
|
||||||
extern gpsData_t gpsData;
|
int16_t groundSpeed;
|
||||||
extern int32_t GPS_coord[2]; // LAT/LON
|
int16_t groundCourse;
|
||||||
|
|
||||||
extern uint8_t GPS_numSat;
|
uint16_t hdop;
|
||||||
extern uint16_t GPS_hdop; // GPS signal quality
|
uint16_t vdop;
|
||||||
extern uint8_t GPS_update; // it's a binary toogle to distinct a GPS position update
|
} gpsSolutionData_t;
|
||||||
extern uint32_t GPS_packetCount;
|
|
||||||
extern uint32_t GPS_svInfoReceivedCount;
|
|
||||||
extern uint16_t GPS_altitude; // altitude in 0.1m
|
|
||||||
extern uint16_t GPS_speed; // speed in 0.1m/s
|
|
||||||
extern uint16_t GPS_ground_course; // degrees * 10
|
|
||||||
extern uint8_t GPS_numCh; // Number of channels
|
|
||||||
extern uint8_t GPS_svinfo_chn[16]; // Channel number
|
|
||||||
extern uint8_t GPS_svinfo_svid[16]; // Satellite ID
|
|
||||||
extern uint8_t GPS_svinfo_quality[16]; // Bitfield Qualtity
|
|
||||||
extern uint8_t GPS_svinfo_cno[16]; // Carrier to Noise Ratio (Signal Strength)
|
|
||||||
|
|
||||||
#define GPS_DBHZ_MIN 0
|
typedef struct {
|
||||||
#define GPS_DBHZ_MAX 55
|
uint16_t lastMessageDt;
|
||||||
|
uint32_t errors; // gps error counter - crc error/lost of data/sync etc..
|
||||||
|
uint32_t timeouts;
|
||||||
|
uint32_t packetCount;
|
||||||
|
} gpsStatistics_t;
|
||||||
|
|
||||||
|
extern gpsSolutionData_t gpsSol;
|
||||||
|
extern gpsStatistics_t gpsStats;
|
||||||
|
|
||||||
void gpsThread(void);
|
void gpsThread(void);
|
||||||
bool gpsNewFrameFromSerial(uint8_t c);
|
|
||||||
void updateGpsIndicator(uint32_t currentTime);
|
void updateGpsIndicator(uint32_t currentTime);
|
||||||
|
|
125
src/main/io/gps_i2cnav.c
Executable file
125
src/main/io/gps_i2cnav.c
Executable file
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Cleanflight.
|
||||||
|
*
|
||||||
|
* Cleanflight 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.
|
||||||
|
*
|
||||||
|
* Cleanflight 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 Cleanflight. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
#include "build_config.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#include "common/maths.h"
|
||||||
|
#include "common/axis.h"
|
||||||
|
#include "common/utils.h"
|
||||||
|
|
||||||
|
#include "drivers/system.h"
|
||||||
|
#include "drivers/serial.h"
|
||||||
|
#include "drivers/serial_uart.h"
|
||||||
|
#include "drivers/gpio.h"
|
||||||
|
#include "drivers/light_led.h"
|
||||||
|
#include "drivers/sensor.h"
|
||||||
|
|
||||||
|
#include "drivers/gps.h"
|
||||||
|
#include "drivers/gps_i2cnav.h"
|
||||||
|
|
||||||
|
#include "sensors/sensors.h"
|
||||||
|
|
||||||
|
#include "io/serial.h"
|
||||||
|
#include "io/display.h"
|
||||||
|
#include "io/gps.h"
|
||||||
|
#include "io/gps_private.h"
|
||||||
|
|
||||||
|
#include "flight/gps_conversion.h"
|
||||||
|
#include "flight/pid.h"
|
||||||
|
#include "flight/hil.h"
|
||||||
|
#include "flight/navigation_rewrite.h"
|
||||||
|
|
||||||
|
#include "config/config.h"
|
||||||
|
#include "config/runtime_config.h"
|
||||||
|
|
||||||
|
#if defined(GPS) && defined(GPS_PROTO_I2C_NAV)
|
||||||
|
|
||||||
|
#define GPS_I2C_POLL_RATE_HZ 20 // Poll I2C GPS at this rate
|
||||||
|
|
||||||
|
bool gpsDetectI2CNAV(void)
|
||||||
|
{
|
||||||
|
return i2cnavGPSModuleDetect();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gpsPollI2CNAV(void)
|
||||||
|
{
|
||||||
|
gpsDataGeneric_t gpsMsg;
|
||||||
|
|
||||||
|
// Check for poll rate timeout
|
||||||
|
if ((millis() - gpsState.lastMessageMs) < (1000 / GPS_I2C_POLL_RATE_HZ))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
i2cnavGPSModuleRead(&gpsMsg);
|
||||||
|
|
||||||
|
debug[2] = gpsMsg.flags.gpsOk;
|
||||||
|
debug[3] = gpsMsg.flags.newData;
|
||||||
|
|
||||||
|
if (gpsMsg.flags.gpsOk) {
|
||||||
|
gpsSol.flags.fix3D = gpsMsg.flags.fix3D;
|
||||||
|
|
||||||
|
// sat count
|
||||||
|
gpsSol.numSat = gpsMsg.numSat;
|
||||||
|
|
||||||
|
// Other data
|
||||||
|
if (gpsMsg.flags.newData) {
|
||||||
|
if (gpsMsg.flags.fix3D) {
|
||||||
|
gpsSol.hdop = gpsMsg.hdop;
|
||||||
|
gpsSol.groundSpeed = gpsMsg.speed;
|
||||||
|
gpsSol.groundCourse = gpsMsg.ground_course;
|
||||||
|
gpsSol.llh.lat = gpsMsg.latitude;
|
||||||
|
gpsSol.llh.lon = gpsMsg.longitude;
|
||||||
|
gpsSol.llh.alt = gpsMsg.altitude;
|
||||||
|
gpsSol.flags.validVelNE = 0;
|
||||||
|
gpsSol.flags.validVelD = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpsStats.packetCount++;
|
||||||
|
|
||||||
|
gpsSol.flags.gpsHeartbeat = !gpsSol.flags.gpsHeartbeat;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gpsHandleI2CNAV(void)
|
||||||
|
{
|
||||||
|
// Process state
|
||||||
|
switch(gpsState.state) {
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case GPS_CONFIGURE:
|
||||||
|
gpsSetState(GPS_RECEIVING_DATA);
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case GPS_RECEIVING_DATA:
|
||||||
|
return gpsPollI2CNAV();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
331
src/main/io/gps_nmea.c
Executable file
331
src/main/io/gps_nmea.c
Executable file
|
@ -0,0 +1,331 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Cleanflight.
|
||||||
|
*
|
||||||
|
* Cleanflight 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.
|
||||||
|
*
|
||||||
|
* Cleanflight 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 Cleanflight. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
#include "build_config.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#include "common/maths.h"
|
||||||
|
#include "common/axis.h"
|
||||||
|
#include "common/utils.h"
|
||||||
|
|
||||||
|
#include "drivers/system.h"
|
||||||
|
#include "drivers/serial.h"
|
||||||
|
#include "drivers/serial_uart.h"
|
||||||
|
#include "drivers/gpio.h"
|
||||||
|
#include "drivers/light_led.h"
|
||||||
|
#include "drivers/sensor.h"
|
||||||
|
|
||||||
|
#include "drivers/gps.h"
|
||||||
|
#include "drivers/gps_i2cnav.h"
|
||||||
|
|
||||||
|
#include "sensors/sensors.h"
|
||||||
|
|
||||||
|
#include "io/serial.h"
|
||||||
|
#include "io/display.h"
|
||||||
|
#include "io/gps.h"
|
||||||
|
#include "io/gps_private.h"
|
||||||
|
|
||||||
|
#include "flight/gps_conversion.h"
|
||||||
|
#include "flight/pid.h"
|
||||||
|
#include "flight/hil.h"
|
||||||
|
#include "flight/navigation_rewrite.h"
|
||||||
|
|
||||||
|
#include "config/config.h"
|
||||||
|
#include "config/runtime_config.h"
|
||||||
|
|
||||||
|
#if defined(GPS) && defined(GPS_PROTO_NMEA)
|
||||||
|
|
||||||
|
/* This is a light implementation of a GPS frame decoding
|
||||||
|
This should work with most of modern GPS devices configured to output 5 frames.
|
||||||
|
It assumes there are some NMEA GGA frames to decode on the serial bus
|
||||||
|
Now verifies checksum correctly before applying data
|
||||||
|
|
||||||
|
Here we use only the following data :
|
||||||
|
- latitude
|
||||||
|
- longitude
|
||||||
|
- GPS fix is/is not ok
|
||||||
|
- GPS num sat (4 is enough to be +/- reliable)
|
||||||
|
// added by Mis
|
||||||
|
- GPS altitude (for OSD displaying)
|
||||||
|
- GPS speed (for OSD displaying)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define NO_FRAME 0
|
||||||
|
#define FRAME_GGA 1
|
||||||
|
#define FRAME_RMC 2
|
||||||
|
#define FRAME_GSV 3
|
||||||
|
|
||||||
|
static uint32_t grab_fields(char *src, uint8_t mult)
|
||||||
|
{ // convert string to uint32
|
||||||
|
uint32_t i;
|
||||||
|
uint32_t tmp = 0;
|
||||||
|
for (i = 0; src[i] != 0; i++) {
|
||||||
|
if (src[i] == '.') {
|
||||||
|
i++;
|
||||||
|
if (mult == 0)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
src[i + mult] = 0;
|
||||||
|
}
|
||||||
|
tmp *= 10;
|
||||||
|
if (src[i] >= '0' && src[i] <= '9')
|
||||||
|
tmp += src[i] - '0';
|
||||||
|
if (i >= 15)
|
||||||
|
return 0; // out of bounds
|
||||||
|
}
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct gpsDataNmea_s {
|
||||||
|
bool fix;
|
||||||
|
int32_t latitude;
|
||||||
|
int32_t longitude;
|
||||||
|
uint8_t numSat;
|
||||||
|
uint16_t altitude;
|
||||||
|
uint16_t speed;
|
||||||
|
uint16_t ground_course;
|
||||||
|
} gpsDataNmea_t;
|
||||||
|
|
||||||
|
static bool gpsNewFrameNMEA(char c)
|
||||||
|
{
|
||||||
|
static gpsDataNmea_t gps_Msg;
|
||||||
|
|
||||||
|
uint8_t frameOK = 0;
|
||||||
|
static uint8_t param = 0, offset = 0, parity = 0;
|
||||||
|
static char string[15];
|
||||||
|
static uint8_t checksum_param, gps_frame = NO_FRAME;
|
||||||
|
static uint8_t svMessageNum = 0;
|
||||||
|
uint8_t svSatNum = 0, svPacketIdx = 0, svSatParam = 0;
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case '$':
|
||||||
|
param = 0;
|
||||||
|
offset = 0;
|
||||||
|
parity = 0;
|
||||||
|
break;
|
||||||
|
case ',':
|
||||||
|
case '*':
|
||||||
|
string[offset] = 0;
|
||||||
|
if (param == 0) { //frame identification
|
||||||
|
gps_frame = NO_FRAME;
|
||||||
|
if (string[0] == 'G' && string[1] == 'P' && string[2] == 'G' && string[3] == 'G' && string[4] == 'A')
|
||||||
|
gps_frame = FRAME_GGA;
|
||||||
|
if (string[0] == 'G' && string[1] == 'P' && string[2] == 'R' && string[3] == 'M' && string[4] == 'C')
|
||||||
|
gps_frame = FRAME_RMC;
|
||||||
|
if (string[0] == 'G' && string[1] == 'P' && string[2] == 'G' && string[3] == 'S' && string[4] == 'V')
|
||||||
|
gps_frame = FRAME_GSV;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (gps_frame) {
|
||||||
|
case FRAME_GGA: //************* GPGGA FRAME parsing
|
||||||
|
switch(param) {
|
||||||
|
// case 1: // Time information
|
||||||
|
// break;
|
||||||
|
case 2:
|
||||||
|
gps_Msg.latitude = GPS_coord_to_degrees(string);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (string[0] == 'S')
|
||||||
|
gps_Msg.latitude *= -1;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
gps_Msg.longitude = GPS_coord_to_degrees(string);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
if (string[0] == 'W')
|
||||||
|
gps_Msg.longitude *= -1;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
if (string[0] > '0') {
|
||||||
|
gps_Msg.fix = true;
|
||||||
|
} else {
|
||||||
|
gps_Msg.fix = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
gps_Msg.numSat = grab_fields(string, 0);
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
gps_Msg.altitude = grab_fields(string, 1) * 10; // altitude in meters added by Mis (cm)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FRAME_RMC: //************* GPRMC FRAME parsing
|
||||||
|
switch(param) {
|
||||||
|
case 7:
|
||||||
|
gps_Msg.speed = ((grab_fields(string, 1) * 5144L) / 1000L); // speed in cm/s added by Mis
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
gps_Msg.ground_course = (grab_fields(string, 1)); // ground course deg * 10
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FRAME_GSV:
|
||||||
|
switch(param) {
|
||||||
|
/*case 1:
|
||||||
|
// Total number of messages of this type in this cycle
|
||||||
|
break; */
|
||||||
|
case 2:
|
||||||
|
// Message number
|
||||||
|
svMessageNum = grab_fields(string, 0);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
// Total number of SVs visible
|
||||||
|
gpsSol.numCh = grab_fields(string, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(param < 4)
|
||||||
|
break;
|
||||||
|
|
||||||
|
svPacketIdx = (param - 4) / 4 + 1; // satellite number in packet, 1-4
|
||||||
|
svSatNum = svPacketIdx + (4 * (svMessageNum - 1)); // global satellite number
|
||||||
|
svSatParam = param - 3 - (4 * (svPacketIdx - 1)); // parameter number for satellite
|
||||||
|
|
||||||
|
if(svSatNum > GPS_SV_MAXSATS)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch(svSatParam) {
|
||||||
|
case 1:
|
||||||
|
// SV PRN number
|
||||||
|
gpsSol.svInfo[svSatNum - 1].chn = svSatNum;
|
||||||
|
gpsSol.svInfo[svSatNum - 1].svid = grab_fields(string, 0);
|
||||||
|
break;
|
||||||
|
/*case 2:
|
||||||
|
// Elevation, in degrees, 90 maximum
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
// Azimuth, degrees from True North, 000 through 359
|
||||||
|
break; */
|
||||||
|
case 4:
|
||||||
|
// SNR, 00 through 99 dB (null when not tracking)
|
||||||
|
gpsSol.svInfo[svSatNum - 1].cno = grab_fields(string, 0);
|
||||||
|
gpsSol.svInfo[svSatNum - 1].quality = 0; // only used by ublox
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
param++;
|
||||||
|
offset = 0;
|
||||||
|
if (c == '*')
|
||||||
|
checksum_param = 1;
|
||||||
|
else
|
||||||
|
parity ^= c;
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
if (checksum_param) { //parity checksum
|
||||||
|
uint8_t checksum = 16 * ((string[0] >= 'A') ? string[0] - 'A' + 10 : string[0] - '0') + ((string[1] >= 'A') ? string[1] - 'A' + 10 : string[1] - '0');
|
||||||
|
if (checksum == parity) {
|
||||||
|
gpsStats.packetCount++;
|
||||||
|
switch (gps_frame) {
|
||||||
|
case FRAME_GGA:
|
||||||
|
frameOK = 1;
|
||||||
|
if (STATE(GPS_FIX)) {
|
||||||
|
gpsSol.numSat = gps_Msg.numSat;
|
||||||
|
gpsSol.llh.lat = gps_Msg.latitude;
|
||||||
|
gpsSol.llh.lon = gps_Msg.longitude;
|
||||||
|
gpsSol.llh.alt = gps_Msg.altitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NMEA does not report VELNED
|
||||||
|
gpsSol.flags.validVelNE = 0;
|
||||||
|
gpsSol.flags.validVelD = 0;
|
||||||
|
break;
|
||||||
|
case FRAME_RMC:
|
||||||
|
gpsSol.groundSpeed = gps_Msg.speed;
|
||||||
|
gpsSol.groundCourse = gps_Msg.ground_course;
|
||||||
|
break;
|
||||||
|
} // end switch
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gpsStats.errors++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checksum_param = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (offset < 15)
|
||||||
|
string[offset++] = c;
|
||||||
|
if (!checksum_param)
|
||||||
|
parity ^= c;
|
||||||
|
}
|
||||||
|
return frameOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool gpsInitialize(void)
|
||||||
|
{
|
||||||
|
// NMEA is receive-only, we can only cycle thru baud rates and check if we are receiving anything
|
||||||
|
gpsState.baudrateIndex = gpsState.autoBaudrateIndex;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool gpsConfigure(void)
|
||||||
|
{
|
||||||
|
// No autoconfig, switch straight to receiving data
|
||||||
|
gpsSetState(GPS_RECEIVING_DATA);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool gpsReceiveData(void)
|
||||||
|
{
|
||||||
|
bool hasNewData = false;
|
||||||
|
|
||||||
|
if (gpsState.gpsPort) {
|
||||||
|
while (serialRxBytesWaiting(gpsState.gpsPort)) {
|
||||||
|
uint8_t newChar = serialRead(gpsState.gpsPort);
|
||||||
|
if (gpsNewFrameNMEA(newChar)) {
|
||||||
|
gpsSol.flags.gpsHeartbeat = !gpsSol.flags.gpsHeartbeat;
|
||||||
|
gpsSol.flags.validVelNE = 0;
|
||||||
|
gpsSol.flags.validVelD = 0;
|
||||||
|
hasNewData = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasNewData;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gpsHandleNMEA(void)
|
||||||
|
{
|
||||||
|
// Receive data
|
||||||
|
bool hasNewData = gpsReceiveData();
|
||||||
|
|
||||||
|
// Process state
|
||||||
|
switch(gpsState.state) {
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case GPS_INITIALIZING:
|
||||||
|
return gpsInitialize();
|
||||||
|
|
||||||
|
case GPS_CONFIGURE:
|
||||||
|
return gpsConfigure();
|
||||||
|
|
||||||
|
case GPS_RECEIVING_DATA:
|
||||||
|
return hasNewData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
57
src/main/io/gps_private.h
Executable file
57
src/main/io/gps_private.h
Executable file
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Cleanflight.
|
||||||
|
*
|
||||||
|
* Cleanflight 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.
|
||||||
|
*
|
||||||
|
* Cleanflight 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 Cleanflight. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef GPS
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GPS_UNKNOWN, // 0
|
||||||
|
GPS_INITIALIZING, // 1
|
||||||
|
GPS_CHANGE_BAUD, // 2
|
||||||
|
GPS_CONFIGURE, // 3
|
||||||
|
GPS_RECEIVING_DATA, // 4
|
||||||
|
GPS_LOST_COMMUNICATION, // 5
|
||||||
|
} gpsState_e;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
gpsConfig_t * gpsConfig;
|
||||||
|
serialConfig_t * serialConfig;
|
||||||
|
serialPort_t * gpsPort; // Serial GPS only
|
||||||
|
|
||||||
|
gpsState_e state;
|
||||||
|
gpsBaudRate_e baudrateIndex;
|
||||||
|
gpsBaudRate_e autoBaudrateIndex; // Driver internal use (for autoBaud)
|
||||||
|
uint8_t autoConfigStep; // Driver internal use (for autoConfig)
|
||||||
|
uint8_t autoConfigPosition; // Driver internal use (for autoConfig)
|
||||||
|
|
||||||
|
uint32_t lastStateSwitchMs;
|
||||||
|
uint32_t lastLastMessageMs;
|
||||||
|
uint32_t lastMessageMs;
|
||||||
|
} gpsReceiverData_t;
|
||||||
|
|
||||||
|
extern gpsReceiverData_t gpsState;
|
||||||
|
|
||||||
|
extern baudRate_e gpsToSerialBaudRate[GPS_BAUDRATE_COUNT];
|
||||||
|
|
||||||
|
extern void gpsSetState(gpsState_e state);
|
||||||
|
extern bool gpsHandleNMEA(void);
|
||||||
|
extern bool gpsHandleUBLOX(void);
|
||||||
|
extern bool gpsHandleI2CNAV(void);
|
||||||
|
extern bool gpsDetectI2CNAV(void);
|
||||||
|
|
||||||
|
#endif
|
512
src/main/io/gps_ublox.c
Executable file
512
src/main/io/gps_ublox.c
Executable file
|
@ -0,0 +1,512 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Cleanflight.
|
||||||
|
*
|
||||||
|
* Cleanflight 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.
|
||||||
|
*
|
||||||
|
* Cleanflight 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 Cleanflight. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
#include "build_config.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#include "common/maths.h"
|
||||||
|
#include "common/axis.h"
|
||||||
|
#include "common/utils.h"
|
||||||
|
|
||||||
|
#include "drivers/system.h"
|
||||||
|
#include "drivers/serial.h"
|
||||||
|
#include "drivers/serial_uart.h"
|
||||||
|
#include "drivers/gpio.h"
|
||||||
|
#include "drivers/light_led.h"
|
||||||
|
#include "drivers/sensor.h"
|
||||||
|
|
||||||
|
#include "drivers/gps.h"
|
||||||
|
#include "drivers/gps_i2cnav.h"
|
||||||
|
|
||||||
|
#include "sensors/sensors.h"
|
||||||
|
|
||||||
|
#include "io/serial.h"
|
||||||
|
#include "io/display.h"
|
||||||
|
#include "io/gps.h"
|
||||||
|
#include "io/gps_private.h"
|
||||||
|
|
||||||
|
#include "flight/gps_conversion.h"
|
||||||
|
#include "flight/pid.h"
|
||||||
|
#include "flight/hil.h"
|
||||||
|
#include "flight/navigation_rewrite.h"
|
||||||
|
|
||||||
|
#include "config/config.h"
|
||||||
|
#include "config/runtime_config.h"
|
||||||
|
|
||||||
|
#if defined(GPS) && defined(GPS_PROTO_UBLOX)
|
||||||
|
|
||||||
|
static const char * baudInitData[GPS_BAUDRATE_COUNT] = {
|
||||||
|
"$PUBX,41,1,0003,0001,115200,0*1E\r\n", // GPS_BAUDRATE_115200
|
||||||
|
"$PUBX,41,1,0003,0001,57600,0*2D\r\n", // GPS_BAUDRATE_57600
|
||||||
|
"$PUBX,41,1,0003,0001,38400,0*26\r\n", // GPS_BAUDRATE_38400
|
||||||
|
"$PUBX,41,1,0003,0001,19200,0*23\r\n", // GPS_BAUDRATE_19200
|
||||||
|
"$PUBX,41,1,0003,0001,9600,0*16\r\n" // GPS_BAUDRATE_9600
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t ubloxInit6[] = {
|
||||||
|
|
||||||
|
0xB5, 0x62, 0x06, 0x24, 0x24, 0x00, 0xFF, 0xFF, 0x06, 0x02, 0x00, // CFG-NAV5 - Set engine settings
|
||||||
|
0x00, 0x00, 0x00, 0x10, 0x27, 0x00, 0x00, 0x05, 0x00, 0xFA, 0x00, // Airborne <1G 3D fix only
|
||||||
|
0xFA, 0x00, 0x64, 0x00, 0x2C, 0x01, 0x00, 0x3C, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0xC7,
|
||||||
|
|
||||||
|
0xB5, 0x62, 0x06, 0x23, 0x28, 0x00, 0x00, 0x00, 0x4C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // CFG-NAVX5 min 5 SV
|
||||||
|
0x05, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xCD,
|
||||||
|
|
||||||
|
// DISABLE NMEA messages
|
||||||
|
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x05, 0x00, 0xFF, 0x19, // VGS: Course over ground and Ground speed
|
||||||
|
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x03, 0x00, 0xFD, 0x15, // GSV: GNSS Satellites in View
|
||||||
|
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x01, 0x00, 0xFB, 0x11, // GLL: Latitude and longitude, with time of position fix and status
|
||||||
|
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x00, 0x00, 0xFA, 0x0F, // GGA: Global positioning system fix data
|
||||||
|
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x02, 0x00, 0xFC, 0x13, // GSA: GNSS DOP and Active Satellites
|
||||||
|
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x04, 0x00, 0xFE, 0x17, // RMC: Recommended Minimum data
|
||||||
|
|
||||||
|
// Enable UBLOX messages
|
||||||
|
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x01, 0x02, 0x01, 0x0E, 0x47, // set POSLLH MSG rate
|
||||||
|
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x01, 0x03, 0x01, 0x0F, 0x49, // set STATUS MSG rate
|
||||||
|
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x01, 0x06, 0x01, 0x12, 0x4F, // set SOL MSG rate
|
||||||
|
//0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x01, 0x30, 0x01, 0x3C, 0xA3, // set SVINFO MSG rate (every cycle - high bandwidth)
|
||||||
|
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x01, 0x30, 0x05, 0x40, 0xA7, // set SVINFO MSG rate (evey 5 cycles - low bandwidth)
|
||||||
|
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x01, 0x12, 0x01, 0x1E, 0x67, // set VELNED MSG rate
|
||||||
|
|
||||||
|
0xB5, 0x62, 0x06, 0x08, 0x06, 0x00, 0xC8, 0x00, 0x01, 0x00, 0x01, 0x00, 0xDE, 0x6A, // set rate to 5Hz (measurement period: 200ms, navigation rate: 1 cycle)
|
||||||
|
};
|
||||||
|
|
||||||
|
// UBlox 6 Protocol documentation - GPS.G6-SW-10018-F
|
||||||
|
// SBAS Configuration Settings Desciption, Page 4/210
|
||||||
|
// 31.21 CFG-SBAS (0x06 0x16), Page 142/210
|
||||||
|
// A.10 SBAS Configuration (UBX-CFG-SBAS), Page 198/210 - GPS.G6-SW-10018-F
|
||||||
|
|
||||||
|
#define UBLOX_SBAS_MESSAGE_LENGTH 16
|
||||||
|
typedef struct ubloxSbas_s {
|
||||||
|
sbasMode_e mode;
|
||||||
|
uint8_t message[UBLOX_SBAS_MESSAGE_LENGTH];
|
||||||
|
} ubloxSbas_t;
|
||||||
|
|
||||||
|
// Note: these must be defined in the same order is sbasMode_e since no lookup table is used.
|
||||||
|
static const ubloxSbas_t ubloxSbas[] = {
|
||||||
|
// NOTE this could be optimized to save a few bytes of flash space since the same prefix is used for each command.
|
||||||
|
{ SBAS_AUTO, { 0xB5, 0x62, 0x06, 0x16, 0x08, 0x00, 0x03, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0xE5}},
|
||||||
|
{ SBAS_EGNOS, { 0xB5, 0x62, 0x06, 0x16, 0x08, 0x00, 0x03, 0x07, 0x03, 0x00, 0x51, 0x08, 0x00, 0x00, 0x8A, 0x41}},
|
||||||
|
{ SBAS_WAAS, { 0xB5, 0x62, 0x06, 0x16, 0x08, 0x00, 0x03, 0x07, 0x03, 0x00, 0x04, 0xE0, 0x04, 0x00, 0x19, 0x9D}},
|
||||||
|
{ SBAS_MSAS, { 0xB5, 0x62, 0x06, 0x16, 0x08, 0x00, 0x03, 0x07, 0x03, 0x00, 0x00, 0x02, 0x02, 0x00, 0x35, 0xEF}},
|
||||||
|
{ SBAS_GAGAN, { 0xB5, 0x62, 0x06, 0x16, 0x08, 0x00, 0x03, 0x07, 0x03, 0x00, 0x80, 0x01, 0x00, 0x00, 0xB2, 0xE8}}
|
||||||
|
};
|
||||||
|
|
||||||
|
// UBX support
|
||||||
|
typedef struct {
|
||||||
|
uint8_t preamble1;
|
||||||
|
uint8_t preamble2;
|
||||||
|
uint8_t msg_class;
|
||||||
|
uint8_t msg_id;
|
||||||
|
uint16_t length;
|
||||||
|
} ubx_header;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t time; // GPS msToW
|
||||||
|
int32_t longitude;
|
||||||
|
int32_t latitude;
|
||||||
|
int32_t altitude_ellipsoid;
|
||||||
|
int32_t altitude_msl;
|
||||||
|
uint32_t horizontal_accuracy;
|
||||||
|
uint32_t vertical_accuracy;
|
||||||
|
} ubx_nav_posllh;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t time; // GPS msToW
|
||||||
|
uint8_t fix_type;
|
||||||
|
uint8_t fix_status;
|
||||||
|
uint8_t differential_status;
|
||||||
|
uint8_t res;
|
||||||
|
uint32_t time_to_first_fix;
|
||||||
|
uint32_t uptime; // milliseconds
|
||||||
|
} ubx_nav_status;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t time;
|
||||||
|
int32_t time_nsec;
|
||||||
|
int16_t week;
|
||||||
|
uint8_t fix_type;
|
||||||
|
uint8_t fix_status;
|
||||||
|
int32_t ecef_x;
|
||||||
|
int32_t ecef_y;
|
||||||
|
int32_t ecef_z;
|
||||||
|
uint32_t position_accuracy_3d;
|
||||||
|
int32_t ecef_x_velocity;
|
||||||
|
int32_t ecef_y_velocity;
|
||||||
|
int32_t ecef_z_velocity;
|
||||||
|
uint32_t speed_accuracy;
|
||||||
|
uint16_t position_DOP;
|
||||||
|
uint8_t res;
|
||||||
|
uint8_t satellites;
|
||||||
|
uint32_t res2;
|
||||||
|
} ubx_nav_solution;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t time; // GPS msToW
|
||||||
|
int32_t ned_north;
|
||||||
|
int32_t ned_east;
|
||||||
|
int32_t ned_down;
|
||||||
|
uint32_t speed_3d;
|
||||||
|
uint32_t speed_2d;
|
||||||
|
int32_t heading_2d;
|
||||||
|
uint32_t speed_accuracy;
|
||||||
|
uint32_t heading_accuracy;
|
||||||
|
} ubx_nav_velned;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t chn; // Channel number, 255 for SVx not assigned to channel
|
||||||
|
uint8_t svid; // Satellite ID
|
||||||
|
uint8_t flags; // Bitmask
|
||||||
|
uint8_t quality; // Bitfield
|
||||||
|
uint8_t cno; // Carrier to Noise Ratio (Signal Strength) // dbHz, 0-55.
|
||||||
|
uint8_t elev; // Elevation in integer degrees
|
||||||
|
int16_t azim; // Azimuth in integer degrees
|
||||||
|
int32_t prRes; // Pseudo range residual in centimetres
|
||||||
|
} ubx_nav_svinfo_channel;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t time; // GPS Millisecond time of week
|
||||||
|
uint8_t numCh; // Number of channels
|
||||||
|
uint8_t globalFlags; // Bitmask, Chip hardware generation 0:Antaris, 1:u-blox 5, 2:u-blox 6
|
||||||
|
uint16_t reserved2; // Reserved
|
||||||
|
ubx_nav_svinfo_channel channel[16]; // 16 satellites * 12 byte
|
||||||
|
} ubx_nav_svinfo;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PREAMBLE1 = 0xb5,
|
||||||
|
PREAMBLE2 = 0x62,
|
||||||
|
CLASS_NAV = 0x01,
|
||||||
|
CLASS_ACK = 0x05,
|
||||||
|
CLASS_CFG = 0x06,
|
||||||
|
MSG_ACK_NACK = 0x00,
|
||||||
|
MSG_ACK_ACK = 0x01,
|
||||||
|
MSG_POSLLH = 0x2,
|
||||||
|
MSG_STATUS = 0x3,
|
||||||
|
MSG_SOL = 0x6,
|
||||||
|
MSG_VELNED = 0x12,
|
||||||
|
MSG_SVINFO = 0x30,
|
||||||
|
MSG_CFG_PRT = 0x00,
|
||||||
|
MSG_CFG_RATE = 0x08,
|
||||||
|
MSG_CFG_SET_RATE = 0x01,
|
||||||
|
MSG_CFG_NAV_SETTINGS = 0x24
|
||||||
|
} ubx_protocol_bytes;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FIX_NONE = 0,
|
||||||
|
FIX_DEAD_RECKONING = 1,
|
||||||
|
FIX_2D = 2,
|
||||||
|
FIX_3D = 3,
|
||||||
|
FIX_GPS_DEAD_RECKONING = 4,
|
||||||
|
FIX_TIME = 5
|
||||||
|
} ubs_nav_fix_type;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
NAV_STATUS_FIX_VALID = 1
|
||||||
|
} ubx_nav_status_bits;
|
||||||
|
|
||||||
|
// Packet checksum accumulators
|
||||||
|
static uint8_t _ck_a;
|
||||||
|
static uint8_t _ck_b;
|
||||||
|
|
||||||
|
// State machine state
|
||||||
|
static bool _skip_packet;
|
||||||
|
static uint8_t _step;
|
||||||
|
static uint8_t _msg_id;
|
||||||
|
static uint16_t _payload_length;
|
||||||
|
static uint16_t _payload_counter;
|
||||||
|
|
||||||
|
static bool next_fix;
|
||||||
|
static uint8_t _class;
|
||||||
|
|
||||||
|
// do we have new position information?
|
||||||
|
static bool _new_position;
|
||||||
|
|
||||||
|
// do we have new speed information?
|
||||||
|
static bool _new_speed;
|
||||||
|
|
||||||
|
// Example packet sizes from UBlox u-center from a Glonass capable GPS receiver.
|
||||||
|
//15:17:55 R -> UBX NAV-STATUS, Size 24, 'Navigation Status'
|
||||||
|
//15:17:55 R -> UBX NAV-POSLLH, Size 36, 'Geodetic Position'
|
||||||
|
//15:17:55 R -> UBX NAV-VELNED, Size 44, 'Velocity in WGS 84'
|
||||||
|
//15:17:55 R -> UBX NAV-CLOCK, Size 28, 'Clock Status'
|
||||||
|
//15:17:55 R -> UBX NAV-AOPSTATUS, Size 24, 'AOP Status'
|
||||||
|
//15:17:55 R -> UBX 03-09, Size 208, 'Unknown'
|
||||||
|
//15:17:55 R -> UBX 03-10, Size 336, 'Unknown'
|
||||||
|
//15:17:55 R -> UBX NAV-SOL, Size 60, 'Navigation Solution'
|
||||||
|
//15:17:55 R -> UBX NAV, Size 100, 'Navigation'
|
||||||
|
//15:17:55 R -> UBX NAV-SVINFO, Size 328, 'Satellite Status and Information'
|
||||||
|
|
||||||
|
// from the UBlox6 document, the largest payout we receive i the NAV-SVINFO and the payload size
|
||||||
|
// is calculated as 8 + 12*numCh. numCh in the case of a Glonass receiver is 28.
|
||||||
|
#define UBLOX_PAYLOAD_SIZE 344
|
||||||
|
|
||||||
|
|
||||||
|
// Receive buffer
|
||||||
|
static union {
|
||||||
|
ubx_nav_posllh posllh;
|
||||||
|
ubx_nav_status status;
|
||||||
|
ubx_nav_solution solution;
|
||||||
|
ubx_nav_velned velned;
|
||||||
|
ubx_nav_svinfo svinfo;
|
||||||
|
uint8_t bytes[UBLOX_PAYLOAD_SIZE];
|
||||||
|
} _buffer;
|
||||||
|
|
||||||
|
void _update_checksum(uint8_t *data, uint8_t len, uint8_t *ck_a, uint8_t *ck_b)
|
||||||
|
{
|
||||||
|
while (len--) {
|
||||||
|
*ck_a += *data;
|
||||||
|
*ck_b += *ck_a;
|
||||||
|
data++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool gpsParceFrameUBLOX(void)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
switch (_msg_id) {
|
||||||
|
case MSG_POSLLH:
|
||||||
|
//i2c_dataset.time = _buffer.posllh.time;
|
||||||
|
gpsSol.llh.lon = _buffer.posllh.longitude;
|
||||||
|
gpsSol.llh.lat = _buffer.posllh.latitude;
|
||||||
|
gpsSol.llh.alt = _buffer.posllh.altitude_msl / 10; //alt in cm
|
||||||
|
gpsSol.flags.fix3D = next_fix ? 1 : 0;
|
||||||
|
_new_position = true;
|
||||||
|
break;
|
||||||
|
case MSG_STATUS:
|
||||||
|
next_fix = (_buffer.status.fix_status & NAV_STATUS_FIX_VALID) && (_buffer.status.fix_type == FIX_3D);
|
||||||
|
if (!next_fix)
|
||||||
|
gpsSol.flags.fix3D = 0;
|
||||||
|
break;
|
||||||
|
case MSG_SOL:
|
||||||
|
next_fix = (_buffer.solution.fix_status & NAV_STATUS_FIX_VALID) && (_buffer.solution.fix_type == FIX_3D);
|
||||||
|
if (!next_fix)
|
||||||
|
gpsSol.flags.fix3D = 0;
|
||||||
|
gpsSol.numSat = _buffer.solution.satellites;
|
||||||
|
gpsSol.hdop = _buffer.solution.position_DOP;
|
||||||
|
break;
|
||||||
|
case MSG_VELNED:
|
||||||
|
gpsSol.groundSpeed = _buffer.velned.speed_2d; // cm/s
|
||||||
|
gpsSol.groundCourse = (uint16_t) (_buffer.velned.heading_2d / 10000); // Heading 2D deg * 100000 rescaled to deg * 10
|
||||||
|
gpsSol.velNED[0] = _buffer.velned.ned_north;
|
||||||
|
gpsSol.velNED[1] = _buffer.velned.ned_east;
|
||||||
|
gpsSol.velNED[2] = _buffer.velned.ned_down;
|
||||||
|
gpsSol.flags.validVelNE = 1;
|
||||||
|
gpsSol.flags.validVelD = 1;
|
||||||
|
_new_speed = true;
|
||||||
|
break;
|
||||||
|
case MSG_SVINFO:
|
||||||
|
gpsSol.numCh = _buffer.svinfo.numCh;
|
||||||
|
if (gpsSol.numCh > 16)
|
||||||
|
gpsSol.numCh = 16;
|
||||||
|
for (i = 0; i < gpsSol.numCh; i++){
|
||||||
|
gpsSol.svInfo[i].chn = _buffer.svinfo.channel[i].chn;
|
||||||
|
gpsSol.svInfo[i].svid = _buffer.svinfo.channel[i].svid;
|
||||||
|
gpsSol.svInfo[i].quality = _buffer.svinfo.channel[i].quality;
|
||||||
|
gpsSol.svInfo[i].cno = _buffer.svinfo.channel[i].cno;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we only return true when we get new position and speed data
|
||||||
|
// this ensures we don't use stale data
|
||||||
|
if (_new_position && _new_speed) {
|
||||||
|
gpsSol.flags.gpsHeartbeat = !gpsSol.flags.gpsHeartbeat;
|
||||||
|
_new_speed = _new_position = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool gpsNewFrameUBLOX(uint8_t data)
|
||||||
|
{
|
||||||
|
bool parsed = false;
|
||||||
|
|
||||||
|
switch (_step) {
|
||||||
|
case 0: // Sync char 1 (0xB5)
|
||||||
|
if (PREAMBLE1 == data) {
|
||||||
|
_skip_packet = false;
|
||||||
|
_step++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1: // Sync char 2 (0x62)
|
||||||
|
if (PREAMBLE2 != data) {
|
||||||
|
_step = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_step++;
|
||||||
|
break;
|
||||||
|
case 2: // Class
|
||||||
|
_step++;
|
||||||
|
_class = data;
|
||||||
|
_ck_b = _ck_a = data; // reset the checksum accumulators
|
||||||
|
break;
|
||||||
|
case 3: // Id
|
||||||
|
_step++;
|
||||||
|
_ck_b += (_ck_a += data); // checksum byte
|
||||||
|
_msg_id = data;
|
||||||
|
break;
|
||||||
|
case 4: // Payload length (part 1)
|
||||||
|
_step++;
|
||||||
|
_ck_b += (_ck_a += data); // checksum byte
|
||||||
|
_payload_length = data; // payload length low byte
|
||||||
|
break;
|
||||||
|
case 5: // Payload length (part 2)
|
||||||
|
_step++;
|
||||||
|
_ck_b += (_ck_a += data); // checksum byte
|
||||||
|
_payload_length += (uint16_t)(data << 8);
|
||||||
|
if (_payload_length > UBLOX_PAYLOAD_SIZE) {
|
||||||
|
_skip_packet = true;
|
||||||
|
}
|
||||||
|
_payload_counter = 0; // prepare to receive payload
|
||||||
|
if (_payload_length == 0) {
|
||||||
|
_step = 7;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
_ck_b += (_ck_a += data); // checksum byte
|
||||||
|
if (_payload_counter < UBLOX_PAYLOAD_SIZE) {
|
||||||
|
_buffer.bytes[_payload_counter] = data;
|
||||||
|
}
|
||||||
|
if (++_payload_counter >= _payload_length) {
|
||||||
|
_step++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
_step++;
|
||||||
|
if (_ck_a != data) {
|
||||||
|
_skip_packet = true; // bad checksum
|
||||||
|
gpsStats.errors++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
_step = 0;
|
||||||
|
|
||||||
|
if (_ck_b != data) {
|
||||||
|
gpsStats.errors++;
|
||||||
|
break; // bad checksum
|
||||||
|
}
|
||||||
|
|
||||||
|
gpsStats.packetCount++;
|
||||||
|
|
||||||
|
if (_skip_packet) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gpsParceFrameUBLOX()) {
|
||||||
|
parsed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool gpsInitialize(void)
|
||||||
|
{
|
||||||
|
// UBLOX will be forced to the baud selected for the serial port. Autobaud will cycle thru autoBaudrateIndex, baudrateIndex is never changed
|
||||||
|
serialSetBaudRate(gpsState.gpsPort, baudRates[gpsToSerialBaudRate[gpsState.autoBaudrateIndex]]);
|
||||||
|
|
||||||
|
// print our FIXED init string for the baudrate we want to be at
|
||||||
|
serialPrint(gpsState.gpsPort, baudInitData[gpsState.baudrateIndex]);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool gpsConfigure(void)
|
||||||
|
{
|
||||||
|
switch (gpsState.autoConfigStep) {
|
||||||
|
case 0: // Config
|
||||||
|
if (gpsState.autoConfigPosition < sizeof(ubloxInit6)) {
|
||||||
|
serialWrite(gpsState.gpsPort, ubloxInit6[gpsState.autoConfigPosition]);
|
||||||
|
gpsState.autoConfigPosition++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gpsState.autoConfigPosition = 0;
|
||||||
|
gpsState.autoConfigStep++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: // SBAS
|
||||||
|
if (gpsState.autoConfigPosition < UBLOX_SBAS_MESSAGE_LENGTH) {
|
||||||
|
serialWrite(gpsState.gpsPort, ubloxSbas[gpsState.gpsConfig->sbasMode].message[gpsState.autoConfigPosition]);
|
||||||
|
gpsState.autoConfigPosition++;
|
||||||
|
} else {
|
||||||
|
gpsState.autoConfigPosition = 0;
|
||||||
|
gpsState.autoConfigStep++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
case 2:
|
||||||
|
// ublox should be initialised, try receiving
|
||||||
|
gpsSetState(GPS_RECEIVING_DATA);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool gpsReceiveData(void)
|
||||||
|
{
|
||||||
|
bool hasNewData = false;
|
||||||
|
|
||||||
|
if (gpsState.gpsPort) {
|
||||||
|
while (serialRxBytesWaiting(gpsState.gpsPort)) {
|
||||||
|
uint8_t newChar = serialRead(gpsState.gpsPort);
|
||||||
|
if (gpsNewFrameUBLOX(newChar)) {
|
||||||
|
hasNewData = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasNewData;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gpsHandleUBLOX(void)
|
||||||
|
{
|
||||||
|
// Receive data
|
||||||
|
bool hasNewData = gpsReceiveData();
|
||||||
|
|
||||||
|
// Process state
|
||||||
|
switch(gpsState.state) {
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case GPS_INITIALIZING:
|
||||||
|
return gpsInitialize();
|
||||||
|
|
||||||
|
case GPS_CONFIGURE:
|
||||||
|
return gpsConfigure();
|
||||||
|
|
||||||
|
case GPS_RECEIVING_DATA:
|
||||||
|
return hasNewData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -322,7 +322,7 @@ static const char * const lookupTableAlignment[] = {
|
||||||
|
|
||||||
#ifdef GPS
|
#ifdef GPS
|
||||||
static const char * const lookupTableGPSProvider[] = {
|
static const char * const lookupTableGPSProvider[] = {
|
||||||
"NMEA", "UBLOX", "I2C"
|
"NMEA", "UBLOX", "I2CNAV"
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char * const lookupTableGPSSBASMode[] = {
|
static const char * const lookupTableGPSSBASMode[] = {
|
||||||
|
|
|
@ -1101,18 +1101,18 @@ static bool processOutCommand(uint8_t cmdMSP)
|
||||||
case MSP_RAW_GPS:
|
case MSP_RAW_GPS:
|
||||||
headSerialReply(16);
|
headSerialReply(16);
|
||||||
serialize8(STATE(GPS_FIX));
|
serialize8(STATE(GPS_FIX));
|
||||||
serialize8(GPS_numSat);
|
serialize8(gpsSol.numSat);
|
||||||
serialize32(GPS_coord[LAT]);
|
serialize32(gpsSol.llh.lat);
|
||||||
serialize32(GPS_coord[LON]);
|
serialize32(gpsSol.llh.lon);
|
||||||
serialize16(GPS_altitude);
|
serialize16(gpsSol.llh.alt);
|
||||||
serialize16(GPS_speed);
|
serialize16(gpsSol.groundSpeed);
|
||||||
serialize16(GPS_ground_course);
|
serialize16(gpsSol.groundCourse);
|
||||||
break;
|
break;
|
||||||
case MSP_COMP_GPS:
|
case MSP_COMP_GPS:
|
||||||
headSerialReply(5);
|
headSerialReply(5);
|
||||||
serialize16(GPS_distanceToHome);
|
serialize16(GPS_distanceToHome);
|
||||||
serialize16(GPS_directionToHome);
|
serialize16(GPS_directionToHome);
|
||||||
serialize8(GPS_update & 1);
|
serialize8(gpsSol.flags.gpsHeartbeat ? 1 : 0);
|
||||||
break;
|
break;
|
||||||
#ifdef NAV
|
#ifdef NAV
|
||||||
case MSP_NAV_STATUS:
|
case MSP_NAV_STATUS:
|
||||||
|
@ -1141,13 +1141,13 @@ static bool processOutCommand(uint8_t cmdMSP)
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case MSP_GPSSVINFO:
|
case MSP_GPSSVINFO:
|
||||||
headSerialReply(1 + (GPS_numCh * 4));
|
headSerialReply(1 + (gpsSol.numCh * 4));
|
||||||
serialize8(GPS_numCh);
|
serialize8(gpsSol.numCh);
|
||||||
for (i = 0; i < GPS_numCh; i++){
|
for (i = 0; i < gpsSol.numCh; i++){
|
||||||
serialize8(GPS_svinfo_chn[i]);
|
serialize8(gpsSol.svInfo[i].chn);
|
||||||
serialize8(GPS_svinfo_svid[i]);
|
serialize8(gpsSol.svInfo[i].svid);
|
||||||
serialize8(GPS_svinfo_quality[i]);
|
serialize8(gpsSol.svInfo[i].quality);
|
||||||
serialize8(GPS_svinfo_cno[i]);
|
serialize8(gpsSol.svInfo[i].cno);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
@ -1631,14 +1631,14 @@ static bool processInCommand(void)
|
||||||
} else {
|
} else {
|
||||||
DISABLE_STATE(GPS_FIX);
|
DISABLE_STATE(GPS_FIX);
|
||||||
}
|
}
|
||||||
GPS_numSat = read8();
|
gpsSol.numSat = read8();
|
||||||
GPS_coord[LAT] = read32();
|
gpsSol.llh.lat = read32();
|
||||||
GPS_coord[LON] = read32();
|
gpsSol.llh.lon = read32();
|
||||||
GPS_altitude = read16();
|
gpsSol.llh.alt = read16();
|
||||||
GPS_speed = read16();
|
gpsSol.groundSpeed = read16();
|
||||||
// Feed data to navigation
|
// Feed data to navigation
|
||||||
sensorsSet(SENSOR_GPS);
|
sensorsSet(SENSOR_GPS);
|
||||||
onNewGPSData(GPS_coord[LAT], GPS_coord[LON], GPS_altitude, 0, 0, 0, false, false, 9999);
|
onNewGPSData(gpsSol.llh.lat, gpsSol.llh.lon, gpsSol.llh.alt, 0, 0, 0, false, false, 9999);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef NAV
|
#ifdef NAV
|
||||||
|
|
|
@ -114,6 +114,7 @@ void mixerInit(mixerMode_e mixerMode, motorMixer_t *customMotorMixers);
|
||||||
#endif
|
#endif
|
||||||
void mixerUsePWMOutputConfiguration(pwmOutputConfiguration_t *pwmOutputConfiguration);
|
void mixerUsePWMOutputConfiguration(pwmOutputConfiguration_t *pwmOutputConfiguration);
|
||||||
void rxInit(rxConfig_t *rxConfig, modeActivationCondition_t *modeActivationConditions);
|
void rxInit(rxConfig_t *rxConfig, modeActivationCondition_t *modeActivationConditions);
|
||||||
|
void gpsPreInit(gpsConfig_t *initialGpsConfig);
|
||||||
void gpsInit(serialConfig_t *serialConfig, gpsConfig_t *initialGpsConfig);
|
void gpsInit(serialConfig_t *serialConfig, gpsConfig_t *initialGpsConfig);
|
||||||
void imuInit(void);
|
void imuInit(void);
|
||||||
void displayInit(rxConfig_t *intialRxConfig);
|
void displayInit(rxConfig_t *intialRxConfig);
|
||||||
|
@ -371,6 +372,12 @@ void init(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef GPS
|
||||||
|
if (feature(FEATURE_GPS)) {
|
||||||
|
gpsPreInit(&masterConfig.gpsConfig);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!sensorsAutodetect(&masterConfig.sensorAlignmentConfig, masterConfig.gyro_lpf,
|
if (!sensorsAutodetect(&masterConfig.sensorAlignmentConfig, masterConfig.gyro_lpf,
|
||||||
masterConfig.acc_hardware, masterConfig.mag_hardware, masterConfig.baro_hardware, currentProfile->mag_declination,
|
masterConfig.acc_hardware, masterConfig.mag_hardware, masterConfig.baro_hardware, currentProfile->mag_declination,
|
||||||
masterConfig.looptime, masterConfig.gyroSync, masterConfig.gyroSyncDenominator)) {
|
masterConfig.looptime, masterConfig.gyroSync, masterConfig.gyroSyncDenominator)) {
|
||||||
|
|
|
@ -319,7 +319,7 @@ void mwArm(void)
|
||||||
|
|
||||||
//beep to indicate arming
|
//beep to indicate arming
|
||||||
#ifdef GPS
|
#ifdef GPS
|
||||||
if (feature(FEATURE_GPS) && STATE(GPS_FIX) && GPS_numSat >= 5)
|
if (feature(FEATURE_GPS) && STATE(GPS_FIX) && gpsSol.numSat >= 5)
|
||||||
beeper(BEEPER_ARMING_GPS_FIX);
|
beeper(BEEPER_ARMING_GPS_FIX);
|
||||||
else
|
else
|
||||||
beeper(BEEPER_ARMING);
|
beeper(BEEPER_ARMING);
|
||||||
|
|
|
@ -23,7 +23,8 @@ typedef enum {
|
||||||
MAG_NONE = 1,
|
MAG_NONE = 1,
|
||||||
MAG_HMC5883 = 2,
|
MAG_HMC5883 = 2,
|
||||||
MAG_AK8975 = 3,
|
MAG_AK8975 = 3,
|
||||||
MAG_FAKE = 4
|
MAG_GPS = 4,
|
||||||
|
MAG_FAKE = 5
|
||||||
} magSensor_e;
|
} magSensor_e;
|
||||||
|
|
||||||
#define MAG_MAX MAG_FAKE
|
#define MAG_MAX MAG_FAKE
|
||||||
|
|
|
@ -72,6 +72,10 @@
|
||||||
#include "hardware_revision.h"
|
#include "hardware_revision.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef GPS
|
||||||
|
extern bool gpsMagDetect(mag_t *mag);
|
||||||
|
#endif
|
||||||
|
|
||||||
extern float magneticDeclination;
|
extern float magneticDeclination;
|
||||||
|
|
||||||
extern gyro_t gyro;
|
extern gyro_t gyro;
|
||||||
|
@ -674,6 +678,18 @@ retry:
|
||||||
#endif
|
#endif
|
||||||
; // fallthrough
|
; // fallthrough
|
||||||
|
|
||||||
|
case MAG_GPS:
|
||||||
|
#ifdef GPS
|
||||||
|
if (gpsMagDetect(&mag)) {
|
||||||
|
#ifdef MAG_GPS_ALIGN
|
||||||
|
magAlign = MAG_GPS_ALIGN;
|
||||||
|
#endif
|
||||||
|
magHardware = MAG_GPS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
; // fallthrough
|
||||||
|
|
||||||
case MAG_FAKE:
|
case MAG_FAKE:
|
||||||
#ifdef USE_FAKE_MAG
|
#ifdef USE_FAKE_MAG
|
||||||
if (fakeMagDetect(&mag)) {
|
if (fakeMagDetect(&mag)) {
|
||||||
|
|
|
@ -113,6 +113,10 @@
|
||||||
//#define BLACKBOX
|
//#define BLACKBOX
|
||||||
#define SERIAL_RX
|
#define SERIAL_RX
|
||||||
//#define GPS
|
//#define GPS
|
||||||
|
//#define GPS_PROTO_NMEA
|
||||||
|
//#define GPS_PROTO_UBLOX
|
||||||
|
//#define GPS_PROTO_I2C_NAV
|
||||||
|
|
||||||
#define GTUNE
|
#define GTUNE
|
||||||
//#define DISPLAY
|
//#define DISPLAY
|
||||||
#define USE_SERVOS
|
#define USE_SERVOS
|
||||||
|
|
|
@ -108,7 +108,12 @@
|
||||||
#define RSSI_ADC_CHANNEL ADC_Channel_1
|
#define RSSI_ADC_CHANNEL ADC_Channel_1
|
||||||
|
|
||||||
#define GPS
|
#define GPS
|
||||||
|
#define GPS_PROTO_NMEA
|
||||||
|
#define GPS_PROTO_UBLOX
|
||||||
|
#define GPS_PROTO_I2C_NAV
|
||||||
|
|
||||||
#define NAV
|
#define NAV
|
||||||
|
|
||||||
//#define LED_STRIP
|
//#define LED_STRIP
|
||||||
//#define LED_STRIP_TIMER TIM3
|
//#define LED_STRIP_TIMER TIM3
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,10 @@
|
||||||
#define EXTERNAL1_ADC_CHANNEL ADC_Channel_9
|
#define EXTERNAL1_ADC_CHANNEL ADC_Channel_9
|
||||||
|
|
||||||
#define GPS
|
#define GPS
|
||||||
|
#define GPS_PROTO_NMEA
|
||||||
|
#define GPS_PROTO_UBLOX
|
||||||
|
#define GPS_PROTO_I2C_NAV
|
||||||
|
|
||||||
#define LED_STRIP
|
#define LED_STRIP
|
||||||
#if 1
|
#if 1
|
||||||
#define LED_STRIP_TIMER TIM16
|
#define LED_STRIP_TIMER TIM16
|
||||||
|
|
|
@ -143,7 +143,12 @@
|
||||||
#define EXTERNAL1_ADC_CHANNEL ADC_Channel_9
|
#define EXTERNAL1_ADC_CHANNEL ADC_Channel_9
|
||||||
|
|
||||||
#define BLACKBOX
|
#define BLACKBOX
|
||||||
|
|
||||||
#define GPS
|
#define GPS
|
||||||
|
#define GPS_PROTO_NMEA
|
||||||
|
#define GPS_PROTO_UBLOX
|
||||||
|
#define GPS_PROTO_I2C_NAV
|
||||||
|
|
||||||
#define GTUNE
|
#define GTUNE
|
||||||
#define LED_STRIP
|
#define LED_STRIP
|
||||||
|
|
||||||
|
|
|
@ -118,6 +118,10 @@
|
||||||
#define EXTERNAL1_ADC_CHANNEL ADC_Channel_5
|
#define EXTERNAL1_ADC_CHANNEL ADC_Channel_5
|
||||||
|
|
||||||
#define GPS
|
#define GPS
|
||||||
|
#define GPS_PROTO_NMEA
|
||||||
|
#define GPS_PROTO_UBLOX
|
||||||
|
#define GPS_PROTO_I2C_NAV
|
||||||
|
|
||||||
#define LED_STRIP
|
#define LED_STRIP
|
||||||
#define LED_STRIP_TIMER TIM3
|
#define LED_STRIP_TIMER TIM3
|
||||||
|
|
||||||
|
|
|
@ -113,6 +113,10 @@
|
||||||
#define BLACKBOX
|
#define BLACKBOX
|
||||||
#define SERIAL_RX
|
#define SERIAL_RX
|
||||||
//#define GPS
|
//#define GPS
|
||||||
|
// #define GPS_PROTO_NMEA
|
||||||
|
// #define GPS_PROTO_UBLOX
|
||||||
|
// #define GPS_PROTO_I2C_NAV
|
||||||
|
|
||||||
#define DISPLAY
|
#define DISPLAY
|
||||||
#define USE_SERVOS
|
#define USE_SERVOS
|
||||||
#define USE_FLASHFS
|
#define USE_FLASHFS
|
||||||
|
|
|
@ -170,6 +170,10 @@
|
||||||
#define EXTERNAL1_ADC_CHANNEL ADC_Channel_5
|
#define EXTERNAL1_ADC_CHANNEL ADC_Channel_5
|
||||||
|
|
||||||
#define GPS
|
#define GPS
|
||||||
|
#define GPS_PROTO_NMEA
|
||||||
|
#define GPS_PROTO_UBLOX
|
||||||
|
#define GPS_PROTO_I2C_NAV
|
||||||
|
|
||||||
#define NAV
|
#define NAV
|
||||||
|
|
||||||
//#define GTUNE
|
//#define GTUNE
|
||||||
|
|
|
@ -41,7 +41,12 @@
|
||||||
#define I2C_DEVICE (I2CDEV_1)
|
#define I2C_DEVICE (I2CDEV_1)
|
||||||
|
|
||||||
#define BLACKBOX
|
#define BLACKBOX
|
||||||
|
|
||||||
#define GPS
|
#define GPS
|
||||||
|
#define GPS_PROTO_NMEA
|
||||||
|
#define GPS_PROTO_UBLOX
|
||||||
|
#define GPS_PROTO_I2C_NAV
|
||||||
|
|
||||||
#define GTUNE
|
#define GTUNE
|
||||||
#define SERIAL_RX
|
#define SERIAL_RX
|
||||||
#define TELEMETRY
|
#define TELEMETRY
|
||||||
|
|
|
@ -104,6 +104,10 @@
|
||||||
#define EXTERNAL1_ADC_CHANNEL ADC_Channel_5
|
#define EXTERNAL1_ADC_CHANNEL ADC_Channel_5
|
||||||
|
|
||||||
#define GPS
|
#define GPS
|
||||||
|
#define GPS_PROTO_NMEA
|
||||||
|
#define GPS_PROTO_UBLOX
|
||||||
|
#define GPS_PROTO_I2C_NAV
|
||||||
|
|
||||||
#define LED_STRIP
|
#define LED_STRIP
|
||||||
#define LED_STRIP_TIMER TIM3
|
#define LED_STRIP_TIMER TIM3
|
||||||
|
|
||||||
|
|
|
@ -149,7 +149,12 @@
|
||||||
#define LED_STRIP_TIMER TIM3
|
#define LED_STRIP_TIMER TIM3
|
||||||
|
|
||||||
#define BLACKBOX
|
#define BLACKBOX
|
||||||
|
|
||||||
#define GPS
|
#define GPS
|
||||||
|
#define GPS_PROTO_NMEA
|
||||||
|
#define GPS_PROTO_UBLOX
|
||||||
|
#define GPS_PROTO_I2C_NAV
|
||||||
|
|
||||||
#define GTUNE
|
#define GTUNE
|
||||||
#define SERIAL_RX
|
#define SERIAL_RX
|
||||||
#define TELEMETRY
|
#define TELEMETRY
|
||||||
|
|
|
@ -156,7 +156,12 @@
|
||||||
#define WS2811_IRQ DMA1_Channel2_IRQn
|
#define WS2811_IRQ DMA1_Channel2_IRQn
|
||||||
|
|
||||||
#define GPS
|
#define GPS
|
||||||
|
#define GPS_PROTO_NMEA
|
||||||
|
#define GPS_PROTO_UBLOX
|
||||||
|
#define GPS_PROTO_I2C_NAV
|
||||||
|
|
||||||
#define NAV
|
#define NAV
|
||||||
|
|
||||||
#define BLACKBOX
|
#define BLACKBOX
|
||||||
#define TELEMETRY
|
#define TELEMETRY
|
||||||
#define SERIAL_RX
|
#define SERIAL_RX
|
||||||
|
|
|
@ -108,8 +108,13 @@
|
||||||
#define CURRENT_METER_ADC_CHANNEL ADC_Channel_4
|
#define CURRENT_METER_ADC_CHANNEL ADC_Channel_4
|
||||||
|
|
||||||
#define BLACKBOX
|
#define BLACKBOX
|
||||||
#define GPS
|
|
||||||
#define NAV
|
#define NAV
|
||||||
|
#define GPS
|
||||||
|
#define GPS_PROTO_NMEA
|
||||||
|
#define GPS_PROTO_UBLOX
|
||||||
|
#define GPS_PROTO_I2C_NAV
|
||||||
|
|
||||||
#define GTUNE
|
#define GTUNE
|
||||||
#define DISPLAY
|
#define DISPLAY
|
||||||
#define SERIAL_RX
|
#define SERIAL_RX
|
||||||
|
|
|
@ -160,8 +160,14 @@
|
||||||
#define ENABLE_BLACKBOX_LOGGING_ON_SPIFLASH_BY_DEFAULT
|
#define ENABLE_BLACKBOX_LOGGING_ON_SPIFLASH_BY_DEFAULT
|
||||||
|
|
||||||
#define DISPLAY
|
#define DISPLAY
|
||||||
|
|
||||||
#define GPS
|
#define GPS
|
||||||
|
#define GPS_PROTO_NMEA
|
||||||
|
#define GPS_PROTO_UBLOX
|
||||||
|
#define GPS_PROTO_I2C_NAV
|
||||||
|
|
||||||
#define NAV
|
#define NAV
|
||||||
|
|
||||||
#define GTUNE
|
#define GTUNE
|
||||||
#define SERIAL_RX
|
#define SERIAL_RX
|
||||||
#define TELEMETRY
|
#define TELEMETRY
|
||||||
|
|
|
@ -90,7 +90,12 @@
|
||||||
#define EXTERNAL1_ADC_CHANNEL ADC_Channel_9
|
#define EXTERNAL1_ADC_CHANNEL ADC_Channel_9
|
||||||
|
|
||||||
#define BLACKBOX
|
#define BLACKBOX
|
||||||
|
|
||||||
#define GPS
|
#define GPS
|
||||||
|
#define GPS_PROTO_NMEA
|
||||||
|
#define GPS_PROTO_UBLOX
|
||||||
|
#define GPS_PROTO_I2C_NAV
|
||||||
|
|
||||||
#define GTUNE
|
#define GTUNE
|
||||||
#define LED_STRIP
|
#define LED_STRIP
|
||||||
#define LED_STRIP_TIMER TIM16
|
#define LED_STRIP_TIMER TIM16
|
||||||
|
|
|
@ -181,7 +181,7 @@ static void sendBaro(void)
|
||||||
#ifdef GPS
|
#ifdef GPS
|
||||||
static void sendGpsAltitude(void)
|
static void sendGpsAltitude(void)
|
||||||
{
|
{
|
||||||
uint16_t altitude = GPS_altitude;
|
uint16_t altitude = gpsSol.llh.alt;
|
||||||
//Send real GPS altitude only if it's reliable (there's a GPS fix)
|
//Send real GPS altitude only if it's reliable (there's a GPS fix)
|
||||||
if (!STATE(GPS_FIX)) {
|
if (!STATE(GPS_FIX)) {
|
||||||
altitude = 0;
|
altitude = 0;
|
||||||
|
@ -221,9 +221,9 @@ static void sendTemperature1(void)
|
||||||
#ifdef GPS
|
#ifdef GPS
|
||||||
static void sendSatalliteSignalQualityAsTemperature2(void)
|
static void sendSatalliteSignalQualityAsTemperature2(void)
|
||||||
{
|
{
|
||||||
uint16_t satellite = GPS_numSat;
|
uint16_t satellite = gpsSol.numSat;
|
||||||
if (GPS_hdop > GPS_BAD_QUALITY && ( (cycleNum % 16 ) < 8)) {//Every 1s
|
if (gpsSol.hdop > GPS_BAD_QUALITY && ( (cycleNum % 16 ) < 8)) {//Every 1s
|
||||||
satellite = constrain(GPS_hdop, 0, GPS_MAX_HDOP_VAL);
|
satellite = constrain(gpsSol.hdop, 0, GPS_MAX_HDOP_VAL);
|
||||||
}
|
}
|
||||||
sendDataHead(ID_TEMPRATURE2);
|
sendDataHead(ID_TEMPRATURE2);
|
||||||
|
|
||||||
|
@ -245,9 +245,9 @@ static void sendSpeed(void)
|
||||||
//Speed should be sent in knots (GPS speed is in cm/s)
|
//Speed should be sent in knots (GPS speed is in cm/s)
|
||||||
sendDataHead(ID_GPS_SPEED_BP);
|
sendDataHead(ID_GPS_SPEED_BP);
|
||||||
//convert to knots: 1cm/s = 0.0194384449 knots
|
//convert to knots: 1cm/s = 0.0194384449 knots
|
||||||
serialize16(GPS_speed * 1944 / 100000);
|
serialize16(gpsSol.groundSpeed * 1944 / 100000);
|
||||||
sendDataHead(ID_GPS_SPEED_AP);
|
sendDataHead(ID_GPS_SPEED_AP);
|
||||||
serialize16((GPS_speed * 1944 / 100) % 100);
|
serialize16((gpsSol.groundSpeed * 1944 / 100) % 100);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -328,11 +328,14 @@ static void sendFakeLatLongThatAllowsHeadingDisplay(void)
|
||||||
static void sendGPSLatLong(void)
|
static void sendGPSLatLong(void)
|
||||||
{
|
{
|
||||||
static uint8_t gpsFixOccured = 0;
|
static uint8_t gpsFixOccured = 0;
|
||||||
|
int32_t coord[2] = {0,0};
|
||||||
|
|
||||||
if (STATE(GPS_FIX) || gpsFixOccured == 1) {
|
if (STATE(GPS_FIX) || gpsFixOccured == 1) {
|
||||||
// If we have ever had a fix, send the last known lat/long
|
// If we have ever had a fix, send the last known lat/long
|
||||||
gpsFixOccured = 1;
|
gpsFixOccured = 1;
|
||||||
sendLatLong(GPS_coord);
|
coord[LAT] = gpsSol.llh.lat;
|
||||||
|
coord[LON] = gpsSol.llh.lon;
|
||||||
|
sendLatLong(coord);
|
||||||
} else {
|
} else {
|
||||||
// otherwise send fake lat/long in order to display compass value
|
// otherwise send fake lat/long in order to display compass value
|
||||||
sendFakeLatLong();
|
sendFakeLatLong();
|
||||||
|
|
|
@ -178,30 +178,30 @@ void addGPSCoordinates(HOTT_GPS_MSG_t *hottGPSMessage, int32_t latitude, int32_t
|
||||||
|
|
||||||
void hottPrepareGPSResponse(HOTT_GPS_MSG_t *hottGPSMessage)
|
void hottPrepareGPSResponse(HOTT_GPS_MSG_t *hottGPSMessage)
|
||||||
{
|
{
|
||||||
hottGPSMessage->gps_satelites = GPS_numSat;
|
hottGPSMessage->gps_satelites = gpsSol.numSat;
|
||||||
|
|
||||||
if (!STATE(GPS_FIX)) {
|
if (!STATE(GPS_FIX)) {
|
||||||
hottGPSMessage->gps_fix_char = GPS_FIX_CHAR_NONE;
|
hottGPSMessage->gps_fix_char = GPS_FIX_CHAR_NONE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GPS_numSat >= 5) {
|
if (gpsSol.numSat >= 5) {
|
||||||
hottGPSMessage->gps_fix_char = GPS_FIX_CHAR_3D;
|
hottGPSMessage->gps_fix_char = GPS_FIX_CHAR_3D;
|
||||||
} else {
|
} else {
|
||||||
hottGPSMessage->gps_fix_char = GPS_FIX_CHAR_2D;
|
hottGPSMessage->gps_fix_char = GPS_FIX_CHAR_2D;
|
||||||
}
|
}
|
||||||
|
|
||||||
addGPSCoordinates(hottGPSMessage, GPS_coord[LAT], GPS_coord[LON]);
|
addGPSCoordinates(hottGPSMessage, gpsSol.llh.lat, gpsSol.llh.lon);
|
||||||
|
|
||||||
// GPS Speed is returned in cm/s (from io/gps.c) and must be sent in km/h (Hott requirement)
|
// GPS Speed is returned in cm/s (from io/gps.c) and must be sent in km/h (Hott requirement)
|
||||||
uint16_t speed = (GPS_speed * 36) / 1000;
|
uint16_t speed = (gpsSol.groundSpeed * 36) / 1000;
|
||||||
hottGPSMessage->gps_speed_L = speed & 0x00FF;
|
hottGPSMessage->gps_speed_L = speed & 0x00FF;
|
||||||
hottGPSMessage->gps_speed_H = speed >> 8;
|
hottGPSMessage->gps_speed_H = speed >> 8;
|
||||||
|
|
||||||
hottGPSMessage->home_distance_L = GPS_distanceToHome & 0x00FF;
|
hottGPSMessage->home_distance_L = GPS_distanceToHome & 0x00FF;
|
||||||
hottGPSMessage->home_distance_H = GPS_distanceToHome >> 8;
|
hottGPSMessage->home_distance_H = GPS_distanceToHome >> 8;
|
||||||
|
|
||||||
uint16_t hottGpsAltitude = (GPS_altitude / 10) + HOTT_GPS_ALTITUDE_OFFSET; // 1 / 0.1f == 10, GPS_altitude of 1 == 0.1m
|
uint16_t hottGpsAltitude = (gpsSol.llh.alt / 10) + HOTT_GPS_ALTITUDE_OFFSET; // 1 / 0.1f == 10, GPS_altitude of 1 == 0.1m
|
||||||
|
|
||||||
hottGPSMessage->altitude_L = hottGpsAltitude & 0x00FF;
|
hottGPSMessage->altitude_L = hottGpsAltitude & 0x00FF;
|
||||||
hottGPSMessage->altitude_H = hottGpsAltitude >> 8;
|
hottGPSMessage->altitude_H = hottGpsAltitude >> 8;
|
||||||
|
|
|
@ -137,23 +137,23 @@ static void ltm_gframe(void)
|
||||||
|
|
||||||
if (!STATE(GPS_FIX))
|
if (!STATE(GPS_FIX))
|
||||||
gps_fix_type = 1;
|
gps_fix_type = 1;
|
||||||
else if (GPS_numSat < 5)
|
else if (gpsSol.numSat < 5)
|
||||||
gps_fix_type = 2;
|
gps_fix_type = 2;
|
||||||
else
|
else
|
||||||
gps_fix_type = 3;
|
gps_fix_type = 3;
|
||||||
|
|
||||||
ltm_initialise_packet('G');
|
ltm_initialise_packet('G');
|
||||||
ltm_serialise_32(GPS_coord[LAT]);
|
ltm_serialise_32(gpsSol.llh.lat);
|
||||||
ltm_serialise_32(GPS_coord[LON]);
|
ltm_serialise_32(gpsSol.llh.lon);
|
||||||
ltm_serialise_8((uint8_t)(GPS_speed / 100));
|
ltm_serialise_8((uint8_t)(gpsSol.groundSpeed / 100));
|
||||||
|
|
||||||
#if defined(NAV)
|
#if defined(NAV)
|
||||||
ltm_alt = (sensors(SENSOR_SONAR) || sensors(SENSOR_BARO)) ? getEstimatedActualPosition(Z) : GPS_altitude * 100;
|
ltm_alt = (sensors(SENSOR_SONAR) || sensors(SENSOR_BARO)) ? getEstimatedActualPosition(Z) : gpsSol.llh.alt * 100;
|
||||||
#else
|
#else
|
||||||
ltm_alt = GPS_altitude * 100;
|
ltm_alt = gpsSol.llh.alt * 100;
|
||||||
#endif
|
#endif
|
||||||
ltm_serialise_32(ltm_alt);
|
ltm_serialise_32(ltm_alt);
|
||||||
ltm_serialise_8((GPS_numSat << 2) | gps_fix_type);
|
ltm_serialise_8((gpsSol.numSat << 2) | gps_fix_type);
|
||||||
ltm_finalise();
|
ltm_finalise();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -316,7 +316,7 @@ void handleSmartPortTelemetry(void)
|
||||||
#ifdef GPS
|
#ifdef GPS
|
||||||
case FSSP_DATAID_SPEED :
|
case FSSP_DATAID_SPEED :
|
||||||
if (sensors(SENSOR_GPS) && STATE(GPS_FIX)) {
|
if (sensors(SENSOR_GPS) && STATE(GPS_FIX)) {
|
||||||
uint32_t tmpui = (GPS_speed * 36 + 36 / 2) / 100;
|
uint32_t tmpui = (gpsSol.groundSpeed * 36 + 36 / 2) / 100;
|
||||||
smartPortSendPackage(id, tmpui); // given in 0.1 m/s, provide in KM/H
|
smartPortSendPackage(id, tmpui); // given in 0.1 m/s, provide in KM/H
|
||||||
smartPortHasRequest = 0;
|
smartPortHasRequest = 0;
|
||||||
}
|
}
|
||||||
|
@ -357,14 +357,14 @@ void handleSmartPortTelemetry(void)
|
||||||
// the MSB of the sent uint32_t helps FrSky keep track
|
// the MSB of the sent uint32_t helps FrSky keep track
|
||||||
// the even/odd bit of our counter helps us keep track
|
// the even/odd bit of our counter helps us keep track
|
||||||
if (smartPortIdCnt & 1) {
|
if (smartPortIdCnt & 1) {
|
||||||
tmpui = abs(GPS_coord[LON]); // now we have unsigned value and one bit to spare
|
tmpui = abs(gpsSol.llh.lon); // now we have unsigned value and one bit to spare
|
||||||
tmpui = (tmpui + tmpui / 2) / 25 | 0x80000000; // 6/100 = 1.5/25, division by power of 2 is fast
|
tmpui = (tmpui + tmpui / 2) / 25 | 0x80000000; // 6/100 = 1.5/25, division by power of 2 is fast
|
||||||
if (GPS_coord[LON] < 0) tmpui |= 0x40000000;
|
if (gpsSol.llh.lon < 0) tmpui |= 0x40000000;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
tmpui = abs(GPS_coord[LAT]); // now we have unsigned value and one bit to spare
|
tmpui = abs(gpsSol.llh.lat); // now we have unsigned value and one bit to spare
|
||||||
tmpui = (tmpui + tmpui / 2) / 25; // 6/100 = 1.5/25, division by power of 2 is fast
|
tmpui = (tmpui + tmpui / 2) / 25; // 6/100 = 1.5/25, division by power of 2 is fast
|
||||||
if (GPS_coord[LAT] < 0) tmpui |= 0x40000000;
|
if (gpsSol.llh.lat < 0) tmpui |= 0x40000000;
|
||||||
}
|
}
|
||||||
smartPortSendPackage(id, tmpui);
|
smartPortSendPackage(id, tmpui);
|
||||||
smartPortHasRequest = 0;
|
smartPortHasRequest = 0;
|
||||||
|
@ -446,7 +446,7 @@ void handleSmartPortTelemetry(void)
|
||||||
if (sensors(SENSOR_GPS)) {
|
if (sensors(SENSOR_GPS)) {
|
||||||
#ifdef GPS
|
#ifdef GPS
|
||||||
// provide GPS lock status
|
// provide GPS lock status
|
||||||
smartPortSendPackage(id, (STATE(GPS_FIX) ? 1000 : 0) + (STATE(GPS_FIX_HOME) ? 2000 : 0) + GPS_numSat);
|
smartPortSendPackage(id, (STATE(GPS_FIX) ? 1000 : 0) + (STATE(GPS_FIX_HOME) ? 2000 : 0) + gpsSol.numSat);
|
||||||
smartPortHasRequest = 0;
|
smartPortHasRequest = 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -458,7 +458,7 @@ void handleSmartPortTelemetry(void)
|
||||||
#ifdef GPS
|
#ifdef GPS
|
||||||
case FSSP_DATAID_GPS_ALT :
|
case FSSP_DATAID_GPS_ALT :
|
||||||
if (sensors(SENSOR_GPS) && STATE(GPS_FIX)) {
|
if (sensors(SENSOR_GPS) && STATE(GPS_FIX)) {
|
||||||
smartPortSendPackage(id, GPS_altitude * 100); // given in 0.1m , requested in 10 = 1m (should be in mm, probably a bug in opentx, tested on 2.0.1.7)
|
smartPortSendPackage(id, gpsSol.llh.alt * 100); // given in 0.1m , requested in 10 = 1m (should be in mm, probably a bug in opentx, tested on 2.0.1.7)
|
||||||
smartPortHasRequest = 0;
|
smartPortHasRequest = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue