#include #include "navmon.hh" #include #include #include #include "bits.hh" #include #include #include "galileo.hh" #include "nmmsender.hh" #include "CLI/CLI.hpp" #include "swrappers.hh" #include "sclasses.hh" #include "version.hh" using namespace std; static int sepsig2ubx(int sep) { if(sep == 1) // GPS L1P return 0; else if(sep == 2) // GPS L2P return 4; else if(sep== 4) // GPS L5 return 7; // ?? else if(sep == 17) return 1; // Galileo E1 else if(sep == 19) return 8; // Galileo E6 else if(sep == 20) return 6; // Galileo E5a else if(sep==21) return 5; // Galileo E5b else if(sep==22) return 6; // Galileo "AltBoc" else if(sep==0) return 0; // GPS L1 else if(sep==3) return 4; // GPS L2c else throw runtime_error("Asked to convert unknown Septentrio signal id "+to_string(sep)); return -1; } struct SEPMessage { SEPMessage(const std::basic_string& str) : d_store(str) {} uint16_t getID() // includes revision { return d_store[4] + 256*d_store[5]; } uint16_t getIDBare() // includes revision { return getID() & 0xFFF; } std::basic_string getPayload() { return d_store.substr(8); } std::basic_string d_store; }; /* format: 01 23 45 67 $@ CRC blk-id len [len-8 bytes] | multiple of four bits 0-12 of blk-id are the type */ std::pair getSEPMessage(int fd, double* timeout) { uint8_t marker[2]={0}; bool hadskip=false; for(;;) { marker[0] = marker[1]; int res = readn2Timeout(fd, marker+1, 1, timeout); if(res < 0) { cerr<<"Readn2Timeout failed: "< msg; msg.append(marker, 2); // 0,1 uint8_t b[6]; readn2Timeout(fd, b, 6, timeout); msg.append(b, 6); // crc id len // 0,1 = crc, 2-3 = marker, 4, 5 // uint16_t blkid = htons(b[2] + 256*b[3]); uint16_t len = b[4] + 256*b[5]; // cerr<<"Got message of type "< destinations; g_dtLS = 18; bool doVERSION{false}, doSTDOUT{false}; CLI::App app(program); string sourceaddr; bool quiet{false}; app.add_option("--source", sourceaddr, "Connect to this IP address:port to source SBF (otherwise stdin)"); app.add_option("--destination,-d", destinations, "Send output to this IPv4/v6 address"); app.add_option("--station", g_srcid, "Station id")->required(); app.add_option("--quiet", quiet, "Don't emit noise"); app.add_flag("--version", doVERSION, "show program version and copyright"); app.add_flag("--stdout", doSTDOUT, "Emit output to stdout"); try { app.parse(argc, argv); } catch(const CLI::Error &e) { return app.exit(e); } if(doVERSION) { showVersion(program, g_gitHash); exit(0); } signal(SIGPIPE, SIG_IGN); NMMSender ns; ns.d_debug = true; for(const auto& s : destinations) { auto res=resolveName(s, true, true); if(res.empty()) { cerr<<"Unable to resolve '"< payload; for(unsigned int i = 0 ; i < 8; ++i) { payload.append(1, si.navBits[4 * i + 3]); payload.append(1, si.navBits[4 * i + 2]); payload.append(1, si.navBits[4 * i + 1]); payload.append(1, si.navBits[4 * i + 0]); } basic_string inav2; // copy in the even page for(int n = 0 ; n < 14; ++n) inav2.append(1, getbitu(payload.c_str(), 2 + n*8, 8)); // odd page for(int n = 0 ; n < 2; ++n) inav2.append(1, getbitu(payload.c_str(), 116 + n*8, 8)); // cerr< reserved1; for(int n=0; n < 5 ; ++n) reserved1.append(1, getbitu(payload.c_str(), 116 + 16 + n*8, 8)); NavMonMessage nmm; double t = utcFromGST(si.wn - 1024, si.towMsec / 1000.0); // cerr<set_gnsswn(si.wn - 1024); nmm.mutable_gi()->set_gnsstow(si.towMsec/1000.0); nmm.mutable_gi()->set_gnssid(2); nmm.mutable_gi()->set_gnsssv(si.sv - 70); nmm.mutable_gi()->set_contents((const char*)&inav2[0], inav2.size()); nmm.mutable_gi()->set_sigid(sepsig2ubx(sigid)); nmm.mutable_gi()->set_reserved1((const char*)&reserved1[0], reserved1.size()); ns.emitNMM( nmm); } else if(res.first.getID() == 5914) { // current time } else if(res.first.getID() == 4026) { // GLONASS } else if(res.first.getID() == 4017) { // GPS-CA } else if(res.first.getID() == 4018) { // GPS-L2C } else if(res.first.getID() == 4019) { // GPS raw L5 } else if(res.first.getID() == 4093) { // navic raw } else if(res.first.getID() == 4022) { // F/NAV auto str = res.first.getPayload(); struct SEPFnav { uint32_t towMsec; uint16_t wn; uint8_t sv; uint8_t crcPassed; uint8_t viterbiCount; uint8_t src; uint8_t ign1; uint8_t rxChannel; uint8_t navBits[32]; } __attribute__((packed)); SEPFnav sf; memcpy(&sf, str.c_str(), sizeof(sf)); int sigid = sf.src & 31; // cerr<<"tow "< payload; for(unsigned int i = 0 ; i < 8; ++i) { payload.append(1, sf.navBits[4 * i + 3]); payload.append(1, sf.navBits[4 * i + 2]); payload.append(1, sf.navBits[4 * i + 1]); payload.append(1, sf.navBits[4 * i + 0]); } NavMonMessage nmm; double t = utcFromGST(sf.wn - 1024, sf.towMsec / 1000.0); // cerr<set_gnsswn(sf.wn - 1024); nmm.mutable_gf()->set_gnsstow(sf.towMsec/1000.0); nmm.mutable_gf()->set_gnssid(2); nmm.mutable_gf()->set_gnsssv(sf.sv - 70); nmm.mutable_gf()->set_contents((const char*)&payload[0], payload.size()); nmm.mutable_gf()->set_sigid(sepsig2ubx(sigid)); ns.emitNMM( nmm); } else if(res.first.getIDBare() == 4047) { // BDSRaw } else if(res.first.getIDBare() == 4006) { auto str = res.first.getPayload(); struct PVTCartesian { uint32_t towMsec; uint16_t wn; uint8_t mode, error; double x, y, z; float undulation; float vx, vy, vz; } __attribute__((packed)); PVTCartesian pc; memcpy(&pc, str.c_str(), sizeof(pc)); NavMonMessage nmm; nmm.set_type(NavMonMessage::ObserverPositionType); nmm.set_localutcseconds(utcFromGST(pc.wn - 1024, pc.towMsec / 1000.0)); nmm.set_localutcnanoseconds(0); nmm.set_sourceid(g_srcid); nmm.mutable_op()->set_x(pc.x); nmm.mutable_op()->set_y(pc.y); nmm.mutable_op()->set_z(pc.z); nmm.mutable_op()->set_acc(3.14); ns.emitNMM( nmm); { NavMonMessage nmm; nmm.set_sourceid(g_srcid); nmm.set_localutcseconds(utcFromGST(pc.wn - 1024, pc.towMsec / 1000.0)); nmm.set_localutcnanoseconds(0); nmm.set_type(NavMonMessage::ObserverDetailsType); nmm.mutable_od()->set_vendor("Septentrio"); nmm.mutable_od()->set_hwversion("Mosaic"); nmm.mutable_od()->set_swversion(""); nmm.mutable_od()->set_serialno("3060601"); nmm.mutable_od()->set_modules(""); nmm.mutable_od()->set_clockoffsetns(0); nmm.mutable_od()->set_clockoffsetdriftns(0); nmm.mutable_od()->set_clockaccuracyns(0); nmm.mutable_od()->set_freqaccuracyps(0); nmm.mutable_od()->set_owner("Septentrio"); nmm.mutable_od()->set_remark(""); nmm.mutable_od()->set_recvgithash(g_gitHash); nmm.mutable_od()->set_uptime(time(0) - starttime); ns.emitNMM( nmm); } } else if(res.first.getIDBare() == 4024) { // GALRawCNAV struct SEPCnav { uint32_t towMsec; uint16_t wn; uint8_t sv; uint8_t crcPassed; uint8_t viterbiCount; uint8_t src; uint8_t ign1; uint8_t rxChannel; uint8_t navBits[64]; } __attribute__((packed)); SEPCnav sc; auto str = res.first.getPayload(); memcpy(&sc, str.c_str(), sizeof(sc)); int sigid = sc.src & 31; // cerr<<"C/NAV tow "< payload; for(unsigned int i = 0 ; i < 16; ++i) { payload.append(1, sc.navBits[4 * i + 3]); payload.append(1, sc.navBits[4 * i + 2]); payload.append(1, sc.navBits[4 * i + 1]); payload.append(1, sc.navBits[4 * i + 0]); } unsigned char crc_buff[58]={0}; unsigned int i; for (i=0; i< 462;i++) setbitu(crc_buff, 2+i, 1,getbitu(payload.c_str(),i, 1)); int calccrc=rtk_crc24q(crc_buff,58); int realcrc= getbitu(payload.c_str(), 14+448, 24); if (calccrc != realcrc) { cerr << "CRC mismatch, " << calccrc << " != " << realcrc <set_gnsswn(sc.wn - 1024); nmm.mutable_gc()->set_gnsstow(sc.towMsec/1000.0); nmm.mutable_gc()->set_gnssid(2); nmm.mutable_gc()->set_gnsssv(sc.sv - 70); nmm.mutable_gc()->set_contents((const char*)&payload[0], payload.size()); nmm.mutable_gc()->set_sigid(sepsig2ubx(sigid)); ns.emitNMM( nmm); } else if(res.first.getIDBare() == 4027) { auto str = res.first.getPayload(); struct MeasEpoch { uint32_t towMsec; uint16_t wn; uint8_t n1; uint8_t sb1len; uint8_t sb2len; uint8_t commonFlags; uint8_t clkJumps; uint8_t res1; } __attribute__((packed)); MeasEpoch me; memcpy(&me, str.c_str(), sizeof(me)); // cerr<<"Got "<<(int)me.n1<<" signal statuses, block1 "<<(int)me.sb1len<<", block2 "<<(int)me.sb2len< 70 && b1.sv <= 106)) { NavMonMessage nmm; nmm.set_sourceid(g_srcid); nmm.set_localutcseconds(utcFromGST(me.wn - 1024, me.towMsec / 1000.0)); nmm.set_localutcnanoseconds(0); nmm.set_type(NavMonMessage::ReceptionDataType); nmm.mutable_rd()->set_gnssid(b1.sv > 70 ? 2 : 0 ); nmm.mutable_rd()->set_gnsssv(b1.sv <= 37 ? b1.sv : b1.sv - 70); nmm.mutable_rd()->set_db(db); nmm.mutable_rd()->set_el(0); nmm.mutable_rd()->set_azi(0); nmm.mutable_rd()->set_prres(-1); nmm.mutable_rd()->set_qi(7); try { nmm.mutable_rd()->set_sigid(sepsig2ubx(sigid)); ns.emitNMM(nmm); } catch(...){} /* LSB of the pseudorange. The pseudorange expressed in meters is computed as follows: PR type1 [m] = ( CodeMSB *4294967296+ CodeLSB )*0.001 codeMSB hides in bits 0-3 of misc. */ } for(int m = 0 ; m < b1.n2; ++m) { Block2 b2; memcpy(&b2, str.c_str() + pos, sizeof(b2)); pos += me.sb2len; sigid = b2.type & 31; // cerr<<"\t sigid "<<(int)sigid<<" cn0 "; if(sigid==1 || sigid ==2) db= b2.cn0 *0.25; else db = b2.cn0 * 0.25 + 10; // cerr< 70 && b1.sv <= 106)) { NavMonMessage nmm; nmm.set_sourceid(g_srcid); nmm.set_localutcseconds(utcFromGST(me.wn - 1024, me.towMsec / 1000.0)); nmm.set_localutcnanoseconds(0); nmm.set_type(NavMonMessage::ReceptionDataType); nmm.mutable_rd()->set_gnssid(b1.sv > 70 ? 2 : 0 ); nmm.mutable_rd()->set_gnsssv(b1.sv <= 37 ? b1.sv : b1.sv - 70); nmm.mutable_rd()->set_db(db); nmm.mutable_rd()->set_el(0); nmm.mutable_rd()->set_azi(0); nmm.mutable_rd()->set_prres(0); nmm.mutable_rd()->set_qi(7); try { nmm.mutable_rd()->set_sigid(sepsig2ubx(sigid)); ns.emitNMM(nmm); }catch(...){} // might be unknown signal type } } } } else { if(!quiet) cerr<<"Unknown message "<