00001 #pragma ident "$Id: MDPHeader.cpp 3201 2012-07-12 17:46:04Z snelsen $"
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include <cstring>
00040
00041 #include "StringUtils.hpp"
00042 #include "BinUtils.hpp"
00043 #include "TimeString.hpp"
00044 #include "GPSWeekSecond.hpp"
00045 #include "MDPHeader.hpp"
00046 #include "MDPStream.hpp"
00047
00048 using namespace std;
00049
00050 using gpstk::BinUtils::computeCRC;
00051 using gpstk::StringUtils::asString;
00052 using gpstk::StringUtils::d2x;
00053 using gpstk::StringUtils::int2x;
00054 using gpstk::BinUtils::netToHost;
00055 using gpstk::BinUtils::hostToNet;
00056 using gpstk::BinUtils::encodeVar;
00057 using gpstk::BinUtils::decodeVar;
00058
00059
00060 namespace gpstk
00061 {
00062 const uint16_t MDPHeader::myLength = 16;
00063 const uint16_t MDPHeader::frameWord = 0x9c9c;
00064
00065
00066
00067
00068
00069
00070 int MDPHeader::debugLevel = 0;
00071
00072
00073 bool MDPHeader::hexDump = false;
00074
00075
00076 string MDPHeader::encode() const
00077 throw()
00078 {
00079 short week=static_cast<GPSWeekSecond>(time).week;
00080 unsigned long sow100=static_cast<unsigned long>(
00081 0.5 + static_cast<GPSWeekSecond>(time).sow * 100);
00082 if (sow100==60480000)
00083 {
00084 sow100=0;
00085 week++;
00086 }
00087
00088 string str;
00089 str += encodeVar<uint16_t>(frameWord);
00090 str += encodeVar<uint16_t>(id);
00091 str += encodeVar<uint16_t>(length);
00092 str += encodeVar<uint16_t>(week);
00093 str += encodeVar<uint32_t>(sow100);
00094 str += encodeVar<uint16_t>(freshnessCount);
00095 str += encodeVar<uint16_t>(0);
00096
00097
00098
00099 return str;
00100 }
00101
00102
00103
00104 void MDPHeader::decode(string str)
00105 throw()
00106 {
00107 if (str.length() != myLength)
00108 return;
00109
00110 clearstate(lenbit);
00111
00112 unsigned short fw = decodeVar<uint16_t>(str);
00113 id = decodeVar<uint16_t>(str);
00114 length = decodeVar<uint16_t>(str);
00115 unsigned short week = decodeVar<uint16_t>(str);
00116 unsigned long sow100 = decodeVar<uint32_t>(str);
00117 freshnessCount = decodeVar<uint16_t>(str);
00118 crc = decodeVar<uint16_t>(str);
00119
00120 const unsigned long MaxSOW=604800;
00121 if (fw != frameWord ||
00122 sow100 > MaxSOW*100 || week>5000 ||
00123 length > 1024 ||
00124 id > 1024)
00125 {
00126 if (debugLevel>1)
00127 {
00128 cout << "Insane header:" << endl;
00129 dump(cout);
00130 }
00131 length=0;
00132 return;
00133 }
00134
00135 if (sow100 == MaxSOW*100)
00136 {
00137 week += 1;
00138 sow100 = 0;
00139 }
00140
00141 time=GPSWeekSecond(week, double(sow100)/100);
00142
00143 clearstate(fmtbit);
00144
00145
00146 if (id==0)
00147 clearstate(crcbit);
00148 }
00149
00150
00151
00152
00153
00154 void MDPHeader::setCRC(string& str) const
00155 throw(FFStreamError)
00156 {
00157
00158
00159 if(str.length() != length)
00160 {
00161 FFStreamError e("Message Length should be >= " +
00162 asString(length) + ". Was: " +
00163 asString(str.length()));
00164 GPSTK_THROW(e);
00165 }
00166
00167
00168 str.replace(14, 2, 2, (char)0);
00169
00170
00171 crc = computeCRC((const unsigned char*)str.c_str(),
00172 length, gpstk::BinUtils::CRCCCITT);
00173
00174
00175 unsigned short tmp = hostToNet(crc);
00176 str.replace(14, 2, (char*)&tmp, 2);
00177 }
00178
00179
00180
00181
00182 void MDPHeader::checkCRC(string str)
00183 throw()
00184 {
00185
00186 str.replace(14, 2, 2, (char)0);
00187
00188 unsigned short ccrc1 = computeCRC((const unsigned char*)str.c_str(),
00189 length, gpstk::BinUtils::CRCCCITT);
00190 if (ccrc1 == crc)
00191 {
00192 clearstate(crcbit);
00193 return;
00194 }
00195
00196
00197 uint16_t ccrc2 = computeCRC((const unsigned char*)str.c_str(),
00198 length, gpstk::BinUtils::CRC16);
00199 if (ccrc2 == crc)
00200 {
00201 clearstate(crcbit);
00202 return;
00203 }
00204
00205 if (debugLevel)
00206 cout << "Bad CRC. Received " << hex << crc
00207 << " computed " << ccrc1
00208 << " and " << ccrc2
00209 << ". Message ID=" << dec << id << endl;
00210 }
00211
00212
00213
00214 void MDPHeader::reallyPutRecord(FFStream& ffs) const
00215 throw(std::exception, gpstk::StringUtils::StringException,
00216 gpstk::FFStreamError)
00217 {
00218 if (typeid(*this) == typeid(MDPHeader))
00219 {
00220 gpstk::FFStreamError e("Directly writing an MDPHeader object to an"
00221 " FFStream is not supported.");
00222 GPSTK_THROW(e);
00223 }
00224
00225 MDPStream& stream = dynamic_cast<MDPStream&>(ffs);
00226
00227 string body = encode();
00228 length = body.length() + MDPHeader::myLength;
00229
00230 string str = MDPHeader::encode() + body;
00231 setCRC(str);
00232
00233 stream << str;
00234
00235 if (hexDump)
00236 {
00237 cout << endl;
00238 StringUtils::hexDumpData(cout, str);
00239 }
00240 }
00241
00242
00243
00244 void MDPHeader::readHeader(MDPStream& ffs)
00245 throw(FFStreamError, EndOfFile)
00246 {
00247 if (ffs.streamState == MDPStream::gotHeader)
00248 readBody(ffs);
00249
00250
00251 char buff[MDPHeader::myLength];
00252 ffs.streamState = MDPStream::outOfSync;
00253
00254 streampos p0 = ffs.tellg();
00255 uint16_t fw=0;
00256 const int maxTries=1024;
00257 uint16_t b2[maxTries];
00258 int i;
00259 for (i=0; ffs && i<maxTries; i++)
00260 {
00261 fw = ffs.getData<uint16_t>();
00262 b2[i] = fw;
00263 fw = netToHost(fw);
00264 if (fw!=MDPHeader::frameWord)
00265 continue;
00266 std::memcpy(buff, &fw, sizeof(fw));
00267 break;
00268 }
00269 streampos p1 = ffs.tellg();
00270
00271 if ((hexDump || debugLevel) && i>0)
00272 {
00273 string s((const char*)b2, i*2) ;
00274 cout << "Skipped " << s.size() << " bytes looking for frame word" << endl;
00275 if (debugLevel>1)
00276 StringUtils::hexDumpData(cout, s);
00277 }
00278
00279 if (fw != MDPHeader::frameWord)
00280 {
00281 if (debugLevel>1)
00282 cout << "Failed to find frame word between " << hex << p0
00283 << " to " << p1 << dec << endl;
00284 return;
00285 }
00286
00287 p1-=2;
00288 if (debugLevel>2)
00289 cout << "Found frame word at " << hex << p1 << dec << endl;
00290
00291
00292 ffs.getData(buff+2, MDPHeader::myLength-2);
00293 if (ffs.fail())
00294 return;
00295
00296 ffs.rawHeader = string(buff, MDPHeader::myLength);
00297 MDPHeader::decode(ffs.rawHeader);
00298 ffs.streamState = MDPStream::gotHeader;
00299 ffs.header = *this;
00300 ffs.headerCount++;
00301 if (debugLevel>2)
00302 {
00303 cout << "Got header at " << ffs.tellg()
00304 << " for id=" << id
00305 << " body, length=" << length << endl;
00306 StringUtils::hexDumpData(cout, ffs.rawHeader);
00307 }
00308 }
00309
00310
00311
00312 string MDPHeader::readBody(MDPStream& ffs)
00313 throw(FFStreamError, EndOfFile)
00314 {
00315 if (ffs.streamState != MDPStream::gotHeader)
00316 return string();
00317
00318
00319 if (length <= MDPHeader::myLength)
00320 {
00321 if (debugLevel)
00322 cout << "Received a runt message at " << hex << ffs.tellg()
00323 << ", ignoring body" << dec << endl;
00324 ffs.streamState = MDPStream::gotBody;
00325 return string();
00326 }
00327
00328
00329 const unsigned myLen = length - MDPHeader::myLength;
00330 char *buff = new char[myLen];
00331 if (debugLevel>2)
00332 cout << "Reading " << myLen
00333 << " bytes for message id " << id
00334 << " body at offset " << hex << ffs.tellg() << dec << endl;
00335 ffs.getData(buff, myLen);
00336 if (ffs.gcount() == myLen)
00337 ffs.streamState = MDPStream::gotBody;
00338 string str(buff, ffs.gcount());
00339 delete buff;
00340 return str;
00341 }
00342
00343
00344
00345 void MDPHeader::reallyGetRecord(FFStream& ffs)
00346 throw(std::exception, gpstk::StringUtils::StringException,
00347 gpstk::FFStreamError, gpstk::EndOfFile)
00348 {
00349
00350 MDPStream& stream=dynamic_cast<MDPStream&>(ffs);
00351
00352 unsigned reqId = id;
00353 if (typeid(*this) == typeid(MDPHeader))
00354 reqId = 0;
00355 if (debugLevel>2)
00356 cout << "Reading at " << stream.tellg()
00357 << " for id=" << reqId
00358 << " streamState=" << stream.streamState << endl;
00359
00360
00361 clear(fmtbit | lenbit | crcbit);
00362
00363
00364
00365
00366 bool haveDesiredHeader = stream.header.id == reqId
00367 && reqId != 0
00368 && stream.streamState == MDPStream::gotHeader
00369 && stream.header.length > 0;
00370 if (haveDesiredHeader)
00371 {
00372 *this = stream.header;
00373 if (debugLevel>2)
00374 {
00375 cout << "Using header from previous reallyGetRecord:" << endl;
00376 stream.header.dump(cout);
00377 }
00378 }
00379 else
00380 {
00381 while (!haveDesiredHeader && stream)
00382 {
00383 readHeader(stream);
00384 if (stream.streamState != MDPStream::gotHeader)
00385 break;
00386 haveDesiredHeader = (stream.header.id == reqId || reqId == 0)
00387 && stream.header.length > 0;
00388 }
00389 }
00390
00391 if (!haveDesiredHeader)
00392 {
00393 if (debugLevel)
00394 cout << "Failed to get header" << endl;
00395 return;
00396 }
00397
00398
00399 if (reqId == 0)
00400 {
00401 setstate(crcbit|lenbit|fmtbit);
00402 return;
00403 }
00404
00405
00406 string body = readBody(stream);
00407 if (!stream || body.size() == 0)
00408 return;
00409
00410 setstate(crcbit);
00411 checkCRC(stream.rawHeader+body);
00412
00413
00414 if (crcerr())
00415 return;
00416
00417 decode(body);
00418
00419 if (debugLevel && (rdstate() || stream.rdstate()))
00420 MDPHeader::dump(cout);
00421
00422 if (hexDump || (debugLevel>1 && rdstate()))
00423 {
00424 cout << "Record Number:" << stream.recordNumber << endl;
00425 StringUtils::hexDumpData(cout, stream.rawHeader+body);
00426 }
00427 }
00428
00429
00430
00431 void MDPHeader::dump(ostream& out) const
00432 throw()
00433 {
00434 ostringstream oss;
00435 oss << getName() << " :"
00436 << " ID:" << id
00437 << " Len:" << length
00438 << " Time:" << printTime(time,"%4Y/%03j/%02H:%02M:%05.2f")
00439 << " FC:" << hex << setfill('0') << setw(4) << freshnessCount
00440 << " crc:" << setw(4) << crc
00441 << " rdstate:" << rdstate();
00442
00443 if (crcerr())
00444 oss << "-crc";
00445 if (fmterr())
00446 oss << "-fmt";
00447 if (lenerr())
00448 oss << "-len";
00449 if (parerr())
00450 oss << "-par";
00451
00452 out << oss.str() << endl;
00453 }
00454
00455 }