MDPHeader.cpp

Go to the documentation of this file.
00001 #pragma ident "$Id: MDPHeader.cpp 2921 2011-10-06 03:52:18Z ocibu $"
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 
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    // Set to zero for no debugging output
00065    // set to 1 to output text messages about decode/format/range errors
00066    // set to 2 to add a hex dump of those messages
00067    // set to 3+ to add the tossed bytes whether or not they are bad and informational
00068    //   messages about the state of the parsing
00069    int MDPHeader::debugLevel = 0;
00070 
00071    // set true to print a hex dump of every message to cout
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); // placeholder for the CRC
00095 
00096       // No, the CRC is not computed here. That needs to be done after
00097       // the body of the message has been encoded.
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       // only clear the this bit if this object isn't a leaf data member
00145       if (id==0)
00146          clearstate(crcbit);
00147    }
00148       
00149 
00150    //---------------------------------------------------------------------------
00151    // Compute and set the CRC in an encoded representation of this
00152    // object
00153    void MDPHeader::setCRC(string& str) const
00154       throw(FFStreamError)
00155    {
00156       // Here we make sure that the length of the string matches
00157       // the length in the header.
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       // clear out the spot for the crc
00167       str.replace(14, 2, 2, (char)0);
00168          
00169       // calculate the crc on the string
00170       crc = computeCRC((const unsigned char*)str.c_str(),
00171                        length, gpstk::BinUtils::CRCCCITT);
00172 
00173       // and place that value in the string
00174       unsigned short tmp = hostToNet(crc);
00175       str.replace(14, 2, (char*)&tmp, 2);
00176    } // MDPHeader::encode()
00177       
00178 
00179    //---------------------------------------------------------------------------
00180    // Compute the CRC of the string and set the crcbit appropriately.
00181    void MDPHeader::checkCRC(string str)
00182       throw()
00183    {
00184       // zero the CRC in the incoming string
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       // This crc will also be accepted until such time as it is no longer needed
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    } // MDPHeader::checkCRC()
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    } // MDPHeader::reallyPutRecord()
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       // first reset the data status
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       // then read in the rest of a header
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       // Need to make sure we have a 'sane' length before we continue reading
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       // Read in the body of the message
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       // Note that this will generate a bad_cast exception if it doesn't work.
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       // first, make sure the data is flagged bad.
00360       clear(fmtbit | lenbit | crcbit);
00361 
00362       // If we already have a reasonable header for the desired message,
00363       // then we can skip reading a new header. If a header is the desired
00364       // message, then always read a new header.
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       // We are done if this object is a MDPHeader
00398       if (reqId == 0)
00399       {
00400          setstate(crcbit|lenbit|fmtbit);
00401          return;
00402       }
00403 
00404       // read in the message body
00405       string body = readBody(stream);
00406       if (!stream || body.size() == 0)
00407          return;
00408 
00409       setstate(crcbit);
00410       checkCRC(stream.rawHeader+body);
00411       
00412          // Dump the body in the river if there's a crc error.
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    } // MDPHeader::reallyGetRecord()
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    }  // MDPHeader::dump()
00453 
00454 } // namespace gpstk

Generated on Wed Feb 8 03:31:00 2012 for GPS ToolKit Software Library by  doxygen 1.3.9.1