<commit_before>#pragma ident "$Id$"

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published
//  by the Free Software Foundation; either version 2.1 of the License, or
//  any later version.
//
//  The GPSTk is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with GPSTk; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Copyright 2004, The University of Texas at Austin
//
//============================================================================

//============================================================================
//
//This software developed by Applied Research Laboratories at the University of
//Texas at Austin, under contract to an agency or agencies within the U.S.
//Department of Defense. The U.S. Government retains all rights to use,
//duplicate, distribute, disclose, or release this software.
//
//Pursuant to DoD Directive 523024
//
// DISTRIBUTION STATEMENT A: This software has been approved for public
//                           release, distribution is unlimited.
//
//=============================================================================

/** @file Translates between various similiar objects */

#include "StringUtils.hpp"
#include "RinexObsID.hpp"
#include "icd_200_constants.hpp"

#include "ObsUtils.hpp"

using namespace std;

namespace gpstk
{
   //---------------------------------------------------------------------------
   SvObsEpoch makeSvObsEpoch(const MDPObsEpoch& mdp) throw()
   {
      SvObsEpoch obs;
      MDPObsEpoch::ObsMap::const_iterator i;
      obs.svid = SatID(mdp.prn, SatID::systemGPS);
      obs.elevation = mdp.elevation;
      obs.elevation = mdp.azimuth;
      for (i=mdp.obs.begin(); i!=mdp.obs.end(); i++)
      {
         CarrierCode cc = i->first.first;
         RangeCode rc = i->first.second;
         const MDPObsEpoch::Observation& mdp_obs = i->second;

         ObsID::CarrierBand cb;
         ObsID::TrackingCode tc;

         switch(cc)
         {
            case ccL1: cb = ObsID::cbL1; break;
            case ccL2: cb = ObsID::cbL2; break;
            case ccL5: cb = ObsID::cbL5; break;
            default:   cb = ObsID::cbUnknown;
         }

         switch (rc)
         {
            case rcCA:       tc = ObsID::tcCA; break;
            case rcPcode:    tc = ObsID::tcP; break;
            case rcYcode:    tc = ObsID::tcY; break;
            case rcCodeless: tc = ObsID::tcW; break;
            case rcCM:       tc = ObsID::tcC2M; break;
            case rcCL:       tc = ObsID::tcC2L; break;
            case rcMcode1:   tc = ObsID::tcM; break;
            case rcMcode2:   tc = ObsID::tcM; break;
            case rcCMCL:     tc = ObsID::tcC2LM; break;
            default:         tc = ObsID::tcUnknown;
         }

         obs[ObsID(ObsID::otRange,   cb, tc)] = mdp_obs.pseudorange;
         obs[ObsID(ObsID::otPhase,   cb, tc)] = mdp_obs.phase;
         obs[ObsID(ObsID::otDoppler, cb, tc)] = mdp_obs.doppler;
         obs[ObsID(ObsID::otSNR,     cb, tc)] = mdp_obs.snr;
         obs[ObsID(ObsID::otLLI,     cb, tc)] = mdp_obs.lockCount;
      }
      return obs;
   }

   //---------------------------------------------------------------------------
   SvObsEpoch makeSvObsEpoch(const RinexObsData::RinexObsTypeMap& rotm) throw()
   {
      SvObsEpoch soe;

      RinexObsData::RinexObsTypeMap::const_iterator rotm_itr;
      for (rotm_itr = rotm.begin(); rotm_itr != rotm.end(); rotm_itr++)
      {
         const RinexObsHeader::RinexObsType& rot = rotm_itr->first;
         const RinexObsData::RinexDatum& rd = rotm_itr->second;
         RinexObsID oid(rot);
         soe[oid] = rd.data;
         if (rd.ssi>0)
         {
            oid.type = ObsID::otSSI;
            soe[oid] = rd.ssi;
         }
         if (rd.lli>0)
         {
            oid.type = ObsID::otLLI;
            soe[oid] = rd.lli;
         }
      }

      return soe;
   }

   //---------------------------------------------------------------------------
   ObsEpoch makeObsEpoch(const RinexObsData& rod) throw()
   {
      ObsEpoch oe;
      oe.time = rod.time;

      RinexObsData::RinexSatMap::const_iterator rsm_itr;
      for (rsm_itr = rod.obs.begin(); rsm_itr != rod.obs.end(); rsm_itr++)
      {
         const SatID svid(rsm_itr->first);
         const RinexObsData::RinexObsTypeMap& rotm = rsm_itr->second;
         oe[svid] = makeSvObsEpoch(rotm);
      }

      return oe;
   }

   //---------------------------------------------------------------------------
   ObsEpoch makeObsEpoch(const MDPEpoch& mdp) throw()
   {
      ObsEpoch oe;
      oe.time = mdp.begin()->second.time;

      for (MDPEpoch::const_iterator i=mdp.begin(); i!=mdp.end(); i++)
      {
         const MDPObsEpoch& moe = i->second;
         SatID svid(moe.prn, SatID::systemGPS);
         oe[svid] = makeSvObsEpoch(moe);
      }
      return oe;
   }

   //---------------------------------------------------------------------------
   WxObservation makeWxObs(const SMODFData& smod) throw()
   {
      WxObservation wx;

      wx.t = smod.time;

      if (smod.tempSource)
      {
         wx.temperature = smod.temp;
         wx.temperatureSource = WxObservation::obsWx;
      }
      else
         wx.temperatureSource = WxObservation::noWx;;

      if (smod.pressSource)
      {
         wx.pressure = smod.pressure;
         wx.pressureSource = WxObservation::obsWx;
      }
      else
         wx.pressureSource = WxObservation::noWx;;

      if (smod.humidSource)
      {
         wx.humidity = smod.humidity;
         wx.humiditySource = WxObservation::obsWx;
      }
      else
         wx.humiditySource = WxObservation::noWx;

      return wx;
   }

   //---------------------------------------------------------------------------
   void addMDPObservation(MDPObsEpoch& moe,
                          const AshtechMBEN::code_block& cb,
                          CarrierCode cc,
                          RangeCode rc,
                          const MDPObsEpoch& moe_hint) throw()
   {
      // fixup the range code to match what is indicated by the goodbad flag
      if (rc != rcCA)
         switch (cb.goodbad)
         {
            case 22: rc = rcPcode; break; //0x16
            case 24: rc = rcYcode; break; //0x18
            case 25: rc = rcCodeless; break; //0x19
         }

      float chipRate=PY_CHIP_FREQ;
      if (rc == rcCA)
         chipRate = CA_CHIP_FREQ;

      MDPObsEpoch::Observation obs;
      obs.carrier = cc;
      obs.range = rc;
      obs.snr = cb.snr(chipRate);
      obs.pseudorange = cb.raw_range * C_GPS_M;
      obs.phase = cb.full_phase;
      obs.doppler = -cb.doppler; // yeah, the Ashtech sign is backwards
      obs.bw=1;
      obs.lockCount = 0;

      if (moe_hint.haveObservation(cc, rc))
      {
         MDPObsEpoch::Observation obs_hint = moe_hint.getObservation(cc, rc);
         obs.bw = obs_hint.bw;

         // if any bits in 3-5, 7,8 are set we are are questionable
         if (!(cb.warning & ~0x23))
            obs.lockCount = obs_hint.lockCount+1;
      }

      moe.obs[MDPObsEpoch::ObsKey(cc, rc)] = obs;
   }

   //---------------------------------------------------------------------------
   MDPObsEpoch makeMDPObsEpoch(
      const AshtechMBEN& mben,
      const MDPObsEpoch& hint) throw()
   {
      MDPObsEpoch moe;

      // Get the full time from the hint and make the sow match the MBEN
      moe.time = hint.time;
      double sow1 = moe.time.GPSsecond();
      int sow2 = static_cast<int>(sow1/1800);
      double sow3 = static_cast<double>(sow2 * 1800);
      double sow_mben = 0.05 * mben.seq;
      double sow4 = sow3 + sow_mben;
      long week = moe.time.GPSfullweek();
      if (sow4 < sow1) // Assume that time only moves forward
         sow4 += 1800;
      while (sow4 >= DayTime::FULLWEEK)
      {
         sow4 -= DayTime::FULLWEEK;
         week += 1;
      }
      moe.time.setGPS(week, sow4);

      moe.numSVs = hint.numSVs;
      moe.channel = mben.chid;
      moe.prn = mben.svprn;
      moe.status = hint.status;
      moe.elevation = mben.el;
      moe.azimuth = mben.az;

      addMDPObservation(moe, mben.ca, ccL1, rcCA, hint);

      if (mben.id == AshtechMBEN::mpcId)
      {
         addMDPObservation(moe, mben.p1, ccL1, rcPcode, hint);
         addMDPObservation(moe, mben.p2, ccL2, rcPcode, hint);
      }
      return moe;
   }

   //---------------------------------------------------------------------------
   MDPPVTSolution makeMDPPVTSolution(
      const AshtechPBEN& pben,
      const unsigned week) throw()
   {
      MDPPVTSolution pvt;

      pvt.x[0] = pben.navx;
      pvt.x[1] = pben.navy;
      pvt.x[2] = pben.navz;
      pvt.dtime = pben.navt / C_GPS_M;
      pvt.v[0] = pben.navxdot;
      pvt.v[1] = pben.navydot;
      pvt.v[2] = pben.navzdot;
      pvt.ddtime = pben.navtdot / C_GPS_M;

      pvt.time.setGPS(week, pben.sow);
      pvt.timep = pvt.time + pvt.dtime;

      pvt.fom = pben.pdop;
      pvt.numSVs = (int)pben.numSV;
      pvt.pvtMode = 0;
      pvt.corrections = 0;

      return pvt;
   }

   //---------------------------------------------------------------------------
   MDPEpoch makeMDPEpoch(const ATSData& ats, const MDPEpoch& hint) throw()
   {
      MDPEpoch me;
      DayTime t0(DayTime::BEGINNING_OF_TIME);

      for (int i=0; i < ats.channels.size(); i++)
      {
         const ATSData::ChannelBlock& cb = ats.channels[i];
         short week = static_cast<short>(cb.absTime / DayTime::FULLWEEK);
         // It appears that week 0 is output before a channel really starts
         // tracking.
         if (week==0)
            continue;

         double sow = cb.absTime - week * DayTime::FULLWEEK;
         DayTime t(week, sow);
         if (i==0 || t0 == DayTime(DayTime::BEGINNING_OF_TIME))
            t0 = t;
         else if (std::abs(t - t0) > 0.1)
         {
            if (ats.debugLevel>1)
               cout << "Epoch with inconsistent times t:" << t
                    << ", t0:" << t0 << endl;
            continue;
         }

         MDPObsEpoch moe;

         moe.time = t;
         moe.prn = cb.svid.id;
         moe.status = 0;
         moe.elevation = 0;
         moe.azimuth = 0;
         moe.channel = i + 1;

         MDPObsEpoch moe_hint;
         MCIP mcip = hint.equal_range(cb.svid.id);

         MDPEpoch::const_iterator k;
         for (k=mcip.first; k != mcip.second; k++)
            if (k->second.channel == moe.channel)
            {
               moe_hint = k->second;
               break;
            }

         for (int j=0; j<ats.numSubChan; j++)
         {
            const ATSData::SubChannelBlock& scb=cb.subChannels[j];

            MDPObsEpoch::ObsKey obsKey;
            switch (j)
            {
               case 0: obsKey = MDPObsEpoch::ObsKey(ccL1, rcCA);     break;
               case 1: obsKey = MDPObsEpoch::ObsKey(ccL1, rcYcode);  break;
               case 2: obsKey = MDPObsEpoch::ObsKey(ccL2, rcYcode);  break;
               case 3: obsKey = MDPObsEpoch::ObsKey(ccL1, rcMcode1); break;
               case 4: obsKey = MDPObsEpoch::ObsKey(ccL2, rcMcode2); break;
            }

            MDPObsEpoch::Observation obs;
            obs.carrier = obsKey.first;
            obs.range = obsKey.second;
            obs.bw = 1;
            obs.snr = scb.cn0;
            obs.pseudorange = scb.pseudorange;
            obs.phase = scb.phase;
            obs.lockCount = 0;
            // bit0: loss of lock, bit1: code tracking, bit2 carrier tracking
            // bit3: gps time, bit4: tbd, bits5-7: Data rate
            // It appears that the M codes loss of lock bit doesn't work
            if (scb.flags & 0x1 && j<3)
               continue;  //Drop obs with loss of lock set
            else if (scb.cn0 < 20)
               continue;  //Drop obs with snr that indicates noise
            else if (moe_hint.haveObservation(obsKey))
            {
               MDPObsEpoch::Observation oh = moe_hint.getObservation(obsKey);
               obs.lockCount = oh.lockCount+1;
            }

            if (obs.carrier == ccL1)
               obs.doppler = scb.rangeRate ;
            else if (obs.carrier == ccL2)
               obs.doppler = scb.rangeRate;

            moe.obs[obsKey] = obs;
         }

         me.insert(pair<const int, MDPObsEpoch>(moe.prn, moe));
      }
      // now compute how many SVs were really tracked...
      int numSVs = me.size();
      MDPEpoch::iterator i;
      for (i=me.begin(); i != me.end(); i++)
         i->second.numSVs = numSVs;
      return me;
   }

} // namespace gpstk
<commit_msg>Breaking out the concept of a tracking counter from the LLI<commit_after>#pragma ident "$Id$"

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published
//  by the Free Software Foundation; either version 2.1 of the License, or
//  any later version.
//
//  The GPSTk is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with GPSTk; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Copyright 2004, The University of Texas at Austin
//
//============================================================================

