1 //============================================================================== 2 // 3 // This file is part of GPSTk, the GPS Toolkit. 4 // 5 // The GPSTk is free software; you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published 7 // by the Free Software Foundation; either version 3.0 of the License, or 8 // any later version. 9 // 10 // The GPSTk is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public 16 // License along with GPSTk; if not, write to the Free Software Foundation, 17 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 18 // 19 // This software was developed by Applied Research Laboratories at the 20 // University of Texas at Austin. 21 // Copyright 2004-2020, The Board of Regents of The University of Texas System 22 // 23 //============================================================================== 24 25 //============================================================================== 26 // 27 // This software was developed by Applied Research Laboratories at the 28 // University of Texas at Austin, under contract to an agency or agencies 29 // within the U.S. Department of Defense. The U.S. Government retains all 30 // rights to use, duplicate, distribute, disclose, or release this software. 31 // 32 // Pursuant to DoD Directive 523024 33 // 34 // DISTRIBUTION STATEMENT A: This software has been approved for public 35 // release, distribution is unlimited. 36 // 37 //============================================================================== 38 39 #include "AshtechMBEN.hpp" 40 #include "AshtechStream.hpp" 41 #include "GNSSconstants.hpp" 42 43 using namespace std; 44 45 namespace gpstk 46 { 47 const char* AshtechMBEN::mpcId = "MPC"; 48 const char* AshtechMBEN::mcaId = "MCA"; 49 50 51 //--------------------------------------------------------------------------- reallyGetRecord(FFStream & ffs)52 void AshtechMBEN::reallyGetRecord(FFStream& ffs) 53 { 54 AshtechStream& stream=dynamic_cast<AshtechStream&>(ffs); 55 56 // make sure the object is reset before starting the search 57 clear(fmtbit | lenbit | crcbit); 58 string& rawData = stream.rawData; 59 60 // If this object doesn't have an id set yet, assume that the streams 61 // most recent read id is what we need to be 62 if (id == "" && rawData.size()>=11 && 63 rawData.substr(0,7) == preamble && 64 rawData[10]==',') 65 id = rawData.substr(7,3); 66 67 // If that didn't work, or this is object is not of the right type, 68 // then give up. 69 if (id == "" || !checkId(id)) 70 return; 71 72 readBody(stream); 73 } 74 75 76 //--------------------------------------------------------------------------- decode(const std::string & data)77 void AshtechMBEN::decode(const std::string& data) 78 { 79 using gpstk::BinUtils::decodeVar; 80 81 string str(data); 82 83 uint8_t csum=0; 84 if (str.length() == 108 || str.length()==52) 85 { 86 ascii=false; 87 header = str.substr(0,11); str.erase(0,11); 88 89 seq = decodeVar<uint16_t>(str); 90 left = decodeVar<uint8_t>(str); 91 svprn = decodeVar<uint8_t>(str); 92 el = decodeVar<uint8_t>(str); 93 az = decodeVar<uint8_t>(str); 94 chid = decodeVar<uint8_t>(str); 95 96 ca.decodeBIN(str); 97 98 if (id == mpcId) 99 { 100 p1.decodeBIN(str); 101 p2.decodeBIN(str); 102 } 103 104 checksum = decodeVar<uint8_t>(str); 105 106 clear(); 107 108 int end = data.size() - 3; 109 for (int i=11; i<end; i++) 110 csum ^= data[i]; 111 } 112 else 113 { 114 ascii=true; 115 header = str.substr(0,11); str.erase(0,11); 116 stringstream iss(str); 117 char c; 118 iss >> seq >> c 119 >> left >> c 120 >> svprn >> c 121 >> el >> c 122 >> az >> c 123 >> chid >> c; 124 125 ca.decodeASCII(iss); 126 127 if (id == mpcId) 128 { 129 p1.decodeASCII(iss); 130 p2.decodeASCII(iss); 131 } 132 133 iss >> checksum; 134 135 if (iss) 136 clear(); 137 138 int end=data.rfind(','); 139 for (int i=11; i<=end; i++) 140 csum ^= data[i]; 141 } 142 143 144 if (csum != checksum) 145 { 146 setstate(crcbit); 147 if (debugLevel) 148 cout << "checksum error, computed:" << hex << (uint16_t) csum 149 << " received:" << checksum << dec << endl; 150 } 151 152 if (seq>36000) 153 setstate(fmtbit); 154 } 155 156 157 //--------------------------------------------------------------------------- decodeASCII(stringstream & str)158 void AshtechMBEN::code_block::decodeASCII(stringstream& str) 159 { 160 char c; 161 str >> warning >> c 162 >> goodbad >> c 163 >> polarity_known>> c 164 >> ireg >> c 165 >> qa_phase >> c 166 >> full_phase >> c 167 >> raw_range >> c 168 >> doppler >> c 169 >> smoothing >> c 170 >> smooth_cnt >> c; 171 172 // The ashtech docs say this field should be in 1e-4 Hz 173 // The data sure doesn't look like it, however 174 //doppler *= 1e-4; 175 raw_range *= 1e-3; //convert ms to sec 176 } 177 178 179 //--------------------------------------------------------------------------- decodeBIN(string & str)180 void AshtechMBEN::code_block::decodeBIN(string& str) 181 { 182 using gpstk::BinUtils::decodeVar; 183 uint32_t smo; 184 warning = decodeVar<uint8_t>(str); 185 goodbad = decodeVar<uint8_t>(str); 186 polarity_known = decodeVar<uint8_t>(str); 187 ireg = decodeVar<uint8_t>(str); 188 qa_phase = decodeVar<uint8_t>(str); 189 full_phase = decodeVar<double>(str); 190 raw_range = decodeVar<double>(str); 191 doppler = decodeVar<int32_t>(str); 192 smo = decodeVar<uint32_t>(str); 193 194 doppler *= 1e-4; 195 smoothing = (smo & 0x800000 ? -1e-3 : 1e-3) * (smo & 0x7fffff); 196 smooth_cnt = (smo >> 24) & 0xff; 197 } 198 199 200 //--------------------------------------------------------------------------- dump(ostream & out) const201 void AshtechMBEN::code_block::dump(ostream& out) const 202 { 203 using gpstk::StringUtils::asString; 204 out << hex 205 << "warn:" << (int)warning 206 << " gb:" << (int)goodbad 207 << " pol:" << (int)polarity_known 208 << dec 209 << " ireg:" << (int)ireg 210 << " qa:" << (int)qa_phase 211 << " phase:" << asString(full_phase, 1) 212 << " range:" << asString(raw_range*1e3, 3) 213 << " doppler:" << doppler 214 << " smo:" << smoothing 215 << " smo_cnt:" << smooth_cnt; 216 } 217 218 219 //--------------------------------------------------------------------------- snr(float chipRate,float m) const220 float AshtechMBEN::code_block::snr(float chipRate, float m) const throw() 221 { 222 const float n = 20000; // number of samples in 1 ms 223 const float bw = 0.9 * chipRate; // equivalent noise bandwidth (Hz) 224 225 const float d = PI/(n*n*m*m*4.0); 226 float snr=0; 227 // Note that ireg is as output from the MBEN which is 0-255, not the 0-99 228 // as displayed on the front panel. 229 if (ireg) 230 { 231 snr = exp(((float)ireg)/25.0); 232 snr = snr*snr*bw*d; 233 snr = 10 * log10(snr); 234 } 235 236 return snr; 237 } 238 239 //--------------------------------------------------------------------------- dump(ostream & out) const240 void AshtechMBEN::dump(ostream& out) const throw() 241 { 242 ostringstream oss; 243 using gpstk::StringUtils::asString; 244 245 AshtechData::dump(oss); 246 oss << getName() << "1:" 247 << " seq:" << 0.05 * seq 248 << " left:" << (int)left 249 << " prn:" << (int)svprn 250 << " el:" << (int)el 251 << " az:" << (int)az 252 << " chid:" << (int)chid 253 << " " << (ascii?"ascii":"bin") 254 << endl; 255 256 oss << getName() << "2: ca "; 257 ca.dump(oss); 258 oss << endl; 259 260 if (id == mpcId) 261 { 262 oss << getName() << "3: p1 "; 263 p1.dump(oss); 264 oss << endl; 265 oss << getName() << "4: p2 "; 266 p2.dump(oss); 267 oss << endl; 268 } 269 out << oss.str() << flush; 270 } 271 } // namespace gpstk 272