<commit_before>/*
 * (C) Copyright 2015 Kurento (http://kurento.org/)
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * This library 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.
 *
 */

#define BOOST_TEST_STATIC_LINK
#define BOOST_TEST_PROTECTED_VIRTUAL

#include <boost/test/included/unit_test.hpp>
#include <MediaPipelineImpl.hpp>
#include <objects/WebRtcEndpointImpl.hpp>
#include <IceCandidate.hpp>
#include <mutex>
#include <condition_variable>
#include <ModuleManager.hpp>
#include <KurentoException.hpp>
#include <MediaSet.hpp>
#include <MediaElementImpl.hpp>

using namespace kurento;
using namespace boost::unit_test;

boost::property_tree::ptree config;
std::string mediaPipelineId;
ModuleManager moduleManager;

struct GF {
  GF();
  ~GF();
};

BOOST_GLOBAL_FIXTURE (GF)

GF::GF()
{
  boost::property_tree::ptree ac, audioCodecs, vc, videoCodecs;
  gst_init (NULL, NULL);

  moduleManager.loadModulesFromDirectories ("../../src/server");

  config.add ("configPath", "../../../tests" );
  config.add ("modules.kurento.SdpEndpoint.numAudioMedias", 1);
  config.add ("modules.kurento.SdpEndpoint.numVideoMedias", 1);

  ac.put ("name", "opus/48000/2");
  audioCodecs.push_back (std::make_pair ("", ac) );
  config.add_child ("modules.kurento.SdpEndpoint.audioCodecs", audioCodecs);

  vc.put ("name", "VP8/90000");
  videoCodecs.push_back (std::make_pair ("", vc) );
  config.add_child ("modules.kurento.SdpEndpoint.videoCodecs", videoCodecs);

  mediaPipelineId = moduleManager.getFactory ("MediaPipeline")->createObject (
                      config, "",
                      Json::Value() )->getId();
}

GF::~GF()
{
  MediaSet::deleteMediaSet();
}

static std::shared_ptr <WebRtcEndpointImpl>
createWebrtc (void)
{
  std::shared_ptr <kurento::MediaObjectImpl> webrtcEndpoint;
  Json::Value constructorParams;

  constructorParams ["mediaPipeline"] = mediaPipelineId;

  webrtcEndpoint = moduleManager.getFactory ("WebRtcEndpoint")->createObject (
                     config, "",
                     constructorParams );

  return std::dynamic_pointer_cast <WebRtcEndpointImpl> (webrtcEndpoint);
}

static void
releaseWebRtc (std::shared_ptr<WebRtcEndpointImpl> &ep)
{
  std::string id = ep->getId();

  ep.reset();
  MediaSet::getMediaSet ()->release (id);
}

static std::shared_ptr <MediaElementImpl>
createTestSrc (void)
{
  std::shared_ptr <MediaElementImpl> src = std::dynamic_pointer_cast
      <MediaElementImpl> (MediaSet::getMediaSet()->ref (new  MediaElementImpl (
                            boost::property_tree::ptree(),
                            MediaSet::getMediaSet()->getMediaObject (mediaPipelineId),
                            "dummysrc") ) );

  g_object_set (src->getGstreamerElement(), "audio", TRUE, "video", TRUE, NULL);

  return std::dynamic_pointer_cast <MediaElementImpl> (src);
}

static void
releaseTestSrc (std::shared_ptr<MediaElementImpl> &ep)
{
  std::string id = ep->getId();

  ep.reset();
  MediaSet::getMediaSet ()->release (id);
}

static void
gathering_done ()
{
  std::atomic<bool> gathering_done (false);
  std::condition_variable cv;
  std::mutex mtx;
  std::unique_lock<std::mutex> lck (mtx);
  std::shared_ptr <WebRtcEndpointImpl> webRtcEp = createWebrtc();

  webRtcEp->signalOnIceGatheringDone.connect ([&] (OnIceGatheringDone event) {
    gathering_done = true;
    cv.notify_one();
  });

  webRtcEp->generateOffer ();
  webRtcEp->gatherCandidates ();

  cv.wait (lck, [&] () {
    return gathering_done.load();
  });

  if (!gathering_done) {
    BOOST_ERROR ("Gathering not done");
  }

  releaseWebRtc (webRtcEp);
}

static  void
ice_state_changes()
{
  std::atomic<bool> ice_state_changed (false);
  std::condition_variable cv;
  std::mutex mtx;
  std::unique_lock<std::mutex> lck (mtx);

  std::shared_ptr <WebRtcEndpointImpl> webRtcEpOfferer = createWebrtc();
  std::shared_ptr <WebRtcEndpointImpl> webRtcEpAnswerer = createWebrtc();

  webRtcEpOfferer->setName ("offerer");
  webRtcEpAnswerer->setName ("answerer");

  webRtcEpOfferer->signalOnIceCandidate.connect ([&] (OnIceCandidate event) {
    webRtcEpAnswerer->addIceCandidate (event.getCandidate() );
  });

  webRtcEpAnswerer->signalOnIceCandidate.connect ([&] (OnIceCandidate event) {
    webRtcEpOfferer->addIceCandidate (event.getCandidate() );
  });

  webRtcEpOfferer->signalOnIceComponentStateChanged.connect ([&] (
  OnIceComponentStateChanged event) {
    ice_state_changed = true;
    cv.notify_one();
  });

  std::string offer = webRtcEpOfferer->generateOffer ();
  std::string answer = webRtcEpAnswerer->processOffer (offer);
  webRtcEpOfferer->processAnswer (answer);

  webRtcEpOfferer->gatherCandidates ();
  webRtcEpAnswerer->gatherCandidates ();

  cv.wait (lck, [&] () {
    return ice_state_changed.load();
  });

  if (!ice_state_changed) {
    BOOST_ERROR ("ICE state not chagned");
  }

  releaseWebRtc (webRtcEpOfferer);
  releaseWebRtc (webRtcEpAnswerer);
}

static  void
stun_turn_properties ()
{
  std::string stunServerAddress ("10.0.0.1");
  int stunServerPort = 2345;
  std::string turnUrl ("user0:pass0@10.0.0.2:3456");

  std::shared_ptr <WebRtcEndpointImpl> webRtcEp  = createWebrtc();

  webRtcEp->setStunServerAddress (stunServerAddress);
  std::string stunServerAddressRet = webRtcEp->getStunServerAddress ();
  BOOST_CHECK (stunServerAddressRet == stunServerAddress);

  webRtcEp->setStunServerPort (stunServerPort);
  int stunServerPortRet = webRtcEp->getStunServerPort ();
  BOOST_CHECK (stunServerPortRet == stunServerPort);

  webRtcEp->setTurnUrl (turnUrl);
  std::string turnUrlRet = webRtcEp->getTurnUrl ();
  BOOST_CHECK (turnUrlRet == turnUrl);

  releaseWebRtc (webRtcEp);
}

static void
media_state_changes ()
{
  std::atomic<bool> media_state_changed (false);
  std::condition_variable cv;
  std::mutex mtx;
  std::unique_lock<std::mutex> lck (mtx);

  std::shared_ptr <WebRtcEndpointImpl> webRtcEpOfferer = createWebrtc();
  std::shared_ptr <WebRtcEndpointImpl> webRtcEpAnswerer = createWebrtc();
  std::shared_ptr <MediaElementImpl> src = createTestSrc();

  src->connect (webRtcEpOfferer);

  webRtcEpOfferer->signalOnIceCandidate.connect ([&] (OnIceCandidate event) {
    BOOST_TEST_MESSAGE ("Offerer: adding candidate " +
                        event.getCandidate()->getCandidate() );
    webRtcEpAnswerer->addIceCandidate (event.getCandidate() );
  });

  webRtcEpAnswerer->signalOnIceCandidate.connect ([&] (OnIceCandidate event) {
    BOOST_TEST_MESSAGE ("Answerer: adding candidate " +
                        event.getCandidate()->getCandidate() );
    webRtcEpOfferer->addIceCandidate (event.getCandidate() );
  });

  webRtcEpOfferer->signalOnIceGatheringDone.connect ([&] (
  OnIceGatheringDone event) {
    BOOST_TEST_MESSAGE ("Offerer: Gathering done");
  });

  webRtcEpAnswerer->signalOnIceGatheringDone.connect ([&] (
  OnIceGatheringDone event) {
    BOOST_TEST_MESSAGE ("Answerer: Gathering done");
  });

  webRtcEpAnswerer->signalMediaStateChanged.connect ([&] (
  MediaStateChanged event) {
    media_state_changed = true;
    cv.notify_one();
  });

  std::string offer = webRtcEpOfferer->generateOffer ();
  BOOST_TEST_MESSAGE ("offer: " + offer);

  std::string answer = webRtcEpAnswerer->processOffer (offer);
  BOOST_TEST_MESSAGE ("answer: " + answer);

  webRtcEpOfferer->processAnswer (answer);

  webRtcEpOfferer->gatherCandidates ();
  webRtcEpAnswerer->gatherCandidates ();

  cv.wait (lck, [&] () {

    return media_state_changed.load();
  });

  if (!media_state_changed) {
    BOOST_ERROR ("Not media state chagned");
  }

  releaseTestSrc (src);
  releaseWebRtc (webRtcEpOfferer);
  releaseWebRtc (webRtcEpAnswerer);
}

test_suite *
init_unit_test_suite ( int , char* [] )
{
  test_suite *test = BOOST_TEST_SUITE ( "WebRtcEndpoint" );
  test->add (BOOST_TEST_CASE ( &gathering_done ), 0, /* timeout */ 15);
  test->add (BOOST_TEST_CASE ( &ice_state_changes ), 0, /* timeout */ 15);
  test->add (BOOST_TEST_CASE ( &stun_turn_properties ), 0, /* timeout */ 15);
  test->add (BOOST_TEST_CASE ( &media_state_changes ), 0, /* timeout */ 15);

  return test;
}
<commit_msg>webRtcEndpoint: add test for connection state<commit_after>/*
 * (C) Copyright 2015 Kurento (http://kurento.org/)
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * This library 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.
 *
 */

#define BOOST_TEST_STATIC_LINK
#define BOOST_TEST_PROTECTED_VIRTUAL

#include <boost/test/included/unit_test.hpp>
#include <MediaPipelineImpl.hpp>
#include <objects/WebRtcEndpointImpl.hpp>
#include <IceCandidate.hpp>
#include <mutex>
#include <condition_variable>
#include <ModuleManager.hpp>
#include <KurentoException.hpp>
#include <MediaSet.hpp>
#include <MediaElementImpl.hpp>
#include <ConnectionState.hpp>

using namespace kurento;
using namespace boost::unit_test;

boost::property_tree::ptree config;
std::string mediaPipelineId;
ModuleManager moduleManager;

struct GF {
  GF();
  ~GF();
};

BOOST_GLOBAL_FIXTURE (GF)

GF::GF()
{
  boost::property_tree::ptree ac, audioCodecs, vc, videoCodecs;
  gst_init (NULL, NULL);

  moduleManager.loadModulesFromDirectories ("../../src/server");

  config.add ("configPath", "../../../tests" );
  config.add ("modules.kurento.SdpEndpoint.numAudioMedias", 1);
  config.add ("modules.kurento.SdpEndpoint.numVideoMedias", 1);

  ac.put ("name", "opus/48000/2");
  audioCodecs.push_back (std::make_pair ("", ac) );
  config.add_child ("modules.kurento.SdpEndpoint.audioCodecs", audioCodecs);

  vc.put ("name", "VP8/90000");
  videoCodecs.push_back (std::make_pair ("", vc) );
  config.add_child ("modules.kurento.SdpEndpoint.videoCodecs", videoCodecs);

  mediaPipelineId = moduleManager.getFactory ("MediaPipeline")->createObject (
                      config, "",
                      Json::Value() )->getId();
}