//============================================================================
//
//This software developed by Applied Research Laboratories at the University of
//Texas at Austin, under contract to an agency or agencies within the U.S.
//Department of Defense. The U.S. Government retains all rights to use,
//duplicate, distribute, disclose, or release this software.
//
//Pursuant to DoD Directive 523024
//
// DISTRIBUTION STATEMENT A: This software has been approved for public
//                           release, distribution is unlimited.
//
//=============================================================================

/** @file Translates between various similiar objects */

#include "StringUtils.hpp"
#include "RinexObsID.hpp"
#include "icd_200_constants.hpp"

#include "ObsUtils.hpp"

using namespace std;

namespace gpstk
{
   //---------------------------------------------------------------------------
   SvObsEpoch makeSvObsEpoch(const MDPObsEpoch& mdp) throw()
   {
      SvObsEpoch obs;
      MDPObsEpoch::ObsMap::const_iterator i;
      obs.svid = SatID(mdp.prn, SatID::systemGPS);
      obs.elevation = mdp.elevation;
      obs.elevation = mdp.azimuth;
      for (i=mdp.obs.begin(); i!=mdp.obs.end(); i++)
      {
         CarrierCode cc = i->first.first;
         RangeCode rc = i->first.second;
         const MDPObsEpoch::Observation& mdp_obs = i->second;

         ObsID::CarrierBand cb;
         ObsID::TrackingCode tc;

         switch(cc)
         {
            case ccL1: cb = ObsID::cbL1; break;
            case ccL2: cb = ObsID::cbL2; break;
            case ccL5: cb = ObsID::cbL5; break;
            default:   cb = ObsID::cbUnknown;
         }

         switch (rc)
         {
            case rcCA:       tc = ObsID::tcCA; break;
            case rcPcode:    tc = ObsID::tcP; break;
            case rcYcode:    tc = ObsID::tcY; break;
            case rcCodeless: tc = ObsID::tcW; break;
            case rcCM:       tc = ObsID::tcC2M; break;
            case rcCL:       tc = ObsID::tcC2L; break;
            case rcMcode1:   tc = ObsID::tcM; break;
            case rcMcode2:   tc = ObsID::tcM; break;
            case rcCMCL:     tc = ObsID::tcC2LM; break;
            default:         tc = ObsID::tcUnknown;
         }

         obs[ObsID(ObsID::otRange,    cb, tc)] = mdp_obs.pseudorange;
         obs[ObsID(ObsID::otPhase,    cb, tc)] = mdp_obs.phase;
         obs[ObsID(ObsID::otDoppler,  cb, tc)] = mdp_obs.doppler;
         obs[ObsID(ObsID::otSNR,      cb, tc)] = mdp_obs.snr;
         obs[ObsID(ObsID::otTrackLen, cb, tc)] = mdp_obs.lockCount;
      }
      return obs;
   }

   //---------------------------------------------------------------------------
   SvObsEpoch makeSvObsEpoch(const RinexObsData::RinexObsTypeMap& rotm) throw()
   {
      SvObsEpoch soe;

      RinexObsData::RinexObsTypeMap::const_iterator rotm_itr;
      for (rotm_itr = rotm.begin(); rotm_itr != rotm.end(); rotm_itr++)
      {
         const RinexObsHeader::RinexObsType& rot = rotm_itr->first;
         const RinexObsData::RinexDatum& rd = rotm_itr->second;
         RinexObsID oid(rot);
         soe[oid] = rd.data;
         if (rd.ssi>0)
         {
            oid.type = ObsID::otSSI;
            soe[oid] = rd.ssi;
         }
         if (rd.lli>0)
         {
            oid.type = ObsID::otLLI;
            soe[oid] = rd.lli;
         }
      }

      return soe;
   }

   //---------------------------------------------------------------------------
   ObsEpoch makeObsEpoch(const RinexObsData& rod) throw()
   {
      ObsEpoch oe;
      oe.time = rod.time;

      RinexObsData::RinexSatMap::const_iterator rsm_itr;
      for (rsm_itr = rod.obs.begin(); rsm_itr != rod.obs.end(); rsm_itr++)
      {
         const SatID svid(rsm_itr->first);
         const RinexObsData::RinexObsTypeMap& rotm = rsm_itr->second;
         oe[svid] = makeSvObsEpoch(rotm);
      }

      return oe;
   }

   //---------------------------------------------------------------------------
   ObsEpoch makeObsEpoch(const MDPEpoch& mdp) throw()
   {
      ObsEpoch oe;
      oe.time = mdp.begin()->second.time;

      for (MDPEpoch::const_iterator i=mdp.begin(); i!=mdp.end(); i++)
      {
         const MDPObsEpoch& moe = i->second;
         SatID svid(moe.prn, SatID::systemGPS);
         oe[svid] = makeSvObsEpoch(moe);
      }
      return oe;
   }

   //---------------------------------------------------------------------------
   WxObservation makeWxObs(const SMODFData& smod) throw()
   {
      WxObservation wx;

      wx.t = smod.time;

      if (smod.tempSource)
      {
         wx.temperature = smod.temp;
         wx.temperatureSource = WxObservation::obsWx;
      }
      else
         wx.temperatureSource = WxObservation::noWx;;

      if (smod.pressSource)
      {
         wx.pressure = smod.pressure;
         wx.pressureSource = WxObservation::obsWx;
      }
      else
         wx.pressureSource = WxObservation::noWx;;

      if (smod.humidSource)
      {
         wx.humidity = smod.humidity;
         wx.humiditySource = WxObservation::obsWx;
      }
      else
         wx.humiditySource = WxObservation::noWx;

      return wx;
   }

   //---------------------------------------------------------------------------
   void addMDPObservation(MDPObsEpoch& moe,
                          const AshtechMBEN::code_block& cb,
                          CarrierCode cc,
                          RangeCode rc,
                          const MDPObsEpoch& moe_hint) throw()
   {
      // fixup the range code to match what is indicated by the goodbad flag
      if (rc != rcCA)
         switch (cb.goodbad)
         {
            case 22: rc = rcPcode; break; //0x16
            case 24: rc = rcYcode; break; //0x18
            case 25: rc = rcCodeless; break; //0x19
         }

      float chipRate=PY_CHIP_FREQ;
      if (rc == rcCA)
         chipRate = CA_CHIP_FREQ;

      MDPObsEpoch::Observation obs;
      obs.carrier = cc;
      obs.range = rc;
      obs.snr = cb.snr(chipRate);
      obs.pseudorange = cb.raw_range * C_GPS_M;
      obs.phase = cb.full_phase;
      obs.doppler = -cb.doppler; // yeah, the Ashtech sign is backwards
      obs.bw=1;
      obs.lockCount = 0;

      if (moe_hint.haveObservation(cc, rc))
      {
         MDPObsEpoch::Observation obs_hint = moe_hint.getObservation(cc, rc);
         obs.bw = obs_hint.bw;

         // if any bits in 3-5, 7,8 are set we are are questionable
         if (!(cb.warning & ~0x23))
            obs.lockCount = obs_hint.lockCount+1;
      }

      moe.obs[MDPObsEpoch::ObsKey(cc, rc)] = obs;
   }

   //---------------------------------------------------------------------------
   MDPObsEpoch makeMDPObsEpoch(
      const AshtechMBEN& mben,
      const MDPObsEpoch& hint) throw()
   {
      MDPObsEpoch moe;

      // Get the full time from the hint and make the sow match the MBEN
      moe.time = hint.time;
      double sow1 = moe.time.GPSsecond();
      int sow2 = static_cast<int>(sow1/1800);
      double sow3 = static_cast<double>(sow2 * 1800);
      double sow_mben = 0.05 * mben.seq;
      double sow4 = sow3 + sow_mben;
      long week = moe.time.GPSfullweek();
      if (sow4 < sow1) // Assume that time only moves forward
         sow4 += 1800;
      while (sow4 >= DayTime::FULLWEEK)
      {
         sow4 -= DayTime::FULLWEEK;
         week += 1;
      }
      moe.time.setGPS(week, sow4);

      moe.numSVs = hint.numSVs;
      moe.channel = mben.chid;
      moe.prn = mben.svprn;
      moe.status = hint.status;
      moe.elevation = mben.el;
      moe.azimuth = mben.az;

      addMDPObservation(moe, mben.ca, ccL1, rcCA, hint);

      if (mben.id == AshtechMBEN::mpcId)
      {
         addMDPObservation(moe, mben.p1, ccL1, rcPcode, hint);
         addMDPObservation(moe, mben.p2, ccL2, rcPcode, hint);
      }
      return moe;
   }

   //---------------------------------------------------------------------------
   MDPPVTSolution makeMDPPVTSolution(
      const AshtechPBEN& pben,
      const unsigned week) throw()
   {
      MDPPVTSolution pvt;

      pvt.x[0] = pben.navx;
      pvt.x[1] = pben.navy;
      pvt.x[2] = pben.navz;
      pvt.dtime = pben.navt / C_GPS_M;
      pvt.v[0] = pben.navxdot;
      pvt.v[1] = pben.navydot;
      pvt.v[2] = pben.navzdot;
      pvt.ddtime = pben.navtdot / C_GPS_M;

      pvt.time.setGPS(week, pben.sow);
      pvt.timep = pvt.time + pvt.dtime;

      pvt.fom = pben.pdop;
      pvt.numSVs = (int)pben.numSV;
      pvt.pvtMode = 0;
      pvt.corrections = 0;

      return pvt;
   }

   //---------------------------------------------------------------------------
   MDPEpoch makeMDPEpoch(const ATSData& ats, const MDPEpoch& hint) throw()
   {
      MDPEpoch me;
      DayTime t0(DayTime::BEGINNING_OF_TIME);

      for (int i=0; i < ats.channels.size(); i++)
      {
         const ATSData::ChannelBlock& cb = ats.channels[i];
         short week = static_cast<short>(cb.absTime / DayTime::FULLWEEK);
         // It appears that week 0 is output before a channel really starts
         // tracking.
         if (week==0)
            continue;

         double sow = cb.absTime - week * DayTime::FULLWEEK;
         DayTime t(week, sow);
         if (i==0 || t0 == DayTime(DayTime::BEGINNING_OF_TIME))
            t0 = t;
         else if (std::abs(t - t0) > 0.1)
         {
            if (ats.debugLevel>1)
               cout << "Epoch with inconsistent times t:" << t
                    << ", t0:" << t0 << endl;
            continue;
         }

         MDPObsEpoch moe;

         moe.time = t;
         moe.prn = cb.svid.id;
         moe.status = 0;
         moe.elevation = 0;
         moe.azimuth = 0;
         moe.channel = i + 1;

         MDPObsEpoch moe_hint;
         MCIP mcip = hint.equal_range(cb.svid.id);

         MDPEpoch::const_iterator k;
         for (k=mcip.first; k != mcip.second; k++)
            if (k->second.channel == moe.channel)
            {
               moe_hint = k->second;
               break;
            }

         for (int j=0; j<ats.numSubChan; j++)
         {
            const ATSData::SubChannelBlock& scb=cb.subChannels[j];

            MDPObsEpoch::ObsKey obsKey;
            switch (j)
            {
               case 0: obsKey = MDPObsEpoch::ObsKey(ccL1, rcCA);     break;
               case 1: obsKey = MDPObsEpoch::ObsKey(ccL1, rcYcode);  break;
               case 2: obsKey = MDPObsEpoch::ObsKey(ccL2, rcYcode);  break;
               case 3: obsKey = MDPObsEpoch::ObsKey(ccL1, rcMcode1); break;
               case 4: obsKey = MDPObsEpoch::ObsKey(ccL2, rcMcode2); break;
            }

            MDPObsEpoch::Observation obs;
            obs.carrier = obsKey.first;
            obs.range = obsKey.second;
            obs.bw = 1;
            obs.snr = scb.cn0;
            obs.pseudorange = scb.pseudorange;
            obs.phase = scb.phase;
            obs.lockCount = 0;
            // bit0: loss of lock, bit1: code tracking, bit2 carrier tracking
            // bit3: gps time, bit4: tbd, bits5-7: Data rate
            // It appears that the M codes loss of lock bit doesn't work
            if (scb.flags & 0x1 && j<3)
               continue;  //Drop obs with loss of lock set
            else if (scb.cn0 < 20)
               continue;  //Drop obs with snr that indicates noise
            else if (moe_hint.haveObservation(obsKey))
            {
               MDPObsEpoch::Observation oh = moe_hint.getObservation(obsKey);
               obs.lockCount = oh.lockCount+1;
            }

            if (obs.carrier == ccL1)
               obs.doppler = scb.rangeRate ;
            else if (obs.carrier == ccL2)
               obs.doppler = scb.rangeRate;

            moe.obs[obsKey] = obs;
         }

         me.insert(pair<const int, MDPObsEpoch>(moe.prn, moe));
      }
      // now compute how many SVs were really tracked...
      int numSVs = me.size();
      MDPEpoch::iterator i;
      for (i=me.begin(); i != me.end(); i++)
         i->second.numSVs = numSVs;
      return me;
   }

} // namespace gpstk
<|endoftext|>


