MDPHeader.cpp

Go to the documentation of this file.
00001 #pragma ident "$Id: MDPHeader.cpp 3201 2012-07-12 17:46:04Z snelsen $"
00002 
00003 //============================================================================
00004 //
00005 //  This file is part of GPSTk, the GPS Toolkit.
00006 //
00007 //  The GPSTk is free software; you can redistribute it and/or modify
00008 //  it under the terms of the GNU Lesser General Public License as published
00009 //  by the Free Software Foundation; either version 2.1 of the License, or
00010 //  any later version.
00011 //
00012 //  The GPSTk is distributed in the hope that it will be useful,
00013 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 //  GNU Lesser General Public License for more details.
00016 //
00017 //  You should have received a copy of the GNU Lesser General Public
00018 //  License along with GPSTk; if not, write to the Free Software Foundation,
00019 //  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
00020 //  
00021 //  Copyright 2004, The University of Texas at Austin
00022 //
00023 //============================================================================
00024 
00025 //============================================================================
00026 //
00027 //This software developed by Applied Research Laboratories at the University of
00028 //Texas at Austin, under contract to an agency or agencies within the U.S. 
00029 //Department of Defense. The U.S. Government retains all rights to use,
00030 //duplicate, distribute, disclose, or release this software. 
00031 //
00032 //Pursuant to DoD Directive 523024 
00033 //
00034 // DISTRIBUTION STATEMENT A: This software has been approved for public 
00035 //                           release, distribution is unlimited.
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    // Set to zero for no debugging output
00066    // set to 1 to output text messages about decode/format/range errors
00067    // set to 2 to add a hex dump of those messages
00068    // set to 3+ to add the tossed bytes whether or not they are bad and informational
00069    //   messages about the state of the parsing
00070    int MDPHeader::debugLevel = 0;
00071 
00072    // set true to print a hex dump of every message to cout
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); // placeholder for the CRC
00096 
00097       // No, the CRC is not computed here. That needs to be done after
00098       // the body of the message has been encoded.
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       // only clear the this bit if this object isn't a leaf data member
00146       if (id==0)
00147          clearstate(crcbit);
00148    }
00149       
00150 
00151    //---------------------------------------------------------------------------
00152    // Compute and set the CRC in an encoded representation of this
00153    // object
00154    void MDPHeader::setCRC(string& str) const
00155       throw(FFStreamError)
00156    {
00157       // Here we make sure that the length of the string matches
00158       // the length in the header.
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       // clear out the spot for the crc
00168       str.replace(14, 2, 2, (char)0);
00169          
00170       // calculate the crc on the string
00171       crc = computeCRC((const unsigned char*)str.c_str(),
00172                        length, gpstk::BinUtils::CRCCCITT);
00173 
00174       // and place that value in the string
00175       unsigned short tmp = hostToNet(crc);
00176       str.replace(14, 2, (char*)&tmp, 2);
00177    } // MDPHeader::encode()
00178       
00179 
00180    //---------------------------------------------------------------------------
00181    // Compute the CRC of the string and set the crcbit appropriately.
00182    void MDPHeader::checkCRC(string str)
00183       throw()
00184    {
00185       // zero the CRC in the incoming string
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       // This crc will also be accepted until such time as it is no longer needed
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    } // MDPHeader::checkCRC()
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    } // MDPHeader::reallyPutRecord()
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       // first reset the data status
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       // then read in the rest of a header
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       // Need to make sure we have a 'sane' length before we continue reading
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       // Read in the body of the message
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       // Note that this will generate a bad_cast exception if it doesn't work.
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       // first, make sure the data is flagged bad.
00361       clear(fmtbit | lenbit | crcbit);
00362 
00363       // If we already have a reasonable header for the desired message,
00364       // then we can skip reading a new header. If a header is the desired
00365       // message, then always read a new header.
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       // We are done if this object is a MDPHeader
00399       if (reqId == 0)
00400       {
00401          setstate(crcbit|lenbit|fmtbit);
00402          return;
00403       }
00404 
00405       // read in the message body
00406       string body = readBody(stream);
00407       if (!stream || body.size() == 0)
00408          return;
00409 
00410       setstate(crcbit);
00411       checkCRC(stream.rawHeader+body);
00412       
00413          // Dump the body in the river if there's a crc error.
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    } // MDPHeader::reallyGetRecord()
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    }  // MDPHeader::dump()
00454 
00455 } // namespace gpstk

Generated on Wed May 22 03:31:09 2013 for GPS ToolKit Software Library by  doxygen 1.3.9.1