#include #include #include #include #include #include #include #include #include #include #include #include #include "ubx.hh" #include #include #include #include "fmt/format.h" #include "fmt/printf.h" #include "bits.hh" #include "galileo.hh" #include #include "navmon.pb.h" #include "gps.hh" struct timespec g_gstutc; uint16_t g_wn; using namespace std; uint16_t g_srcid{2}; #define BAUDRATE B921600 #define MODEMDEVICE "/dev/ttyACM0" namespace { struct EofException{}; } size_t readn2(int fd, void* buffer, size_t len) { size_t pos=0; ssize_t res; for(;;) { res = read(fd, (char*)buffer + pos, len - pos); if(res == 0) throw EofException(); if(res < 0) { throw runtime_error("failed in readn2: "+string(strerror(errno))); } pos+=(size_t)res; if(pos == len) break; } return len; } size_t writen2(int fd, const void *buf, size_t count) { const char *ptr = (char*)buf; const char *eptr = ptr + count; ssize_t res; while(ptr != eptr) { res = ::write(fd, ptr, eptr - ptr); if(res < 0) { throw runtime_error("failed in writen2: "+string(strerror(errno))); } else if (res == 0) throw EofException(); ptr += (size_t) res; } return count; } /* inav schedule: 1) Find plausible start time of next cycle Current cycle: TOW - (TOW%30) Next cycle: TOW - (TOW%30) + 30 t n w 0 1: 2 wn % 30 == 0 2 2: 4 wn % 30 == 2 4 3: 6 WN/TOW 4 -> set startTow, startTowFresh 6 4: 7/9 8 5: 8/10 10 6: 0 TOW 12 7: 0 WN/TOW 14 8: 0 WN/TOW 16 9: 0 WN/TOW 18 10: 0 WN/TOW 20 11: 1 22 12: 3 24 13: 5 WN/TOW 26 14: 0 WN/TOW 28 15: 0 WN/TOW */ /* if(ubxClass == 2 && ubxType == 89) { // SAR string hexstring; for(int n = 0; n < 15; ++n) hexstring+=fmt::format("%x", (int)getbitu(msg.c_str(), 36 + 4*n, 4)); // int sv = (int)msg[2]; // wk.emitLine(sv, "SAR "+hexstring); // cout<<"SAR: sv = "<< (int)msg[2] <<" "; // for(int n=4; n < 12; ++n) // fmt::printf("%02x", (int)msg[n]); // for(int n = 0; n < 15; ++n) // fmt::printf("%x", (int)getbitu(msg.c_str(), 36 + 4*n, 4)); // cout << " Type: "<< (int) msg[12] <<"\n"; // cout<<"Parameter: (len = "< src) { d_raw = src; if(d_raw.size() < 6) throw std::runtime_error("Partial UBX message"); uint16_t csum = calcUbxChecksum(getClass(), getType(), d_raw.substr(6, d_raw.size()-8)); if(csum != d_raw.at(d_raw.size()-2) + 256*d_raw.at(d_raw.size()-1)) throw BadChecksum(); } uint8_t getClass() const { return d_raw.at(2); } uint8_t getType() const { return d_raw.at(3); } std::basic_string getPayload() const { return d_raw.substr(6, d_raw.size()-8); } std::basic_string d_raw; }; bool g_fromFile{false}; std::pair getUBXMessage(int fd) { static int logfile; if(!logfile && !g_fromFile) { logfile = open("./logfile", O_WRONLY|O_CREAT|O_APPEND, 0600); if(!logfile) throw std::runtime_error("Failed to open logfile for writing"); } uint8_t marker[2]={0}; for(;;) { marker[0] = marker[1]; int res = readn2(fd, marker+1, 1); if(res < 0) throw EofException(); // cerr<<"marker now: "<< (int)marker[0]<<" " <<(int)marker[1]< msg; msg.append(marker, 2); // 0,1 uint8_t b[4]; readn2(fd, b, 4); msg.append(b, 4); // class, type, len1, len2 uint16_t len = b[2] + 256*b[3]; // cerr<<"Got class "<<(int)msg[2]<<" type "<<(int)msg[3]<<", len = "< msg; cerr<<"Asking for rate"<, struct timeval> lasttv, tv; int curCycleTOW{-1}; // means invalid for(;;) { try { auto [msg, timestamp] = getUBXMessage(fd); (void)timestamp; auto payload = msg.getPayload(); // should turn this into protobuf if(msg.getClass() == 0x01 && msg.getType() == 0x07) { // UBX-NAV-PVT struct PVT { uint32_t itow; uint16_t year; uint8_t month; // jan = 1 uint8_t day; uint8_t hour; // 24 uint8_t min; uint8_t sec; uint8_t valid; uint32_t tAcc; int32_t nano; uint8_t fixtype; } __attribute__((packed)); PVT pvt; memcpy(&pvt, &payload[0], sizeof(pvt)); struct tm tm; memset(&tm, 0, sizeof(tm)); tm.tm_year = pvt.year - 1900; tm.tm_mon = pvt.month - 1; tm.tm_mday = pvt.day; tm.tm_hour = pvt.hour; tm.tm_min = pvt.min; tm.tm_sec = pvt.sec; uint32_t satt = timegm(&tm); double satutc = timegm(&tm) + pvt.nano/1000000000.0; // negative is no problem here if(pvt.nano < 0) { pvt.sec--; satt--; pvt.nano += 1000000000; } g_gstutc.tv_sec = satt; g_gstutc.tv_nsec = pvt.nano; double seconds= pvt.sec + pvt.nano/1000000000.0; // fmt::fprintf(stderr, "Satellite UTC: %02d:%02d:%06.4f -> %.4f or %d:%f\n", tm.tm_hour, tm.tm_min, seconds, satutc, timegm(&tm), pvt.nano/1000.0); if(!g_fromFile) { struct tm ourtime; time_t ourt = timestamp.tv_sec; gmtime_r(&ourt, &ourtime); double ourutc = ourt + timestamp.tv_usec/1000000.0; seconds = ourtime.tm_sec + timestamp.tv_usec/1000000.0; // fmt::fprintf(stderr, "Our UTC : %02d:%02d:%06.4f -> %.4f or %d:%f -> delta = %.4fs\n", tm.tm_hour, tm.tm_min, seconds, ourutc, timestamp.tv_sec, 1.0*timestamp.tv_usec, ourutc - satutc); } } else if(msg.getClass() == 0x02 && msg.getType() == 0x15) { // RAWX // cerr<<"Got "<<(int)payload[11] <<" measurements "<set_gnssid(gnssid); nmm.mutable_rfd()->set_gnsssv(sv); nmm.mutable_rfd()->set_rcvtow(rcvTow); nmm.mutable_rfd()->set_rcvwn(rcvWn); nmm.mutable_rfd()->set_doppler(doppler); nmm.mutable_rfd()->set_carrierphase(cpMes); nmm.mutable_rfd()->set_pseudorange(prMes); nmm.mutable_rfd()->set_prstd(ldexp(0.01, prStddev)); nmm.mutable_rfd()->set_dostd(ldexp(0.002, doStddev)); nmm.mutable_rfd()->set_cpstd(cpStddev*0.4); nmm.mutable_rfd()->set_locktimems(locktimems); emitNMM(1, nmm); } } else if(msg.getClass() == 0x01 && msg.getType() == 0x01) { // POSECF struct pos { uint32_t iTOW; int32_t ecefX; int32_t ecefY; int32_t ecefZ; uint32_t pAcc; }; pos p; memcpy(&p, payload.c_str(), sizeof(pos)); cerr<<"Position: ("<< p.ecefX / 100000.0<<", " << p.ecefY / 100000.0<<", " << p.ecefZ / 100000.0<<") +- "<set_x(p.ecefX /100.0); nmm.mutable_op()->set_y(p.ecefY /100.0); nmm.mutable_op()->set_z(p.ecefZ /100.0); nmm.mutable_op()->set_acccm(p.pAcc /100.0); emitNMM(1, nmm); } else if(msg.getClass() == 2 && msg.getType() == 0x13) { // SFRBX // order: 2, 4, 6, 7/9, 8/10, 0, 0, 0, 0, 0, 1, 3, 5, 0, 0 // * * * * * * * // tow try { pair id = make_pair(payload[0], payload[1]); if(id.first == 0) { NavMonMessage nmm; nmm.set_type(NavMonMessage::GPSInavType); nmm.set_localutcseconds(g_gstutc.tv_sec); nmm.set_localutcnanoseconds(g_gstutc.tv_nsec); nmm.set_sourceid(g_srcid); // cerr<<"GPS frame, numwords: "<<(int)payload[4]<<", version: "<<(int)payload[6]<set_gnsswn(wn); // XXX this sucks nmm.mutable_gpsi()->set_gnsstow(tow); // "with 6 second increments" -- needs to be adjusted nmm.mutable_gpsi()->set_gnssid(id.first); nmm.mutable_gpsi()->set_gnsssv(id.second); nmm.mutable_gpsi()->set_contents(string((char*)gpsframe.c_str(), gpsframe.size())); emitNMM(1, nmm); continue; } auto inav = getInavFromSFRBXMsg(payload); unsigned int wtype = getbitu(&inav[0], 0, 6); tv[id] = timestamp; // cerr<<"gnssid "<set_gnsswn(g_wn); nmm.mutable_gi()->set_gnsstow(msgTOW); nmm.mutable_gi()->set_gnssid(id.first); nmm.mutable_gi()->set_gnsssv(id.second); nmm.mutable_gi()->set_contents((const char*)&inav[0], inav.size()); emitNMM(1, nmm); if(0 && lasttv.count(id)) { fmt::fprintf(stderr, "gnssid %d sv %d wtype %d, %d:%d -> %d:%d, delta=%d\n", payload[0], payload[1], wtype, lasttv[id].tv_sec, lasttv[id].tv_usec, tv[id].tv_sec, tv[id].tv_usec, tv[id].tv_usec - lasttv[id].tv_usec); } lasttv[id]=tv[id]; } catch(CRCMismatch& cm) { cerr<<"Had CRC mismatch!"<set_gnssid(gnssid); nmm.mutable_rd()->set_gnsssv(sv); nmm.mutable_rd()->set_db(db); nmm.mutable_rd()->set_el(el); nmm.mutable_rd()->set_azi(azi); nmm.mutable_rd()->set_prres(*((int16_t*)(payload.c_str()+ 14 +12*n)) *0.1); emitNMM(1, nmm); } } // writen2(1, payload.d_raw.c_str(),msg.d_raw.size()); } catch(UBXMessage::BadChecksum &e) { cerr<<"Bad UBX checksum, skipping message"<