<commit_before>#include "cmm_socket_receiver.h"
#include "cmm_socket_sender.h"
#include <pthread.h>
#include "debug.h"
#include <vector>
using std::vector;

class ReadyIROB {
  public:
    bool operator()(PendingIROB *pi) {
        assert(pi);
        PendingReceiverIROB *pirob = static_cast<PendingReceiverIROB*>(pi);
        assert(pirob);
        return (pirob->is_complete() && pirob->is_released());
    }
};

CMMSocketReceiver::CMMSocketReceiver(CMMSocketImpl *sk_)
    : sk(sk_)
{
    handle(CMM_CONTROL_MSG_BEGIN_IROB, this,
           &CMMSocketReceiver::do_begin_irob);
    handle(CMM_CONTROL_MSG_END_IROB, this, &CMMSocketReceiver::do_end_irob);
    handle(CMM_CONTROL_MSG_IROB_CHUNK, this,
           &CMMSocketReceiver::do_irob_chunk);
    handle(CMM_CONTROL_MSG_NEW_INTERFACE, this,
           &CMMSocketReceiver::do_new_interface);
    handle(CMM_CONTROL_MSG_DOWN_INTERFACE, this,
           &CMMSocketReceiver::do_down_interface);
    handle(CMM_CONTROL_MSG_ACK, this, &CMMSocketReceiver::do_ack);
}

CMMSocketReceiver::~CMMSocketReceiver()
{
    PendingIROBHash::accessor ac;
    while (pending_irobs.any(ac)) {
        PendingIROB *victim = ac->second;
        pending_irobs.erase(ac);
        delete victim;
        ac.release();
    }
}

void
CMMSocketReceiver::dispatch(struct CMMSocketControlHdr hdr)
{
    dbgprintf("Got request\n%s\n", hdr.describe().c_str());
    CMMSocketScheduler<struct CMMSocketControlHdr>::dispatch(hdr);
}

void
CMMSocketReceiver::do_begin_irob(struct CMMSocketControlHdr hdr)
{
    assert(ntohs(hdr.type) == CMM_CONTROL_MSG_BEGIN_IROB);
    if (hdr.op.begin_irob.numdeps > 0) {
        assert(hdr.op.begin_irob.deps);
    }

    PendingIROB *pirob = new PendingReceiverIROB(hdr.op.begin_irob);
    PendingIROBHash::accessor ac;
    if (!pending_irobs.insert(ac, pirob)) {
        delete pirob;
        throw Exception::make("Tried to begin IROB that already exists",
                                  hdr);
    }

    if (hdr.op.begin_irob.numdeps > 0) {
        delete [] hdr.op.begin_irob.deps;
    }
}

void
CMMSocketReceiver::do_end_irob(struct CMMSocketControlHdr hdr)
{
    assert(ntohs(hdr.type) == CMM_CONTROL_MSG_END_IROB);
    PendingIROBHash::accessor ac;
    irob_id_t id = ntohl(hdr.op.end_irob.id);
    if (!pending_irobs.find(ac, id)) {
        if (pending_irobs.past_irob_exists(id)) {
            throw Exception::make("Tried to end committed IROB", hdr);
        } else {
            throw Exception::make("Tried to end nonexistent IROB", hdr);
        }
    }
    PendingIROB *pirob = ac->second;
    assert(pirob);
    if (!pirob->finish()) {
        throw Exception::make("Tried to end already-done IROB", hdr);
    }

    PendingReceiverIROB *prirob = static_cast<PendingReceiverIROB*>(pirob);
    pending_irobs.release_if_ready(prirob, ReadyIROB());
}

void
CMMSocketReceiver::do_irob_chunk(struct CMMSocketControlHdr hdr)
{
    assert(ntohs(hdr.type) == CMM_CONTROL_MSG_IROB_CHUNK);
    PendingIROBHash::accessor ac;
    irob_id_t id = ntohl(hdr.op.irob_chunk.id);
    if (!pending_irobs.find(ac, id)) {
        if (pending_irobs.past_irob_exists(id)) {
            throw Exception::make("Tried to add to committed IROB", hdr);
        } else {
            throw Exception::make("Tried to add to nonexistent IROB", hdr);
        }
    }
    struct irob_chunk_data chunk;
    chunk.id = id;
    chunk.seqno = ntohl(hdr.op.irob_chunk.seqno);
    chunk.datalen = ntohl(hdr.op.irob_chunk.datalen);
    chunk.data = hdr.op.irob_chunk.data;

    PendingIROB *pirob = ac->second;
    assert(pirob);
    if (!pirob->add_chunk(chunk)) {
        throw Exception::make("Tried to add to completed IROB", hdr);
    } else {
	dbgprintf("Successfully added chunk %d to IROB %d\n",
		  chunk.seqno, id);
    }
}

void
CMMSocketReceiver::do_new_interface(struct CMMSocketControlHdr hdr)
{
    assert(ntohs(hdr.type) == CMM_CONTROL_MSG_NEW_INTERFACE);
    struct net_interface iface = {hdr.op.new_interface.ip_addr,
                                  hdr.op.new_interface.labels};
    sk->setup(iface, false);
}

void
CMMSocketReceiver::do_down_interface(struct CMMSocketControlHdr hdr)
{
    assert(ntohs(hdr.type) == CMM_CONTROL_MSG_DOWN_INTERFACE);
    struct net_interface iface = {hdr.op.down_interface.ip_addr};
    sk->teardown(iface, false);
}

void
CMMSocketReceiver::do_ack(struct CMMSocketControlHdr hdr)
{
    assert(ntohs(hdr.type) == CMM_CONTROL_MSG_ACK);
    sk->sendr->ack_received(ntohl(hdr.op.ack.id), ntohl(hdr.op.ack.seqno));
}

/* This is where all the scheduling logic happens.
 * This function decides how to pass IROB data to the application.
 *
 * Additionally, this function is the only place we need
 * to worry about race conditions with the Receiver thread.
 * Thus, the locking discipline of that thread will be informed
 * by whatever reads and writes are necessary here.
 *
 * Initial stab at requirements:
 *   This thread definitely needs to read from the pending_irobs
 *   data structure, to figure out what data to pass to the
 *   application.  It also needs to update this data structure
 *   and the past_irobs set as IROBs are committed.
 * Thought: we could make this function read-only by using the
 *   msg_queue to cause the Receiver thread to do any needed updates.
 */
/* TODO: nonblocking mode */
ssize_t
CMMSocketReceiver::recv(void *bufp, size_t len, int flags, u_long *recv_labels)
{
    vector<PendingReceiverIROB *> pirobs;
    char *buf = (char*)bufp;

    ssize_t bytes_ready = 0;
    while ((size_t)bytes_ready < len) {
        PendingReceiverIROB *pirob = pending_irobs.get_ready_irob();
        assert(pirob); /* XXX: nonblocking version could return NULL */

        /* after the IROB is returned here, no other thread will
         * unsafely modify it.
         * XXX: this will not be true if we allow get_next_irob
         * to return released, incomplete IROBs.
         * We could fix that by simply having a sentinel chunk
         * on the concurrent_queue of chunks. */

        assert(pirob->is_released());
        assert(pirob->is_complete()); /* XXX: see get_next_irob */

        ssize_t bytes = pirob->numbytes();
        assert(bytes > 0);
        bytes_ready += bytes;

        pirobs.push_back(pirob);

        if (!pirob->is_complete()) {
            break;
        }
    }

    ssize_t bytes_passed = 0;
    bool partial_irob = false;
    for (size_t i = 0; i < pirobs.size(); i++) {
        PendingIROBHash::accessor ac;
        PendingReceiverIROB *pirob = pirobs[i];
        if (!pending_irobs.find(ac, pirob->id)) {
            assert(0);
        }
        assert(pirob == ac->second);
        if (i == 0) {
            if (recv_labels) {
                *recv_labels = pirob->send_labels;
            }
        }

        bytes_passed += pirob->read_data(buf + bytes_passed,
                                         len - bytes_passed);
        if (pirob->is_complete() && pirob->numbytes() == 0) {
            pending_irobs.erase(ac);
            pending_irobs.release_dependents(pirob, ReadyIROB());
            delete pirob;
        } else {
            if (!pirob->is_complete()) {
                /* This should still be the last one in the list,
                 * since it MUST finish before any IROB can be
                 * passed to the application. */
            }
            /* this should be true for at most the last IROB
             * in the vector */
            assert(!partial_irob);
            partial_irob = true;
            pending_irobs.partially_read(pirob);
        }
    }
    return bytes_passed;
}
<commit_msg>corrected receiver side to use PendingReceiverIROB::add_chunk.  sigh.<commit_after>#include "cmm_socket_receiver.h"
#include "cmm_socket_sender.h"
#include <pthread.h>
#include "debug.h"
#include <vector>
using std::vector;

class ReadyIROB {
  public:
    bool operator()(PendingIROB *pi) {
        assert(pi);
        PendingReceiverIROB *pirob = static_cast<PendingReceiverIROB*>(pi);
        assert(pirob);
        return (pirob->is_complete() && pirob->is_released());
    }
};

CMMSocketReceiver::CMMSocketReceiver(CMMSocketImpl *sk_)
    : sk(sk_)
{
    handle(CMM_CONTROL_MSG_BEGIN_IROB, this,
           &CMMSocketReceiver::do_begin_irob);
    handle(CMM_CONTROL_MSG_END_IROB, this, &CMMSocketReceiver::do_end_irob);
    handle(CMM_CONTROL_MSG_IROB_CHUNK, this,
           &CMMSocketReceiver::do_irob_chunk);
    handle(CMM_CONTROL_MSG_NEW_INTERFACE, this,
           &CMMSocketReceiver::do_new_interface);
    handle(CMM_CONTROL_MSG_DOWN_INTERFACE, this,
           &CMMSocketReceiver::do_down_interface);
    handle(CMM_CONTROL_MSG_ACK, this, &CMMSocketReceiver::do_ack);
}

CMMSocketReceiver::~CMMSocketReceiver()
{
    PendingIROBHash::accessor ac;
    while (pending_irobs.any(ac)) {
        PendingIROB *victim = ac->second;
        pending_irobs.erase(ac);
        delete victim;
        ac.release();
    }
}

void
CMMSocketReceiver::dispatch(struct CMMSocketControlHdr hdr)
{
    dbgprintf("Got request\n%s\n", hdr.describe().c_str());
    CMMSocketScheduler<struct CMMSocketControlHdr>::dispatch(hdr);
}

void
CMMSocketReceiver::do_begin_irob(struct CMMSocketControlHdr hdr)
{
    assert(ntohs(hdr.type) == CMM_CONTROL_MSG_BEGIN_IROB);
    if (hdr.op.begin_irob.numdeps > 0) {
        assert(hdr.op.begin_irob.deps);
    }

    PendingIROB *pirob = new PendingReceiverIROB(hdr.op.begin_irob);
    PendingIROBHash::accessor ac;
    if (!pending_irobs.insert(ac, pirob)) {
        delete pirob;
        throw Exception::make("Tried to begin IROB that already exists",
                                  hdr);
    }

    if (hdr.op.begin_irob.numdeps > 0) {
        delete [] hdr.op.begin_irob.deps;
    }
}

void
CMMSocketReceiver::do_end_irob(struct CMMSocketControlHdr hdr)
{
    assert(ntohs(hdr.type) == CMM_CONTROL_MSG_END_IROB);
    PendingIROBHash::accessor ac;
    irob_id_t id = ntohl(hdr.op.end_irob.id);
    if (!pending_irobs.find(ac, id)) {
        if (pending_irobs.past_irob_exists(id)) {
            throw Exception::make("Tried to end committed IROB", hdr);
        } else {
            throw Exception::make("Tried to end nonexistent IROB", hdr);
        }
    }
    PendingIROB *pirob = ac->second;
    assert(pirob);
    if (!pirob->finish()) {
        throw Exception::make("Tried to end already-done IROB", hdr);
    }

    PendingReceiverIROB *prirob = static_cast<PendingReceiverIROB*>(pirob);
    pending_irobs.release_if_ready(prirob, ReadyIROB());
}

