2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
25 #include "build_config.h"
28 #include "common/maths.h"
29 #include "common/axis.h"
30 #include "common/utils.h"
32 #include "drivers/system.h"
33 #include "drivers/serial.h"
34 #include "drivers/serial_uart.h"
36 #include "io/serial.h"
38 #include "io/gps_private.h"
40 #include "flight/gps_conversion.h"
42 #include "config/config.h"
43 #include "config/runtime_config.h"
45 #if defined(GPS) && defined(GPS_PROTO_NAZA)
47 #define NAZA_MAX_PAYLOAD_SIZE 256
62 uint32_t time
; // GPS msToW 0
63 int32_t longitude
; // 4
64 int32_t latitude
; // 8
65 int32_t altitude_msl
; // 12
69 int32_t ned_north
; // 28
70 int32_t ned_east
; // 32
71 int32_t ned_down
; // 36
76 uint8_t satellites
; // 48
78 uint8_t fix_type
; // 50
80 uint8_t fix_status
; // 52
94 } naza_protocol_bytes
;
108 uint8_t bytes
[NAZA_MAX_PAYLOAD_SIZE
];
111 // Packet checksum accumulators
112 static uint8_t _ck_a
;
113 static uint8_t _ck_b
;
115 // State machine state
116 static bool _skip_packet
;
117 static uint8_t _step
;
118 static uint8_t _msg_id
;
119 static uint16_t _payload_length
;
120 static uint16_t _payload_counter
;
122 // do we have new position information?
123 static bool _new_position
;
125 // do we have new speed information?
126 static bool _new_speed
;
128 int32_t decodeLong(uint32_t idx
, uint8_t mask
)
130 union { uint32_t l
; uint8_t b
[4]; } val
;
132 for(int i
= 0; i
< 4; i
++) val
.b
[i
] ^= mask
;
136 int16_t decodeShort(uint16_t idx
, uint8_t mask
)
138 union { uint16_t s
; uint8_t b
[2]; } val
;
140 for(int i
= 0; i
< 2; i
++) val
.b
[i
] ^= mask
;
144 static bool NAZA_parse_gps(void)
151 mask
= _buffernaza
.nav
.mask
;
153 //uint32_t time = decodeLong(_buffernaza.nav.time, mask);
154 //uint32_t second = time & 0b00111111; time >>= 6;
155 //uint32_t minute = time & 0b00111111; time >>= 6;
156 //uint32_t hour = time & 0b00001111; time >>= 4;
157 //uint32_t day = time & 0b00011111; time >>= 5;
158 //uint32_t month = time & 0b00001111; time >>= 4;
159 //uint32_t year = time & 0b01111111;
161 gpsSol
.llh
.lon
= decodeLong(_buffernaza
.nav
.longitude
, mask
);
162 gpsSol
.llh
.lat
= decodeLong(_buffernaza
.nav
.latitude
, mask
);
163 gpsSol
.llh
.alt
= decodeLong(_buffernaza
.nav
.altitude_msl
, mask
) / 10.0f
; //alt in cm
165 uint8_t fixType
= _buffernaza
.nav
.fix_type
^ mask
;
166 //uint8_t fixFlags = _buffernaza.nav.fix_status ^ mask;
168 //uint8_t r3 = _buffernaza.nav.reserved3 ^ mask;
169 //uint8_t r4 = _buffernaza.nav.reserved4 ^ mask;
170 //uint8_t r5 = _buffernaza.nav.reserved5 ^ mask;
171 //uint8_t r6 = _buffernaza.nav.reserved6 ^ mask;
173 gpsSol
.flags
.fix3D
= (fixType
== FIX_3D
) ? 1 : 0;
175 uint32_t h_acc
= decodeLong(_buffernaza
.nav
.h_acc
, mask
); // mm
176 uint32_t v_acc
= decodeLong(_buffernaza
.nav
.v_acc
, mask
); // mm
177 //uint32_t test = decodeLong(_buffernaza.nav.reserved, mask);
179 gpsSol
.velNED
[0] = decodeLong(_buffernaza
.nav
.ned_north
, mask
); // cm/s
180 gpsSol
.velNED
[1] = decodeLong(_buffernaza
.nav
.ned_east
, mask
); // cm/s
181 gpsSol
.velNED
[2] = decodeLong(_buffernaza
.nav
.ned_down
, mask
); // cm/s
184 //uint16_t pdop = decodeShort(_buffernaza.nav.pdop, mask); // pdop
185 //uint16_t vdop = decodeShort(_buffernaza.nav.vdop, mask); // vdop
186 //uint16_t ndop = decodeShort(_buffernaza.nav.ndop, mask);
187 //uint16_t edop = decodeShort(_buffernaza.nav.edop, mask);
188 //gpsSol.hdop = sqrtf(powf(ndop,2)+powf(edop,2));
189 //gpsSol.vdop = decodeShort(_buffernaza.nav.vdop, mask); // vdop
191 gpsSol
.eph
= gpsConstrainEPE(h_acc
/ 10); // hAcc in cm
192 gpsSol
.epv
= gpsConstrainEPE(v_acc
/ 10); // vAcc in cm
193 gpsSol
.numSat
= _buffernaza
.nav
.satellites
;
194 gpsSol
.groundSpeed
= sqrtf(powf(gpsSol
.velNED
[0], 2)+powf(gpsSol
.velNED
[1], 2)); //cm/s
196 // calculate gps heading from VELNE
197 gpsSol
.groundCourse
= (uint16_t) (fmodf(RADIANS_TO_DECIDEGREES(atan2_approx(gpsSol
.velNED
[1], gpsSol
.velNED
[0]))+3600.0f
,3600.0f
));
199 gpsSol
.flags
.validVelNE
= 1;
200 gpsSol
.flags
.validVelD
= 1;
201 gpsSol
.flags
.validEPE
= 1;
203 _new_position
= true;
207 mask_mag
= (_buffernaza
.mag
.z
)&0xFF;
208 mask_mag
= (((mask_mag
^ (mask_mag
>> 4)) & 0x0F) | ((mask_mag
<< 3) & 0xF0)) ^ (((mask_mag
& 0x01) << 3) | ((mask_mag
& 0x01) << 7));
210 gpsSol
.magData
[0] = decodeShort(_buffernaza
.mag
.x
, mask_mag
);
211 gpsSol
.magData
[1] = decodeShort(_buffernaza
.mag
.y
, mask_mag
);
212 gpsSol
.magData
[2] = (_buffernaza
.mag
.z
^ (mask_mag
<<8));
221 // we only return true when we get new position and speed data
222 // this ensures we don't use stale data
223 if (_new_position
&& _new_speed
) {
224 _new_speed
= _new_position
= false;
230 static bool gpsNewFrameNAZA(uint8_t data
)
235 case 0: // Sync char 1 (0x55)
236 if (HEADER1
== data
) {
237 _skip_packet
= false;
241 case 1: // Sync char 2 (0xAA)
242 if (HEADER2
!= data
) {
250 _ck_b
= _ck_a
= data
; // reset the checksum accumulators
253 case 3: // Payload length
255 _ck_b
+= (_ck_a
+= data
); // checksum byte
256 _payload_length
= data
; // payload length low byte
257 if (_payload_length
> NAZA_MAX_PAYLOAD_SIZE
) {
258 // we can't receive the whole packet, just log the error and start searching for the next packet.
263 // prepare to receive payload
264 _payload_counter
= 0;
265 if (_payload_length
== 0) {
270 _ck_b
+= (_ck_a
+= data
); // checksum byte
271 if (_payload_counter
< NAZA_MAX_PAYLOAD_SIZE
) {
272 _buffernaza
.bytes
[_payload_counter
] = data
;
274 if (++_payload_counter
>= _payload_length
) {
281 _skip_packet
= true; // bad checksum
289 break; // bad checksum
292 gpsStats
.packetCount
++;
298 if (NAZA_parse_gps()) {
305 static bool gpsReceiveData(void)
307 bool hasNewData
= false;
309 if (gpsState
.gpsPort
) {
310 while (serialRxBytesWaiting(gpsState
.gpsPort
)) {
311 uint8_t newChar
= serialRead(gpsState
.gpsPort
);
312 if (gpsNewFrameNAZA(newChar
)) {
313 gpsSol
.flags
.gpsHeartbeat
= !gpsSol
.flags
.gpsHeartbeat
;
322 static bool gpsInitialize(void)
324 gpsSetState(GPS_CHANGE_BAUD
);
328 static bool gpsChangeBaud(void)
330 gpsFinalizeChangeBaud();
334 bool gpsHandleNAZA(void)
337 bool hasNewData
= gpsReceiveData();
340 switch(gpsState
.state
) {
344 case GPS_INITIALIZING
:
345 return gpsInitialize();
347 case GPS_CHANGE_BAUD
:
348 return gpsChangeBaud();
350 case GPS_CHECK_VERSION
:
352 // No autoconfig, switch straight to receiving data
353 gpsSetState(GPS_RECEIVING_DATA
);
356 case GPS_RECEIVING_DATA
: