/** Generate and send periodic NMEA GPGSV, GPRMC, GPVTG, GPGLL * (but not GPGGA) messages. * * Called from solution thread. * * \param soln Pointer to gnss_solution struct. * \param n Number of satellites in use * \param nav_meas Array of n navigation_measurement structs. */ void nmea_send_msgs(gnss_solution *soln, u8 n, navigation_measurement_t *nm) { if (gpgsv_msg_rate < 1) { gpgsv_msg_rate = 1; } if (gprmc_msg_rate < 1) { gpgsv_msg_rate = 1; } if (gpvtg_msg_rate < 1) { gpgsv_msg_rate = 1; } if (gpgll_msg_rate < 1) { gpgsv_msg_rate = 1; } DO_EVERY(gpgsv_msg_rate, nmea_gpgsv(n, nm, soln); );
int main(void) { init(); led_toggle(LED_RED); printf("\n\nFirmware info - git: " GIT_VERSION ", built: " __DATE__ " " __TIME__ "\n"); u8 nap_git_hash[20]; nap_conf_rd_git_hash(nap_git_hash); printf("SwiftNAP git: "); for (u8 i=0; i<20; i++) printf("%02x", nap_git_hash[i]); if (nap_conf_rd_git_unclean()) printf(" (unclean)"); printf("\n"); printf("SwiftNAP configured with %d tracking channels\n\n", nap_track_n_channels); cw_setup(); manage_acq_setup(); tick_timer_setup(); timing_setup(); position_setup(); channel_measurement_t meas[nap_track_n_channels]; navigation_measurement_t nav_meas[nap_track_n_channels]; /* TODO: Think about thread safety when updating ephemerides. */ static ephemeris_t es[32]; static ephemeris_t es_old[32]; while(1) { for (u32 i = 0; i < 3000; i++) __asm__("nop"); sbp_process_messages(); manage_track(); manage_acq(); /* Check if there is a new nav msg subframe to process. * TODO: move this into a function */ memcpy(es_old, es, sizeof(es)); for (u8 i=0; i<nap_track_n_channels; i++) if (tracking_channel[i].state == TRACKING_RUNNING && tracking_channel[i].nav_msg.subframe_start_index) { s8 ret = process_subframe(&tracking_channel[i].nav_msg, &es[tracking_channel[i].prn]); if (ret < 0) printf("PRN %02d ret %d\n", tracking_channel[i].prn+1, ret); if (ret == 1 && !es[tracking_channel[i].prn].healthy) printf("PRN %02d unhealthy\n", tracking_channel[i].prn+1); if (memcmp(&es[tracking_channel[i].prn], &es_old[tracking_channel[i].prn], sizeof(ephemeris_t))) { printf("New ephemeris for PRN %02d\n", tracking_channel[i].prn+1); /* TODO: This is a janky way to set the time... */ gps_time_t t; t.wn = es[tracking_channel[i].prn].toe.wn; t.tow = tracking_channel[i].TOW_ms / 1000.0; if (gpsdifftime(t, es[tracking_channel[i].prn].toe) > 2*24*3600) t.wn--; else if (gpsdifftime(t, es[tracking_channel[i].prn].toe) < 2*24*3600) t.wn++; set_time(TIME_COARSE, t); } } DO_EVERY_TICKS(TICK_FREQ/10, u8 n_ready = 0; for (u8 i=0; i<nap_track_n_channels; i++) { if (es[tracking_channel[i].prn].valid == 1 && \ es[tracking_channel[i].prn].healthy == 1 && \ tracking_channel[i].state == TRACKING_RUNNING && \ tracking_channel[i].TOW_ms > 0) { __asm__("CPSID i;"); tracking_update_measurement(i, &meas[n_ready]); __asm__("CPSIE i;"); n_ready++; } } if (n_ready >= 4) { /* Got enough sats/ephemerides, do a solution. */ /* TODO: Instead of passing 32 LSBs of nap_timing_count do something * more intelligent with the solution time. */ calc_navigation_measurement(n_ready, meas, nav_meas, (double)((u32)nap_timing_count())/SAMPLE_FREQ, es); dops_t dops; if (calc_PVT(n_ready, nav_meas, &position_solution, &dops) == 0) { position_updated(); sbp_send_msg(MSG_SOLUTION, sizeof(gnss_solution), (u8 *) &position_solution); nmea_gpgga(&position_solution, &dops); DO_EVERY(10, sbp_send_msg(MSG_DOPS, sizeof(dops_t), (u8 *) &dops); nmea_gpgsv(n_ready, nav_meas, &position_solution); ); }