void
CMMSocketReceiver::do_irob_chunk(struct CMMSocketControlHdr hdr)
{
    assert(ntohs(hdr.type) == CMM_CONTROL_MSG_IROB_CHUNK);
    PendingIROBHash::accessor ac;
    irob_id_t id = ntohl(hdr.op.irob_chunk.id);
    if (!pending_irobs.find(ac, id)) {
        if (pending_irobs.past_irob_exists(id)) {
            throw Exception::make("Tried to add to committed IROB", hdr);
        } else {
            throw Exception::make("Tried to add to nonexistent IROB", hdr);
        }
    }
    struct irob_chunk_data chunk;
    chunk.id = id;
    chunk.seqno = ntohl(hdr.op.irob_chunk.seqno);
    chunk.datalen = ntohl(hdr.op.irob_chunk.datalen);
    chunk.data = hdr.op.irob_chunk.data;

    PendingIROB *pirob = ac->second;
    assert(pirob);
    PendingReceiverIROB *prirob = static_cast<PendingReceiverIROB*>(pirob);
    assert(prirob);
    if (!pirob->add_chunk(chunk)) {
        throw Exception::make("Tried to add to completed IROB", hdr);
    } else {
	dbgprintf("Successfully added chunk %d to IROB %d\n",
		  chunk.seqno, id);
    }
}

void
CMMSocketReceiver::do_new_interface(struct CMMSocketControlHdr hdr)
{
    assert(ntohs(hdr.type) == CMM_CONTROL_MSG_NEW_INTERFACE);
    struct net_interface iface = {hdr.op.new_interface.ip_addr,
                                  hdr.op.new_interface.labels};
    sk->setup(iface, false);
}

void
CMMSocketReceiver::do_down_interface(struct CMMSocketControlHdr hdr)
{
    assert(ntohs(hdr.type) == CMM_CONTROL_MSG_DOWN_INTERFACE);
    struct net_interface iface = {hdr.op.down_interface.ip_addr};
    sk->teardown(iface, false);
}

void
CMMSocketReceiver::do_ack(struct CMMSocketControlHdr hdr)
{
    assert(ntohs(hdr.type) == CMM_CONTROL_MSG_ACK);
    sk->sendr->ack_received(ntohl(hdr.op.ack.id), ntohl(hdr.op.ack.seqno));
}

/* This is where all the scheduling logic happens.
 * This function decides how to pass IROB data to the application.
 *
 * Additionally, this function is the only place we need
 * to worry about race conditions with the Receiver thread.
 * Thus, the locking discipline of that thread will be informed
 * by whatever reads and writes are necessary here.
 *
 * Initial stab at requirements:
 *   This thread definitely needs to read from the pending_irobs
 *   data structure, to figure out what data to pass to the
 *   application.  It also needs to update this data structure
 *   and the past_irobs set as IROBs are committed.
 * Thought: we could make this function read-only by using the
 *   msg_queue to cause the Receiver thread to do any needed updates.
 */
/* TODO: nonblocking mode */
ssize_t
CMMSocketReceiver::recv(void *bufp, size_t len, int flags, u_long *recv_labels)
{
    vector<PendingReceiverIROB *> pirobs;
    char *buf = (char*)bufp;

    ssize_t bytes_ready = 0;
    while ((size_t)bytes_ready < len) {
        PendingReceiverIROB *pirob = pending_irobs.get_ready_irob();
        assert(pirob); /* XXX: nonblocking version could return NULL */

        /* after the IROB is returned here, no other thread will
         * unsafely modify it.
         * XXX: this will not be true if we allow get_next_irob
         * to return released, incomplete IROBs.
         * We could fix that by simply having a sentinel chunk
         * on the concurrent_queue of chunks. */

        assert(pirob->is_released());
        assert(pirob->is_complete()); /* XXX: see get_next_irob */

        ssize_t bytes = pirob->numbytes();
        assert(bytes > 0);
        bytes_ready += bytes;

        pirobs.push_back(pirob);

        if (!pirob->is_complete()) {
            break;
        }
    }

    ssize_t bytes_passed = 0;
    bool partial_irob = false;
    for (size_t i = 0; i < pirobs.size(); i++) {
        PendingIROBHash::accessor ac;
        PendingReceiverIROB *pirob = pirobs[i];
        if (!pending_irobs.find(ac, pirob->id)) {
            assert(0);
        }
        assert(pirob == ac->second);
        if (i == 0) {
            if (recv_labels) {
                *recv_labels = pirob->send_labels;
            }
        }

        bytes_passed += pirob->read_data(buf + bytes_passed,
                                         len - bytes_passed);
        if (pirob->is_complete() && pirob->numbytes() == 0) {
            pending_irobs.erase(ac);
            pending_irobs.release_dependents(pirob, ReadyIROB());
            delete pirob;
        } else {
            if (!pirob->is_complete()) {
                /* This should still be the last one in the list,
                 * since it MUST finish before any IROB can be
                 * passed to the application. */
            }
            /* this should be true for at most the last IROB
             * in the vector */
            assert(!partial_irob);
            partial_irob = true;
            pending_irobs.partially_read(pirob);
        }
    }
    return bytes_passed;
}
<|endoftext|>


<commit_before><commit_msg>main: Teardown Messaging only after deleting environment.<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (C) 2004-2013 ZNC, see the NOTICE file for details.
 * Copyright (C) 2013 Rasmus Eskola <fruitiex@gmail.com>
 * based on sample.cpp sample module code
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <znc/FileUtils.h>
#include <znc/Client.h>
#include <znc/Chan.h>
#include <znc/User.h>
#include <znc/IRCNetwork.h>
#include <znc/Modules.h>
#include <dirent.h>
#include <vector>
#include <algorithm>

class CBacklogMod : public CModule {
public:
	MODCONSTRUCTOR(CBacklogMod) {}

	virtual bool OnLoad(const CString& sArgs, CString& sMessage);
	virtual ~CBacklogMod();
	virtual void OnModCommand(const CString& sCommand);
	bool inChan(const CString& Chan);

private:
	CString			LogPath;
};

bool CBacklogMod::OnLoad(const CString& sArgs, CString& sMessage) {
	LogPath = sArgs;

	if(LogPath.empty()) {
		LogPath = GetNV("LogPath");
		if(LogPath.empty()) {
			// TODO: guess logpath?
			PutModule("LogPath is empty, set it with the LogPath command");
			PutModule("Usage: LogPath <path> (use keywords $USER, $NETWORK, $WINDOW)");
		}
	} else {
		SetNV("LogPath", LogPath);
		PutModule("LogPath set to: " + LogPath);
	}
	return true;
}

CBacklogMod::~CBacklogMod() {
}

void CBacklogMod::OnModCommand(const CString& sCommand) {
	if (sCommand.Token(0).CaseCmp("help") == 0) {
		// TODO: proper help text, look how AddHelpCommand() does it in other ZNC code
		PutModule("Help");
		return;
	}
	else if (sCommand.Token(0).CaseCmp("logpath") == 0) {
		if(sCommand.Token(1, true).empty()) {
			PutModule("Usage: LogPath <path> (use keywords $USER, $NETWORK, $WINDOW)");
			PutModule("Current LogPath is set to: " + GetNV("LogPath"));
			return;
		}

		LogPath = sCommand.Token(1, true);
		SetNV("LogPath", LogPath);
		PutModule("LogPath set to: " + LogPath);
		return;
	}

	// TODO: handle these differently depending on how the module was loaded
	CString User = (m_pUser ? m_pUser->GetUserName() : "UNKNOWN");
	CString Network = (m_pNetwork ? m_pNetwork->GetName() : "znc");
	CString Channel = sCommand.Token(0);

	int printedLines = 0;
	int reqLines = sCommand.Token(1).ToInt();
	if(reqLines <= 0) {
		reqLines = 150;
	}

	CString Path = LogPath.substr(); // make copy
	Path.Replace("$NETWORK", Network);
	Path.Replace("$WINDOW", Channel);
	Path.Replace("$USER", User);

	CString DirPath = Path.substr(0, Path.find_last_of("/"));
	CString FilePath;

	std::vector<CString> FileList;
	std::vector<CString> LinesToPrint;

	// gather list of all log files for requested channel/window
	DIR *dir;
	struct dirent *ent;
	if ((dir = opendir (DirPath.c_str())) != NULL) {
		while ((ent = readdir (dir)) != NULL) {
			FilePath = DirPath + "/" + ent->d_name;
			//PutModule("DEBUG: " + FilePath + " " + Path);
			if(FilePath.StrCmp(Path, Path.find_last_of("*")) == 0) {
				FileList.push_back(FilePath);
			}
		}
		closedir (dir);
	} else {
		PutModule("Could not list directory " + DirPath + ": " + strerror(errno));
		return;
	}

	std::sort(FileList.begin(), FileList.end());

	// loop through list of log files one by one starting from most recent...
	for (std::vector<CString>::reverse_iterator it = FileList.rbegin(); it != FileList.rend(); ++it) {
		CFile LogFile(*it);
		CString Line;
		std::vector<CString> Lines;

		if (LogFile.Open()) {
			while (LogFile.ReadLine(Line)) {
				// store lines from file into Lines
				Lines.push_back(Line);
			}
		} else {
			PutModule("Could not open log file [" + sCommand + "]: " + strerror(errno));
			continue;
		}

		LogFile.Close();

		// loop through Lines in reverse order, push to LinesToPrint
		for (std::vector<CString>::reverse_iterator itl = Lines.rbegin(); itl != Lines.rend(); ++itl) {
			LinesToPrint.push_back(*itl);
			printedLines++;

			if(printedLines >= reqLines) {
				break;
			}
		}

		if(printedLines >= reqLines) {
			break;
		}
	}

	bool isInChan = CBacklogMod::inChan(Channel);

	if(printedLines == 0) {
		PutModule("No log files found for window " + Channel + " in " + DirPath + "/");
		return;
	} else if (isInChan) {
		m_pNetwork->PutUser(":***!znc@znc.in PRIVMSG " + Channel + " :" + "Backlog playback...", GetClient());
	} else {
		PutModule("*** Backlog playback...");
	}

	// now actually print
	for (std::vector<CString>::reverse_iterator it = LinesToPrint.rbegin(); it != LinesToPrint.rend(); ++it) {
		 if(isInChan) {
			CString Line = *it;
			size_t FirstSpace = Line.find_first_of(' ');
			size_t Len = Line.find_first_of(' ', FirstSpace + 1) - FirstSpace;
			CString Nick = Line.substr(FirstSpace + 2, Len - 3);

			m_pNetwork->PutUser(":" + Nick + "!znc@znc.in PRIVMSG " + Channel + " :" + Line.substr(0, FirstSpace) + Line.substr(FirstSpace + Len, Line.npos), GetClient());
		 } else {
			PutModule(*it);
		 }
	}

	if (isInChan) {
		m_pNetwork->PutUser(":***!znc@znc.in PRIVMSG " + Channel + " :" + "Playback complete.", GetClient());
	} else {
		PutModule("*** Playback complete.");
	}
}

bool CBacklogMod::inChan(const CString& Chan) {
	const std::vector <CChan*>& vChans (m_pNetwork->GetChans());

	for (std::vector<CChan*>::const_iterator it = vChans.begin(); it != vChans.end(); ++it) {
		CChan *curChan = *it;
		if(Chan.StrCmp(curChan->GetName()) == 0) {
			return true;
		}
	}

	return false;
}

template<> void TModInfo<CBacklogMod>(CModInfo& Info) {
	Info.AddType(CModInfo::NetworkModule);
	Info.AddType(CModInfo::GlobalModule);
	Info.SetWikiPage("backlog");
	Info.SetArgsHelpText("Takes as optional argument (and if given, sets) the log path, use keywords: $USER, $NETWORK and $WINDOW");
	Info.SetHasArgs(true);
}