GF::~GF()
{
  MediaSet::deleteMediaSet();
}

static std::shared_ptr <WebRtcEndpointImpl>
createWebrtc (void)
{
  std::shared_ptr <kurento::MediaObjectImpl> webrtcEndpoint;
  Json::Value constructorParams;

  constructorParams ["mediaPipeline"] = mediaPipelineId;

  webrtcEndpoint = moduleManager.getFactory ("WebRtcEndpoint")->createObject (
                     config, "",
                     constructorParams );

  return std::dynamic_pointer_cast <WebRtcEndpointImpl> (webrtcEndpoint);
}

static void
releaseWebRtc (std::shared_ptr<WebRtcEndpointImpl> &ep)
{
  std::string id = ep->getId();

  ep.reset();
  MediaSet::getMediaSet ()->release (id);
}

static std::shared_ptr <MediaElementImpl>
createTestSrc (void)
{
  std::shared_ptr <MediaElementImpl> src = std::dynamic_pointer_cast
      <MediaElementImpl> (MediaSet::getMediaSet()->ref (new  MediaElementImpl (
                            boost::property_tree::ptree(),
                            MediaSet::getMediaSet()->getMediaObject (mediaPipelineId),
                            "dummysrc") ) );

  g_object_set (src->getGstreamerElement(), "audio", TRUE, "video", TRUE, NULL);

  return std::dynamic_pointer_cast <MediaElementImpl> (src);
}

static void
releaseTestSrc (std::shared_ptr<MediaElementImpl> &ep)
{
  std::string id = ep->getId();

  ep.reset();
  MediaSet::getMediaSet ()->release (id);
}

static void
gathering_done ()
{
  std::atomic<bool> gathering_done (false);
  std::condition_variable cv;
  std::mutex mtx;
  std::unique_lock<std::mutex> lck (mtx);
  std::shared_ptr <WebRtcEndpointImpl> webRtcEp = createWebrtc();

  webRtcEp->signalOnIceGatheringDone.connect ([&] (OnIceGatheringDone event) {
    gathering_done = true;
    cv.notify_one();
  });

  webRtcEp->generateOffer ();
  webRtcEp->gatherCandidates ();

  cv.wait (lck, [&] () {
    return gathering_done.load();
  });

  if (!gathering_done) {
    BOOST_ERROR ("Gathering not done");
  }

  releaseWebRtc (webRtcEp);
}

static  void
ice_state_changes()
{
  std::atomic<bool> ice_state_changed (false);
  std::condition_variable cv;
  std::mutex mtx;
  std::unique_lock<std::mutex> lck (mtx);

  std::shared_ptr <WebRtcEndpointImpl> webRtcEpOfferer = createWebrtc();
  std::shared_ptr <WebRtcEndpointImpl> webRtcEpAnswerer = createWebrtc();

  webRtcEpOfferer->setName ("offerer");
  webRtcEpAnswerer->setName ("answerer");

  webRtcEpOfferer->signalOnIceCandidate.connect ([&] (OnIceCandidate event) {
    webRtcEpAnswerer->addIceCandidate (event.getCandidate() );
  });

  webRtcEpAnswerer->signalOnIceCandidate.connect ([&] (OnIceCandidate event) {
    webRtcEpOfferer->addIceCandidate (event.getCandidate() );
  });

  webRtcEpOfferer->signalOnIceComponentStateChanged.connect ([&] (
  OnIceComponentStateChanged event) {
    ice_state_changed = true;
    cv.notify_one();
  });

  std::string offer = webRtcEpOfferer->generateOffer ();
  std::string answer = webRtcEpAnswerer->processOffer (offer);
  webRtcEpOfferer->processAnswer (answer);

  webRtcEpOfferer->gatherCandidates ();
  webRtcEpAnswerer->gatherCandidates ();

  cv.wait (lck, [&] () {
    return ice_state_changed.load();
  });

  if (!ice_state_changed) {
    BOOST_ERROR ("ICE state not chagned");
  }

  releaseWebRtc (webRtcEpOfferer);
  releaseWebRtc (webRtcEpAnswerer);
}

static  void
stun_turn_properties ()
{
  std::string stunServerAddress ("10.0.0.1");
  int stunServerPort = 2345;
  std::string turnUrl ("user0:pass0@10.0.0.2:3456");

  std::shared_ptr <WebRtcEndpointImpl> webRtcEp  = createWebrtc();

  webRtcEp->setStunServerAddress (stunServerAddress);
  std::string stunServerAddressRet = webRtcEp->getStunServerAddress ();
  BOOST_CHECK (stunServerAddressRet == stunServerAddress);

  webRtcEp->setStunServerPort (stunServerPort);
  int stunServerPortRet = webRtcEp->getStunServerPort ();
  BOOST_CHECK (stunServerPortRet == stunServerPort);

  webRtcEp->setTurnUrl (turnUrl);
  std::string turnUrlRet = webRtcEp->getTurnUrl ();
  BOOST_CHECK (turnUrlRet == turnUrl);

  releaseWebRtc (webRtcEp);
}

static void
media_state_changes ()
{
  std::atomic<bool> media_state_changed (false);
  std::condition_variable cv;
  std::mutex mtx;
  std::unique_lock<std::mutex> lck (mtx);

  std::shared_ptr <WebRtcEndpointImpl> webRtcEpOfferer = createWebrtc();
  std::shared_ptr <WebRtcEndpointImpl> webRtcEpAnswerer = createWebrtc();
  std::shared_ptr <MediaElementImpl> src = createTestSrc();

  src->connect (webRtcEpOfferer);

  webRtcEpOfferer->signalOnIceCandidate.connect ([&] (OnIceCandidate event) {
    BOOST_TEST_MESSAGE ("Offerer: adding candidate " +
                        event.getCandidate()->getCandidate() );
    webRtcEpAnswerer->addIceCandidate (event.getCandidate() );
  });

  webRtcEpAnswerer->signalOnIceCandidate.connect ([&] (OnIceCandidate event) {
    BOOST_TEST_MESSAGE ("Answerer: adding candidate " +
                        event.getCandidate()->getCandidate() );
    webRtcEpOfferer->addIceCandidate (event.getCandidate() );
  });

  webRtcEpOfferer->signalOnIceGatheringDone.connect ([&] (
  OnIceGatheringDone event) {
    BOOST_TEST_MESSAGE ("Offerer: Gathering done");
  });

  webRtcEpAnswerer->signalOnIceGatheringDone.connect ([&] (
  OnIceGatheringDone event) {
    BOOST_TEST_MESSAGE ("Answerer: Gathering done");
  });

  webRtcEpAnswerer->signalMediaStateChanged.connect ([&] (
  MediaStateChanged event) {
    media_state_changed = true;
    cv.notify_one();
  });

  std::string offer = webRtcEpOfferer->generateOffer ();
  BOOST_TEST_MESSAGE ("offer: " + offer);

  std::string answer = webRtcEpAnswerer->processOffer (offer);
  BOOST_TEST_MESSAGE ("answer: " + answer);

  webRtcEpOfferer->processAnswer (answer);

  webRtcEpOfferer->gatherCandidates ();
  webRtcEpAnswerer->gatherCandidates ();

  cv.wait (lck, [&] () {
    return media_state_changed.load();
  });

  if (!media_state_changed) {
    BOOST_ERROR ("Not media state chagned");
  }

  releaseTestSrc (src);
  releaseWebRtc (webRtcEpOfferer);
  releaseWebRtc (webRtcEpAnswerer);
}

static void
connection_state_changes ()
{
  std::atomic<bool> conn_state_changed (false);
  std::condition_variable cv;
  std::mutex mtx;
  std::unique_lock<std::mutex> lck (mtx);

  std::shared_ptr <WebRtcEndpointImpl> webRtcEpOfferer = createWebrtc();
  std::shared_ptr <WebRtcEndpointImpl> webRtcEpAnswerer = createWebrtc();

  webRtcEpOfferer->signalOnIceCandidate.connect ([&] (OnIceCandidate event) {
    BOOST_TEST_MESSAGE ("Offerer: adding candidate " +
                        event.getCandidate()->getCandidate() );
    webRtcEpAnswerer->addIceCandidate (event.getCandidate() );
  });

  webRtcEpAnswerer->signalOnIceCandidate.connect ([&] (OnIceCandidate event) {
    BOOST_TEST_MESSAGE ("Answerer: adding candidate " +
                        event.getCandidate()->getCandidate() );
    webRtcEpOfferer->addIceCandidate (event.getCandidate() );
  });

  webRtcEpOfferer->signalOnIceGatheringDone.connect ([&] (
  OnIceGatheringDone event) {
    BOOST_TEST_MESSAGE ("Offerer: Gathering done");
  });

  webRtcEpAnswerer->signalOnIceGatheringDone.connect ([&] (
  OnIceGatheringDone event) {
    BOOST_TEST_MESSAGE ("Answerer: Gathering done");
  });

  webRtcEpAnswerer->signalConnectionStateChanged.connect ([&] (
  ConnectionStateChanged event) {
    conn_state_changed = true;
    cv.notify_one();
  });

  std::string offer = webRtcEpOfferer->generateOffer ();
  BOOST_TEST_MESSAGE ("offer: " + offer);

  std::string answer = webRtcEpAnswerer->processOffer (offer);
  BOOST_TEST_MESSAGE ("answer: " + answer);

  webRtcEpOfferer->processAnswer (answer);

  if (webRtcEpAnswerer->getConnectionState ()->getValue () !=
      ConnectionState::DISCONNECTED) {
    BOOST_ERROR ("Connection must be disconnected");
  }

  webRtcEpOfferer->gatherCandidates ();
  webRtcEpAnswerer->gatherCandidates ();

  cv.wait (lck, [&] () {
    return conn_state_changed.load();
  });

  if (!conn_state_changed) {
    BOOST_ERROR ("Not conn state chagned");
  }

  if (webRtcEpAnswerer->getConnectionState ()->getValue () !=
      ConnectionState::CONNECTED) {
    BOOST_ERROR ("Connection must be connected");
  }

  releaseWebRtc (webRtcEpOfferer);
  releaseWebRtc (webRtcEpAnswerer);
}

