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