NETWORKMODULEDEFS(CBacklogMod, "Module for getting the last X lines of a channels log.")
<commit_msg>improve help texts in the module itself<commit_after>/*
 * Copyright (C) 2004-2013 ZNC, see the NOTICE file for details.
 * Copyright (C) 2013 Rasmus Eskola <fruitiex@gmail.com>
 * based on sample.cpp sample module code
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <znc/FileUtils.h>
#include <znc/Client.h>
#include <znc/Chan.h>
#include <znc/User.h>
#include <znc/IRCNetwork.h>
#include <znc/Modules.h>
#include <dirent.h>
#include <vector>
#include <algorithm>

class CBacklogMod : public CModule {
public:
	MODCONSTRUCTOR(CBacklogMod) {}

	virtual bool OnLoad(const CString& sArgs, CString& sMessage);
	virtual ~CBacklogMod();
	virtual void OnModCommand(const CString& sCommand);
	bool inChan(const CString& Chan);

private:
	CString			LogPath;
};

bool CBacklogMod::OnLoad(const CString& sArgs, CString& sMessage) {
	LogPath = sArgs;

	if(LogPath.empty()) {
		LogPath = GetNV("LogPath");
		if(LogPath.empty()) {
			// TODO: guess logpath?
			PutModule("LogPath is empty, set it with the LogPath command (help for more info)");
		}
	} else {
		SetNV("LogPath", LogPath);
		PutModule("LogPath set to: " + LogPath);
	}
	return true;
}

CBacklogMod::~CBacklogMod() {
}

void CBacklogMod::OnModCommand(const CString& sCommand) {
	if (sCommand.Token(0).CaseCmp("help") == 0) {
		// TODO: proper help text, look how AddHelpCommand() does it in other ZNC code
		PutModule("Usage:");
		PutModule("<window-name> [num-lines] (e.g. #foo 42)");
		PutModule("");
		PutModule("Commands:");
		PutModule("Help (print this text)");
		PutModule("LogPath <path> (use keywords $USER, $NETWORK, $WINDOW and an asterisk * for date)");
		return;
	}
	else if (sCommand.Token(0).CaseCmp("logpath") == 0) {
		if(sCommand.Token(1, true).empty()) {
			PutModule("Usage: LogPath <path> (use keywords $USER, $NETWORK, $WINDOW and an asterisk * for date:)");
			PutModule("Current LogPath is set to: " + GetNV("LogPath"));
			return;
		}

		LogPath = sCommand.Token(1, true);
		SetNV("LogPath", LogPath);
		PutModule("LogPath set to: " + LogPath);
		return;
	}

	// TODO: handle these differently depending on how the module was loaded
	CString User = (m_pUser ? m_pUser->GetUserName() : "UNKNOWN");
	CString Network = (m_pNetwork ? m_pNetwork->GetName() : "znc");
	CString Channel = sCommand.Token(0);

	int printedLines = 0;
	int reqLines = sCommand.Token(1).ToInt();
	if(reqLines <= 0) {
		reqLines = 150;
	}

	CString Path = LogPath.substr(); // make copy
	Path.Replace("$NETWORK", Network);
	Path.Replace("$WINDOW", Channel);
	Path.Replace("$USER", User);

	CString DirPath = Path.substr(0, Path.find_last_of("/"));
	CString FilePath;

	std::vector<CString> FileList;
	std::vector<CString> LinesToPrint;

	// gather list of all log files for requested channel/window
	DIR *dir;
	struct dirent *ent;
	if ((dir = opendir (DirPath.c_str())) != NULL) {
		while ((ent = readdir (dir)) != NULL) {
			FilePath = DirPath + "/" + ent->d_name;
			//PutModule("DEBUG: " + FilePath + " " + Path);
			if(FilePath.StrCmp(Path, Path.find_last_of("*")) == 0) {
				FileList.push_back(FilePath);
			}
		}
		closedir (dir);
	} else {
		PutModule("Could not list directory " + DirPath + ": " + strerror(errno));
		return;
	}

	std::sort(FileList.begin(), FileList.end());

	// loop through list of log files one by one starting from most recent...
	for (std::vector<CString>::reverse_iterator it = FileList.rbegin(); it != FileList.rend(); ++it) {
		CFile LogFile(*it);
		CString Line;
		std::vector<CString> Lines;

		if (LogFile.Open()) {
			while (LogFile.ReadLine(Line)) {
				// store lines from file into Lines
				Lines.push_back(Line);
			}
		} else {
			PutModule("Could not open log file [" + sCommand + "]: " + strerror(errno));
			continue;
		}

		LogFile.Close();

		// loop through Lines in reverse order, push to LinesToPrint
		for (std::vector<CString>::reverse_iterator itl = Lines.rbegin(); itl != Lines.rend(); ++itl) {
			LinesToPrint.push_back(*itl);
			printedLines++;

			if(printedLines >= reqLines) {
				break;
			}
		}

		if(printedLines >= reqLines) {
			break;
		}
	}

	bool isInChan = CBacklogMod::inChan(Channel);

	if(printedLines == 0) {
		PutModule("No log files found for window " + Channel + " in " + DirPath + "/");
		return;
	} else if (isInChan) {
		m_pNetwork->PutUser(":***!znc@znc.in PRIVMSG " + Channel + " :" + "Backlog playback...", GetClient());
	} else {
		PutModule("*** Backlog playback...");
	}

	// now actually print
	for (std::vector<CString>::reverse_iterator it = LinesToPrint.rbegin(); it != LinesToPrint.rend(); ++it) {
		 if(isInChan) {
			CString Line = *it;
			size_t FirstSpace = Line.find_first_of(' ');
			size_t Len = Line.find_first_of(' ', FirstSpace + 1) - FirstSpace;
			CString Nick = Line.substr(FirstSpace + 2, Len - 3);

			m_pNetwork->PutUser(":" + Nick + "!znc@znc.in PRIVMSG " + Channel + " :" + Line.substr(0, FirstSpace) + Line.substr(FirstSpace + Len, Line.npos), GetClient());
		 } else {
			PutModule(*it);
		 }
	}

	if (isInChan) {
		m_pNetwork->PutUser(":***!znc@znc.in PRIVMSG " + Channel + " :" + "Playback complete.", GetClient());
	} else {
		PutModule("*** Playback complete.");
	}
}

bool CBacklogMod::inChan(const CString& Chan) {
	const std::vector <CChan*>& vChans (m_pNetwork->GetChans());

	for (std::vector<CChan*>::const_iterator it = vChans.begin(); it != vChans.end(); ++it) {
		CChan *curChan = *it;
		if(Chan.StrCmp(curChan->GetName()) == 0) {
			return true;
		}
	}

	return false;
}

template<> void TModInfo<CBacklogMod>(CModInfo& Info) {
	Info.AddType(CModInfo::NetworkModule);
	Info.AddType(CModInfo::GlobalModule);
	Info.SetWikiPage("backlog");
	Info.SetArgsHelpText("Takes as optional argument (and if given, sets) the log path, use keywords: $USER, $NETWORK and $WINDOW");
	Info.SetHasArgs(true);
}

NETWORKMODULEDEFS(CBacklogMod, "Module for getting the last X lines of a channels log.")
<|endoftext|>


<commit_before>/**
 *  @file PseudoBinaryVPSSTP.cpp
 *   Definitions for intermediate ThermoPhase object for phases which
 *   employ excess gibbs free energy formulations
 *  (see \ref thermoprops
 * and class \link Cantera::PseudoBinaryVPSSTP PseudoBinaryVPSSTP\endlink).
 *
 * Header file for a derived class of ThermoPhase that handles
 * variable pressure standard state methods for calculating
 * thermodynamic properties that are further based upon expressions
 * for the excess gibbs free energy expressed as a function of
 * the mole fractions.
 */
/*
 * Copywrite (2009) Sandia Corporation. Under the terms of
 * Contract DE-AC04-94AL85000 with Sandia Corporation, the
 * U.S. Government retains certain rights in this software.
 */
/*
 *  $Date$
 *  $Revision$
 */

#include "PseudoBinaryVPSSTP.h"
using namespace std;

namespace Cantera {

  /*
   * Default constructor.
   *
   */
  PseudoBinaryVPSSTP::PseudoBinaryVPSSTP() :
    GibbsExcessVPSSTP(),
    PBType_(PBTYPE_PASSTHROUGH),
    numPBSpecies_(m_kk),
    indexSpecialSpecies_(-1),
    numCationSpecies_(0),
    numAnionSpecies_(0),
    numPassThroughSpecies_(0),
    neutralPBindexStart(0),
    cationPhase_(0),
    anionPhase_(0)
  {
  }

  /*
   * Copy Constructor:
   *
   *  Note this stuff will not work until the underlying phase
   *  has a working copy constructor
   */
  PseudoBinaryVPSSTP::PseudoBinaryVPSSTP(const PseudoBinaryVPSSTP &b) :
    GibbsExcessVPSSTP(),
    PBType_(PBTYPE_PASSTHROUGH),
    numPBSpecies_(m_kk),
    indexSpecialSpecies_(-1),
    numCationSpecies_(0),
    numAnionSpecies_(0),
    numPassThroughSpecies_(0),
    neutralPBindexStart(0),
    cationPhase_(0),
    anionPhase_(0)
  {
    *this = operator=(b);
  }

  /*
   * operator=()
   *
   *  Note this stuff will not work until the underlying phase
   *  has a working assignment operator
   */
  PseudoBinaryVPSSTP& PseudoBinaryVPSSTP::
  operator=(const PseudoBinaryVPSSTP &b) {
    if (&b != this) {
      GibbsExcessVPSSTP::operator=(b);
    }

    PBType_                     = b.PBType_;
    numPBSpecies_               = b.numPBSpecies_;
    indexSpecialSpecies_        = b.indexSpecialSpecies_;
    PBMoleFractions_            = b.PBMoleFractions_;
    cationList_                 = b.cationList_;
    numCationSpecies_           = b.numCationSpecies_;
    anionList_                  = b.anionList_;
    numAnionSpecies_            = b.numAnionSpecies_;
    passThroughList_            = b.passThroughList_;
    numPassThroughSpecies_      = b.numPassThroughSpecies_;
    neutralPBindexStart         = b.neutralPBindexStart;
    cationPhase_                = b.cationPhase_;
    anionPhase_                 = b.anionPhase_;
    moleFractionsTmp_           = b.moleFractionsTmp_;

    return *this;
  }

  /**
   *
   * ~PseudoBinaryVPSSTP():   (virtual)
   *
   * Destructor: does nothing:
   *
   */
  PseudoBinaryVPSSTP::~PseudoBinaryVPSSTP() {
  }

  /*
   * This routine duplicates the current object and returns
   * a pointer to ThermoPhase.
   */
  ThermoPhase*
  PseudoBinaryVPSSTP::duplMyselfAsThermoPhase() const {
    PseudoBinaryVPSSTP* mtp = new PseudoBinaryVPSSTP(*this);
    return (ThermoPhase *) mtp;
  }

  /*
   *  -------------- Utilities -------------------------------
   */

  // Equation of state type flag.
  /*
   * The ThermoPhase base class returns
   * zero. Subclasses should define this to return a unique
   * non-zero value. Known constants defined for this purpose are
   * listed in mix_defs.h. The PseudoBinaryVPSSTP class also returns
   * zero, as it is a non-complete class.
   */
  int PseudoBinaryVPSSTP::eosType() const {
    return 0;
  }

  /*
   * ------------ Molar Thermodynamic Properties ----------------------
   */

  /*
   * - Activities, Standard States, Activity Concentrations -----------
   */

  doublereal PseudoBinaryVPSSTP::standardConcentration(int k) const {
    err("standardConcentration");
    return -1.0;
  }

  doublereal PseudoBinaryVPSSTP::logStandardConc(int k) const {
    err("logStandardConc");
    return -1.0;
  }

  void PseudoBinaryVPSSTP::getElectrochemPotentials(doublereal* mu) const {
    getChemPotentials(mu);
    double ve = Faraday * electricPotential();
    for (int k = 0; k < m_kk; k++) {
      mu[k] += ve*charge(k);
    }
  }

  void PseudoBinaryVPSSTP::calcPseudoBinaryMoleFractions() const {
    int k;
    doublereal sumCat;
    doublereal sumAnion;
    doublereal sum = 0.0;
    switch (PBType_) {
    case PBTYPE_PASSTHROUGH:
      for (k = 0; k < m_kk; k++) {
	PBMoleFractions_[k] = moleFractions_[k];
      }
      break;
    case PBTYPE_SINGLEANION:
      sumCat = 0.0;
      sumAnion = 0.0;
      for (k = 0; k < m_kk; k++) {
	moleFractionsTmp_[k] = moleFractions_[k];
      }
      for (k = 0; k < (int) cationList_.size(); k++) {
	sumCat += moleFractions_[cationList_[k]];
      }
      sumAnion =  moleFractions_[anionList_[k]];
      PBMoleFractions_[0] = sumCat -sumAnion;
      moleFractionsTmp_[indexSpecialSpecies_] -= PBMoleFractions_[0];

      for (k = 0; k < numCationSpecies_; k++) {
	PBMoleFractions_[1+k] = moleFractionsTmp_[cationList_[k]];
      }

      for (k = 0; k <  numPassThroughSpecies_; k++) {
	PBMoleFractions_[neutralPBindexStart + k] =
	  moleFractions_[cationList_[k]];
      }

      sum = fmax(0.0, PBMoleFractions_[0]);
      for (k = 1; k < numPBSpecies_; k++) {
	sum += PBMoleFractions_[k];
      }
      for (k = 0; k < numPBSpecies_; k++) {
	PBMoleFractions_[k] /= sum;
      }

      break;
    case PBTYPE_SINGLECATION:
      throw CanteraError("eosType", "Unknown type");

      break;

    case PBTYPE_MULTICATIONANION:
      throw CanteraError("eosType", "Unknown type");

      break;
    default:
      throw CanteraError("eosType", "Unknown type");
      break;

    }
  }