test_suite *
init_unit_test_suite ( int , char* [] )
{
  test_suite *test = BOOST_TEST_SUITE ( "WebRtcEndpoint" );
  test->add (BOOST_TEST_CASE ( &gathering_done ), 0, /* timeout */ 15);
  test->add (BOOST_TEST_CASE ( &ice_state_changes ), 0, /* timeout */ 15);
  test->add (BOOST_TEST_CASE ( &stun_turn_properties ), 0, /* timeout */ 15);
  test->add (BOOST_TEST_CASE ( &media_state_changes ), 0, /* timeout */ 15);
  test->add (BOOST_TEST_CASE ( &connection_state_changes ), 0, /* timeout */ 15);

  return test;
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the demonstration applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <stdlib.h>
#include <qdeclarativeextensionplugin.h>
#include <qdeclarativecontext.h>
#include <qdeclarativeengine.h>
#include <qdeclarative.h>

#include <QTime>
#include <QTimer>

class Tile : public QObject
{
    Q_OBJECT
public:
    Tile() : _hasFlag(false), _hasMine(false), _hint(-1), _flipped(false) {}

    Q_PROPERTY(bool hasFlag READ hasFlag WRITE setHasFlag NOTIFY hasFlagChanged);
    bool hasFlag() const { return _hasFlag; }

    Q_PROPERTY(bool hasMine READ hasMine NOTIFY hasMineChanged);
    bool hasMine() const { return _hasMine; }

    Q_PROPERTY(int hint READ hint NOTIFY hintChanged);
    int hint() const { return _hint; }

    Q_PROPERTY(bool flipped READ flipped NOTIFY flippedChanged());
    bool flipped() const { return _flipped; }

    void setHasFlag(bool flag) {if(flag==_hasFlag) return; _hasFlag = flag; emit hasFlagChanged();}
    void setHasMine(bool mine) {if(mine==_hasMine) return; _hasMine = mine; emit hasMineChanged();}
    void setHint(int hint) { if(hint == _hint) return; _hint = hint; emit hintChanged(); }
    void flip() { if (_flipped) return; _flipped = true; emit flippedChanged(); }
    void unflip() { if(!_flipped) return; _flipped = false; emit flippedChanged(); }

signals:
    void flippedChanged();
    void hasFlagChanged();
    void hintChanged();
    void hasMineChanged();

private:
    bool _hasFlag;
    bool _hasMine;
    int _hint;
    bool _flipped;
};

class MinehuntGame : public QObject
{
    Q_OBJECT
public:
    MinehuntGame();

    Q_PROPERTY(QDeclarativeListProperty<Tile> tiles READ tiles CONSTANT);
    QDeclarativeListProperty<Tile> tiles() { return QDeclarativeListProperty<Tile>(this, _tiles); }

    Q_PROPERTY(bool isPlaying READ isPlaying NOTIFY isPlayingChanged);
    bool isPlaying() {return playing;}

    Q_PROPERTY(bool hasWon READ hasWon NOTIFY hasWonChanged);
    bool hasWon() {return won;}

    Q_PROPERTY(int numMines READ numMines NOTIFY numMinesChanged);
    int numMines() const{return nMines;}

    Q_PROPERTY(int numFlags READ numFlags NOTIFY numFlagsChanged);
    int numFlags() const{return nFlags;}

public slots:
    Q_INVOKABLE bool flip(int row, int col);
    Q_INVOKABLE bool flag(int row, int col);
    void setBoard();
    void reset();

signals:
    void isPlayingChanged();
    void hasWonChanged();
    void numMinesChanged();
    void numFlagsChanged();

private:
    bool onBoard( int r, int c ) const { return r >= 0 && r < numRows && c >= 0 && c < numCols; }
    Tile *tile( int row, int col ) { return onBoard(row, col) ? _tiles[col+numRows*row] : 0; }
    int getHint(int row, int col);
    void setPlaying(bool b){if(b==playing) return; playing=b; emit isPlayingChanged();}

    QList<Tile *> _tiles;
    int numCols;
    int numRows;
    bool playing;
    bool won;
    int remaining;
    int nMines;
    int nFlags;
};

MinehuntGame::MinehuntGame()
: numCols(9), numRows(9), playing(true), won(false)
{
    setObjectName("mainObject");
    srand(QTime(0,0,0).secsTo(QTime::currentTime()));

    //initialize array
    for(int ii = 0; ii < numRows * numCols; ++ii) {
        _tiles << new Tile;
    }
    reset();

}

void MinehuntGame::setBoard()
{
    foreach(Tile* t, _tiles){
        t->setHasMine(false);
        t->setHint(-1);
    }
    //place mines
    int mines = nMines;
    remaining = numRows*numCols-mines;
    while ( mines ) {
        int col = int((double(rand()) / double(RAND_MAX)) * numCols);
        int row = int((double(rand()) / double(RAND_MAX)) * numRows);

        Tile* t = tile( row, col );

        if (t && !t->hasMine()) {
            t->setHasMine( true );
            mines--;
        }
    }

    //set hints
    for (int r = 0; r < numRows; r++)
        for (int c = 0; c < numCols; c++) {
            Tile* t = tile(r, c);
            if (t && !t->hasMine()) {
                int hint = getHint(r,c);
                t->setHint(hint);
            }
        }

    setPlaying(true);
}

void MinehuntGame::reset()
{
    foreach(Tile* t, _tiles){
        t->unflip();
        t->setHasFlag(false);
    }
    nMines = 12;
    nFlags = 0;
    setPlaying(false);
    QTimer::singleShot(600,this, SLOT(setBoard()));
}

int MinehuntGame::getHint(int row, int col)
{
    int hint = 0;
    for (int c = col-1; c <= col+1; c++)
        for (int r = row-1; r <= row+1; r++) {
            Tile* t = tile(r, c);
            if (t && t->hasMine())
                hint++;
        }
    return hint;
}

bool MinehuntGame::flip(int row, int col)
{
    if(!playing)
        return false;

    Tile *t = tile(row, col);
    if (!t || t->hasFlag())
        return false;

    if(t->flipped()){
        int flags = 0;
        for (int c = col-1; c <= col+1; c++)
            for (int r = row-1; r <= row+1; r++) {
                Tile *nearT = tile(r, c);
                if(!nearT || nearT == t)
                    continue;
                if(nearT->hasFlag())
                    flags++;
            }
        if(!t->hint() || t->hint() != flags)
            return false;
        for (int c = col-1; c <= col+1; c++)
            for (int r = row-1; r <= row+1; r++) {
                Tile *nearT = tile(r, c);
                if (nearT && !nearT->flipped() && !nearT->hasFlag()) {
                    flip( r, c );
                }
            }
        return true;
    }

    t->flip();

    if (t->hint() == 0) {
        for (int c = col-1; c <= col+1; c++)
            for (int r = row-1; r <= row+1; r++) {
                Tile* t = tile(r, c);
                if (t && !t->flipped()) {
                    flip( r, c );
                }
            }
    }

    if(t->hasMine()){
        for (int r = 0; r < numRows; r++)//Flip all other mines
            for (int c = 0; c < numCols; c++) {
                Tile* t = tile(r, c);
                if (t && t->hasMine()) {
                    flip(r, c);
                }
            }
        won = false;
        hasWonChanged();
        setPlaying(false);
    }

    remaining--;
    if(!remaining){
        won = true;
        hasWonChanged();
        setPlaying(false);
    }
    return true;
}

bool MinehuntGame::flag(int row, int col)
{
    Tile *t = tile(row, col);
    if(!t)
        return false;

    t->setHasFlag(!t->hasFlag());
    nFlags += (t->hasFlag()?1:-1);
    emit numFlagsChanged();
    return true;
}

QML_DECLARE_TYPE(Tile);
QML_DECLARE_TYPE(MinehuntGame);

class MinehuntExtensionPlugin : public QDeclarativeExtensionPlugin
{
    Q_OBJECT

    public:
    void registerTypes(const char *uri) {
        qmlRegisterType<Tile>(uri, 0, 1, "Tile");
        qmlRegisterType<MinehuntGame>(uri, 0, 1, "Game");
    }

    void initializeEngine(QDeclarativeEngine *engine, const char *uri) {
        Q_UNUSED(uri);

        srand(QTime(0,0,0).secsTo(QTime::currentTime()));

        MinehuntGame* game = new MinehuntGame();

        engine->rootContext()->setContextObject(game);
    }
};

#include "minehunt.moc"

Q_EXPORT_PLUGIN(MinehuntExtensionPlugin);

<commit_msg>Use QDeclarativeListProperty properly<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the demonstration applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <stdlib.h>
#include <qdeclarativeextensionplugin.h>
#include <qdeclarativecontext.h>
#include <qdeclarativeengine.h>
#include <qdeclarative.h>

#include <QTime>
#include <QTimer>

class Tile : public QObject
{
    Q_OBJECT
public:
    Tile() : _hasFlag(false), _hasMine(false), _hint(-1), _flipped(false) {}

    Q_PROPERTY(bool hasFlag READ hasFlag WRITE setHasFlag NOTIFY hasFlagChanged);
    bool hasFlag() const { return _hasFlag; }

    Q_PROPERTY(bool hasMine READ hasMine NOTIFY hasMineChanged);
    bool hasMine() const { return _hasMine; }

    Q_PROPERTY(int hint READ hint NOTIFY hintChanged);
    int hint() const { return _hint; }

    Q_PROPERTY(bool flipped READ flipped NOTIFY flippedChanged());
    bool flipped() const { return _flipped; }

    void setHasFlag(bool flag) {if(flag==_hasFlag) return; _hasFlag = flag; emit hasFlagChanged();}
    void setHasMine(bool mine) {if(mine==_hasMine) return; _hasMine = mine; emit hasMineChanged();}
    void setHint(int hint) { if(hint == _hint) return; _hint = hint; emit hintChanged(); }
    void flip() { if (_flipped) return; _flipped = true; emit flippedChanged(); }
    void unflip() { if(!_flipped) return; _flipped = false; emit flippedChanged(); }

signals:
    void flippedChanged();
    void hasFlagChanged();
    void hintChanged();
    void hasMineChanged();

private:
    bool _hasFlag;
    bool _hasMine;
    int _hint;
    bool _flipped;
};

class MinehuntGame : public QObject
{
    Q_OBJECT
public:
    MinehuntGame();

    Q_PROPERTY(QDeclarativeListProperty<Tile> tiles READ tiles CONSTANT);
    QDeclarativeListProperty<Tile> tiles();

    Q_PROPERTY(bool isPlaying READ isPlaying NOTIFY isPlayingChanged);
    bool isPlaying() {return playing;}

    Q_PROPERTY(bool hasWon READ hasWon NOTIFY hasWonChanged);
    bool hasWon() {return won;}

    Q_PROPERTY(int numMines READ numMines NOTIFY numMinesChanged);
    int numMines() const{return nMines;}

    Q_PROPERTY(int numFlags READ numFlags NOTIFY numFlagsChanged);
    int numFlags() const{return nFlags;}

public slots:
    Q_INVOKABLE bool flip(int row, int col);
    Q_INVOKABLE bool flag(int row, int col);
    void setBoard();
    void reset();

signals:
    void isPlayingChanged();
    void hasWonChanged();
    void numMinesChanged();
    void numFlagsChanged();

private:
    bool onBoard( int r, int c ) const { return r >= 0 && r < numRows && c >= 0 && c < numCols; }
    Tile *tile( int row, int col ) { return onBoard(row, col) ? _tiles[col+numRows*row] : 0; }
    int getHint(int row, int col);
    void setPlaying(bool b){if(b==playing) return; playing=b; emit isPlayingChanged();}

    QList<Tile *> _tiles;
    int numCols;
    int numRows;
    bool playing;
    bool won;
    int remaining;
    int nMines;
    int nFlags;
};

void tilesPropAppend(QDeclarativeListProperty<Tile>* prop, Tile* value)
{
    Q_UNUSED(prop);
    Q_UNUSED(value);
    return; //Append not supported
}

int tilesPropCount(QDeclarativeListProperty<Tile>* prop)
{
    return static_cast<QList<Tile*>*>(prop->data)->count();
}

Tile* tilesPropAt(QDeclarativeListProperty<Tile>* prop, int index)
{
    return static_cast<QList<Tile*>*>(prop->data)->at(index);
}

QDeclarativeListProperty<Tile> MinehuntGame::tiles(){
    return QDeclarativeListProperty<Tile>(this, &_tiles, &tilesPropAppend,
            &tilesPropCount, &tilesPropAt, 0);
}

MinehuntGame::MinehuntGame()
: numCols(9), numRows(9), playing(true), won(false)
{
    setObjectName("mainObject");
    srand(QTime(0,0,0).secsTo(QTime::currentTime()));

    //initialize array
    for(int ii = 0; ii < numRows * numCols; ++ii) {
        _tiles << new Tile;
    }
    reset();

}

void MinehuntGame::setBoard()
{
    foreach(Tile* t, _tiles){
        t->setHasMine(false);
        t->setHint(-1);
    }
    //place mines
    int mines = nMines;
    remaining = numRows*numCols-mines;
    while ( mines ) {
        int col = int((double(rand()) / double(RAND_MAX)) * numCols);
        int row = int((double(rand()) / double(RAND_MAX)) * numRows);

        Tile* t = tile( row, col );

        if (t && !t->hasMine()) {
            t->setHasMine( true );
            mines--;
        }
    }

    //set hints
    for (int r = 0; r < numRows; r++)
        for (int c = 0; c < numCols; c++) {
            Tile* t = tile(r, c);
            if (t && !t->hasMine()) {
                int hint = getHint(r,c);
                t->setHint(hint);
            }
        }

    setPlaying(true);
}

void MinehuntGame::reset()
{
    foreach(Tile* t, _tiles){
        t->unflip();
        t->setHasFlag(false);
    }
    nMines = 12;
    nFlags = 0;
    setPlaying(false);
    QTimer::singleShot(600,this, SLOT(setBoard()));
}

int MinehuntGame::getHint(int row, int col)
{
    int hint = 0;
    for (int c = col-1; c <= col+1; c++)
        for (int r = row-1; r <= row+1; r++) {
            Tile* t = tile(r, c);
            if (t && t->hasMine())
                hint++;
        }
    return hint;
}

bool MinehuntGame::flip(int row, int col)
{
    if(!playing)
        return false;

    Tile *t = tile(row, col);
    if (!t || t->hasFlag())
        return false;

    if(t->flipped()){
        int flags = 0;
        for (int c = col-1; c <= col+1; c++)
            for (int r = row-1; r <= row+1; r++) {
                Tile *nearT = tile(r, c);
                if(!nearT || nearT == t)
                    continue;
                if(nearT->hasFlag())
                    flags++;
            }
        if(!t->hint() || t->hint() != flags)
            return false;
        for (int c = col-1; c <= col+1; c++)
            for (int r = row-1; r <= row+1; r++) {
                Tile *nearT = tile(r, c);
                if (nearT && !nearT->flipped() && !nearT->hasFlag()) {
                    flip( r, c );
                }
            }
        return true;
    }

    t->flip();

    if (t->hint() == 0) {
        for (int c = col-1; c <= col+1; c++)
            for (int r = row-1; r <= row+1; r++) {
                Tile* t = tile(r, c);
                if (t && !t->flipped()) {
                    flip( r, c );
                }
            }
    }

    if(t->hasMine()){
        for (int r = 0; r < numRows; r++)//Flip all other mines
            for (int c = 0; c < numCols; c++) {
                Tile* t = tile(r, c);
                if (t && t->hasMine()) {
                    flip(r, c);
                }
            }
        won = false;
        hasWonChanged();
        setPlaying(false);
    }

    remaining--;
    if(!remaining){
        won = true;
        hasWonChanged();
        setPlaying(false);
    }
    return true;
}

bool MinehuntGame::flag(int row, int col)
{
    Tile *t = tile(row, col);
    if(!t)
        return false;

    t->setHasFlag(!t->hasFlag());
    nFlags += (t->hasFlag()?1:-1);
    emit numFlagsChanged();
    return true;
}

QML_DECLARE_TYPE(Tile);
QML_DECLARE_TYPE(MinehuntGame);

class MinehuntExtensionPlugin : public QDeclarativeExtensionPlugin
{
    Q_OBJECT

    public:
    void registerTypes(const char *uri) {
        qmlRegisterType<Tile>(uri, 0, 1, "Tile");
        qmlRegisterType<MinehuntGame>(uri, 0, 1, "Game");
    }

    void initializeEngine(QDeclarativeEngine *engine, const char *uri) {
        Q_UNUSED(uri);

        srand(QTime(0,0,0).secsTo(QTime::currentTime()));

        MinehuntGame* game = new MinehuntGame();

        engine->rootContext()->setContextObject(game);
    }
};

#include "minehunt.moc"

Q_EXPORT_PLUGIN(MinehuntExtensionPlugin);

<|endoftext|>


<commit_before>#include "zcm/transport.h"
#include "zcm/transport_registrar.h"
#include "zcm/transport_register.hpp"

#include "zcm/zcm-cpp.hpp"
#include "zcm/util/debug.h"
//#include "zcm/util/lockfile.h"

#include "util/Types.hpp"
#include "util/TimeUtil.hpp"

#include <cstdio>
#include <cassert>
#include <unordered_map>
#include <mutex>
#include <unistd.h>
#include <limits.h>

#define ZCM_TRANS_CLASSNAME TransportFile
#define MTU (SSIZE_MAX)

using namespace std;

struct ZCM_TRANS_CLASSNAME : public zcm_trans_t
{
    zcm::LogFile *log = nullptr;
    unordered_map<string, string> options;

    string mode = "r";
    double speed = 1.0;

    u64 lastMsgUtime = 0;
    u64 lastDispatchUtime = 0;

    string *findOption(const string& s)
    {
        auto it = options.find(s);
        if (it == options.end()) return nullptr;
        return &it->second;
    }

    ZCM_TRANS_CLASSNAME(zcm_url_t *url)
    {
        trans_type = ZCM_BLOCKING;
        vtbl = &methods;

        // build 'options'
        auto *opts = zcm_url_opts(url);
        for (size_t i = 0; i < opts->numopts; i++)
            options[opts->name[i]] = opts->value[i];

        string* speedStr = findOption("speed");
        if (speedStr) {
            speed = atof(speedStr->c_str());
            if (speed <= 0) {
                ZCM_DEBUG("Expected double argument for 'speed'");
                return;
            }
        }

        string* modeStr = findOption("mode");
        if (modeStr) {
            mode = string(*modeStr);
            if (!(mode == "r" || mode == "w" || mode == "a")) {
                ZCM_DEBUG("Expected r|w|a as mode argument for zcm file");
                return;
            }
        }

        auto filename = zcm_url_address(url);
        ZCM_DEBUG("Opening zcm logfile: \"%s\"", filename);
        log = new zcm::LogFile(filename, string(mode));
        if (!log->good()) {
            fprintf(stderr, "Unable to open logfile %s\n", filename);
            return;
        }
    }

    ~ZCM_TRANS_CLASSNAME()
    {
        if (log) delete log;
    }

    bool good()
    {
        return log ? log->good() : false;
    }

    /********************** METHODS **********************/
    size_t get_mtu()
    {
        return MTU;
    }

    // TODO: Test the sendmsg function
    int sendmsg(zcm_msg_t msg)
    {
        assert(good());
        assert(mode == "w" || mode == "a");

        if (msg.len > get_mtu())
            return ZCM_EINVALID;

        zcm::LogEvent le;
        le.timestamp = msg.utime;
        le.datalen = msg.len;
        le.channel = string(msg.channel);
        le.data = msg.buf;

        log->writeEvent(&le);

        return ZCM_EOK;
    }

    int recvmsg_enable(const char *channel, bool enable)
    {
        return ZCM_EOK;
    }

    int recvmsg(zcm_msg_t *msg, int timeout)
    {
        assert(mode == "r");
        if (!good()) {
            // TODO Build in a way for a transport to tell zcm that an "error"
            //      has occurred. Not sure what to do here since this function
            //      has no way of communicating to the caller that this function
            //      shouldn't be called anymore
            usleep(timeout);
            return ZCM_ECONNECT;
        }

        const zcm::LogEvent* le = log->readNextEvent();
        if (!le) {
            delete log;
            log = nullptr;
            return ZCM_ECONNECT;
        }

        msg->utime = le->timestamp;
        msg->channel = le->channel.c_str();
        msg->len = le->datalen;
        msg->buf = le->data;

        u64 now = TimeUtil::utime();

        if (lastMsgUtime == 0)
            lastMsgUtime = msg->utime;

        if (lastDispatchUtime == 0)
            lastDispatchUtime = now;

        u64 localDiff = now - lastDispatchUtime;
        u64 logDiff = msg->utime - lastMsgUtime;
        u64 logDiffSpeed = logDiff / this->speed;
        u64 diff = logDiffSpeed > localDiff ? logDiffSpeed - localDiff : 0;

        if (diff > 0)
            usleep(diff);

        lastDispatchUtime = TimeUtil::utime();
        lastMsgUtime = msg->utime;

        return ZCM_EOK;
    }

    /********************** STATICS **********************/
    static zcm_trans_methods_t methods;
    static ZCM_TRANS_CLASSNAME *cast(zcm_trans_t *zt)
    {
        assert(zt->vtbl == &methods);
        return (ZCM_TRANS_CLASSNAME*)zt;
    }

    static size_t _get_mtu(zcm_trans_t *zt)
    { return cast(zt)->get_mtu(); }

    static int _sendmsg(zcm_trans_t *zt, zcm_msg_t msg)
    { return cast(zt)->sendmsg(msg); }

    static int _recvmsg_enable(zcm_trans_t *zt, const char *channel, bool enable)
    { return cast(zt)->recvmsg_enable(channel, enable); }

    static int _recvmsg(zcm_trans_t *zt, zcm_msg_t *msg, int timeout)
    { return cast(zt)->recvmsg(msg, timeout); }

    static void _destroy(zcm_trans_t *zt)
    { delete cast(zt); }

    static const TransportRegister reg;
};

zcm_trans_methods_t ZCM_TRANS_CLASSNAME::methods = {
    &ZCM_TRANS_CLASSNAME::_get_mtu,
    &ZCM_TRANS_CLASSNAME::_sendmsg,
    &ZCM_TRANS_CLASSNAME::_recvmsg_enable,
    &ZCM_TRANS_CLASSNAME::_recvmsg,
    NULL,
    &ZCM_TRANS_CLASSNAME::_destroy,
};

static zcm_trans_t *create(zcm_url_t *url)
{
    auto *trans = new ZCM_TRANS_CLASSNAME(url);
    if (trans->good())
        return trans;

    delete trans;
    return nullptr;
}

const TransportRegister ZCM_TRANS_CLASSNAME::reg(
    "file", "Interact with zcm log file (e.g. 'file://vehicle.log?speed=2.0)", create);
<commit_msg>Removed comment<commit_after>#include "zcm/transport.h"
#include "zcm/transport_registrar.h"
#include "zcm/transport_register.hpp"

#include "zcm/zcm-cpp.hpp"
#include "zcm/util/debug.h"
//#include "zcm/util/lockfile.h"

#include "util/Types.hpp"
#include "util/TimeUtil.hpp"

#include <cstdio>
#include <cassert>
#include <unordered_map>
#include <mutex>
#include <unistd.h>
#include <limits.h>

#define ZCM_TRANS_CLASSNAME TransportFile
#define MTU (SSIZE_MAX)

using namespace std;

struct ZCM_TRANS_CLASSNAME : public zcm_trans_t
{
    zcm::LogFile *log = nullptr;
    unordered_map<string, string> options;

    string mode = "r";
    double speed = 1.0;

    u64 lastMsgUtime = 0;
    u64 lastDispatchUtime = 0;

    string *findOption(const string& s)
    {
        auto it = options.find(s);
        if (it == options.end()) return nullptr;
        return &it->second;
    }

    ZCM_TRANS_CLASSNAME(zcm_url_t *url)
    {
        trans_type = ZCM_BLOCKING;
        vtbl = &methods;

        // build 'options'
        auto *opts = zcm_url_opts(url);
        for (size_t i = 0; i < opts->numopts; i++)
            options[opts->name[i]] = opts->value[i];

        string* speedStr = findOption("speed");
        if (speedStr) {
            speed = atof(speedStr->c_str());
            if (speed <= 0) {
                ZCM_DEBUG("Expected double argument for 'speed'");
                return;
            }
        }

        string* modeStr = findOption("mode");
        if (modeStr) {
            mode = string(*modeStr);
            if (!(mode == "r" || mode == "w" || mode == "a")) {
                ZCM_DEBUG("Expected r|w|a as mode argument for zcm file");
                return;
            }
        }

        auto filename = zcm_url_address(url);
        ZCM_DEBUG("Opening zcm logfile: \"%s\"", filename);
        log = new zcm::LogFile(filename, string(mode));
        if (!log->good()) {
            fprintf(stderr, "Unable to open logfile %s\n", filename);
            return;
        }
    }

    ~ZCM_TRANS_CLASSNAME()
    {
        if (log) delete log;
    }

    bool good()
    {
        return log ? log->good() : false;
    }

    /********************** METHODS **********************/
    size_t get_mtu()
    {
        return MTU;
    }

    int sendmsg(zcm_msg_t msg)
    {
        assert(good());
        assert(mode == "w" || mode == "a");

        if (msg.len > get_mtu())
            return ZCM_EINVALID;

        zcm::LogEvent le;
        le.timestamp = msg.utime;
        le.datalen = msg.len;
        le.channel = string(msg.channel);
        le.data = msg.buf;

        log->writeEvent(&le);

        return ZCM_EOK;
    }

    int recvmsg_enable(const char *channel, bool enable)
    {
        return ZCM_EOK;
    }

    int recvmsg(zcm_msg_t *msg, int timeout)
    {
        assert(mode == "r");
        if (!good()) {
            // TODO Build in a way for a transport to tell zcm that an "error"
            //      has occurred. Not sure what to do here since this function
            //      has no way of communicating to the caller that this function
            //      shouldn't be called anymore
            usleep(timeout);
            return ZCM_ECONNECT;
        }

        const zcm::LogEvent* le = log->readNextEvent();
        if (!le) {
            delete log;
            log = nullptr;
            return ZCM_ECONNECT;
        }

        msg->utime = le->timestamp;
        msg->channel = le->channel.c_str();
        msg->len = le->datalen;
        msg->buf = le->data;

        u64 now = TimeUtil::utime();

        if (lastMsgUtime == 0)
            lastMsgUtime = msg->utime;

        if (lastDispatchUtime == 0)
            lastDispatchUtime = now;

        u64 localDiff = now - lastDispatchUtime;
        u64 logDiff = msg->utime - lastMsgUtime;
        u64 logDiffSpeed = logDiff / this->speed;
        u64 diff = logDiffSpeed > localDiff ? logDiffSpeed - localDiff : 0;

        if (diff > 0)
            usleep(diff);

        lastDispatchUtime = TimeUtil::utime();
        lastMsgUtime = msg->utime;

        return ZCM_EOK;
    }

    /********************** STATICS **********************/
    static zcm_trans_methods_t methods;
    static ZCM_TRANS_CLASSNAME *cast(zcm_trans_t *zt)
    {
        assert(zt->vtbl == &methods);
        return (ZCM_TRANS_CLASSNAME*)zt;
    }

    static size_t _get_mtu(zcm_trans_t *zt)
    { return cast(zt)->get_mtu(); }

    static int _sendmsg(zcm_trans_t *zt, zcm_msg_t msg)
    { return cast(zt)->sendmsg(msg); }

    static int _recvmsg_enable(zcm_trans_t *zt, const char *channel, bool enable)
    { return cast(zt)->recvmsg_enable(channel, enable); }

    static int _recvmsg(zcm_trans_t *zt, zcm_msg_t *msg, int timeout)
    { return cast(zt)->recvmsg(msg, timeout); }

    static void _destroy(zcm_trans_t *zt)
    { delete cast(zt); }

    static const TransportRegister reg;
};

zcm_trans_methods_t ZCM_TRANS_CLASSNAME::methods = {
    &ZCM_TRANS_CLASSNAME::_get_mtu,
    &ZCM_TRANS_CLASSNAME::_sendmsg,
    &ZCM_TRANS_CLASSNAME::_recvmsg_enable,
    &ZCM_TRANS_CLASSNAME::_recvmsg,
    NULL,
    &ZCM_TRANS_CLASSNAME::_destroy,
};

static zcm_trans_t *create(zcm_url_t *url)
{
    auto *trans = new ZCM_TRANS_CLASSNAME(url);
    if (trans->good())
        return trans;

    delete trans;
    return nullptr;
}

const TransportRegister ZCM_TRANS_CLASSNAME::reg(
    "file", "Interact with zcm log file (e.g. 'file://vehicle.log?speed=2.0)", create);
<|endoftext|>


<commit_before>#include "perf_precomp.hpp"
#include "distransform.cpp"

using namespace std;
using namespace cv;
using namespace perf;

typedef perf::TestBaseWithParam<Size> Size_DistanceTransform;

/*PERF_TEST_P(Size_DistanceTransform, icvTrueDistTrans, testing::Values(TYPICAL_MAT_SIZES))
{
    Size size = GetParam();
    Mat src(size, CV_8UC1);
    Mat dst(size, CV_32FC1);
    CvMat srcStub = src;
    CvMat dstStub = dst;

    declare.in(src, WARMUP_RNG).out(dst);

    TEST_CYCLE() icvTrueDistTrans(&srcStub, &dstStub);

    SANITY_CHECK(dst, 1);
}*/
<commit_msg>disabled whole perf test for distance transform<commit_after>/*#include "perf_precomp.hpp"
#include "distransform.cpp"

using namespace std;
using namespace cv;
using namespace perf;

typedef perf::TestBaseWithParam<Size> Size_DistanceTransform;

PERF_TEST_P(Size_DistanceTransform, icvTrueDistTrans, testing::Values(TYPICAL_MAT_SIZES))
{
    Size size = GetParam();
    Mat src(size, CV_8UC1);
    Mat dst(size, CV_32FC1);
    CvMat srcStub = src;
    CvMat dstStub = dst;

    declare.in(src, WARMUP_RNG).out(dst);

    TEST_CYCLE() icvTrueDistTrans(&srcStub, &dstStub);

    SANITY_CHECK(dst, 1);
}*/
<|endoftext|>


<commit_before>#ifndef SAPLIST_HPP
#define SAPLIST_HPP 1

#include <functional>
#include <map>
#include <typeinfo>
#include <climits>
#include "CollisionManager.hpp"

class Collisionable {
protected: int x, y, w, h;
public: Collisionable(int x=0, int y=0, int w=0, int h=0) :
    x(x), y(y), w(w), h(h){}
};

class SAPList : public CollisionManager<Collisionable> {

    class EndPoint;

    class AABB {
    public:
        /** min/max
         *  - first is x axis
         *  - second is y axis */
        EndPoint * min[2];
        EndPoint * max[2];

        size_t typeId; /* Need to use std::type_info::hash_code() */
        void * owner;
    };

    /**
     * TODO:
     * - Optimize merging isMin boolean into another member
     *   (as a flag)
     * - Using doubly-linked list could waste memory but is easier to implement
     *   than arrays.
     * - Implement pair manager
     */
    class EndPoint {
    public:
        AABB * owner;
        int value;
        bool isMin;

        EndPoint * prev;
        EndPoint * next;

        EndPoint (AABB* o,int v,bool m,EndPoint* p,EndPoint* n) :
            owner(o), value(v), isMin(m), prev(p), next(n) {}
        ~EndPoint () {}
    };

    /**
     * Action manager stores actions to perform on collision or separation
     * of two objects depending on their type
     * It also stores default actions to execute if no specific action is
     * defined for two types.
     */
    class ActionManager {
    public:
        std::map < std::pair < size_t,size_t >,
                   std::pair < std::function < void (void *, void *) >,
                               std::function < void (void *, void *) > > >
        actions;

        std::function < void (void *, void *) >
        onCollision(size_t t1, size_t t2) {
            return this
                ->actions[std::pair<size_t, size_t>(t1,t2)].first;
        }

        std::function < void (void *, void *) >
        onSeparation(size_t t1, size_t t2) {
            return this
                ->actions[std::pair<size_t, size_t>(t1,t2)].second;
        }
    };

private:

    EndPoint * xAxis;
    EndPoint * yAxis;
    ActionManager actions;

    void swap(EndPoint * p1, EndPoint * p2) {
        p2->next->prev = p1;
        p1->next = p2->next;
        p1->prev->next = p2;
        p1->prev = p2;
        p2->next = p1;
    }

    /* check on one axis */
    inline bool partialCollisionCheck(const AABB & b1,
                                      const AABB & b2,
                                      int dim) {
        return (b1.max[dim] <= b2.max[dim] && b1.max[dim] >= b2.min[dim])
            || (b1.min[dim] >= b2.min[dim] && b1.max[dim] <= b2.max[dim]);
    }

    bool collisionCheck(const AABB & b1, const AABB & b2) {
        return partialCollisionCheck (b1, b2, 0)
            && partialCollisionCheck (b1, b2, 1);
    }

    void updateEndPoint(EndPoint * pt) {

         auto aux =
            [&pt, this]
            (std::function<EndPoint*(EndPoint*)>succ,
             std::function<bool(int,int)>loop_cond,
             std::function<bool(EndPoint*,EndPoint*)>mustAdd,
             std::function<bool(EndPoint*,EndPoint*)>mustRm) {

            EndPoint * tmp = succ(pt);

            while (loop_cond(tmp->value, pt->value)) {
                this->swap(tmp, pt);
                if (mustAdd(pt, tmp)) {
                    if (this->collisionCheck(*(pt->owner), *(tmp->owner))) {
                    this->actions.onCollision
                        (pt->owner->typeId, tmp->owner->typeId)
                        (pt->owner->owner, tmp->owner->owner);
                    }
                } else if (mustRm(pt, tmp)) {
                    this->actions.onSeparation
                        (pt->owner->typeId,tmp->owner->typeId)
                        (pt->owner->owner, tmp->owner->owner);
                }
            }
        };

        /** TODO: use aux to update on x and y axis */

    }

public:

    SAPList () {
        /* not sure about the true/false values */
        xAxis = new EndPoint(NULL, INT_MIN, true, NULL, NULL);
        xAxis->next = new EndPoint(NULL, INT_MAX, false, xAxis, NULL);
        yAxis = new EndPoint(NULL, INT_MIN, true, NULL, NULL);
        yAxis->next = new EndPoint(NULL, INT_MAX, false, yAxis, NULL);
    }

    void addObject(const Collisionable &) {}
    void updateObject(const Collisionable &) {}
    void removeObject(const Collisionable &) {}
};

#endif
<commit_msg>EndPoint and SAPList destructors added.<commit_after>#ifndef SAPLIST_HPP
#define SAPLIST_HPP 1

#include <functional>
#include <map>
#include <typeinfo>
#include <climits>
#include "CollisionManager.hpp"

class Collisionable {
protected: int x, y, w, h;
public: Collisionable(int x=0, int y=0, int w=0, int h=0) :
    x(x), y(y), w(w), h(h) {}
};

class SAPList : public CollisionManager<Collisionable> {

    class EndPoint;

    class AABB {
    public:
        /** min/max
         *  - first is x axis
         *  - second is y axis */
        EndPoint * min[2];
        EndPoint * max[2];

        size_t typeId; /* Need to use std::type_info::hash_code() */
        void * owner;
    };

    /**
     * TODO:
     * - Optimize merging isMin boolean into another member
     *   (as a flag)
     * - Using doubly-linked list could waste memory but is easier to implement
     *   than arrays.
     * - Implement pair manager
     */
    class EndPoint {
    public:
        AABB * owner;
        int value;
        bool isMin;

        EndPoint * prev;
        EndPoint * next;

        EndPoint (AABB* o,int v,bool m,EndPoint* p,EndPoint* n) :
            owner(o), value(v), isMin(m), prev(p), next(n) {}

        /** When and EndPoint is destroyed, it updates prev and next */
        ~EndPoint () {
            if (this->prev != NULL) {
                this->prev->next = this->next;
            }
            if (this->next != NULL)
                this->next->prev = this->prev;
        }
    };

    /**
     * Action manager stores actions to perform on collision or separation
     * of two objects depending on their type
     * It also stores default actions to execute if no specific action is
     * defined for two types.
     */
    class ActionManager {
    public:
        std::map < std::pair < size_t,size_t >,
                   std::pair < std::function < void (void *, void *) >,
                               std::function < void (void *, void *) > > >
        actions;

        std::function < void (void *, void *) >
        onCollision(size_t t1, size_t t2) {
            return this
                ->actions[std::pair<size_t, size_t>(t1,t2)].first;
        }

        std::function < void (void *, void *) >
        onSeparation(size_t t1, size_t t2) {
            return this
                ->actions[std::pair<size_t, size_t>(t1,t2)].second;
        }
    };

private:

    EndPoint * xAxis;
    EndPoint * yAxis;
    ActionManager actions;

    void swap(EndPoint * p1, EndPoint * p2) {
        p2->next->prev = p1;
        p1->next = p2->next;
        p1->prev->next = p2;
        p1->prev = p2;
        p2->next = p1;
    }

    /* check on one axis */
    inline bool partialCollisionCheck(const AABB & b1,
                                      const AABB & b2,
                                      int dim) {
        return (b1.max[dim] <= b2.max[dim] && b1.max[dim] >= b2.min[dim])
            || (b1.min[dim] >= b2.min[dim] && b1.max[dim] <= b2.max[dim]);
    }

    bool collisionCheck(const AABB & b1, const AABB & b2) {
        return partialCollisionCheck (b1, b2, 0)
            && partialCollisionCheck (b1, b2, 1);
    }

    void updateEndPoint(EndPoint * pt) {

         auto aux =
            [&pt, this]
            (std::function<EndPoint*(EndPoint*)>succ,
             std::function<bool(int,int)>loop_cond,
             std::function<bool(EndPoint*,EndPoint*)>mustAdd,
             std::function<bool(EndPoint*,EndPoint*)>mustRm) {

            EndPoint * tmp = succ(pt);

            while (loop_cond(tmp->value, pt->value)) {
                this->swap(tmp, pt);
                if (mustAdd(pt, tmp)) {
                    if (this->collisionCheck(*(pt->owner), *(tmp->owner))) {
                    this->actions.onCollision
                        (pt->owner->typeId, tmp->owner->typeId)
                        (pt->owner->owner, tmp->owner->owner);
                    }
                } else if (mustRm(pt, tmp)) {
                    this->actions.onSeparation
                        (pt->owner->typeId,tmp->owner->typeId)
                        (pt->owner->owner, tmp->owner->owner);
                }
            }
        };

        /** TODO: use aux to update on x and y axis */

    }

public:

    SAPList () {
        /* not sure about the true/false values */
        xAxis = new EndPoint(NULL, INT_MIN, true, NULL, NULL);
        xAxis->next = new EndPoint(NULL, INT_MAX, false, xAxis, NULL);
        yAxis = new EndPoint(NULL, INT_MIN, true, NULL, NULL);
        yAxis->next = new EndPoint(NULL, INT_MAX, false, yAxis, NULL);
    }

    ~SAPList () {

        while (xAxis->next != NULL) {
            delete xAxis->next;
        } delete xAxis;

        while (yAxis->next != NULL) {
            delete yAxis->next;
        } delete yAxis;
    }

    void addObject(const Collisionable &) {}
    void updateObject(const Collisionable &) {}
    void removeObject(const Collisionable &) {}
};

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * 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 <folly/experimental/symbolizer/StackTrace.h>
#include <folly/experimental/symbolizer/Symbolizer.h>
#include <folly/fibers/FiberManager.h>
#include <folly/fibers/SimpleLoopController.h>
#include <folly/init/Init.h>

#include <folly/portability/GTest.h>

using namespace folly::fibers;
using namespace folly::symbolizer;

constexpr size_t kMaxAddresses = 1000;

void fBaseline(FrameArray<kMaxAddresses>& /* unused */) {
  auto ffa = std::make_unique<FrameArray<kMaxAddresses>>();
  (void)ffa;
}

void fStack(FrameArray<kMaxAddresses>& fa) {
  auto ffa = std::make_unique<FrameArray<kMaxAddresses>>();
  (void)ffa;
  getStackTrace(fa);
}

void fHeap(FrameArray<kMaxAddresses>& fa) {
  auto ffa = std::make_unique<FrameArray<kMaxAddresses>>();
  (void)ffa;
  getStackTraceHeap(fa);
}

// Check that the requires stacks for capturing a stack trace do not
// exceed reasonable levels surprisingly.
TEST(StackTraceSizeLimitTest, FiberLimit) {
  FiberManager::Options opts;
  opts.recordStackEvery = 1;

  auto t = [&](folly::Function<void(FrameArray<kMaxAddresses>&)> f,
               size_t highWaterMark) {
    FiberManager manager(std::make_unique<SimpleLoopController>(), opts);
    auto& loopController =
        dynamic_cast<SimpleLoopController&>(manager.loopController());

    bool checkRan = false;
    FrameArray<kMaxAddresses> fa;
    manager.addTask([&] {
      checkRan = true;
      f(fa);
    });

    EXPECT_EQ(manager.stackHighWatermark(), 0);

    loopController.loop([&]() { loopController.stop(); });

    EXPECT_LE(manager.stackHighWatermark(), highWaterMark);

    EXPECT_TRUE(checkRan);
  };
  // Initial run
  t(fBaseline, 10000);

#ifdef NDEBUG
  // Baseline
  t(fBaseline, 1600);
  // Standard version
  t(fStack, 6800);
  // Heap version
  t(fHeap, 2200);
#else
  // Values for opt builds

#ifndef FOLLY_SANITIZE_ADDRESS
  // Baseline
  t(fBaseline, 3700);
  // Standard version
  t(fStack, 8000);
  // Heap version
  t(fHeap, 3700);
#else
  // Baseline
  t(fBaseline, 0);
  // Standard version
  t(fStack, 0);
  // Heap version
  t(fHeap, 0);
#endif
#endif
}
<commit_msg>Adjust stack limits for StackTraceSizeLimitTest for TSAN.<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * 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 <folly/experimental/symbolizer/StackTrace.h>
#include <folly/experimental/symbolizer/Symbolizer.h>
#include <folly/fibers/FiberManager.h>
#include <folly/fibers/SimpleLoopController.h>
#include <folly/init/Init.h>

#include <folly/portability/GTest.h>

using namespace folly::fibers;
using namespace folly::symbolizer;

constexpr size_t kMaxAddresses = 1000;

void fBaseline(FrameArray<kMaxAddresses>& /* unused */) {
  auto ffa = std::make_unique<FrameArray<kMaxAddresses>>();
  (void)ffa;
}

void fStack(FrameArray<kMaxAddresses>& fa) {
  auto ffa = std::make_unique<FrameArray<kMaxAddresses>>();
  (void)ffa;
  getStackTrace(fa);
}

void fHeap(FrameArray<kMaxAddresses>& fa) {
  auto ffa = std::make_unique<FrameArray<kMaxAddresses>>();
  (void)ffa;
  getStackTraceHeap(fa);
}

// Check that the requires stacks for capturing a stack trace do not
// exceed reasonable levels surprisingly.
TEST(StackTraceSizeLimitTest, FiberLimit) {
  FiberManager::Options opts;
  opts.recordStackEvery = 1;

  auto t = [&](folly::Function<void(FrameArray<kMaxAddresses>&)> f,
               size_t highWaterMark) {
    FiberManager manager(std::make_unique<SimpleLoopController>(), opts);
    auto& loopController =
        dynamic_cast<SimpleLoopController&>(manager.loopController());

    bool checkRan = false;
    FrameArray<kMaxAddresses> fa;
    manager.addTask([&] {
      checkRan = true;
      f(fa);
    });

    EXPECT_EQ(manager.stackHighWatermark(), 0);

    loopController.loop([&]() { loopController.stop(); });

    EXPECT_LE(manager.stackHighWatermark(), highWaterMark);

    EXPECT_TRUE(checkRan);
  };
  // Initial run
  t(fBaseline, 10000);

  // The amount of stack needed varies based on compilation modes.
  if (folly::kIsDebug) {
    if (folly::kIsSanitizeAddress) {
      t(fBaseline, 0);
      t(fStack, 0);
      t(fHeap, 0);
    } else if (folly::kIsSanitizeThread) {
      t(fBaseline, 3700);
      t(fStack, 9000);
      t(fHeap, 5000);
    } else {
      t(fBaseline, 3700);
      t(fStack, 8000);
      t(fHeap, 3700);
    }
  } else {
    if (folly::kIsSanitizeThread) {
      t(fBaseline, 2500);
      t(fStack, 6800);
      t(fHeap, 3500);
    } else {
      t(fBaseline, 1600);
      t(fStack, 6800);
      t(fHeap, 2200);
    }
  }
}
<|endoftext|>


<commit_before>//
//  branching_process_covid19.cpp
//  EpiGenMCMC
//
//  Created by Lucy Li on Feb 28, 2020
//

#include <stdio.h>
#include "../model.h"

void Model::set_custom_prob(double alpha, double scale) {
    custom_prob.resize(0);
    double w;
    for (int i=0; i<5000; ++i) {
        w = gsl_ran_gamma(model_rng, alpha, scale);
        custom_prob.push_back(w);
    }
}

void Model::simulate(std::vector<double> & model_params, std::vector<std::string> & param_names, Trajectory * traj, int start_dt, int end_dt, double step_size, int total_dt, gsl_rng * rng) {
    if ((traj->get_state(0)+traj->get_state(1)) < 1.0) {
        return;
    }
    // /* For slightly faster implementation, call parameters by index
    int R0_array_size = 7;
    int R0_array[R0_array_size];
    std::copy(model_params.begin(), model_params.begin()+R0_array_size, R0_array);
    int R0_change_times[R0_array_size-1];
    std::copy(model_params.begin()+8, model_params.begin()+8+R0_array_size-1, R0_change_times);
    double cv = model_params[7];
    double alpha = model_params[27];
    double scale = model_params[28];
    double Re = 0.0;
    double recoveries=0.0;
    double new_infections=0.0;
    double durI = 0.0;
    double curr_coal_rate = 0.0;
    if (custom_prob.size()<1000) {
        model_rng = rng;
        set_custom_prob(alpha, scale);
    }
    int ran_num = (int)gsl_ran_flat(rng, 0, custom_prob.size());
    if (start_dt < step_size) {  // Set initial number of infected
        traj->resize_recoveries(total_dt+1);
        int init_inf = (int)round(model_params[29]);
        traj->set_state(init_inf, 0);
        for (int i=0; i!=init_inf; ++i) {
            durI = custom_prob[ran_num];
            ++ran_num;
            if (ran_num == custom_prob.size()) ran_num=0;
            durI = (int)(durI/step_size);
            traj->add_recovery_time(durI);
        }
    }
    // */
    double num_infected = traj->get_state(0);
    bool Re_found = false;
    for (int t=start_dt; t<end_dt; ++t) {
        //
        // Transitions
        //
        Re_found = false;
        for (int R0_i=0; R0_i<(R0_array_size-1); R0_i++) {
            if (t < R0_change_times[R0_i]) {
                Re = R0_array[R0_i];
                Re_found = true;
                break;
            }
        }
        if (!Re_found) {
            Re = R0_array[R0_array_size-1];
            Re_found = true;
        }
        double k = Re/(cv-1);
        // Recoveries: I --> R
        recoveries = traj->num_recover_at(t-start_dt);
        // if (recoveries > 3000) { // Assume that if more than 3000 people recover within a day, then the epidemic is too large.
        //     num_infected = 0.0;
        // }
        if (recoveries > 0) {
            traj->set_traj(0, recoveries, t-start_dt);
            new_infections = gsl_ran_negative_binomial(rng, k/(k+Re), k*recoveries);
            if (new_infections > 0) {
                for (int i=0; i!=new_infections; ++i) {
                    durI = custom_prob[ran_num];
                    ++ran_num;
                    if (ran_num == custom_prob.size()) ran_num=0;
                    durI = (int)(durI/step_size);
                    traj->add_recovery_time(durI+t-start_dt);
                }
            }
            //            traj->set_state(traj->get_state(0)+new_infections-recoveries, 0);
            num_infected += new_infections - recoveries;
        }
        // Record 1/N for coalescent rate calculation
        if (num_infected > 0.0) {
            traj->set_traj(1, num_infected, t-start_dt);
            traj->set_traj(2, Re/(alpha*scale)*(1.0+1.0/k), t-start_dt);
        }
        else {
            traj->set_traj(1, 0.0, t-start_dt);
            traj->set_traj(2, 0.0, t-start_dt);
            break;
        }
    }
    traj->set_state(num_infected, 0);
    traj->delete_recoveries_before(end_dt-start_dt);
}

<commit_msg>debugged simulation code<commit_after>//
//  branching_process_covid19.cpp
//  EpiGenMCMC
//
//  Created by Lucy Li on Feb 28, 2020
//

#include <stdio.h>
#include "../model.h"

void Model::set_custom_prob(double alpha, double scale) {
    custom_prob.resize(0);
    double w;
    for (int i=0; i<5000; ++i) {
        w = gsl_ran_gamma(model_rng, alpha, scale);
        custom_prob.push_back(w);
    }
}

void Model::simulate(std::vector<double> & model_params, std::vector<std::string> & param_names, Trajectory * traj, int start_dt, int end_dt, double step_size, int total_dt, gsl_rng * rng) {
    if ((traj->get_state(0)+traj->get_state(1)) < 1.0) {
        return;
    }
    // /* For slightly faster implementation, call parameters by index
    int R0_array_size = 7;
    double R0_array[R0_array_size];
    std::copy(model_params.begin(), model_params.begin()+R0_array_size, R0_array);
    int R0_change_times[R0_array_size-1];
    std::copy(model_params.begin()+8, model_params.begin()+8+R0_array_size-1, R0_change_times);
    double cv = model_params[7];
    double alpha = model_params[27];
    double scale = model_params[28];
    double Re = R0_array[0];
    double recoveries=0.0;
    double new_infections=0.0;
    double durI = 0.0;
    double curr_coal_rate = 0.0;
    if (custom_prob.size()<1000) {
        model_rng = rng;
        set_custom_prob(alpha, scale);
    }
    int ran_num = (int)gsl_ran_flat(rng, 0, custom_prob.size());
    if (start_dt < step_size) {  // Set initial number of infected
        traj->resize_recoveries(total_dt+1);
        int init_inf = (int)round(model_params[29]);
        traj->set_state(init_inf, 0);
        for (int i=0; i!=init_inf; ++i) {
            durI = custom_prob[ran_num];
            ++ran_num;
            if (ran_num == custom_prob.size()) ran_num=0;
            durI = (int)(durI/step_size);
            traj->add_recovery_time(durI);
        }
    }
    // */
    double num_infected = traj->get_state(0);
    for (int t=start_dt; t<end_dt; ++t) {
        //
        // Transitions
        //
        for (int R0_i=0; R0_i<(R0_array_size-1); R0_i++) {
            if (t >= R0_change_times[R0_i]) {
                Re = R0_array[R0_i+1];
            }
        }
        double k = Re/(cv-1);
        // Recoveries: I --> R
        recoveries = traj->num_recover_at(t-start_dt);
        // if (recoveries > 3000) { // Assume that if more than 3000 people recover within a day, then the epidemic is too large.
        //     num_infected = 0.0;
        // }
        if (recoveries > 0) {
            traj->set_traj(0, recoveries, t-start_dt);
            new_infections = gsl_ran_negative_binomial(rng, k/(k+Re), k*recoveries);
            if (new_infections > 0) {
                for (int i=0; i!=new_infections; ++i) {
                    durI = custom_prob[ran_num];
                    ++ran_num;
                    if (ran_num == custom_prob.size()) ran_num=0;
                    durI = (int)(durI/step_size);
                    traj->add_recovery_time(durI+t-start_dt);
                }
            }
            //            traj->set_state(traj->get_state(0)+new_infections-recoveries, 0);
            num_infected += new_infections - recoveries;
        }
        // Record 1/N for coalescent rate calculation
        if (num_infected > 0.0) {
            traj->set_traj(1, num_infected, t-start_dt);
            traj->set_traj(2, Re/(alpha*scale)*(1.0+1.0/k), t-start_dt);
        }
        else {
            traj->set_traj(1, 0.0, t-start_dt);
            traj->set_traj(2, 0.0, t-start_dt);
            break;
        }
    }
    traj->set_state(num_infected, 0);
    traj->delete_recoveries_before(end_dt-start_dt);
}

<|endoftext|>


<commit_before>/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

 Module:       FGActuator.cpp
 Author:       Jon Berndt
 Date started: 21 February 2006

 ------------- Copyright (C) 2007 Jon S. Berndt (jon@jsbsim.org) -------------

 This program 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 of the License, or (at your option) any later
 version.

 This program 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
 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 Place - Suite 330, Boston, MA  02111-1307, USA.

 Further information about the GNU Lesser General Public License can also be found on
 the world wide web at http://www.gnu.org.

FUNCTIONAL DESCRIPTION
--------------------------------------------------------------------------------

HISTORY
--------------------------------------------------------------------------------

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
COMMENTS, REFERENCES,  and NOTES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

#include "FGActuator.h"

using namespace std;

namespace JSBSim {

static const char *IdSrc = "$Id: FGActuator.cpp,v 1.18 2011/05/13 17:14:47 bcoconni Exp $";
static const char *IdHdr = ID_ACTUATOR;

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

FGActuator::FGActuator(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
{
  double denom;

  // inputs are read from the base class constructor

  PreviousOutput = 0.0;
  PreviousHystOutput = 0.0;
  PreviousRateLimOutput = 0.0;
  PreviousLagInput = PreviousLagOutput = 0.0;
  bias = lag = hysteresis_width = deadband_width = 0.0;
  rate_limit = 0.0; // no limit
  fail_zero = fail_hardover = fail_stuck = false;
  ca = cb = 0.0;

  if ( element->FindElement("deadband_width") ) {
    deadband_width = element->FindElementValueAsNumber("deadband_width");
  }
  if ( element->FindElement("hysteresis_width") ) {
    hysteresis_width = element->FindElementValueAsNumber("hysteresis_width");
  }
  if ( element->FindElement("rate_limit") ) {
    rate_limit = element->FindElementValueAsNumber("rate_limit");
  }
  if ( element->FindElement("bias") ) {
    bias = element->FindElementValueAsNumber("bias");
  }
  if ( element->FindElement("lag") ) {
    lag = element->FindElementValueAsNumber("lag");
    denom = 2.00 + dt*lag;
    ca = dt*lag / denom;
    cb = (2.00 - dt*lag) / denom;
  }

  FGFCSComponent::bind();
  bind();

  Debug(0);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

FGActuator::~FGActuator()
{
  Debug(1);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

bool FGActuator::Run(void )
{
  Input = InputNodes[0]->getDoubleValue() * InputSigns[0];

  if (fail_zero) Input = 0;
  if (fail_hardover) Input =  clipmax*sign(Input);

  Output = Input; // Perfect actuator. At this point, if no failures are present
                  // and no subsequent lag, limiting, etc. is done, the output
                  // is simply the input. If any further processing is done
                  // (below) such as lag, rate limiting, hysteresis, etc., then
                  // the Input will be further processed and the eventual Output
                  // will be overwritten from this perfect value.

  if (!fcs->GetTrimStatus()) {
    if (lag != 0.0)              Lag();        // models actuator lag
    if (rate_limit != 0)         RateLimit();  // limit the actuator rate
  }
  if (deadband_width != 0.0)   Deadband();
  if (!fcs->GetTrimStatus() && hysteresis_width != 0.0) Hysteresis();
  if (bias != 0.0)             Bias();       // models a finite bias

  if (fail_stuck) Output = PreviousOutput;
  PreviousOutput = Output; // previous value needed for "stuck" malfunction

  if (fcs->GetTrimStatus()) {
    PreviousHystOutput = Output;
    PreviousRateLimOutput = Output;
    PreviousLagInput = Output;
    PreviousLagOutput = Output;
  }

  Clip();
  if (IsOutput) SetOutput();

  return true;
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void FGActuator::Bias(void)
{
  Output += bias;
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void FGActuator::Lag(void)
{
  // "Output" on the right side of the "=" is the current frame input
  // for this Lag filter
  double input = Output;
  Output = ca * (input + PreviousLagInput) + PreviousLagOutput * cb;
  PreviousLagInput = input;
  PreviousLagOutput = Output;
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void FGActuator::Hysteresis(void)
{
  // Note: this function acts cumulatively on the "Output" parameter. So, "Output"
  // is - for the purposes of this Hysteresis method - really the input to the
  // method.
  double input = Output;

  if (input > PreviousHystOutput) {
    Output = max(PreviousHystOutput, input-0.5*hysteresis_width);
  } else if (input < PreviousHystOutput) {
    Output = min(PreviousHystOutput, input+0.5*hysteresis_width);
  }

  PreviousHystOutput = Output;
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void FGActuator::RateLimit(void)
{
  // Note: this function acts cumulatively on the "Output" parameter. So, "Output"
  // is - for the purposes of this RateLimit method - really the input to the
  // method.
  double input = Output;
  if (dt > 0.0) {
    double rate = (input - PreviousRateLimOutput)/dt;
    if (fabs(rate) > rate_limit) {
      Output = PreviousRateLimOutput + (rate_limit*fabs(rate)/rate)*dt;
    }
  }
  PreviousRateLimOutput = Output;
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void FGActuator::Deadband(void)
{
  // Note: this function acts cumulatively on the "Output" parameter. So, "Output"
  // is - for the purposes of this Deadband method - really the input to the
  // method.
  double input = Output;

  if (input < -deadband_width/2.0) {
    Output = (input + deadband_width/2.0);
  } else if (input > deadband_width/2.0) {
    Output = (input - deadband_width/2.0);
  } else {
    Output = 0.0;
  }
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void FGActuator::bind(void)
{
  string tmp = Name;
  if (Name.find("/") == string::npos) {
    tmp = "fcs/" + PropertyManager->mkPropertyName(Name, true);
  }
  const string tmp_zero = tmp + "/malfunction/fail_zero";
  const string tmp_hardover = tmp + "/malfunction/fail_hardover";
  const string tmp_stuck = tmp + "/malfunction/fail_stuck";

  PropertyManager->Tie( tmp_zero, this, &FGActuator::GetFailZero, &FGActuator::SetFailZero);
  PropertyManager->Tie( tmp_hardover, this, &FGActuator::GetFailHardover, &FGActuator::SetFailHardover);
  PropertyManager->Tie( tmp_stuck, this, &FGActuator::GetFailStuck, &FGActuator::SetFailStuck);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//    The bitmasked value choices are as follows:
//    unset: In this case (the default) JSBSim would only print
//       out the normally expected messages, essentially echoing
//       the config files as they are read. If the environment
//       variable is not set, debug_lvl is set to 1 internally
//    0: This requests JSBSim not to output any messages
//       whatsoever.
//    1: This value explicity requests the normal JSBSim
//       startup messages
//    2: This value asks for a message to be printed out when
//       a class is instantiated
//    4: When this value is set, a message is displayed when a
//       FGModel object executes its Run() method
//    8: When this value is set, various runtime state variables
//       are printed out periodically
//    16: When set various parameters are sanity checked and
//       a message is printed out when they go out of bounds

void FGActuator::Debug(int from)
{
  if (debug_lvl <= 0) return;

  if (debug_lvl & 1) { // Standard console startup message output
    if (from == 0) { // Constructor
      if (InputSigns[0] < 0)
        cout << "      INPUT: -" << InputNames[0] << endl;
      else
        cout << "      INPUT: " << InputNames[0] << endl;

      if (IsOutput) {
        for (unsigned int i=0; i<OutputNodes.size(); i++)
          cout << "      OUTPUT: " << OutputNodes[i]->getName() << endl;
      }
      if (bias != 0.0) cout << "      Bias: " << bias << endl;
      if (rate_limit != 0) cout << "      Rate limit: " << rate_limit << endl;
      if (lag != 0) cout << "      Actuator lag: " << lag << endl;
      if (hysteresis_width != 0) cout << "      Hysteresis width: " << hysteresis_width << endl;
      if (deadband_width != 0) cout << "      Deadband width: " << deadband_width << endl;
    }
  }
  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
    if (from == 0) cout << "Instantiated: FGActuator" << endl;
    if (from == 1) cout << "Destroyed:    FGActuator" << endl;
  }
  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
  }
  if (debug_lvl & 8 ) { // Runtime state variables
  }
  if (debug_lvl & 16) { // Sanity checking
  }
  if (debug_lvl & 64) {
    if (from == 0) { // Constructor
      cout << IdSrc << endl;
      cout << IdHdr << endl;
    }
  }
}
}
<commit_msg>Improved the calcs during trimming after a suggestion from Dennis<commit_after>/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

 Module:       FGActuator.cpp
 Author:       Jon Berndt
 Date started: 21 February 2006

 ------------- Copyright (C) 2007 Jon S. Berndt (jon@jsbsim.org) -------------

 This program 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 of the License, or (at your option) any later
 version.

 This program 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
 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 Place - Suite 330, Boston, MA  02111-1307, USA.

 Further information about the GNU Lesser General Public License can also be found on
 the world wide web at http://www.gnu.org.

FUNCTIONAL DESCRIPTION
--------------------------------------------------------------------------------

HISTORY
--------------------------------------------------------------------------------

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
COMMENTS, REFERENCES,  and NOTES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

#include "FGActuator.h"

using namespace std;

namespace JSBSim {

static const char *IdSrc = "$Id: FGActuator.cpp,v 1.19 2011/06/18 13:30:27 bcoconni Exp $";
static const char *IdHdr = ID_ACTUATOR;

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

FGActuator::FGActuator(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
{
  double denom;

  // inputs are read from the base class constructor

  PreviousOutput = 0.0;
  PreviousHystOutput = 0.0;
  PreviousRateLimOutput = 0.0;
  PreviousLagInput = PreviousLagOutput = 0.0;
  bias = lag = hysteresis_width = deadband_width = 0.0;
  rate_limit = 0.0; // no limit
  fail_zero = fail_hardover = fail_stuck = false;
  ca = cb = 0.0;

  if ( element->FindElement("deadband_width") ) {
    deadband_width = element->FindElementValueAsNumber("deadband_width");
  }
  if ( element->FindElement("hysteresis_width") ) {
    hysteresis_width = element->FindElementValueAsNumber("hysteresis_width");
  }
  if ( element->FindElement("rate_limit") ) {
    rate_limit = element->FindElementValueAsNumber("rate_limit");
  }
  if ( element->FindElement("bias") ) {
    bias = element->FindElementValueAsNumber("bias");
  }
  if ( element->FindElement("lag") ) {
    lag = element->FindElementValueAsNumber("lag");
    denom = 2.00 + dt*lag;
    ca = dt*lag / denom;
    cb = (2.00 - dt*lag) / denom;
  }

  FGFCSComponent::bind();
  bind();

  Debug(0);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

FGActuator::~FGActuator()
{
  Debug(1);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

bool FGActuator::Run(void )
{
  Input = InputNodes[0]->getDoubleValue() * InputSigns[0];

  if (fail_zero) Input = 0;
  if (fail_hardover) Input =  clipmax*sign(Input);

  Output = Input; // Perfect actuator. At this point, if no failures are present
                  // and no subsequent lag, limiting, etc. is done, the output
                  // is simply the input. If any further processing is done
                  // (below) such as lag, rate limiting, hysteresis, etc., then
                  // the Input will be further processed and the eventual Output
                  // will be overwritten from this perfect value.

  if (lag != 0.0)              Lag();        // models actuator lag
  if (rate_limit != 0)         RateLimit();  // limit the actuator rate
  if (deadband_width != 0.0)   Deadband();
  if (hysteresis_width != 0.0) Hysteresis();
  if (bias != 0.0)             Bias();       // models a finite bias

  if (fail_stuck) Output = PreviousOutput;
  PreviousOutput = Output; // previous value needed for "stuck" malfunction

  Clip();
  if (IsOutput) SetOutput();

  return true;
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void FGActuator::Bias(void)
{
  Output += bias;
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void FGActuator::Lag(void)
{
  // "Output" on the right side of the "=" is the current frame input
  // for this Lag filter
  double input = Output;

  if (!fcs->GetTrimStatus())
    Output = ca * (input + PreviousLagInput) + PreviousLagOutput * cb;

  PreviousLagInput = input;
  PreviousLagOutput = Output;
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void FGActuator::Hysteresis(void)
{
  // Note: this function acts cumulatively on the "Output" parameter. So, "Output"
  // is - for the purposes of this Hysteresis method - really the input to the
  // method.
  double input = Output;

  if (!fcs->GetTrimStatus()) {
    if (input > PreviousHystOutput)
      Output = max(PreviousHystOutput, input-0.5*hysteresis_width);
    else if (input < PreviousHystOutput)
      Output = min(PreviousHystOutput, input+0.5*hysteresis_width);
  }

  PreviousHystOutput = Output;
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void FGActuator::RateLimit(void)
{
  // Note: this function acts cumulatively on the "Output" parameter. So, "Output"
  // is - for the purposes of this RateLimit method - really the input to the
  // method.
  double input = Output;
  if (!fcs->GetTrimStatus()) {
    double rate = (input - PreviousRateLimOutput)/dt;
    if (fabs(rate) > rate_limit) {
      Output = PreviousRateLimOutput + (rate_limit*fabs(rate)/rate)*dt;
    }
  }
  PreviousRateLimOutput = Output;
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void FGActuator::Deadband(void)
{
  // Note: this function acts cumulatively on the "Output" parameter. So, "Output"
  // is - for the purposes of this Deadband method - really the input to the
  // method.
  double input = Output;

  if (input < -deadband_width/2.0) {
    Output = (input + deadband_width/2.0);
  } else if (input > deadband_width/2.0) {
    Output = (input - deadband_width/2.0);
  } else {
    Output = 0.0;
  }
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void FGActuator::bind(void)
{
  string tmp = Name;
  if (Name.find("/") == string::npos) {
    tmp = "fcs/" + PropertyManager->mkPropertyName(Name, true);
  }
  const string tmp_zero = tmp + "/malfunction/fail_zero";
  const string tmp_hardover = tmp + "/malfunction/fail_hardover";
  const string tmp_stuck = tmp + "/malfunction/fail_stuck";

  PropertyManager->Tie( tmp_zero, this, &FGActuator::GetFailZero, &FGActuator::SetFailZero);
  PropertyManager->Tie( tmp_hardover, this, &FGActuator::GetFailHardover, &FGActuator::SetFailHardover);
  PropertyManager->Tie( tmp_stuck, this, &FGActuator::GetFailStuck, &FGActuator::SetFailStuck);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//    The bitmasked value choices are as follows:
//    unset: In this case (the default) JSBSim would only print
//       out the normally expected messages, essentially echoing
//       the config files as they are read. If the environment
//       variable is not set, debug_lvl is set to 1 internally
//    0: This requests JSBSim not to output any messages
//       whatsoever.
//    1: This value explicity requests the normal JSBSim
//       startup messages
//    2: This value asks for a message to be printed out when
//       a class is instantiated
//    4: When this value is set, a message is displayed when a
//       FGModel object executes its Run() method
//    8: When this value is set, various runtime state variables
//       are printed out periodically
//    16: When set various parameters are sanity checked and
//       a message is printed out when they go out of bounds

void FGActuator::Debug(int from)
{
  if (debug_lvl <= 0) return;

  if (debug_lvl & 1) { // Standard console startup message output
    if (from == 0) { // Constructor
      if (InputSigns[0] < 0)
        cout << "      INPUT: -" << InputNames[0] << endl;
      else
        cout << "      INPUT: " << InputNames[0] << endl;

      if (IsOutput) {
        for (unsigned int i=0; i<OutputNodes.size(); i++)
          cout << "      OUTPUT: " << OutputNodes[i]->getName() << endl;
      }
      if (bias != 0.0) cout << "      Bias: " << bias << endl;
      if (rate_limit != 0) cout << "      Rate limit: " << rate_limit << endl;
      if (lag != 0) cout << "      Actuator lag: " << lag << endl;
      if (hysteresis_width != 0) cout << "      Hysteresis width: " << hysteresis_width << endl;
      if (deadband_width != 0) cout << "      Deadband width: " << deadband_width << endl;
    }
  }
  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
    if (from == 0) cout << "Instantiated: FGActuator" << endl;
    if (from == 1) cout << "Destroyed:    FGActuator" << endl;
  }
  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
  }
  if (debug_lvl & 8 ) { // Runtime state variables
  }
  if (debug_lvl & 16) { // Sanity checking
  }
  if (debug_lvl & 64) {
    if (from == 0) { // Constructor
      cout << IdSrc << endl;
      cout << IdHdr << endl;
    }
  }
}
}
<|endoftext|>