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/build_config.h"
28 #if defined(USE_GPS) && defined(USE_GPS_PROTO_NAZA)
30 #include "build/debug.h"
32 #include "common/axis.h"
33 #include "common/gps_conversion.h"
34 #include "common/maths.h"
35 #include "common/utils.h"
37 #include "drivers/serial.h"
38 #include "drivers/time.h"
40 #include "fc/config.h"
41 #include "fc/runtime_config.h"
44 #include "io/gps_private.h"
45 #include "io/serial.h"
47 #include "scheduler/protothreads.h"
49 #define NAZA_MAX_PAYLOAD_SIZE 256
64 uint32_t time
; // GPS msToW 0
65 int32_t longitude
; // 4
66 int32_t latitude
; // 8
67 int32_t altitude_msl
; // 12
71 int32_t ned_north
; // 28
72 int32_t ned_east
; // 32
73 int32_t ned_down
; // 36
78 uint8_t satellites
; // 48
80 uint8_t fix_type
; // 50
82 uint8_t fix_status
; // 52
96 } naza_protocol_bytes
;
110 uint8_t bytes
[NAZA_MAX_PAYLOAD_SIZE
];
113 // Packet checksum accumulators
114 static uint8_t _ck_a
;
115 static uint8_t _ck_b
;
117 // State machine state
118 static bool _skip_packet
;
119 static uint8_t _step
;
120 static uint8_t _msg_id
;
121 static uint16_t _payload_length
;
122 static uint16_t _payload_counter
;
124 // do we have new position information?
125 static bool _new_position
;
127 // do we have new speed information?
128 static bool _new_speed
;
130 int32_t decodeLong(uint32_t idx
, uint8_t mask
)
132 union { uint32_t l
; uint8_t b
[4]; } val
;
134 for (int i
= 0; i
< 4; i
++) val
.b
[i
] ^= mask
;
138 int16_t decodeShort(uint16_t idx
, uint8_t mask
)
140 union { uint16_t s
; uint8_t b
[2]; } val
;
142 for (int i
= 0; i
< 2; i
++) val
.b
[i
] ^= mask
;
146 static bool NAZA_parse_gps(void)
153 mask
= _buffernaza
.nav
.mask
;
155 uint32_t time
= decodeLong(_buffernaza
.nav
.time
, mask
);
156 gpsSol
.time
.seconds
= time
& 0b00111111; time
>>= 6;
157 gpsSol
.time
.minutes
= time
& 0b00111111; time
>>= 6;
158 gpsSol
.time
.hours
= time
& 0b00001111; time
>>= 4;
159 gpsSol
.time
.day
= gpsSol
.time
.hours
> 7?(time
& 0b00011111) + 1:(time
& 0b00011111); time
>>= 5;
160 gpsSol
.time
.month
= time
& 0b00001111; time
>>= 4;
161 gpsSol
.time
.year
= (time
& 0b01111111) + 2000;
163 gpsSol
.llh
.lon
= decodeLong(_buffernaza
.nav
.longitude
, mask
);
164 gpsSol
.llh
.lat
= decodeLong(_buffernaza
.nav
.latitude
, mask
);
165 gpsSol
.llh
.alt
= decodeLong(_buffernaza
.nav
.altitude_msl
, mask
) / 10.0f
; //alt in cm
167 uint8_t fixType
= _buffernaza
.nav
.fix_type
^ mask
;
168 //uint8_t fixFlags = _buffernaza.nav.fix_status ^ mask;
170 //uint8_t r3 = _buffernaza.nav.reserved3 ^ mask;
171 //uint8_t r4 = _buffernaza.nav.reserved4 ^ mask;
172 //uint8_t r5 = _buffernaza.nav.reserved5 ^ mask;
173 //uint8_t r6 = _buffernaza.nav.reserved6 ^ mask;
175 if (fixType
== FIX_2D
)
176 gpsSol
.fixType
= GPS_FIX_2D
;
177 else if (fixType
== FIX_3D
)
178 gpsSol
.fixType
= GPS_FIX_3D
;
180 gpsSol
.fixType
= GPS_NO_FIX
;
182 uint32_t h_acc
= decodeLong(_buffernaza
.nav
.h_acc
, mask
); // mm
183 uint32_t v_acc
= decodeLong(_buffernaza
.nav
.v_acc
, mask
); // mm
184 //uint32_t test = decodeLong(_buffernaza.nav.reserved, mask);
186 gpsSol
.velNED
[0] = decodeLong(_buffernaza
.nav
.ned_north
, mask
); // cm/s
187 gpsSol
.velNED
[1] = decodeLong(_buffernaza
.nav
.ned_east
, mask
); // cm/s
188 gpsSol
.velNED
[2] = decodeLong(_buffernaza
.nav
.ned_down
, mask
); // cm/s
191 uint16_t pdop
= decodeShort(_buffernaza
.nav
.pdop
, mask
); // pdop
192 //uint16_t vdop = decodeShort(_buffernaza.nav.vdop, mask); // vdop
193 //uint16_t ndop = decodeShort(_buffernaza.nav.ndop, mask);
194 //uint16_t edop = decodeShort(_buffernaza.nav.edop, mask);
195 //gpsSol.hdop = sqrtf(powf(ndop,2)+powf(edop,2));
196 //gpsSol.vdop = decodeShort(_buffernaza.nav.vdop, mask); // vdop
198 gpsSol
.hdop
= gpsConstrainEPE(pdop
); // PDOP
199 gpsSol
.eph
= gpsConstrainEPE(h_acc
/ 10); // hAcc in cm
200 gpsSol
.epv
= gpsConstrainEPE(v_acc
/ 10); // vAcc in cm
201 gpsSol
.numSat
= _buffernaza
.nav
.satellites
;
202 gpsSol
.groundSpeed
= sqrtf(powf(gpsSol
.velNED
[0], 2)+powf(gpsSol
.velNED
[1], 2)); //cm/s
204 // calculate gps heading from VELNE
205 gpsSol
.groundCourse
= (uint16_t) (fmodf(RADIANS_TO_DECIDEGREES(atan2_approx(gpsSol
.velNED
[1], gpsSol
.velNED
[0]))+3600.0f
,3600.0f
));
207 gpsSol
.flags
.validVelNE
= 1;
208 gpsSol
.flags
.validVelD
= 1;
209 gpsSol
.flags
.validEPE
= 1;
210 gpsSol
.flags
.validTime
= 1;
212 _new_position
= true;
216 mask_mag
= (_buffernaza
.mag
.z
)&0xFF;
217 mask_mag
= (((mask_mag
^ (mask_mag
>> 4)) & 0x0F) | ((mask_mag
<< 3) & 0xF0)) ^ (((mask_mag
& 0x01) << 3) | ((mask_mag
& 0x01) << 7));
219 gpsSol
.magData
[0] = decodeShort(_buffernaza
.mag
.x
, mask_mag
);
220 gpsSol
.magData
[1] = decodeShort(_buffernaza
.mag
.y
, mask_mag
);
221 gpsSol
.magData
[2] = (_buffernaza
.mag
.z
^ (mask_mag
<<8));
223 gpsSol
.flags
.validMag
= 1;
231 // we only return true when we get new position and speed data
232 // this ensures we don't use stale data
233 if (_new_position
&& _new_speed
) {
234 _new_speed
= _new_position
= false;
240 static bool gpsNewFrameNAZA(uint8_t data
)
245 case 0: // Sync char 1 (0x55)
246 if (HEADER1
== data
) {
247 _skip_packet
= false;
251 case 1: // Sync char 2 (0xAA)
252 if (HEADER2
!= data
) {
260 _ck_b
= _ck_a
= data
; // reset the checksum accumulators
263 case 3: // Payload length
265 _ck_b
+= (_ck_a
+= data
); // checksum byte
266 _payload_length
= data
; // payload length low byte
267 if (_payload_length
> NAZA_MAX_PAYLOAD_SIZE
) {
268 // we can't receive the whole packet, just log the error and start searching for the next packet.
273 // prepare to receive payload
274 _payload_counter
= 0;
275 if (_payload_length
== 0) {
280 _ck_b
+= (_ck_a
+= data
); // checksum byte
281 if (_payload_counter
< NAZA_MAX_PAYLOAD_SIZE
) {
282 _buffernaza
.bytes
[_payload_counter
] = data
;
284 if (++_payload_counter
>= _payload_length
) {
291 _skip_packet
= true; // bad checksum
299 break; // bad checksum
302 gpsStats
.packetCount
++;
308 if (NAZA_parse_gps()) {
315 static ptSemaphore_t semNewDataReady
;
317 STATIC_PROTOTHREAD(gpsProtocolReceiverThread
)
319 ptBegin(gpsProtocolReceiverThread
);
322 // Wait until there are bytes to consume
323 ptWait(serialRxBytesWaiting(gpsState
.gpsPort
));
325 // Consume bytes until buffer empty of until we have full message received
326 while (serialRxBytesWaiting(gpsState
.gpsPort
)) {
327 uint8_t newChar
= serialRead(gpsState
.gpsPort
);
328 if (gpsNewFrameNAZA(newChar
)) {
329 ptSemaphoreSignal(semNewDataReady
);
338 STATIC_PROTOTHREAD(gpsProtocolStateThread
)
340 ptBegin(gpsProtocolStateThread
);
343 ptWait(isSerialTransmitBufferEmpty(gpsState
.gpsPort
));
344 if (gpsState
.gpsConfig
->autoBaud
!= GPS_AUTOBAUD_OFF
) {
345 // Cycle through available baud rates and hope that we will match GPS
346 serialSetBaudRate(gpsState
.gpsPort
, baudRates
[gpsToSerialBaudRate
[gpsState
.autoBaudrateIndex
]]);
347 gpsState
.autoBaudrateIndex
= (gpsState
.autoBaudrateIndex
+ 1) % GPS_BAUDRATE_COUNT
;
348 ptDelayMs(GPS_BAUD_CHANGE_DELAY
);
352 serialSetBaudRate(gpsState
.gpsPort
, baudRates
[gpsToSerialBaudRate
[gpsState
.baudrateIndex
]]);
355 // No configuration is done for NAZA GPS
357 // GPS setup done, reset timeout
358 gpsSetProtocolTimeout(GPS_TIMEOUT
);
360 // GPS is ready - execute the gpsProcessNewSolutionData() based on gpsProtocolReceiverThread semaphore
362 ptSemaphoreWait(semNewDataReady
);
363 gpsProcessNewSolutionData();
369 void gpsRestartNAZA(void)
371 ptSemaphoreInit(semNewDataReady
);
372 ptRestart(ptGetHandle(gpsProtocolReceiverThread
));
373 ptRestart(ptGetHandle(gpsProtocolStateThread
));
376 void gpsHandleNAZA(void)
378 // Run the protocol threads
379 gpsProtocolReceiverThread();
380 gpsProtocolStateThread();
382 // If thread stopped - signal communication loss and restart
383 if (ptIsStopped(ptGetHandle(gpsProtocolReceiverThread
)) || ptIsStopped(ptGetHandle(gpsProtocolStateThread
))) {
384 gpsSetState(GPS_LOST_COMMUNICATION
);