  /*
   * ------------ Partial Molar Properties of the Solution ------------
   */

  doublereal PseudoBinaryVPSSTP::err(std::string msg) const {
    throw CanteraError("PseudoBinaryVPSSTP","Base class method "
		       +msg+" called. Equation of state type: "+int2str(eosType()));
    return 0;
  }

  /*
   * @internal Initialize. This method is provided to allow
   * subclasses to perform any initialization required after all
   * species have been added. For example, it might be used to
   * resize internal work arrays that must have an entry for
   * each species.  The base class implementation does nothing,
   * and subclasses that do not require initialization do not
   * need to overload this method.  When importing a CTML phase
   * description, this method is called just prior to returning
   * from function importPhase.
   *
   * @see importCTML.cpp
   */
  void PseudoBinaryVPSSTP::initThermo() {
    initLengths();
    GibbsExcessVPSSTP::initThermo();
  }

  //   Initialize lengths of local variables after all species have
  //   been identified.
  void  PseudoBinaryVPSSTP::initLengths() {
    m_kk = nSpecies();
    moleFractions_.resize(m_kk);
  }

  /*
   * initThermoXML()                (virtual from ThermoPhase)
   *   Import and initialize a ThermoPhase object
   *
   * @param phaseNode This object must be the phase node of a
   *             complete XML tree
   *             description of the phase, including all of the
   *             species data. In other words while "phase" must
   *             point to an XML phase object, it must have
   *             sibling nodes "speciesData" that describe
   *             the species in the phase.
   * @param id   ID of the phase. If nonnull, a check is done
   *             to see if phaseNode is pointing to the phase
   *             with the correct id.
   */
  void PseudoBinaryVPSSTP::initThermoXML(XML_Node& phaseNode, std::string id) {

    GibbsExcessVPSSTP::initThermoXML(phaseNode, id);
  }

 /**
   * Format a summary of the mixture state for output.
   */
  std::string PseudoBinaryVPSSTP::report(bool show_thermo) const {

    char p[800];
    string s = "";
    try {
      if (name() != "") {
	sprintf(p, " \n  %s:\n", name().c_str());
	s += p;
      }
      sprintf(p, " \n       temperature    %12.6g  K\n", temperature());
      s += p;
      sprintf(p, "          pressure    %12.6g  Pa\n", pressure());
      s += p;
      sprintf(p, "           density    %12.6g  kg/m^3\n", density());
      s += p;
      sprintf(p, "  mean mol. weight    %12.6g  amu\n", meanMolecularWeight());
      s += p;

      doublereal phi = electricPotential();
      sprintf(p, "         potential    %12.6g  V\n", phi);
      s += p;

      int kk = nSpecies();
      array_fp x(kk);
      array_fp molal(kk);
      array_fp mu(kk);
      array_fp muss(kk);
      array_fp acMolal(kk);
      array_fp actMolal(kk);
      getMoleFractions(&x[0]);

      getChemPotentials(&mu[0]);
      getStandardChemPotentials(&muss[0]);
      getActivities(&actMolal[0]);

      if (show_thermo) {
        sprintf(p, " \n");
        s += p;
        sprintf(p, "                          1 kg            1 kmol\n");
        s += p;
        sprintf(p, "                       -----------      ------------\n");
        s += p;
        sprintf(p, "          enthalpy    %12.6g     %12.4g     J\n",
		enthalpy_mass(), enthalpy_mole());
        s += p;
        sprintf(p, "   internal energy    %12.6g     %12.4g     J\n",
		intEnergy_mass(), intEnergy_mole());
        s += p;
        sprintf(p, "           entropy    %12.6g     %12.4g     J/K\n",
		entropy_mass(), entropy_mole());
        s += p;
        sprintf(p, "    Gibbs function    %12.6g     %12.4g     J\n",
		gibbs_mass(), gibbs_mole());
        s += p;
        sprintf(p, " heat capacity c_p    %12.6g     %12.4g     J/K\n",
		cp_mass(), cp_mole());
        s += p;
        try {
	  sprintf(p, " heat capacity c_v    %12.6g     %12.4g     J/K\n",
		  cv_mass(), cv_mole());
	  s += p;
        }
        catch(CanteraError) {
	  sprintf(p, " heat capacity c_v    <not implemented>       \n");
	  s += p;
        }
      }

    } catch (CanteraError) {
      ;
    }
    return s;
  }

}

<commit_msg>Fixed a windows error.<commit_after>/**
 *  @file PseudoBinaryVPSSTP.cpp
 *   Definitions for intermediate ThermoPhase object for phases which
 *   employ excess gibbs free energy formulations
 *  (see \ref thermoprops
 * and class \link Cantera::PseudoBinaryVPSSTP PseudoBinaryVPSSTP\endlink).
 *
 * Header file for a derived class of ThermoPhase that handles
 * variable pressure standard state methods for calculating
 * thermodynamic properties that are further based upon expressions
 * for the excess gibbs free energy expressed as a function of
 * the mole fractions.
 */
/*
 * Copywrite (2009) Sandia Corporation. Under the terms of
 * Contract DE-AC04-94AL85000 with Sandia Corporation, the
 * U.S. Government retains certain rights in this software.
 */
/*
 *  $Date$
 *  $Revision$
 */

#include "PseudoBinaryVPSSTP.h"

#include <cmath>

using namespace std;

namespace Cantera {

  /*
   * Default constructor.
   *
   */
  PseudoBinaryVPSSTP::PseudoBinaryVPSSTP() :
    GibbsExcessVPSSTP(),
    PBType_(PBTYPE_PASSTHROUGH),
    numPBSpecies_(m_kk),
    indexSpecialSpecies_(-1),
    numCationSpecies_(0),
    numAnionSpecies_(0),
    numPassThroughSpecies_(0),
    neutralPBindexStart(0),
    cationPhase_(0),
    anionPhase_(0)
  {
  }

  /*
   * Copy Constructor:
   *
   *  Note this stuff will not work until the underlying phase
   *  has a working copy constructor
   */
  PseudoBinaryVPSSTP::PseudoBinaryVPSSTP(const PseudoBinaryVPSSTP &b) :
    GibbsExcessVPSSTP(),
    PBType_(PBTYPE_PASSTHROUGH),
    numPBSpecies_(m_kk),
    indexSpecialSpecies_(-1),
    numCationSpecies_(0),
    numAnionSpecies_(0),
    numPassThroughSpecies_(0),
    neutralPBindexStart(0),
    cationPhase_(0),
    anionPhase_(0)
  {
    *this = operator=(b);
  }

  /*
   * operator=()
   *
   *  Note this stuff will not work until the underlying phase
   *  has a working assignment operator
   */
  PseudoBinaryVPSSTP& PseudoBinaryVPSSTP::
  operator=(const PseudoBinaryVPSSTP &b) {
    if (&b != this) {
      GibbsExcessVPSSTP::operator=(b);
    }

    PBType_                     = b.PBType_;
    numPBSpecies_               = b.numPBSpecies_;
    indexSpecialSpecies_        = b.indexSpecialSpecies_;
    PBMoleFractions_            = b.PBMoleFractions_;
    cationList_                 = b.cationList_;
    numCationSpecies_           = b.numCationSpecies_;
    anionList_                  = b.anionList_;
    numAnionSpecies_            = b.numAnionSpecies_;
    passThroughList_            = b.passThroughList_;
    numPassThroughSpecies_      = b.numPassThroughSpecies_;
    neutralPBindexStart         = b.neutralPBindexStart;
    cationPhase_                = b.cationPhase_;
    anionPhase_                 = b.anionPhase_;
    moleFractionsTmp_           = b.moleFractionsTmp_;

    return *this;
  }

  /**
   *
   * ~PseudoBinaryVPSSTP():   (virtual)
   *
   * Destructor: does nothing:
   *
   */
  PseudoBinaryVPSSTP::~PseudoBinaryVPSSTP() {
  }

  /*
   * This routine duplicates the current object and returns
   * a pointer to ThermoPhase.
   */
  ThermoPhase*
  PseudoBinaryVPSSTP::duplMyselfAsThermoPhase() const {
    PseudoBinaryVPSSTP* mtp = new PseudoBinaryVPSSTP(*this);
    return (ThermoPhase *) mtp;
  }

  /*
   *  -------------- Utilities -------------------------------
   */

  // Equation of state type flag.
  /*
   * The ThermoPhase base class returns
   * zero. Subclasses should define this to return a unique
   * non-zero value. Known constants defined for this purpose are
   * listed in mix_defs.h. The PseudoBinaryVPSSTP class also returns
   * zero, as it is a non-complete class.
   */
  int PseudoBinaryVPSSTP::eosType() const {
    return 0;
  }

  /*
   * ------------ Molar Thermodynamic Properties ----------------------
   */

  /*
   * - Activities, Standard States, Activity Concentrations -----------
   */

  doublereal PseudoBinaryVPSSTP::standardConcentration(int k) const {
    err("standardConcentration");
    return -1.0;
  }

  doublereal PseudoBinaryVPSSTP::logStandardConc(int k) const {
    err("logStandardConc");
    return -1.0;
  }

  void PseudoBinaryVPSSTP::getElectrochemPotentials(doublereal* mu) const {
    getChemPotentials(mu);
    double ve = Faraday * electricPotential();
    for (int k = 0; k < m_kk; k++) {
      mu[k] += ve*charge(k);
    }
  }

  void PseudoBinaryVPSSTP::calcPseudoBinaryMoleFractions() const {
    int k;
    doublereal sumCat;
    doublereal sumAnion;
    doublereal sum = 0.0;
    switch (PBType_) {
    case PBTYPE_PASSTHROUGH:
      for (k = 0; k < m_kk; k++) {
	PBMoleFractions_[k] = moleFractions_[k];
      }
      break;
    case PBTYPE_SINGLEANION:
      sumCat = 0.0;
      sumAnion = 0.0;
      for (k = 0; k < m_kk; k++) {
	moleFractionsTmp_[k] = moleFractions_[k];
      }
      for (k = 0; k < (int) cationList_.size(); k++) {
	sumCat += moleFractions_[cationList_[k]];
      }
      sumAnion =  moleFractions_[anionList_[k]];
      PBMoleFractions_[0] = sumCat -sumAnion;
      moleFractionsTmp_[indexSpecialSpecies_] -= PBMoleFractions_[0];

      for (k = 0; k < numCationSpecies_; k++) {
        PBMoleFractions_[1+k] = moleFractionsTmp_[cationList_[k]];
      }

      for (k = 0; k <  numPassThroughSpecies_; k++) {
	    PBMoleFractions_[neutralPBindexStart + k] =
			moleFractions_[cationList_[k]];
      }

      sum = fmaxx(0.0, PBMoleFractions_[0]);
      for (k = 1; k < numPBSpecies_; k++) {
        sum += PBMoleFractions_[k];
      }
      for (k = 0; k < numPBSpecies_; k++) {
        PBMoleFractions_[k] /= sum;
      }

      break;
    case PBTYPE_SINGLECATION:
      throw CanteraError("eosType", "Unknown type");

      break;

    case PBTYPE_MULTICATIONANION:
      throw CanteraError("eosType", "Unknown type");

      break;
    default:
      throw CanteraError("eosType", "Unknown type");
      break;

    }
  }

  /*
   * ------------ Partial Molar Properties of the Solution ------------
   */

  doublereal PseudoBinaryVPSSTP::err(std::string msg) const {
    throw CanteraError("PseudoBinaryVPSSTP","Base class method "
		       +msg+" called. Equation of state type: "+int2str(eosType()));
    return 0;
  }

  /*
   * @internal Initialize. This method is provided to allow
   * subclasses to perform any initialization required after all
   * species have been added. For example, it might be used to
   * resize internal work arrays that must have an entry for
   * each species.  The base class implementation does nothing,
   * and subclasses that do not require initialization do not
   * need to overload this method.  When importing a CTML phase
   * description, this method is called just prior to returning
   * from function importPhase.
   *
   * @see importCTML.cpp
   */
  void PseudoBinaryVPSSTP::initThermo() {
    initLengths();
    GibbsExcessVPSSTP::initThermo();
  }

  //   Initialize lengths of local variables after all species have
  //   been identified.
  void  PseudoBinaryVPSSTP::initLengths() {
    m_kk = nSpecies();
    moleFractions_.resize(m_kk);
  }

