123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- #include "AP_NMEA_Output.h"
- #if !HAL_MINIMIZE_FEATURES && AP_AHRS_NAVEKF_AVAILABLE
- #include <AP_Math/definitions.h>
- #include <AP_RTC/AP_RTC.h>
- #include <AP_SerialManager/AP_SerialManager.h>
- #include <stdio.h>
- #include <time.h>
- AP_NMEA_Output* AP_NMEA_Output::_singleton;
- AP_NMEA_Output::AP_NMEA_Output()
- {
- AP_SerialManager& sm = AP::serialmanager();
- for (uint8_t i = 0; i < ARRAY_SIZE(_uart); i++) {
- _uart[i] = sm.find_serial(AP_SerialManager::SerialProtocol_NMEAOutput, i);
- if (_uart[i] == nullptr) {
- break;
- }
- _num_outputs++;
- }
- }
- AP_NMEA_Output* AP_NMEA_Output::probe()
- {
- if (!_singleton && AP::serialmanager().find_serial(AP_SerialManager::SerialProtocol_NMEAOutput, 0) != nullptr) {
- _singleton = new AP_NMEA_Output();
- }
- return _singleton;
- }
- uint8_t AP_NMEA_Output::_nmea_checksum(const char *str)
- {
- uint8_t checksum = 0;
- const uint8_t* bytes = (const uint8_t*) str;
- for (uint16_t i = 1; str[i]; i++) {
- checksum ^= bytes[i];
- }
- return checksum;
- }
- void AP_NMEA_Output::update()
- {
- uint16_t now = AP_HAL::millis16();
- uint16_t time_diff = now - _last_sent;
-
- if (time_diff < 100) {
- return;
- }
-
- uint64_t time_usec;
- bool time_valid = AP::rtc().get_utc_usec(time_usec);
- if (!time_valid) {
- return;
- }
-
- time_t time_sec = time_usec / 1000000;
- struct tm* tm = gmtime(&time_sec);
-
- char tstring[11];
- snprintf(tstring, sizeof(tstring), "%02u%02u%06.3f", tm->tm_hour, tm->tm_min, tm->tm_sec + (time_usec % 1000000) * 1.0e-6);
-
- char dstring[7];
- snprintf(dstring, sizeof(dstring), "%02u%02u%02u", tm->tm_mday, tm->tm_mon+1, tm->tm_year % 100);
- AP_AHRS_NavEKF& ahrs = AP::ahrs_navekf();
-
- Location loc;
- bool pos_valid = ahrs.get_location(loc);
-
- char lat_string[13];
- float deg = fabsf(loc.lat * 1.0e-7f);
- snprintf(lat_string,
- sizeof(lat_string),
- "%02u%08.5f,%c",
- (unsigned) deg,
- double((deg - int(deg)) * 60),
- loc.lat < 0 ? 'S' : 'N');
-
- char lng_string[14];
- deg = fabsf(loc.lng * 1.0e-7f);
- snprintf(lng_string,
- sizeof(lng_string),
- "%03u%08.5f,%c",
- (unsigned) deg,
- double((deg - int(deg)) * 60),
- loc.lng < 0 ? 'W' : 'E');
-
- char* gga = nullptr;
- int16_t gga_res = asprintf(&gga,
- "$GPGGA,%s,%s,%s,%01d,%02d,%04.1f,%07.2f,M,0.0,M,,",
- tstring,
- lat_string,
- lng_string,
- pos_valid ? 1 : 0,
- pos_valid ? 6 : 3,
- 2.0,
- loc.alt * 0.01f);
- char gga_end[6];
- snprintf(gga_end, sizeof(gga_end), "*%02X\r\n", (unsigned) _nmea_checksum(gga));
-
- Vector2f speed = ahrs.groundspeed_vector();
- float speed_knots = norm(speed.x, speed.y) * M_PER_SEC_TO_KNOTS;
- float heading = wrap_360(degrees(atan2f(speed.x, speed.y)));
-
- char* rmc = nullptr;
- int16_t rmc_res = asprintf(&rmc,
- "$GPRMC,%s,%c,%s,%s,%.2f,%.2f,%s,,",
- tstring,
- pos_valid ? 'A' : 'V',
- lat_string,
- lng_string,
- speed_knots,
- heading,
- dstring);
- char rmc_end[6];
- snprintf(rmc_end, sizeof(rmc_end), "*%02X\r\n", (unsigned) _nmea_checksum(rmc));
-
- for (uint8_t i = 0; i < _num_outputs; i++) {
- if (gga_res != -1) {
- _uart[i]->write(gga);
- _uart[i]->write(gga_end);
- }
- if (rmc_res != -1) {
- _uart[i]->write(rmc);
- _uart[i]->write(rmc_end);
- }
- }
- if (gga_res != -1) {
- free(gga);
- }
- if (rmc_res != -1) {
- free(rmc);
- }
- _last_sent = now;
- }
- #endif
|