  /*
   * initThermoXML()                (virtual from ThermoPhase)
   *   Import and initialize a ThermoPhase object
   *
   * @param phaseNode This object must be the phase node of a
   *             complete XML tree
   *             description of the phase, including all of the
   *             species data. In other words while "phase" must
   *             point to an XML phase object, it must have
   *             sibling nodes "speciesData" that describe
   *             the species in the phase.
   * @param id   ID of the phase. If nonnull, a check is done
   *             to see if phaseNode is pointing to the phase
   *             with the correct id.
   */
  void PseudoBinaryVPSSTP::initThermoXML(XML_Node& phaseNode, std::string id) {

    GibbsExcessVPSSTP::initThermoXML(phaseNode, id);
  }

 /**
   * Format a summary of the mixture state for output.
   */
  std::string PseudoBinaryVPSSTP::report(bool show_thermo) const {

    char p[800];
    string s = "";
    try {
      if (name() != "") {
	sprintf(p, " \n  %s:\n", name().c_str());
	s += p;
      }
      sprintf(p, " \n       temperature    %12.6g  K\n", temperature());
      s += p;
      sprintf(p, "          pressure    %12.6g  Pa\n", pressure());
      s += p;
      sprintf(p, "           density    %12.6g  kg/m^3\n", density());
      s += p;
      sprintf(p, "  mean mol. weight    %12.6g  amu\n", meanMolecularWeight());
      s += p;

      doublereal phi = electricPotential();
      sprintf(p, "         potential    %12.6g  V\n", phi);
      s += p;

      int kk = nSpecies();
      array_fp x(kk);
      array_fp molal(kk);
      array_fp mu(kk);
      array_fp muss(kk);
      array_fp acMolal(kk);
      array_fp actMolal(kk);
      getMoleFractions(&x[0]);

      getChemPotentials(&mu[0]);
      getStandardChemPotentials(&muss[0]);
      getActivities(&actMolal[0]);

      if (show_thermo) {
        sprintf(p, " \n");
        s += p;
        sprintf(p, "                          1 kg            1 kmol\n");
        s += p;
        sprintf(p, "                       -----------      ------------\n");
        s += p;
        sprintf(p, "          enthalpy    %12.6g     %12.4g     J\n",
		enthalpy_mass(), enthalpy_mole());
        s += p;
        sprintf(p, "   internal energy    %12.6g     %12.4g     J\n",
		intEnergy_mass(), intEnergy_mole());
        s += p;
        sprintf(p, "           entropy    %12.6g     %12.4g     J/K\n",
		entropy_mass(), entropy_mole());
        s += p;
        sprintf(p, "    Gibbs function    %12.6g     %12.4g     J\n",
		gibbs_mass(), gibbs_mole());
        s += p;
        sprintf(p, " heat capacity c_p    %12.6g     %12.4g     J/K\n",
		cp_mass(), cp_mole());
        s += p;
        try {
	  sprintf(p, " heat capacity c_v    %12.6g     %12.4g     J/K\n",
		  cv_mass(), cv_mole());
	  s += p;
        }
        catch(CanteraError) {
	  sprintf(p, " heat capacity c_v    <not implemented>       \n");
	  s += p;
        }
      }

    } catch (CanteraError) {
      ;
    }
    return s;
  }

}

<|endoftext|>


<commit_before>// Copyright (c) 2016 ASMlover. All rights reserved.
//
//  ____     __
// /\  _`\  /\ \
// \ \ \/\_\\ \ \___      __      ___     ____
//  \ \ \/_/_\ \  _ `\  /'__`\   / __`\  /',__\
//   \ \ \L\ \\ \ \ \ \/\ \L\.\_/\ \L\ \/\__, `\
//    \ \____/ \ \_\ \_\ \__/.\_\ \____/\/\____/
//     \/___/   \/_/\/_/\/__/\/_/\/___/  \/___/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <cstdio>
#if defined(CHAOS_USE_CPP11)
# include <chrono>
# include <thread>
#endif
#include <type_traits>
#include <Chaos/Kern/KernCommon.h>
#include <Chaos/Concurrent/Unexposed/CurrentThread.h>
#include <Chaos/Concurrent/CurrentThread.hh>

namespace Chaos::CurrentThread {

static const int kMainTid = Chaos::kern_gettid();
__chaos_tl int t_cachaed_tid = 0;
__chaos_tl char t_strftid[32];
__chaos_tl int t_strftid_length = 12;
__chaos_tl const char* t_thread_name = "unknown";
static_assert(std::is_same<int, pid_t>::value, "pid_t should be `int`");

namespace Unexposed {
  void set_cached_tid(int cached_tid) {
    CurrentThread::t_cachaed_tid = cached_tid;
  }

  void set_name(const char* name) {
    CurrentThread::t_thread_name = name;
  }
}

void cached_tid(void) {
  if (0 == t_cachaed_tid) {
    t_cachaed_tid = Chaos::kern_gettid();
    t_strftid_length = std::snprintf(t_strftid,
        sizeof(t_strftid), "%11d ", t_cachaed_tid);
  }
}

int get_tid(void) {
  if (__builtin_expect(t_cachaed_tid == 0, 0))
    cached_tid();
  return t_cachaed_tid;
}

const char* get_strftid(void) {
  return t_strftid;
}

int get_strftid_length(void) {
  return t_strftid_length;
}

const char* get_name(void) {
  return t_thread_name;
}

bool is_main_thread(void) {
  return get_tid() == kMainTid;
}

void sleep_microsec(std::uint64_t microsec) {
#if defined(CHAOS_USE_CPP11)
  // use C++11 chrono on windows
  std::this_thread::sleep_for(std::chrono::microseconds(microsec));
#else
  Chaos::kern_100nanosleep(10 * microsec);
#endif
}

}
<commit_msg>:construction: chore(current-thread): updated the current thread module for windows<commit_after>// Copyright (c) 2016 ASMlover. All rights reserved.
//
//  ____     __
// /\  _`\  /\ \
// \ \ \/\_\\ \ \___      __      ___     ____
//  \ \ \/_/_\ \  _ `\  /'__`\   / __`\  /',__\
//   \ \ \L\ \\ \ \ \ \/\ \L\.\_/\ \L\ \/\__, `\
//    \ \____/ \ \_\ \_\ \__/.\_\ \____/\/\____/
//     \/___/   \/_/\/_/\/__/\/_/\/___/  \/___/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <cstdio>
#if defined(CHAOS_USE_CPP11)
# include <chrono>
# include <thread>
#endif
#include <type_traits>
#include <Chaos/Kern/KernCommon.h>
#include <Chaos/Concurrent/Unexposed/CurrentThread.hh>
#include <Chaos/Concurrent/CurrentThread.hh>

namespace Chaos::CurrentThread {

static const int kMainTid = Chaos::kern_gettid();
__chaos_tl int t_cachaed_tid = 0;
__chaos_tl char t_strftid[32];
__chaos_tl int t_strftid_length = 12;
__chaos_tl const char* t_thread_name = "unknown";
static_assert(std::is_same<int, pid_t>::value, "pid_t should be `int`");

namespace Unexposed {
  void set_cached_tid(int cached_tid) {
    CurrentThread::t_cachaed_tid = cached_tid;
  }

  void set_name(const char* name) {
    CurrentThread::t_thread_name = name;
  }
}

void cached_tid(void) {
  if (0 == t_cachaed_tid) {
    t_cachaed_tid = Chaos::kern_gettid();
    t_strftid_length = std::snprintf(t_strftid,
        sizeof(t_strftid), "%11d ", t_cachaed_tid);
  }
}

int get_tid(void) {
  if (__builtin_expect(t_cachaed_tid == 0, 0))
    cached_tid();
  return t_cachaed_tid;
}

const char* get_strftid(void) {
  return t_strftid;
}

int get_strftid_length(void) {
  return t_strftid_length;
}

const char* get_name(void) {
  return t_thread_name;
}

bool is_main_thread(void) {
  return get_tid() == kMainTid;
}

void sleep_microsec(std::uint64_t microsec) {
#if defined(CHAOS_USE_CPP11)
  // use C++11 chrono on windows
  std::this_thread::sleep_for(std::chrono::microseconds(microsec));
#else
  Chaos::kern_100nanosleep(10 * microsec);
#endif
}

}
<|endoftext|>


<commit_before>// You'll need OSCPack to compile this:
// http://www.audiomulch.com/~rossb/code/oscpack/
// Please set the OSCPACK_HOME directory to the directory where you installed oscpack..
// I have included a static LIB for oscpack in the lib dir,
// so if you are compiling with VC .NET then you don't need to compile oscpack..

#ifdef WIN32
#pragma once
#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT  0x0500
#endif

#include <map>
#include <cv.h>
#include <highgui.h>

#include "TouchScreenDevice.h"
#include "TouchData.h"

using namespace touchlib;

#include <stdio.h>
#include <string>

ITouchScreen *screen;

#include "osc/OscOutboundPacketStream.h"
#include "ip/UdpSocket.h"

#define ADDRESS "127.0.0.1"
#define PORT 3333

#define OUTPUT_BUFFER_SIZE 2048

//#define OSC_STRICT 1

///////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////

// FIXME: allow address and port to be specified on the command line or from a config file..

class OSCApp : public ITouchListener
{
public:

	OSCApp()
	{
		transmitSocket = NULL;

		frameSeq = 0;

	}

	~OSCApp()
	{
		delete transmitSocket;
	}

	// Set IP and Port with commandline parameters
	void connectSocket(std::string ip_address, int port)
	{
		transmitSocket = new UdpTransmitSocket( IpEndpointName( ip_address.c_str(), port ) );
		printf("Socket Initialized : %s Port : %i\n\n", ip_address.c_str(), port);
		frameSeq = 0;
	}

	//! Notify that a finger has just been made active.
	virtual void fingerDown(TouchData data)
	{
		RgbPixel c;
		c.r = 255;
		c.g = 255;
		c.b = 255;

		fingerList[data.ID] = data;

		printf("Blob Detected | X: %f Y: %f Area: %f\n", data.X, data.Y, data.area);

	}

	//! Notify that a finger has moved
	virtual void fingerUpdate(TouchData data)
	{

		fingerList[data.ID] = data;

	}

	//! A finger is no longer active..
	virtual void fingerUp(TouchData data)
	{
		std::map<int, TouchData>::iterator iter;

		for(iter=fingerList.begin(); iter != fingerList.end(); iter++)
		{
			if(iter->second.ID == data.ID)
			{
				fingerList.erase(iter);

				return;
			}
		}
	}

	void frame()
	{
		if(!transmitSocket)
			return;

		// send update messages..

		char buffer[OUTPUT_BUFFER_SIZE];
		char buffer2[OUTPUT_BUFFER_SIZE];
		osc::OutboundPacketStream p( buffer, OUTPUT_BUFFER_SIZE );
		osc::OutboundPacketStream p2( buffer, OUTPUT_BUFFER_SIZE );

		std::map<int, TouchData>::iterator iter1, iter2, iter_last;

		if(fingerList.size() > 0)
		{
			//p << osc::BeginBundleImmediate;

			int scount = 0, acount = 0;
			iter1=fingerList.begin();

			bool done=false;

			while(!done)
			{
				p.Clear();
				p2.Clear();

				p << osc::BeginBundle();
				p2 << osc::BeginBundle();

				for(; iter1 != fingerList.end(); iter1++)
				{
					TouchData d = (*iter1).second;
					float m = sqrtf((d.dX*d.dX) + (d.dY*d.dY));
					float area = d.area;
				//	printf(d.area);
					if(!(d.X == 0 && d.Y == 0)) {
						if(d.tagID == 0)
						{
// don't send extra info
#ifdef OSC_STRICT
							p << osc::BeginMessage( "/tuio/2Dcur" ) << "set" << d.ID << d.X << d.Y << d.dX << d.dY << m << osc::EndMessage;
#else
							p << osc::BeginMessage( "/tuio/2Dcur" ) << "set" << d.ID << d.X << d.Y << d.dX << d.dY << m << d.width << d.height << osc::EndMessage;
#endif
						} else {
							// is a fiducial tag

							//FIXME: should we send height and width for obj's too?
							p2 << osc::BeginMessage( "/tuio/2Dobj" ) << "set" << d.ID << d.tagID << d.X << d.Y << d.angle << d.dX << d.dY << 0.0 << m << 0.0 << osc::EndMessage;
						}

						scount ++;
						if(scount >= 10)
						{
							scount = 0;
							break;
						}
					}
				}

				if(iter1 == fingerList.end())
					done = true;

				p << osc::BeginMessage( "/tuio/2Dcur" );
				p << "alive";
				p2 << osc::BeginMessage( "/tuio/2Dobj" );
				p2 << "alive";

				for(iter2=fingerList.begin(); iter2 != fingerList.end(); iter2++)
				{
					TouchData d = (*iter2).second;
					if(d.tagID == 0)
					{
						if(!(d.X == 0 && d.Y == 0)) {
							p << d.ID;
						}
					} else {
						if(!(d.X == 0 && d.Y == 0)) {
							p2 << d.ID;
						}
					}
				}
				p << osc::EndMessage;
				p << osc::BeginMessage( "/tuio/2Dcur" ) << "fseq" << frameSeq << osc::EndMessage;
				p << osc::EndBundle;

				p2 << osc::EndMessage;
				p2 << osc::BeginMessage( "/tuio/2Dobj" ) << "fseq" << frameSeq << osc::EndMessage;
				p2 << osc::EndBundle;

				//printf("%d size. %d #fingers\n", p.Size(), fingerList.size());
				frameSeq ++;
				if(p.IsReady())
					transmitSocket->Send( p.Data(), p.Size() );

				if(p2.IsReady())
					transmitSocket->Send( p2.Data(), p2.Size() );
			}

		} else {
			// do we even need to do this?

			//p << osc::BeginBundleImmediate;
			p.Clear();
			p << osc::BeginBundle();

			p << osc::BeginMessage( "/tuio/2Dcur" );
			p << "alive";
			p << osc::EndMessage;

			p << osc::BeginMessage( "/tuio/2Dcur" ) << "fseq" << frameSeq << osc::EndMessage;

			p << osc::EndBundle;

			frameSeq ++;
			//printf("%d size\n", p.Size());

			if(p.IsReady())
				transmitSocket->Send( p.Data(), p.Size() );
		}

	}

	void clearFingers()
	{
		fingerList.clear();
	}

private:
	UdpTransmitSocket *transmitSocket;

	// Keep track of all finger presses.
	std::map<int, TouchData> fingerList;
	int frameSeq;

};

/////////////////////////////////////////////////////////////////////////

OSCApp app;
bool ok=true;

int main(int argc, char * argv[])
{
	std::string ip_address = ADDRESS;
	int port = PORT;

	// Check if command arguments are specified
	if (argc == 3)
	{
		// Convert parsed values
		ip_address = argv[1];
		port = (int)strtol (argv[2], NULL, 0);
	}

	// Set ip and port
	app.connectSocket(ip_address, port);

	screen = TouchScreenDevice::getTouchScreen();
	screen->setDebugMode(false);
	if(!screen->loadConfig("config.xml"))
	{
		std::string label;
		label = screen->pushFilter("dsvlcapture");
		screen->setParameter(label, "source", "cam");
		screen->pushFilter("mono");
		screen->pushFilter("smooth");
		screen->pushFilter("backgroundremove");

		label = screen->pushFilter("brightnesscontrast");
		screen->setParameter(label, "brightness", "0.1");
		screen->setParameter(label, "contrast", "0.4");
		label = screen->pushFilter("rectify");

		screen->setParameter(label, "level", "25");
		screen->saveConfig("config.xml");
	}

	std::string bgLabel = screen->findFirstFilter("backgroundremove");
	std::string recLabel = screen->findFirstFilter("rectify");
	screen->registerListener((ITouchListener *)&app);
	// Note: Begin processing should only be called after the screen is set up

	SLEEP(1000);
	screen->setParameter(bgLabel, "mask", (char*)screen->getCameraPoints());
	screen->setParameter(bgLabel, "capture", "");

	screen->beginProcessing();
	screen->beginTracking();
    cvNamedWindow( "Touch Listener", CV_WINDOW_AUTOSIZE );
	do
	{
		int keypressed = cvWaitKey(10) & 255;

		if(keypressed != 255 && keypressed > 0)
			printf("KP: %d\n", keypressed);

        if( keypressed == 27) break;		// ESC = quit
        if( keypressed == 98)				// b = recapture background
		{
			screen->setParameter(bgLabel, "capture", "");
			app.clearFingers();
		}

        if( keypressed == 114)				// r = auto rectify..
		{
			screen->setParameter(recLabel, "level", "auto");
		}

		screen->getEvents();

		app.frame();

		SLEEP(1);

	} while( ok );

	TouchScreenDevice::destroy();
	return 0;
}
<commit_msg>Fixed a stupid but fatal bug in osc.cpp which would cause FLOsc to crash<commit_after>// You'll need OSCPack to compile this:
// http://www.audiomulch.com/~rossb/code/oscpack/
// Please set the OSCPACK_HOME directory to the directory where you installed oscpack..
// I have included a static LIB for oscpack in the lib dir,
// so if you are compiling with VC .NET then you don't need to compile oscpack..

#ifdef WIN32
#pragma once
#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT  0x0500
#endif

#include <map>
#include <cv.h>
#include <highgui.h>

#include "TouchScreenDevice.h"
#include "TouchData.h"

using namespace touchlib;

#include <stdio.h>
#include <string>

ITouchScreen *screen;

#include "osc/OscOutboundPacketStream.h"
#include "ip/UdpSocket.h"

#define ADDRESS "127.0.0.1"
#define PORT 3333

#define OUTPUT_BUFFER_SIZE 2048

//#define OSC_STRICT 1

///////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////

// FIXME: allow address and port to be specified on the command line or from a config file..

class OSCApp : public ITouchListener
{
public:

	OSCApp()
	{
		transmitSocket = NULL;

		frameSeq = 0;

	}

	~OSCApp()
	{
		delete transmitSocket;
	}

	// Set IP and Port with commandline parameters
	void connectSocket(std::string ip_address, int port)
	{
		transmitSocket = new UdpTransmitSocket( IpEndpointName( ip_address.c_str(), port ) );
		printf("Socket Initialized : %s Port : %i\n\n", ip_address.c_str(), port);
		frameSeq = 0;
	}

	//! Notify that a finger has just been made active.
	virtual void fingerDown(TouchData data)
	{
		RgbPixel c;
		c.r = 255;
		c.g = 255;
		c.b = 255;

		fingerList[data.ID] = data;

		printf("Blob Detected | X: %f Y: %f Area: %f\n", data.X, data.Y, data.area);

	}

	//! Notify that a finger has moved
	virtual void fingerUpdate(TouchData data)
	{

		fingerList[data.ID] = data;

	}

	//! A finger is no longer active..
	virtual void fingerUp(TouchData data)
	{
		std::map<int, TouchData>::iterator iter;

		for(iter=fingerList.begin(); iter != fingerList.end(); iter++)
		{
			if(iter->second.ID == data.ID)
			{
				fingerList.erase(iter);

				return;
			}
		}
	}

	void frame()
	{
		if(!transmitSocket)
			return;

		// send update messages..

		char buffer[OUTPUT_BUFFER_SIZE];
		char buffer2[OUTPUT_BUFFER_SIZE];
		osc::OutboundPacketStream p( buffer, OUTPUT_BUFFER_SIZE );
		osc::OutboundPacketStream p2( buffer2, OUTPUT_BUFFER_SIZE );

		std::map<int, TouchData>::iterator iter1, iter2, iter_last;

		if(fingerList.size() > 0)
		{
			//p << osc::BeginBundleImmediate;

			int scount = 0, acount = 0;
			iter1=fingerList.begin();

			bool done=false;

			while(!done)
			{
				p.Clear();
				p2.Clear();

				p << osc::BeginBundle();
				p2 << osc::BeginBundle();

				for(; iter1 != fingerList.end(); iter1++)
				{
					TouchData d = (*iter1).second;
					float m = sqrtf((d.dX*d.dX) + (d.dY*d.dY));
					float area = d.area;
				//	printf(d.area);
					if(!(d.X == 0 && d.Y == 0)) {
						if(d.tagID == 0)
						{
// don't send extra info
#ifdef OSC_STRICT
							p << osc::BeginMessage( "/tuio/2Dcur" ) << "set" << d.ID << d.X << d.Y << d.dX << d.dY << m << osc::EndMessage;
#else
							p << osc::BeginMessage( "/tuio/2Dcur" ) << "set" << d.ID << d.X << d.Y << d.dX << d.dY << m << d.width << d.height << osc::EndMessage;
#endif
						} else {
							// is a fiducial tag

							//FIXME: should we send height and width for obj's too?
							p2 << osc::BeginMessage( "/tuio/2Dobj" ) << "set" << d.ID << d.tagID << d.X << d.Y << d.angle << d.dX << d.dY << 0.0 << m << 0.0 << osc::EndMessage;
						}

						scount ++;
						if(scount >= 10)
						{
							scount = 0;
							break;
						}
					}
				}

				if(iter1 == fingerList.end())
					done = true;

				p << osc::BeginMessage( "/tuio/2Dcur" );
				p << "alive";
				p2 << osc::BeginMessage( "/tuio/2Dobj" );
				p2 << "alive";

				for(iter2=fingerList.begin(); iter2 != fingerList.end(); iter2++)
				{
					TouchData d = (*iter2).second;
					if(d.tagID == 0)
					{
						if(!(d.X == 0 && d.Y == 0)) {
							p << d.ID;
						}
					} else {
						if(!(d.X == 0 && d.Y == 0)) {
							p2 << d.ID;
						}
					}
				}
				p << osc::EndMessage;
				p << osc::BeginMessage( "/tuio/2Dcur" ) << "fseq" << frameSeq << osc::EndMessage;
				p << osc::EndBundle;

				p2 << osc::EndMessage;
				p2 << osc::BeginMessage( "/tuio/2Dobj" ) << "fseq" << frameSeq << osc::EndMessage;
				p2 << osc::EndBundle;

				//printf("%d size. %d #fingers\n", p.Size(), fingerList.size());
				frameSeq ++;
				if(p.IsReady())
					transmitSocket->Send( p.Data(), p.Size() );

				if(p2.IsReady())
					transmitSocket->Send( p2.Data(), p2.Size() );
			}

		} else {
			// do we even need to do this?

			//p << osc::BeginBundleImmediate;
			p.Clear();
			p << osc::BeginBundle();

			p << osc::BeginMessage( "/tuio/2Dcur" );
			p << "alive";
			p << osc::EndMessage;

			p << osc::BeginMessage( "/tuio/2Dcur" ) << "fseq" << frameSeq << osc::EndMessage;

			p << osc::EndBundle;

			frameSeq ++;
			//printf("%d size\n", p.Size());

			if(p.IsReady())
				transmitSocket->Send( p.Data(), p.Size() );
		}

	}

	void clearFingers()
	{
		fingerList.clear();
	}

private:
	UdpTransmitSocket *transmitSocket;

	// Keep track of all finger presses.
	std::map<int, TouchData> fingerList;
	int frameSeq;

};

/////////////////////////////////////////////////////////////////////////

OSCApp app;
bool ok=true;

int main(int argc, char * argv[])
{
	std::string ip_address = ADDRESS;
	int port = PORT;

	// Check if command arguments are specified
	if (argc == 3)
	{
		// Convert parsed values
		ip_address = argv[1];
		port = (int)strtol (argv[2], NULL, 0);
	}

	// Set ip and port
	app.connectSocket(ip_address, port);

	screen = TouchScreenDevice::getTouchScreen();
	screen->setDebugMode(false);
	if(!screen->loadConfig("config.xml"))
	{
		std::string label;
		label = screen->pushFilter("dsvlcapture");
		screen->setParameter(label, "source", "cam");
		screen->pushFilter("mono");
		screen->pushFilter("smooth");
		screen->pushFilter("backgroundremove");

		label = screen->pushFilter("brightnesscontrast");
		screen->setParameter(label, "brightness", "0.1");
		screen->setParameter(label, "contrast", "0.4");
		label = screen->pushFilter("rectify");

		screen->setParameter(label, "level", "25");
		screen->saveConfig("config.xml");
	}

	std::string bgLabel = screen->findFirstFilter("backgroundremove");
	std::string recLabel = screen->findFirstFilter("rectify");
	screen->registerListener((ITouchListener *)&app);
	// Note: Begin processing should only be called after the screen is set up

	SLEEP(1000);
	screen->setParameter(bgLabel, "mask", (char*)screen->getCameraPoints());
	screen->setParameter(bgLabel, "capture", "");

	screen->beginProcessing();
	screen->beginTracking();
    cvNamedWindow( "Touch Listener", CV_WINDOW_AUTOSIZE );
	do
	{
		int keypressed = cvWaitKey(10) & 255;

		if(keypressed != 255 && keypressed > 0)
			printf("KP: %d\n", keypressed);

        if( keypressed == 27) break;		// ESC = quit
        if( keypressed == 98)				// b = recapture background
		{
			screen->setParameter(bgLabel, "capture", "");
			app.clearFingers();
		}

        if( keypressed == 114)				// r = auto rectify..
		{
			screen->setParameter(recLabel, "level", "auto");
		}

		screen->getEvents();

		app.frame();

		SLEEP(1);

	} while( ok );

	TouchScreenDevice::destroy();
	return 0;
}
<|endoftext|>