<commit_before>// *****************************************************************************
//
// Copyright (c) 2021, Trinity University
// All rights reserved.
//
// 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 of conditions 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 materials provided with the distribution.
//     * Neither the name of Southwest Research Institute® (SwRI®) nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// 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 <COPYRIGHT HOLDER> 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 <mapviz_plugins/pose_publisher_plugin.h>

// Declare plugin
#include <pluginlib/class_list_macros.h>
PLUGINLIB_EXPORT_CLASS(mapviz_plugins::PosePublisherPlugin, mapviz::MapvizPlugin)

namespace mapviz_plugins
{

PosePublisherPlugin::PosePublisherPlugin() :
    config_widget_(new QWidget()),
    map_canvas_(nullptr),
    is_mouse_down_(false),
    monitoring_action_state_(false)
{
    // TODO - make pose a field
    //pose_pub_ = nh_.advertise<geometry_msgs::PoseWithCovarianceStamped>("/selected_pose", 1, false);

    ui_.setupUi(config_widget_);

    // Set background white
    QPalette p(config_widget_->palette());
    p.setColor(QPalette::Background, Qt::white);
    config_widget_->setPalette(p);
    // Set status text red

    ui_.status->setText("OK");
    QPalette p3(ui_.status->palette());
    p3.setColor(QPalette::Text, Qt::green);
    ui_.status->setPalette(p3);

    QObject::connect(ui_.pushButtonPose, SIGNAL(toggled()),
                     this, SLOT(on_pushButtonPose_toggled()));

    QObject::connect(ui_.topic, SIGNAL(textEdited(const QString&)),
            this, SLOT(topicChanged(const QString&)));

    timer_ = nh_.createTimer(ros::Duration(1.0), &PosePublisherPlugin::timerCallback, this);
    frame_timer_.start(1000);
    QObject::connect(&frame_timer_, SIGNAL(timeout()), this, SLOT(updateFrames()));
}

PosePublisherPlugin::~PosePublisherPlugin()
{
    if (map_canvas_)
    {
        map_canvas_->removeEventFilter(this);
    }
}

void PosePublisherPlugin::PrintError(const std::string& message)
{
    PrintErrorHelper( ui_.status, message);
}

void PosePublisherPlugin::PrintInfo(const std::string& message)
{
    PrintInfoHelper( ui_.status, message);
}

void PosePublisherPlugin::PrintWarning(const std::string& message)
{
    PrintWarningHelper( ui_.status, message);
}

QWidget* PosePublisherPlugin::GetConfigWidget(QWidget* parent)
{
    config_widget_->setParent(parent);
    return config_widget_;
}

bool PosePublisherPlugin::Initialize(QGLWidget* canvas)
{
    map_canvas_ = static_cast<mapviz::MapCanvas*>(canvas);
    map_canvas_->installEventFilter(this);
    initialized_ = true;
    return true;
}

bool PosePublisherPlugin::eventFilter(QObject *object, QEvent* event)
{
    switch (event->type())
    {
    case QEvent::MouseButtonPress:
        return handleMousePress(static_cast<QMouseEvent*>(event));
    case QEvent::MouseButtonRelease:
        return handleMouseRelease(static_cast<QMouseEvent*>(event));
    case QEvent::MouseMove:
        return handleMouseMove(static_cast<QMouseEvent*>(event));
    default:
        return false;
    }
}

void PosePublisherPlugin::timerCallback(const ros::TimerEvent &)
{
  ui_.pushButtonPose->setEnabled( true );
  PrintInfoHelper( ui_.status, "OK");
}

bool PosePublisherPlugin::handleMousePress(QMouseEvent* event)
{
    bool pose_checked = ui_.pushButtonPose->isChecked();

    if( !pose_checked)
    {
        return false;
    }

    if (event->button() == Qt::LeftButton)
    {
        is_mouse_down_ = true;
        arrow_angle_ = 0;
#if QT_VERSION >= 0x050000
      arrow_tail_position_= map_canvas_->MapGlCoordToFixedFrame( event->localPos() );
#else
      arrow_tail_position_= map_canvas_->MapGlCoordToFixedFrame( event->posF() );
#endif
        return true;
    }
    return false;
}

bool PosePublisherPlugin::handleMouseMove(QMouseEvent* event)
{
    if (is_mouse_down_)
    {
#if QT_VERSION >= 0x050000
        QPointF head_pos = map_canvas_->MapGlCoordToFixedFrame( event->localPos() );
#else
        QPointF head_pos = map_canvas_->MapGlCoordToFixedFrame( event->posF() );
#endif
        arrow_angle_ = atan2( head_pos.y() - arrow_tail_position_.y(),
                              head_pos.x() - arrow_tail_position_.x() );
    }
    return false;
}

bool PosePublisherPlugin::handleMouseRelease(QMouseEvent* event)
{
    if( !is_mouse_down_ )
    {
        return false;
    }

    is_mouse_down_ = false;

    bool pose_checked = ui_.pushButtonPose->isChecked();
    if( !pose_checked )
    {
        return false;
    }

    if( pose_checked )
    {
      // Get angle/arrow_tail_position in fixed_frame
      tf::Quaternion quat_ff = tf::createQuaternionFromYaw(arrow_angle_);
      geometry_msgs::PoseWithCovarianceStamped pose;

      // Here it is in the target_frame_
      pose.header.frame_id = target_frame_;
      pose.header.stamp = ros::Time::now();
      pose.pose.pose.position.x = arrow_tail_position_.x();
      pose.pose.pose.position.y = arrow_tail_position_.y();
      pose.pose.pose.position.z = 0.0;
      tf::quaternionTFToMsg( quat_ff, pose.pose.pose.orientation );

      // Try to transform to output_frame
      swri_transform_util::Transform transform;
      std::string output_frame = ui_.outputframe->currentText().toStdString();
      if (tf_manager_->GetTransform(output_frame, target_frame_, transform))
        {
        pose.header.frame_id = output_frame;
        tf::Vector3 pose_oframe = transform * tf::Vector3(pose.pose.pose.position.x,
                                                          pose.pose.pose.position.y, 0);
        pose.pose.pose.position.x = pose_oframe.x();
        pose.pose.pose.position.y = pose_oframe.y();
        tf::Quaternion quat_oframe = transform * quat_ff;
        tf::quaternionTFToMsg( quat_oframe, pose.pose.pose.orientation );
        }
      else
        {
        std::stringstream ss;
        ss << "Couldn't get transform from "<< target_frame_
           << " to frame " << output_frame;
        PrintWarning(ss.str());
        }

      pose_pub_.publish(pose);
      std::stringstream ss;
      ss << "Pose published to topic: " <<  ui_.topic->text().toStdString().c_str()
         << " in frame " << pose.header.frame_id;
      PrintInfo(ss.str());

      ui_.pushButtonPose->setChecked(false);
    }
    return true;
}

void PosePublisherPlugin::Draw(double x, double y, double scale)
{
    std::array<QPointF, 7> arrow_points;
    arrow_points[0] = QPointF(10, 0);
    arrow_points[1] = QPointF(6, -2.5);
    arrow_points[2] = QPointF(6.5, -1);
    arrow_points[3] = QPointF(0, -1);
    arrow_points[4] = QPointF(0, 1);
    arrow_points[5] = QPointF(6.5, 1);
    arrow_points[6] = QPointF(6, 2.5);

    if( is_mouse_down_ )
    {
        QPointF transformed_points[7];
        for (size_t i=0; i<7; i++ )
        {
            tf::Vector3 point(arrow_points[i].x(), arrow_points[i].y(), 0);
            point *= scale*10;
            point = tf::Transform( tf::createQuaternionFromYaw(arrow_angle_)  ) * point;
            transformed_points[i] = QPointF(point.x() + arrow_tail_position_.x(),
                                            point.y() + arrow_tail_position_.y() );
        }
        glColor3f(0.1, 0.9, 0.1);
        glLineWidth(2);
        glBegin(GL_TRIANGLE_FAN);
        for (const QPointF& point: transformed_points )
        {
            glVertex2d(point.x(), point.y());
        }
        glEnd();

        glColor3f(0.0, 0.6, 0.0);
        glBegin(GL_LINE_LOOP);
        for (const QPointF& point: transformed_points )
        {
            glVertex2d(point.x(), point.y());
        }
        glEnd();
    }
}

void PosePublisherPlugin::LoadConfig(const YAML::Node& node, const std::string& path)
{
    std::string tmp;
    if (swri_yaml_util::FindValue(node, "topic"))
    {
      node["topic"] >> tmp;
      ui_.topic->setText(QString(tmp.c_str()));
      topicChanged(ui_.topic->text());
    }

    if (swri_yaml_util::FindValue(node, "output_frame"))
    {
      node["output_frame"] >> tmp;
      ui_.outputframe->addItem(QString(tmp.c_str()));
    }

}

void PosePublisherPlugin::SaveConfig(YAML::Emitter& emitter, const std::string& path)
{
    emitter << YAML::Key << "topic" << YAML::Value << ui_.topic->text().toStdString();
    emitter << YAML::Key << "output_frame" << YAML::Value << ui_.outputframe->currentText().toStdString();
}

void PosePublisherPlugin::on_pushButtonPose_toggled(bool checked)
{
    if(checked)
    {
      QPixmap cursor_pixmap = QPixmap(":/images/green-arrow.png");
      QApplication::setOverrideCursor(QCursor(cursor_pixmap));
    }
    else
    {
      QApplication::restoreOverrideCursor();
    }
}

  void PosePublisherPlugin::topicChanged(const QString& topic)
  {
    std::stringstream ss;
    ss << "Publishing points to topic: " << topic.toStdString().c_str();
    PrintInfo(ss.str());

    if (!topic.isEmpty())
    {
      pose_pub_ = node_.advertise<geometry_msgs::PoseWithCovarianceStamped>(topic.toStdString(), 1000);
    }
  }

  void PosePublisherPlugin::updateFrames()
  {
    std::vector<std::string> frames;
    tf_->getFrameStrings(frames);

    bool supports_wgs84 = tf_manager_->SupportsTransform(
        swri_transform_util::_local_xy_frame,
        swri_transform_util::_wgs84_frame);

    if (supports_wgs84)
    {
      frames.push_back(swri_transform_util::_wgs84_frame);
    }

    if (ui_.outputframe->count() >= 0 &&
        static_cast<size_t>(ui_.outputframe->count()) == frames.size())
    {
      bool changed = false;
      for (size_t i = 0; i < frames.size(); i++)
      {
        if (frames[i] != ui_.outputframe->itemText(static_cast<int>(i)).toStdString())
        {
          changed = true;
        }
      }

      if (!changed)
        return;
    }

    std::string output_frame = ui_.outputframe->currentText().toStdString();

    ui_.outputframe->clear();
    for (size_t i = 0; i < frames.size(); i++)
    {
      ui_.outputframe->addItem(frames[i].c_str());
    }

    if (output_frame != "")
    {
      int index = ui_.outputframe->findText(output_frame.c_str());
      if (index < 0)
      {
        ui_.outputframe->addItem(output_frame.c_str());
      }

      index = ui_.outputframe->findText(output_frame.c_str());
      ui_.outputframe->setCurrentIndex(index);
    }
  }

}
<commit_msg>clean up comments<commit_after>// *****************************************************************************
//
// Copyright (c) 2021, Trinity University
// All rights reserved.
//
// 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 of conditions 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 materials provided with the distribution.
//     * Neither the name of Southwest Research Institute® (SwRI®) nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// 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 <COPYRIGHT HOLDER> 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 <mapviz_plugins/pose_publisher_plugin.h>

// Declare plugin
#include <pluginlib/class_list_macros.h>
PLUGINLIB_EXPORT_CLASS(mapviz_plugins::PosePublisherPlugin, mapviz::MapvizPlugin)

namespace mapviz_plugins
{

PosePublisherPlugin::PosePublisherPlugin() :
    config_widget_(new QWidget()),
    map_canvas_(nullptr),
    is_mouse_down_(false),
    monitoring_action_state_(false)
{
    ui_.setupUi(config_widget_);

    // Set background white
    QPalette p(config_widget_->palette());
    p.setColor(QPalette::Background, Qt::white);
    config_widget_->setPalette(p);

    // Set status text green
    ui_.status->setText("OK");
    QPalette p3(ui_.status->palette());
    p3.setColor(QPalette::Text, Qt::green);
    ui_.status->setPalette(p3);

    QObject::connect(ui_.pushButtonPose, SIGNAL(toggled()),
                     this, SLOT(on_pushButtonPose_toggled()));

    QObject::connect(ui_.topic, SIGNAL(textEdited(const QString&)),
            this, SLOT(topicChanged(const QString&)));

    timer_ = nh_.createTimer(ros::Duration(1.0), &PosePublisherPlugin::timerCallback, this);
    frame_timer_.start(1000);
    QObject::connect(&frame_timer_, SIGNAL(timeout()), this, SLOT(updateFrames()));
}

PosePublisherPlugin::~PosePublisherPlugin()
{
    if (map_canvas_)
    {
        map_canvas_->removeEventFilter(this);
    }
}

void PosePublisherPlugin::PrintError(const std::string& message)
{
    PrintErrorHelper( ui_.status, message);
}

void PosePublisherPlugin::PrintInfo(const std::string& message)
{
    PrintInfoHelper( ui_.status, message);
}

void PosePublisherPlugin::PrintWarning(const std::string& message)
{
    PrintWarningHelper( ui_.status, message);
}

QWidget* PosePublisherPlugin::GetConfigWidget(QWidget* parent)
{
    config_widget_->setParent(parent);
    return config_widget_;
}

bool PosePublisherPlugin::Initialize(QGLWidget* canvas)
{
    map_canvas_ = static_cast<mapviz::MapCanvas*>(canvas);
    map_canvas_->installEventFilter(this);
    initialized_ = true;
    return true;
}

bool PosePublisherPlugin::eventFilter(QObject *object, QEvent* event)
{
    switch (event->type())
    {
    case QEvent::MouseButtonPress:
        return handleMousePress(static_cast<QMouseEvent*>(event));
    case QEvent::MouseButtonRelease:
        return handleMouseRelease(static_cast<QMouseEvent*>(event));
    case QEvent::MouseMove:
        return handleMouseMove(static_cast<QMouseEvent*>(event));
    default:
        return false;
    }
}

void PosePublisherPlugin::timerCallback(const ros::TimerEvent &)
{
  ui_.pushButtonPose->setEnabled( true );
  PrintInfoHelper( ui_.status, "OK");
}

bool PosePublisherPlugin::handleMousePress(QMouseEvent* event)
{
    bool pose_checked = ui_.pushButtonPose->isChecked();

    if( !pose_checked)
    {
        return false;
    }

    if (event->button() == Qt::LeftButton)
    {
        is_mouse_down_ = true;
        arrow_angle_ = 0;
#if QT_VERSION >= 0x050000
      arrow_tail_position_= map_canvas_->MapGlCoordToFixedFrame( event->localPos() );
#else
      arrow_tail_position_= map_canvas_->MapGlCoordToFixedFrame( event->posF() );
#endif
        return true;
    }
    return false;
}

bool PosePublisherPlugin::handleMouseMove(QMouseEvent* event)
{
    if (is_mouse_down_)
    {
#if QT_VERSION >= 0x050000
        QPointF head_pos = map_canvas_->MapGlCoordToFixedFrame( event->localPos() );
#else
        QPointF head_pos = map_canvas_->MapGlCoordToFixedFrame( event->posF() );
#endif
        arrow_angle_ = atan2( head_pos.y() - arrow_tail_position_.y(),
                              head_pos.x() - arrow_tail_position_.x() );
    }
    return false;
}

bool PosePublisherPlugin::handleMouseRelease(QMouseEvent* event)
{
    if( !is_mouse_down_ )
    {
        return false;
    }

    is_mouse_down_ = false;

    bool pose_checked = ui_.pushButtonPose->isChecked();
    if( !pose_checked )
    {
        return false;
    }

    if( pose_checked )
    {
      // Get angle/arrow_tail_position in fixed_frame
      tf::Quaternion quat_ff = tf::createQuaternionFromYaw(arrow_angle_);
      geometry_msgs::PoseWithCovarianceStamped pose;

      // Here it is in the target_frame_
      pose.header.frame_id = target_frame_;
      pose.header.stamp = ros::Time::now();
      pose.pose.pose.position.x = arrow_tail_position_.x();
      pose.pose.pose.position.y = arrow_tail_position_.y();
      pose.pose.pose.position.z = 0.0;
      tf::quaternionTFToMsg( quat_ff, pose.pose.pose.orientation );

      // Try to transform to output_frame
      swri_transform_util::Transform transform;
      std::string output_frame = ui_.outputframe->currentText().toStdString();
      if (tf_manager_->GetTransform(output_frame, target_frame_, transform))
        {
        pose.header.frame_id = output_frame;
        tf::Vector3 pose_oframe = transform * tf::Vector3(pose.pose.pose.position.x,
                                                          pose.pose.pose.position.y, 0);
        pose.pose.pose.position.x = pose_oframe.x();
        pose.pose.pose.position.y = pose_oframe.y();
        tf::Quaternion quat_oframe = transform * quat_ff;
        tf::quaternionTFToMsg( quat_oframe, pose.pose.pose.orientation );
        }
      else
        {
        std::stringstream ss;
        ss << "Couldn't get transform from "<< target_frame_
           << " to frame " << output_frame;
        PrintWarning(ss.str());
        }

      pose_pub_.publish(pose);
      std::stringstream ss;
      ss << "Pose published to topic: " <<  ui_.topic->text().toStdString().c_str()
         << " in frame " << pose.header.frame_id;
      PrintInfo(ss.str());

      ui_.pushButtonPose->setChecked(false);
    }
    return true;
}

void PosePublisherPlugin::Draw(double x, double y, double scale)
{
    std::array<QPointF, 7> arrow_points;
    arrow_points[0] = QPointF(10, 0);
    arrow_points[1] = QPointF(6, -2.5);
    arrow_points[2] = QPointF(6.5, -1);
    arrow_points[3] = QPointF(0, -1);
    arrow_points[4] = QPointF(0, 1);
    arrow_points[5] = QPointF(6.5, 1);
    arrow_points[6] = QPointF(6, 2.5);

    if( is_mouse_down_ )
    {
        QPointF transformed_points[7];
        for (size_t i=0; i<7; i++ )
        {
            tf::Vector3 point(arrow_points[i].x(), arrow_points[i].y(), 0);
            point *= scale*10;
            point = tf::Transform( tf::createQuaternionFromYaw(arrow_angle_)  ) * point;
            transformed_points[i] = QPointF(point.x() + arrow_tail_position_.x(),
                                            point.y() + arrow_tail_position_.y() );
        }
        glColor3f(0.1, 0.9, 0.1);
        glLineWidth(2);
        glBegin(GL_TRIANGLE_FAN);
        for (const QPointF& point: transformed_points )
        {
            glVertex2d(point.x(), point.y());
        }
        glEnd();

        glColor3f(0.0, 0.6, 0.0);
        glBegin(GL_LINE_LOOP);
        for (const QPointF& point: transformed_points )
        {
            glVertex2d(point.x(), point.y());
        }
        glEnd();
    }
}

void PosePublisherPlugin::LoadConfig(const YAML::Node& node, const std::string& path)
{
    std::string tmp;
    if (swri_yaml_util::FindValue(node, "topic"))
    {
      node["topic"] >> tmp;
      ui_.topic->setText(QString(tmp.c_str()));
      topicChanged(ui_.topic->text());
    }

    if (swri_yaml_util::FindValue(node, "output_frame"))
    {
      node["output_frame"] >> tmp;
      ui_.outputframe->addItem(QString(tmp.c_str()));
    }

}

void PosePublisherPlugin::SaveConfig(YAML::Emitter& emitter, const std::string& path)
{
    emitter << YAML::Key << "topic" << YAML::Value << ui_.topic->text().toStdString();
    emitter << YAML::Key << "output_frame" << YAML::Value << ui_.outputframe->currentText().toStdString();
}

void PosePublisherPlugin::on_pushButtonPose_toggled(bool checked)
{
    if(checked)
    {
      QPixmap cursor_pixmap = QPixmap(":/images/green-arrow.png");
      QApplication::setOverrideCursor(QCursor(cursor_pixmap));
    }
    else
    {
      QApplication::restoreOverrideCursor();
    }
}

  void PosePublisherPlugin::topicChanged(const QString& topic)
  {
    std::stringstream ss;
    ss << "Publishing points to topic: " << topic.toStdString().c_str();
    PrintInfo(ss.str());

    if (!topic.isEmpty())
    {
      pose_pub_ = node_.advertise<geometry_msgs::PoseWithCovarianceStamped>(topic.toStdString(), 1000);
    }
  }

  void PosePublisherPlugin::updateFrames()
  {
    std::vector<std::string> frames;
    tf_->getFrameStrings(frames);

    bool supports_wgs84 = tf_manager_->SupportsTransform(
        swri_transform_util::_local_xy_frame,
        swri_transform_util::_wgs84_frame);

    if (supports_wgs84)
    {
      frames.push_back(swri_transform_util::_wgs84_frame);
    }

    if (ui_.outputframe->count() >= 0 &&
        static_cast<size_t>(ui_.outputframe->count()) == frames.size())
    {
      bool changed = false;
      for (size_t i = 0; i < frames.size(); i++)
      {
        if (frames[i] != ui_.outputframe->itemText(static_cast<int>(i)).toStdString())
        {
          changed = true;
        }
      }

      if (!changed)
        return;
    }

    std::string output_frame = ui_.outputframe->currentText().toStdString();

    ui_.outputframe->clear();
    for (size_t i = 0; i < frames.size(); i++)
    {
      ui_.outputframe->addItem(frames[i].c_str());
    }

    if (output_frame != "")
    {
      int index = ui_.outputframe->findText(output_frame.c_str());
      if (index < 0)
      {
        ui_.outputframe->addItem(output_frame.c_str());
      }

      index = ui_.outputframe->findText(output_frame.c_str());
      ui_.outputframe->setCurrentIndex(index);
    }
  }

}
<|endoftext|>


<commit_before>// Copyright 2018 Google LLC
//
// 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
//
//    https://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 "jwt_verify_lib/struct_utils.h"

namespace google {
namespace jwt_verify {

StructUtils::StructUtils(const ::google::protobuf::Struct& struct_pb)
      : struct_pb_(struct_pb) {}

StructUtils::FindResult StructUtils::GetString(const std::string& name, std::string* value) {
  const auto& fields = struct_pb_.fields();
  const auto it = fields.find(name);
  if (it == fields.end()) {
    return MISSING;
  }
  if (it->second.kind_case() != google::protobuf::Value::kStringValue) {
    return WRONG_TYPE;
  }
  *value = it->second.string_value();
  return OK;
}

StructUtils::FindResult StructUtils::GetInt64(const std::string& name, uint64_t* value) {
  const auto& fields = struct_pb_.fields();
  const auto it = fields.find(name);
  if (it == fields.end()) {
    return MISSING;
  }
  if (it->second.kind_case() != google::protobuf::Value::kNumberValue) {
    return WRONG_TYPE;
  }
  *value = static_cast<uint64_t>(it->second.number_value());
  return OK;
}

StructUtils::FindResult StructUtils::GetStringList(const std::string& name,
                         std::vector<std::string>* list) {
  const auto& fields = struct_pb_.fields();
  const auto it = fields.find(name);
  if (it == fields.end()) {
    return MISSING;
  }
  if (it->second.kind_case() == google::protobuf::Value::kStringValue) {
    list->push_back(it->second.string_value());
    return OK;
  }
  if (it->second.kind_case() == google::protobuf::Value::kListValue) {
    for (const auto& v : it->second.list_value().values()) {
      if (v.kind_case() != google::protobuf::Value::kStringValue) {
        return WRONG_TYPE;
      }
      list->push_back(v.string_value());
    }
    return OK;
  }
  return WRONG_TYPE;
}

}  // namespace jwt_verify
}  // namespace google

<commit_msg>Fixed code formatting<commit_after>// Copyright 2018 Google LLC
//
// 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
//
//    https://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 "jwt_verify_lib/struct_utils.h"

namespace google {
namespace jwt_verify {

StructUtils::StructUtils(const ::google::protobuf::Struct& struct_pb)
    : struct_pb_(struct_pb) {}

StructUtils::FindResult StructUtils::GetString(const std::string& name,
                                               std::string* value) {
  const auto& fields = struct_pb_.fields();
  const auto it = fields.find(name);
  if (it == fields.end()) {
    return MISSING;
  }
  if (it->second.kind_case() != google::protobuf::Value::kStringValue) {
    return WRONG_TYPE;
  }
  *value = it->second.string_value();
  return OK;
}

StructUtils::FindResult StructUtils::GetInt64(const std::string& name,
                                              uint64_t* value) {
  const auto& fields = struct_pb_.fields();
  const auto it = fields.find(name);
  if (it == fields.end()) {
    return MISSING;
  }
  if (it->second.kind_case() != google::protobuf::Value::kNumberValue) {
    return WRONG_TYPE;
  }
  *value = static_cast<uint64_t>(it->second.number_value());
  return OK;
}

StructUtils::FindResult StructUtils::GetStringList(
    const std::string& name, std::vector<std::string>* list) {
  const auto& fields = struct_pb_.fields();
  const auto it = fields.find(name);
  if (it == fields.end()) {
    return MISSING;
  }
  if (it->second.kind_case() == google::protobuf::Value::kStringValue) {
    list->push_back(it->second.string_value());
    return OK;
  }
  if (it->second.kind_case() == google::protobuf::Value::kListValue) {
    for (const auto& v : it->second.list_value().values()) {
      if (v.kind_case() != google::protobuf::Value::kStringValue) {
        return WRONG_TYPE;
      }
      list->push_back(v.string_value());
    }
    return OK;
  }
  return WRONG_TYPE;
}

}  // namespace jwt_verify
}  // namespace google
<|endoftext|>


<commit_before>/*
 * Note: LoRaWAN per sub-band duty-cycle limitation is enforced (1% in g1,
 *  0.1% in g2).
 *
 * Change DEVADDR to a unique address!
 * See http://thethingsnetwork.org/wiki/AddressSpace
 *
 * Do not forget to define the radio type correctly in config.h.
 */
#include <SPI.h>
#include "Lora.h"
#include "Logging.h"

#if defined(DISABLE_INVERT_IQ_ON_RX)
#error This example requires DISABLE_INVERT_IQ_ON_RX to be NOT set. Update \
       config.h in the lmic library to set it.
#endif

// Pin mapping
const lmic_pinmap lmic_pins = {
    .nss = 19,
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 18,
    .dio = {16, 5, 6}, // Moved dio0 from 17 because of overlapping ExtInt4 (pin6)
};

typedef enum LoraModeEnum {
  NeedsConfiguration,   // Not enough information to do anything
  ReadyToJoin,          // Has AppKey, AppEUI, and DevEUI
  Ready,                // We have session vars via ABP or OTAA - communicate at will
} LoraMode;

static LoraMode mode = NeedsConfiguration;

static JoinResultCallbackFn onJoinCb = NULL;
static TransmitResultCallbackFn onTransmitCb = NULL;

static u1_t join_appkey[16];
static u1_t join_appeui[8];
static u1_t join_deveui[8];

void os_getArtEui (u1_t* buf) {
  debugLogData("Asking for AppEUI", join_appeui, sizeof(join_appeui));
  memcpy(buf, join_appeui, sizeof(join_appeui));
}
void os_getDevEui (u1_t* buf) {
  debugLogData("Asking for DevEUI", join_deveui, sizeof(join_deveui));
  memcpy(buf, join_deveui, sizeof(join_deveui));
}
void os_getDevKey (u1_t* buf) {
  debugLogData("Asking for AppKey", join_appkey, sizeof(join_appkey));
  memcpy(buf, join_appkey, sizeof(join_appkey));
}

static osjob_t timeoutjob;
static void txtimeout_func(osjob_t *job) {
  if (LMIC.opmode & OP_JOINING) {
     // keep waiting.. and don't time out.
     return;
  }
  digitalWrite(LED_BUILTIN, LOW); // off
  Log.Debug(F("Transmit Timeout" CR));
  //txActive = false;
  LMIC_clrTxData ();
}

bool loraSendBytes(uint8_t *data, uint16_t len) {
  if (mode!=Ready) {
    Log.Debug(F("mode not ready, not sending" CR));
    return false; // Did not enqueue
  }
  ostime_t t = os_getTime();
  //os_setTimedCallback(&txjob, t + ms2osticks(100), tx_func);
  // Check if there is not a current TX/RX job running
    if (LMIC.opmode & OP_TXRXPEND) {
        Log.Debug(F("OP_TXRXPEND, not sending" CR));
        return false; // Did not enqueue
    } else {
        // Prepare upstream data transmission at the next possible time.
        Log.Debug(F("Packet queued" CR));
        digitalWrite(LED_BUILTIN, HIGH); // off
        LMIC_setTxData2(1, data, len, 0);
        if (! (LMIC.opmode & OP_JOINING)) {
          // connection is up, message is queued:
          // Timeout TX after 20 seconds
          os_setTimedCallback(&timeoutjob, t + ms2osticks(20000), txtimeout_func);
        }
        return true;
    }
}

void onEvent (ev_t ev) {
    Log.Debug("%d: ", os_getTime());
    switch(ev) {
        case EV_SCAN_TIMEOUT:
            Log.Debug(F("EV_SCAN_TIMEOUT"));
            break;
        case EV_BEACON_FOUND:
            Log.Debug(F("EV_BEACON_FOUND"));
            break;
        case EV_BEACON_MISSED:
            Log.Debug(F("EV_BEACON_MISSED"));
            break;
        case EV_BEACON_TRACKED:
            Log.Debug(F("EV_BEACON_TRACKED"));
            break;
        case EV_JOINING:
            Log.Debug(F("EV_JOINING"));
            break;
        case EV_JOINED:
            Log.Debug(F("EV_JOINED"));
            mode = Ready;
            if (onJoinCb) {
              u4_t netid = 0;
              devaddr_t devaddr = 0;
              u1_t nwkSKey[16];
              u1_t appSKey[16];
              LMIC_getSessionKeys(&netid, &devaddr, nwkSKey, appSKey);
              devaddr = __builtin_bswap32(devaddr); // Settings and Bluetooth deal with devAddr as big endian byte array
              onJoinCb(appSKey, nwkSKey, (u1_t *)&devaddr);
            }
            break;
        case EV_RFU1:
            Log.Debug(F("EV_RFU1"));
            break;
        case EV_JOIN_FAILED:
            Log.Debug(F("EV_JOIN_FAILED"));
            if (onJoinCb) {
              onJoinCb(NULL, NULL, NULL);
            }
            break;
        case EV_REJOIN_FAILED:
            Log.Debug(F("EV_REJOIN_FAILED"));
            break;
        case EV_TXCOMPLETE:
            os_clearCallback(&timeoutjob);
            Log.Debug(F("EV_TXCOMPLETE (includes waiting for RX windows)" CR));
            digitalWrite(LED_BUILTIN, LOW); // off
            if (onTransmitCb) {
              Log.Debug(F("Calling transmit callback..." CR));
              u1_t *received = NULL;
              u1_t len = 0;
              if (LMIC.dataLen>0) {
                received = LMIC.frame+LMIC.dataBeg;
                len = LMIC.dataLen;

                // Log received data.
                u1_t *p = received;
                for (int i=0; i<LMIC.dataLen; ++i) {
                  Log.Debug("%x", *p++);
                }
                // Log.Debug("%*h", LMIC.dataLen, LMIC.frame+LMIC.dataBeg);
                Log.Debug(CR);
              }
              uint32_t tx_seq_no = LMIC_getSeqnoUp()-1; // LMIC_getSeqnoUp returns the NEXT one. We want to return the one used.
              onTransmitCb(0 /* success */, tx_seq_no, received, len);
            }

            break;
        case EV_LOST_TSYNC:
            Log.Debug(F("EV_LOST_TSYNC"));
            break;
        case EV_RESET:
            Log.Debug(F("EV_RESET"));
            break;
        case EV_RXCOMPLETE:
            // data received in ping slot
            Log.Debug(F("EV_RXCOMPLETE"));
            break;
        case EV_LINK_DEAD:
            Log.Debug(F("EV_LINK_DEAD"));
            break;
        case EV_LINK_ALIVE:
            Log.Debug(F("EV_LINK_ALIVE"));
            break;
        case EV_SCAN_FOUND:
            Log.Debug(F("EV_SCAN_FOUND"));
            break;
        case EV_TXSTART:
            Log.Debug(F("EV_TXSTART"));
            break;
        default:
            Log.Debug(F("Unknown event: %d"), (int)ev);
            break;
    }
    Log.Debug(CR);
}

static void configureLora(uint32_t seq_no) {
  #if defined(CFG_eu868)
    // Set up the channels used by the Things Network, which corresponds
    // to the defaults of most gateways. Without this, only three base
    // channels from the LoRaWAN specification are used, which certainly
    // works, so it is good for debugging, but can overload those
    // frequencies, so be sure to configure the full frequency range of
    // your network here (unless your network autoconfigures them).
    // Setting up channels should happen after LMIC_setSession, as that
    // configures the minimal channel set.
    LMIC_setupChannel(0, 868100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(1, 868300000, DR_RANGE_MAP(DR_SF12, DR_SF7B), BAND_CENTI);      // g-band
    LMIC_setupChannel(2, 868500000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(3, 867100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(4, 867300000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(5, 867500000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(6, 867700000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(7, 867900000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(8, 868800000, DR_RANGE_MAP(DR_FSK,  DR_FSK),  BAND_MILLI);      // g2-band
    // TTN defines an additional channel at 869.525Mhz using SF9 for class B
    // devices' ping slots. LMIC does not have an easy way to define set this
    // frequency and support for class B is spotty and untested, so this
    // frequency is not configured here.
    #endif

    LMIC_selectSubBand(1);

    // Disable link check validation
    LMIC_setLinkCheckMode(0);

    // Set data rate and transmit power (note: txpow seems to be ignored by the library)
    LMIC_setDrTxpow(DR_SF10,20);

    debugLog("Set LoRa seq no:", seq_no);
    LMIC_setSeqnoUp(seq_no);
}

void setupLora(TransmitResultCallbackFn txcb) {
    onTransmitCb = txcb;

    #ifdef VCC_ENABLE
    // For Pinoccio Scout boards
    pinMode(VCC_ENABLE, OUTPUT);
    digitalWrite(VCC_ENABLE, HIGH);
    delay(1000);
    #endif
}

void loopLora() {
  if (mode!=NeedsConfiguration) {
    os_runloop_once();
  }
}

void loraJoin(uint32_t seq_no, u1_t *appkey, u1_t *appeui, u1_t *deveui, JoinResultCallbackFn joincb) {
  onJoinCb = joincb;

  memcpy(join_appkey, appkey, sizeof(join_appkey));
  memcpy(join_appeui, appeui, sizeof(join_appeui));
  memcpy(join_deveui, deveui, sizeof(join_deveui));

  // LMIC init
  os_init();
  // Reset the MAC state. Session and pending data transfers will be discarded.
  LMIC_reset();

  configureLora(seq_no);

  if (LMIC_startJoining()) {
    debugPrint("Started joining.");
  }
  else {
    debugPrint("Error: Expected to start joining, but did not!");
  }

  mode = ReadyToJoin;
}

void loraSetSessionKeys(uint32_t seq_no, u1_t *appskey, u1_t *nwkskey, u1_t *devaddr) {
  debugLogData("Devaddr: ", devaddr, 4);
  debugLogData("appskey", appskey, 16);
  debugLogData("nwkskey", nwkskey, 16);

  // LMIC init
  os_init();
  // Reset the MAC state. Session and pending data transfers will be discarded.
  LMIC_reset();

  devaddr_t da = *(devaddr_t *)devaddr;
  da = __builtin_bswap32(da); // Settings and Bluetooth deal with devAddr as big endian byte array
  LMIC_setSession(0x1 /* TTN_NETWORK_ID */, da, nwkskey, appskey);

  configureLora(seq_no);

  mode = Ready;
}

void loraSetSF(uint sf) {
  dr_t dr;
  switch (sf) {
    case 7: dr = DR_SF7; break;
    case 8: dr = DR_SF8; break;
    case 9: dr = DR_SF9; break;
    case 10: dr = DR_SF10; break;
    default:
      dr = DR_SF10;
      Log.Debug(F("Invalid SF value: %d" CR), sf);
      break;
  }
  LMIC_setDrTxpow(dr,20);
}
<commit_msg>Modified LoRa pin definition so Hackathon boards work.<commit_after>/*
 * Note: LoRaWAN per sub-band duty-cycle limitation is enforced (1% in g1,
 *  0.1% in g2).
 *
 * Change DEVADDR to a unique address!
 * See http://thethingsnetwork.org/wiki/AddressSpace
 *
 * Do not forget to define the radio type correctly in config.h.
 */
#include <SPI.h>
#include "Lora.h"
#include "Logging.h"

#if defined(DISABLE_INVERT_IQ_ON_RX)
#error This example requires DISABLE_INVERT_IQ_ON_RX to be NOT set. Update \
       config.h in the lmic library to set it.
#endif

/*
 * Pin mapping
 *  adjusted to conform to pinout shown in image
 *  from this repo's image.
 */
const lmic_pinmap lmic_pins = {
#if 1
    .nss = 6 /*feather wing pin D*/,
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 5/*feather wing pin E*/,
    .dio = {12/*feather wing pin above A*/, 11/*feather wing pin A*/, 10 /*feather wing pin B*/},
#else
    // alternate pinout
    .nss = 19,
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 18,
    .dio = {16,5,6},
#endif
};

typedef enum LoraModeEnum {
  NeedsConfiguration,   // Not enough information to do anything
  ReadyToJoin,          // Has AppKey, AppEUI, and DevEUI
  Ready,                // We have session vars via ABP or OTAA - communicate at will
} LoraMode;

static LoraMode mode = NeedsConfiguration;

static JoinResultCallbackFn onJoinCb = NULL;
static TransmitResultCallbackFn onTransmitCb = NULL;

static u1_t join_appkey[16];
static u1_t join_appeui[8];
static u1_t join_deveui[8];

void os_getArtEui (u1_t* buf) {
  debugLogData("Asking for AppEUI", join_appeui, sizeof(join_appeui));
  memcpy(buf, join_appeui, sizeof(join_appeui));
}
void os_getDevEui (u1_t* buf) {
  debugLogData("Asking for DevEUI", join_deveui, sizeof(join_deveui));
  memcpy(buf, join_deveui, sizeof(join_deveui));
}
void os_getDevKey (u1_t* buf) {
  debugLogData("Asking for AppKey", join_appkey, sizeof(join_appkey));
  memcpy(buf, join_appkey, sizeof(join_appkey));
}

static osjob_t timeoutjob;
static void txtimeout_func(osjob_t *job) {
  if (LMIC.opmode & OP_JOINING) {
     // keep waiting.. and don't time out.
     return;
  }
  digitalWrite(LED_BUILTIN, LOW); // off
  Log.Debug(F("Transmit Timeout" CR));
  //txActive = false;
  LMIC_clrTxData ();
}

bool loraSendBytes(uint8_t *data, uint16_t len) {
  if (mode!=Ready) {
    Log.Debug(F("mode not ready, not sending" CR));
    return false; // Did not enqueue
  }
  ostime_t t = os_getTime();
  //os_setTimedCallback(&txjob, t + ms2osticks(100), tx_func);
  // Check if there is not a current TX/RX job running
    if (LMIC.opmode & OP_TXRXPEND) {
        Log.Debug(F("OP_TXRXPEND, not sending" CR));
        return false; // Did not enqueue
    } else {
        // Prepare upstream data transmission at the next possible time.
        Log.Debug(F("Packet queued" CR));
        digitalWrite(LED_BUILTIN, HIGH); // off
        LMIC_setTxData2(1, data, len, 0);
        if (! (LMIC.opmode & OP_JOINING)) {
          // connection is up, message is queued:
          // Timeout TX after 20 seconds
          os_setTimedCallback(&timeoutjob, t + ms2osticks(20000), txtimeout_func);
        }
        return true;
    }
}

void onEvent (ev_t ev) {
    Log.Debug("%d: ", os_getTime());
    switch(ev) {
        case EV_SCAN_TIMEOUT:
            Log.Debug(F("EV_SCAN_TIMEOUT"));
            break;
        case EV_BEACON_FOUND:
            Log.Debug(F("EV_BEACON_FOUND"));
            break;
        case EV_BEACON_MISSED:
            Log.Debug(F("EV_BEACON_MISSED"));
            break;
        case EV_BEACON_TRACKED:
            Log.Debug(F("EV_BEACON_TRACKED"));
            break;
        case EV_JOINING:
            Log.Debug(F("EV_JOINING"));
            break;
        case EV_JOINED:
            Log.Debug(F("EV_JOINED"));
            mode = Ready;
            if (onJoinCb) {
              u4_t netid = 0;
              devaddr_t devaddr = 0;
              u1_t nwkSKey[16];
              u1_t appSKey[16];
              LMIC_getSessionKeys(&netid, &devaddr, nwkSKey, appSKey);
              devaddr = __builtin_bswap32(devaddr); // Settings and Bluetooth deal with devAddr as big endian byte array
              onJoinCb(appSKey, nwkSKey, (u1_t *)&devaddr);
            }
            break;
        case EV_RFU1:
            Log.Debug(F("EV_RFU1"));
            break;
        case EV_JOIN_FAILED:
            Log.Debug(F("EV_JOIN_FAILED"));
            if (onJoinCb) {
              onJoinCb(NULL, NULL, NULL);
            }
            break;
        case EV_REJOIN_FAILED:
            Log.Debug(F("EV_REJOIN_FAILED"));
            break;
        case EV_TXCOMPLETE:
            os_clearCallback(&timeoutjob);
            Log.Debug(F("EV_TXCOMPLETE (includes waiting for RX windows)" CR));
            digitalWrite(LED_BUILTIN, LOW); // off
            if (onTransmitCb) {
              Log.Debug(F("Calling transmit callback..." CR));
              u1_t *received = NULL;
              u1_t len = 0;
              if (LMIC.dataLen>0) {
                received = LMIC.frame+LMIC.dataBeg;
                len = LMIC.dataLen;

                // Log received data.
                u1_t *p = received;
                for (int i=0; i<LMIC.dataLen; ++i) {
                  Log.Debug("%x", *p++);
                }
                // Log.Debug("%*h", LMIC.dataLen, LMIC.frame+LMIC.dataBeg);
                Log.Debug(CR);
              }
              uint32_t tx_seq_no = LMIC_getSeqnoUp()-1; // LMIC_getSeqnoUp returns the NEXT one. We want to return the one used.
              onTransmitCb(0 /* success */, tx_seq_no, received, len);
            }

            break;
        case EV_LOST_TSYNC:
            Log.Debug(F("EV_LOST_TSYNC"));
            break;
        case EV_RESET:
            Log.Debug(F("EV_RESET"));
            break;
        case EV_RXCOMPLETE:
            // data received in ping slot
            Log.Debug(F("EV_RXCOMPLETE"));
            break;
        case EV_LINK_DEAD:
            Log.Debug(F("EV_LINK_DEAD"));
            break;
        case EV_LINK_ALIVE:
            Log.Debug(F("EV_LINK_ALIVE"));
            break;
        case EV_SCAN_FOUND:
            Log.Debug(F("EV_SCAN_FOUND"));
            break;
        case EV_TXSTART:
            Log.Debug(F("EV_TXSTART"));
            break;
        default:
            Log.Debug(F("Unknown event: %d"), (int)ev);
            break;
    }
    Log.Debug(CR);
}

static void configureLora(uint32_t seq_no) {
  #if defined(CFG_eu868)
    // Set up the channels used by the Things Network, which corresponds
    // to the defaults of most gateways. Without this, only three base
    // channels from the LoRaWAN specification are used, which certainly
    // works, so it is good for debugging, but can overload those
    // frequencies, so be sure to configure the full frequency range of
    // your network here (unless your network autoconfigures them).
    // Setting up channels should happen after LMIC_setSession, as that
    // configures the minimal channel set.
    LMIC_setupChannel(0, 868100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(1, 868300000, DR_RANGE_MAP(DR_SF12, DR_SF7B), BAND_CENTI);      // g-band
    LMIC_setupChannel(2, 868500000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(3, 867100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(4, 867300000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(5, 867500000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(6, 867700000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(7, 867900000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(8, 868800000, DR_RANGE_MAP(DR_FSK,  DR_FSK),  BAND_MILLI);      // g2-band
    // TTN defines an additional channel at 869.525Mhz using SF9 for class B
    // devices' ping slots. LMIC does not have an easy way to define set this
    // frequency and support for class B is spotty and untested, so this
    // frequency is not configured here.
    #endif

    LMIC_selectSubBand(1);

    // Disable link check validation
    LMIC_setLinkCheckMode(0);

    // Set data rate and transmit power (note: txpow seems to be ignored by the library)
    LMIC_setDrTxpow(DR_SF10,20);

    debugLog("Set LoRa seq no:", seq_no);
    LMIC_setSeqnoUp(seq_no);
}

void setupLora(TransmitResultCallbackFn txcb) {
    onTransmitCb = txcb;

    #ifdef VCC_ENABLE
    // For Pinoccio Scout boards
    pinMode(VCC_ENABLE, OUTPUT);
    digitalWrite(VCC_ENABLE, HIGH);
    delay(1000);
    #endif
}

void loopLora() {
  if (mode!=NeedsConfiguration) {
    os_runloop_once();
  }
}

void loraJoin(uint32_t seq_no, u1_t *appkey, u1_t *appeui, u1_t *deveui, JoinResultCallbackFn joincb) {
  onJoinCb = joincb;

  memcpy(join_appkey, appkey, sizeof(join_appkey));
  memcpy(join_appeui, appeui, sizeof(join_appeui));
  memcpy(join_deveui, deveui, sizeof(join_deveui));

  // LMIC init
  os_init();
  // Reset the MAC state. Session and pending data transfers will be discarded.
  LMIC_reset();

  configureLora(seq_no);

  if (LMIC_startJoining()) {
    debugPrint("Started joining.");
  }
  else {
    debugPrint("Error: Expected to start joining, but did not!");
  }

  mode = ReadyToJoin;
}

void loraSetSessionKeys(uint32_t seq_no, u1_t *appskey, u1_t *nwkskey, u1_t *devaddr) {
  debugLogData("Devaddr: ", devaddr, 4);
  debugLogData("appskey", appskey, 16);
  debugLogData("nwkskey", nwkskey, 16);

  // LMIC init
  os_init();
  // Reset the MAC state. Session and pending data transfers will be discarded.
  LMIC_reset();

  devaddr_t da = *(devaddr_t *)devaddr;
  da = __builtin_bswap32(da); // Settings and Bluetooth deal with devAddr as big endian byte array
  LMIC_setSession(0x1 /* TTN_NETWORK_ID */, da, nwkskey, appskey);

  configureLora(seq_no);

  mode = Ready;
}

void loraSetSF(uint sf) {
  dr_t dr;
  switch (sf) {
    case 7: dr = DR_SF7; break;
    case 8: dr = DR_SF8; break;
    case 9: dr = DR_SF9; break;
    case 10: dr = DR_SF10; break;
    default:
      dr = DR_SF10;
      Log.Debug(F("Invalid SF value: %d" CR), sf);
      break;
  }
  LMIC_setDrTxpow(dr,20);
}
<|endoftext|>


<commit_before>#include <exception>
#include <iostream>
#include <stdexcept>
#include <unordered_map>
#include <unordered_set>

#include <tclap/CmdLine.h>

#include "printer/cprinter.hpp"
#include "printer/cudaprinter.hpp"
#include "printer/infoprinter.hpp"
#include "printer/printeropt.hpp"
#include "printer/simd.hpp"

#include "modccutil.hpp"
#include "module.hpp"
#include "parser.hpp"
#include "perfvisitor.hpp"

#include "io/bulkio.hpp"

using std::cout;
using std::cerr;

// Options and option parsing:

int report_error(const std::string& message) {
    cerr << red("error: ") << message << "\n";
    return 1;
}

int report_ice(const std::string& message) {
    cerr << red("internal compiler error: ") << message << "\n"
         << "\nPlease report this error to the modcc developers.\n";
    return 1;
}

enum class targetKind {
    cpu,
    gpu,
};

std::unordered_map<std::string, targetKind> targetKindMap = {
    {"cpu", targetKind::cpu},
    {"gpu", targetKind::gpu},
};

std::unordered_map<std::string, enum simd_spec::simd_abi> simdAbiMap = {
    {"none", simd_spec::none},
    {"avx",  simd_spec::avx},
    {"avx2", simd_spec::avx2},
    {"avx512", simd_spec::avx512},
    {"default_abi", simd_spec::default_abi},
    {"native", simd_spec::native}
};

template <typename Map, typename V>
auto key_by_value(const Map& map, const V& v) -> decltype(map.begin()->first) {
    for (const auto& kv: map) {
        if (kv.second==v) return kv.first;
    }
    throw std::out_of_range("value not found in map");
}

struct Options {
    std::string outprefix;
    std::string modfile;
    std::string modulename;
    bool verbose = true;
    bool analysis = false;
    std::unordered_set<targetKind, enum_hash> targets;
};

// Helper for formatting tabulated output (option reporting).
struct table_prefix { std::string text; };
std::ostream& operator<<(std::ostream& out, const table_prefix& tb) {
    return out << cyan("| "+tb.text) << std::right << std::setw(58-tb.text.size());
};

std::ostream& operator<<(std::ostream& out, simd_spec simd) {
    std::stringstream s;
    s << key_by_value(simdAbiMap, simd.abi);
    if (simd.width!=0) {
        s << '/' << simd.width;
    }
    return out << s.str();
}

std::ostream& operator<<(std::ostream& out, const Options& opt) {
    static const char* noyes[2] = {"no", "yes"};
    static const std::string line_end = cyan(" |") + "\n";

    std::string targets;
    for (targetKind t: opt.targets) {
        targets += " "+key_by_value(targetKindMap, t);
    }

    return out <<
        table_prefix{"file"} << opt.modfile << line_end <<
        table_prefix{"output"} << (opt.outprefix.empty()? "-": opt.outprefix) << line_end <<
        table_prefix{"verbose"} << noyes[opt.verbose] << line_end <<
        table_prefix{"targets"} << targets << line_end <<
        table_prefix{"analysis"} << noyes[opt.analysis] << line_end;
}

std::ostream& operator<<(std::ostream& out, const printer_options& popt) {
    static const char* noyes[2] = {"no", "yes"};
    static const std::string line_end = cyan(" |") + "\n";

    return out <<
        table_prefix{"namespace"} << popt.cpp_namespace << line_end <<
        table_prefix{"profile"} << noyes[popt.profile] << line_end <<
        table_prefix{"simd"} << popt.simd << line_end;
}

// Constraints for TCLAP arguments that are names for enumertion values.
struct MapConstraint: private std::vector<std::string>, public TCLAP::ValuesConstraint<std::string> {
    template <typename Map>
    MapConstraint(const Map& map):
        std::vector<std::string>(keys(map)),
        TCLAP::ValuesConstraint<std::string>(static_cast<std::vector<std::string>&>(*this)) {}

    template <typename Map>
    static std::vector<std::string> keys(const Map& map) {
        std::vector<std::string> ks;
        for (auto& kv: map) ks.push_back(kv.first);
        return ks;
    }
};

simd_spec parse_simd_spec(std::string spec) {
    auto npos = std::string::npos;
    unsigned width = 0;

    auto suffix = spec.find_last_of('/');
    if (suffix!=npos) {
        width = stoul(spec.substr(suffix+1));
        spec = spec.substr(0, suffix);
    }

    return simd_spec(simdAbiMap.at(spec.c_str()), width);
}

struct SimdAbiConstraint: public TCLAP::Constraint<std::string> {
    std::string description() const override {
        return "simd_abi[/n]";
    }
    std::string shortID() const override {
        return description();
    }
    bool check(const std::string& spec) const override {
        try {
            (void)parse_simd_spec(spec);
            return true;
        }
        catch (...) {
            return false;
        }
    }
};

int main(int argc, char **argv) {
    Options opt;
    printer_options popt;

    try {
        TCLAP::CmdLine cmd("modcc code generator for arbor", ' ', "0.1");

        TCLAP::UnlabeledValueArg<std::string>
            fin_arg("input_file", "the name of the .mod file to compile", true, "", "filename", cmd);

        TCLAP::ValueArg<std::string>
            fout_arg("o", "output", "prefix for output file names", false, "", "filename", cmd);

        TCLAP::ValueArg<std::string>
            namespace_arg("N", "namespace", "namespace for generated code", false, "arb", "name", cmd);

        MapConstraint targets_arg_constraint(targetKindMap);
        TCLAP::MultiArg<std::string>
            target_arg("t", "target", "build module for cpu or gpu back-end", false, &targets_arg_constraint, cmd);

        TCLAP::SwitchArg
            simd_arg("s", "simd", "generate code with explicit SIMD vectorization", cmd, false);

        SimdAbiConstraint simd_abi_constraint;
        TCLAP::ValueArg<std::string>
            simd_abi_arg("S", "simd-abi", "override SIMD ABI in generated code. Use /n suffix to force SIMD width to be size n. Examples: 'avx2', 'native/4', ...", false, "", &simd_abi_constraint, cmd);

        TCLAP::SwitchArg profile_arg("P","profile","build with profiled kernels", cmd, false);

        TCLAP::SwitchArg verbose_arg("V","verbose","toggle verbose mode", cmd, false);

        TCLAP::SwitchArg analysis_arg("A","analyse","toggle analysis mode", cmd, false);

        TCLAP::ValueArg<std::string>
            module_arg("m", "module", "module name to use (default taken from input .mod file)", false, "", "module", cmd);

        cmd.parse(argc, argv);

        opt.outprefix = fout_arg.getValue();
        opt.modfile = fin_arg.getValue();
        opt.modulename = module_arg.getValue();
        opt.verbose = verbose_arg.getValue();
        opt.analysis = analysis_arg.getValue();

        popt.cpp_namespace = namespace_arg.getValue();
        popt.profile = profile_arg.getValue();

        if (simd_arg.getValue()) {
            popt.simd = simd_spec(simd_spec::native);
            if (!simd_abi_arg.getValue().empty()) {
                popt.simd = parse_simd_spec(simd_abi_arg.getValue());
            }
        }

        for (auto& target: target_arg.getValue()) {
            opt.targets.insert(targetKindMap.at(target));
        }
    }
    catch(TCLAP::ArgException &e) {
        return report_error(e.error()+" for argument "+to_string(e.argId()));
    }

    try {
        auto emit_header = [&opt](const char* h) {
            if (opt.verbose) {
                cout << green("[") << h << green("]") << "\n";
            }
        };

        if (opt.verbose) {
            static const std::string tableline = cyan("."+std::string(60, '-')+".")+"\n";
            cout << tableline;
            cout << opt;
            cout << popt;
            cout << tableline;
        }

        // Load module file and initialize Module object.

        Module m(io::read_all(opt.modfile), opt.modfile);

        if (m.empty()) {
            return report_error("empty file: "+opt.modfile);
        }

        if (!opt.modulename.empty()) {
            m.module_name(opt.modulename);
        }

        // Perform parsing and semantic analysis passes.

        emit_header("parsing");
        Parser p(m, false);
        if (!p.parse()) {
            // Parser::parse() writes its own errors to stderr.
            return 1;
        }

        emit_header("semantic analysis");
        m.semantic();
        if (m.has_warning()) {
            cerr << m.warning_string() << "\n";
        }
        if (m.has_error()) {
            return report_error(m.error_string());
        }

        // Generate backend-specific sources for each backend provided.

        emit_header("code generation");

        // If no output prefix given, use the module name.
        std::string prefix = opt.outprefix.empty()? m.module_name(): opt.outprefix;

        io::write_all(build_info_header(m, popt), prefix+".hpp");
        for (targetKind target: opt.targets) {
            std::string outfile = prefix;
            switch (target) {
            case targetKind::gpu:
                io::write_all(emit_cuda_cpp_source(m, popt), outfile+"_gpu.cpp");
                io::write_all(emit_cuda_cu_source(m, popt), outfile+"_gpu.cu");
                break;
            case targetKind::cpu:
                io::write_all(emit_cpp_source(m, popt), outfile+"_cpu.cpp");
                break;
            }
        }

        // Optional analysis report.

        if (opt.analysis) {
            cout << green("performance analysis\n");
            for (auto &symbol: m.symbols()) {
                if (auto method = symbol.second->is_api_method()) {
                    cout << white("-------------------------\n");
                    cout << yellow("method " + method->name()) << "\n";
                    cout << white("-------------------------\n");

                    FlopVisitor flops;
                    method->accept(&flops);
                    cout << white("FLOPS\n") << flops.print() << "\n";

                    MemOpVisitor memops;
                    method->accept(&memops);
                    cout << white("MEMOPS\n") << memops.print() << "\n";
                }
            }
        }
    }
    catch(compiler_exception& e) {
        return report_ice(e.what()+std::string(" @ ")+to_string(e.location()));
    }
    catch(std::exception& e) {
        return report_ice(e.what());
    }
    catch(...) {
        return report_ice("");
    }

    return 0;
}
<commit_msg>Better error message on missing file.<commit_after>#include <exception>
#include <iostream>
#include <stdexcept>
#include <unordered_map>
#include <unordered_set>

#include <tclap/CmdLine.h>

#include "printer/cprinter.hpp"
#include "printer/cudaprinter.hpp"
#include "printer/infoprinter.hpp"
#include "printer/printeropt.hpp"
#include "printer/simd.hpp"

#include "modccutil.hpp"
#include "module.hpp"
#include "parser.hpp"
#include "perfvisitor.hpp"

#include "io/bulkio.hpp"

using std::cout;
using std::cerr;

// Options and option parsing:

int report_error(const std::string& message) {
    cerr << red("error: ") << message << "\n";
    return 1;
}

int report_ice(const std::string& message) {
    cerr << red("internal compiler error: ") << message << "\n"
         << "\nPlease report this error to the modcc developers.\n";
    return 1;
}

enum class targetKind {
    cpu,
    gpu,
};

std::unordered_map<std::string, targetKind> targetKindMap = {
    {"cpu", targetKind::cpu},
    {"gpu", targetKind::gpu},
};

std::unordered_map<std::string, enum simd_spec::simd_abi> simdAbiMap = {
    {"none", simd_spec::none},
    {"avx",  simd_spec::avx},
    {"avx2", simd_spec::avx2},
    {"avx512", simd_spec::avx512},
    {"default_abi", simd_spec::default_abi},
    {"native", simd_spec::native}
};

template <typename Map, typename V>
auto key_by_value(const Map& map, const V& v) -> decltype(map.begin()->first) {
    for (const auto& kv: map) {
        if (kv.second==v) return kv.first;
    }
    throw std::out_of_range("value not found in map");
}

struct Options {
    std::string outprefix;
    std::string modfile;
    std::string modulename;
    bool verbose = true;
    bool analysis = false;
    std::unordered_set<targetKind, enum_hash> targets;
};

// Helper for formatting tabulated output (option reporting).
struct table_prefix { std::string text; };
std::ostream& operator<<(std::ostream& out, const table_prefix& tb) {
    return out << cyan("| "+tb.text) << std::right << std::setw(58-tb.text.size());
};

std::ostream& operator<<(std::ostream& out, simd_spec simd) {
    std::stringstream s;
    s << key_by_value(simdAbiMap, simd.abi);
    if (simd.width!=0) {
        s << '/' << simd.width;
    }
    return out << s.str();
}

std::ostream& operator<<(std::ostream& out, const Options& opt) {
    static const char* noyes[2] = {"no", "yes"};
    static const std::string line_end = cyan(" |") + "\n";

    std::string targets;
    for (targetKind t: opt.targets) {
        targets += " "+key_by_value(targetKindMap, t);
    }

    return out <<
        table_prefix{"file"} << opt.modfile << line_end <<
        table_prefix{"output"} << (opt.outprefix.empty()? "-": opt.outprefix) << line_end <<
        table_prefix{"verbose"} << noyes[opt.verbose] << line_end <<
        table_prefix{"targets"} << targets << line_end <<
        table_prefix{"analysis"} << noyes[opt.analysis] << line_end;
}

std::ostream& operator<<(std::ostream& out, const printer_options& popt) {
    static const char* noyes[2] = {"no", "yes"};
    static const std::string line_end = cyan(" |") + "\n";

    return out <<
        table_prefix{"namespace"} << popt.cpp_namespace << line_end <<
        table_prefix{"profile"} << noyes[popt.profile] << line_end <<
        table_prefix{"simd"} << popt.simd << line_end;
}

// Constraints for TCLAP arguments that are names for enumertion values.
struct MapConstraint: private std::vector<std::string>, public TCLAP::ValuesConstraint<std::string> {
    template <typename Map>
    MapConstraint(const Map& map):
        std::vector<std::string>(keys(map)),
        TCLAP::ValuesConstraint<std::string>(static_cast<std::vector<std::string>&>(*this)) {}

    template <typename Map>
    static std::vector<std::string> keys(const Map& map) {
        std::vector<std::string> ks;
        for (auto& kv: map) ks.push_back(kv.first);
        return ks;
    }
};

simd_spec parse_simd_spec(std::string spec) {
    auto npos = std::string::npos;
    unsigned width = 0;

    auto suffix = spec.find_last_of('/');
    if (suffix!=npos) {
        width = stoul(spec.substr(suffix+1));
        spec = spec.substr(0, suffix);
    }

    return simd_spec(simdAbiMap.at(spec.c_str()), width);
}

struct SimdAbiConstraint: public TCLAP::Constraint<std::string> {
    std::string description() const override {
        return "simd_abi[/n]";
    }
    std::string shortID() const override {
        return description();
    }
    bool check(const std::string& spec) const override {
        try {
            (void)parse_simd_spec(spec);
            return true;
        }
        catch (...) {
            return false;
        }
    }
};

int main(int argc, char **argv) {
    Options opt;
    printer_options popt;

    try {
        TCLAP::CmdLine cmd("modcc code generator for arbor", ' ', "0.1");

        TCLAP::UnlabeledValueArg<std::string>
            fin_arg("input_file", "the name of the .mod file to compile", true, "", "filename", cmd);

        TCLAP::ValueArg<std::string>
            fout_arg("o", "output", "prefix for output file names", false, "", "filename", cmd);

        TCLAP::ValueArg<std::string>
            namespace_arg("N", "namespace", "namespace for generated code", false, "arb", "name", cmd);

        MapConstraint targets_arg_constraint(targetKindMap);
        TCLAP::MultiArg<std::string>
            target_arg("t", "target", "build module for cpu or gpu back-end", false, &targets_arg_constraint, cmd);

        TCLAP::SwitchArg
            simd_arg("s", "simd", "generate code with explicit SIMD vectorization", cmd, false);

        SimdAbiConstraint simd_abi_constraint;
        TCLAP::ValueArg<std::string>
            simd_abi_arg("S", "simd-abi", "override SIMD ABI in generated code. Use /n suffix to force SIMD width to be size n. Examples: 'avx2', 'native/4', ...", false, "", &simd_abi_constraint, cmd);

        TCLAP::SwitchArg profile_arg("P","profile","build with profiled kernels", cmd, false);

        TCLAP::SwitchArg verbose_arg("V","verbose","toggle verbose mode", cmd, false);

        TCLAP::SwitchArg analysis_arg("A","analyse","toggle analysis mode", cmd, false);

        TCLAP::ValueArg<std::string>
            module_arg("m", "module", "module name to use (default taken from input .mod file)", false, "", "module", cmd);

        cmd.parse(argc, argv);

        opt.outprefix = fout_arg.getValue();
        opt.modfile = fin_arg.getValue();
        opt.modulename = module_arg.getValue();
        opt.verbose = verbose_arg.getValue();
        opt.analysis = analysis_arg.getValue();

        popt.cpp_namespace = namespace_arg.getValue();
        popt.profile = profile_arg.getValue();

        if (simd_arg.getValue()) {
            popt.simd = simd_spec(simd_spec::native);
            if (!simd_abi_arg.getValue().empty()) {
                popt.simd = parse_simd_spec(simd_abi_arg.getValue());
            }
        }

        for (auto& target: target_arg.getValue()) {
            opt.targets.insert(targetKindMap.at(target));
        }
    }
    catch(TCLAP::ArgException &e) {
        return report_error(e.error()+" for argument "+to_string(e.argId()));
    }

    try {
        auto emit_header = [&opt](const char* h) {
            if (opt.verbose) {
                cout << green("[") << h << green("]") << "\n";
            }
        };

        if (opt.verbose) {
            static const std::string tableline = cyan("."+std::string(60, '-')+".")+"\n";
            cout << tableline;
            cout << opt;
            cout << popt;
            cout << tableline;
        }

        // Load module file and initialize Module object.

        Module m(io::read_all(opt.modfile), opt.modfile);

        if (m.empty()) {
            return report_error("empty file: "+opt.modfile);
        }

        if (!opt.modulename.empty()) {
            m.module_name(opt.modulename);
        }

        // Perform parsing and semantic analysis passes.

        emit_header("parsing");
        Parser p(m, false);
        if (!p.parse()) {
            // Parser::parse() writes its own errors to stderr.
            return 1;
        }

        emit_header("semantic analysis");
        m.semantic();
        if (m.has_warning()) {
            cerr << m.warning_string() << "\n";
        }
        if (m.has_error()) {
            return report_error(m.error_string());
        }

        // Generate backend-specific sources for each backend provided.

        emit_header("code generation");

        // If no output prefix given, use the module name.
        std::string prefix = opt.outprefix.empty()? m.module_name(): opt.outprefix;

        io::write_all(build_info_header(m, popt), prefix+".hpp");
        for (targetKind target: opt.targets) {
            std::string outfile = prefix;
            switch (target) {
            case targetKind::gpu:
                io::write_all(emit_cuda_cpp_source(m, popt), outfile+"_gpu.cpp");
                io::write_all(emit_cuda_cu_source(m, popt), outfile+"_gpu.cu");
                break;
            case targetKind::cpu:
                io::write_all(emit_cpp_source(m, popt), outfile+"_cpu.cpp");
                break;
            }
        }

        // Optional analysis report.

        if (opt.analysis) {
            cout << green("performance analysis\n");
            for (auto &symbol: m.symbols()) {
                if (auto method = symbol.second->is_api_method()) {
                    cout << white("-------------------------\n");
                    cout << yellow("method " + method->name()) << "\n";
                    cout << white("-------------------------\n");

                    FlopVisitor flops;
                    method->accept(&flops);
                    cout << white("FLOPS\n") << flops.print() << "\n";

                    MemOpVisitor memops;
                    method->accept(&memops);
                    cout << white("MEMOPS\n") << memops.print() << "\n";
                }
            }
        }
    }
    catch (io::bulkio_error& e) {
        return report_error(e.what());
    }
    catch (compiler_exception& e) {
        return report_ice(e.what()+std::string(" @ ")+to_string(e.location()));
    }
    catch (std::exception& e) {
        return report_ice(e.what());
    }
    catch (...) {
        return report_ice("");
    }

    return 0;
}
<|endoftext|>


<commit_before>/*
  Copyright (C) 2005-2012 Steven L. Scott

  This library 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 (at your option) any later version.

  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.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
*/

#include "Models/TimeSeries/ArModel.hpp"
#include <complex>
#include <functional>
#include "LinAlg/Eigen.hpp"
#include "Models/SufstatAbstractCombineImpl.hpp"
#include "cpputil/Polynomial.hpp"
#include "cpputil/report_error.hpp"
#include "distributions.hpp"

namespace BOOM{

  ArSuf::ArSuf(int number_of_lags)
      : reg_suf_(new NeRegSuf(number_of_lags)),
        x_(number_of_lags)
  {}

  ArSuf * ArSuf::clone()const{return new ArSuf(*this);}

  void ArSuf::clear(){
    lags_.clear();
    reg_suf_->clear();
  }

  void ArSuf::Update(const DoubleData &y) {
    double yvalue = y.value();
    if (lags_.size() == reg_suf_->size()) {
      x_.assign(lags_.begin(), lags_.end());
      reg_suf_->add_mixture_data(yvalue, x_, 1.0);
      lags_.push_front(yvalue);
      lags_.pop_back();
    } else if (lags_.size() < reg_suf_->size()) {
      lags_.push_front(yvalue);
    } else {
      report_error("Vector of lags is larger than the AR(p) dimension.");
    }
  }

  void ArSuf::add_mixture_data(double y, const Vector &x, double weight){
    reg_suf_->add_mixture_data(y, x, weight);
  }

  void ArSuf::combine(const Ptr<ArSuf> & s){
    reg_suf_->combine(s->reg_suf_);
  }

  void ArSuf::combine(const ArSuf &s){
    reg_suf_->combine(*s.reg_suf_);
  }

  ArSuf * ArSuf::abstract_combine(Sufstat *s) {
    return abstract_combine_impl<ArSuf>(this, s);
  }

  Vector ArSuf::vectorize(bool minimal)const{
    return reg_suf_->vectorize(minimal);
  }

  Vector::const_iterator ArSuf::unvectorize(Vector::const_iterator &v,
                                         bool minimal){
    return reg_suf_->unvectorize(v, minimal);
  }

  Vector::const_iterator ArSuf::unvectorize(const Vector &v,
                                         bool minimal){
    return reg_suf_->unvectorize(v, minimal);
  }

  ostream & ArSuf::print(ostream &out)const{
    reg_suf_->print(out);
    out << "lags:" << endl;
    for(int i = 0; i < lags_.size(); ++i) {
      out << i+1 << ":  " << lags_[i] << endl;
    }
    return out;
  }

  //======================================================================
  ArModel::ArModel(int number_of_lags)
      : ParamPolicy(new GlmCoefs(Vector(number_of_lags, 0.0),
                                 true),
                    new UnivParams(1.0)),
        DataPolicy(new ArSuf(number_of_lags)),
        filter_coefficients_current_(false)
  {
    Phi_prm()->add_observer([this](){this->observe_phi();});
  }

  ArModel::ArModel(const Ptr<GlmCoefs> &autoregression_coefficients,
                   const Ptr<UnivParams> &innovation_variance)
      : ParamPolicy(autoregression_coefficients, innovation_variance),
        DataPolicy(new ArSuf(autoregression_coefficients->size())),
        filter_coefficients_current_(false)
  {
    bool ok = check_stationary(autoregression_coefficients->value());
    if (!ok) {
      report_error("Attempt to initialize ArModel with an illegal value "
                   "of the autoregression coefficients.");
    }
    Phi_prm()->add_observer([this](){this->observe_phi();});
  }

  ArModel * ArModel::clone()const{return new ArModel(*this);}

  int ArModel::number_of_lags()const{return phi().size();}

  double ArModel::sigma()const{
    return sqrt(Sigsq_prm()->value());
  }

  double ArModel::sigsq()const{
    return Sigsq_prm()->value();
  }

  const Vector &ArModel::phi()const{
    return Phi_prm()->value();
  }

  void ArModel::set_sigma(double sigma){
    Sigsq_prm()->set(sigma * sigma);
  }

  void ArModel::set_sigsq(double sigsq){
    Sigsq_prm()->set(sigsq);
  }

  void ArModel::set_phi(const Vector &phi){
    Phi_prm()->set(phi);
  }

  Ptr<GlmCoefs> ArModel::Phi_prm(){ return prm1(); }
  const Ptr<GlmCoefs> ArModel::Phi_prm()const{ return prm1(); }
  Ptr<UnivParams> ArModel::Sigsq_prm(){ return prm2(); }
  const Ptr<UnivParams> ArModel::Sigsq_prm()const{ return prm2(); }

  const GlmCoefs &ArModel::coef() const { return prm1_ref(); }
  GlmCoefs &ArModel::coef() { return prm1_ref(); }

  bool ArModel::check_stationary(const Vector &phi){
    // The process is stationary if the roots of the polynomial
    //
    // 1 - phi[0]*z - ... - phi[p-1]*z^p.
    //
    // all lie outside the unit circle.  We can do that by explicitly finding
    // and checking the roots, but that's kind of expensive.  Before doing that
    // we can do a quick check to see if the coefficients are within a loose
    // bound.
    //
    // Based on Rouche's theorem:
    // http://en.wikipedia.org/wiki/Properties_of_polynomial_roots#Based_on_the_Rouch.C3.A9_theorem
    // All the roots will be at least 1 in absolute value as long as
    // sum(abs(phi)) < 1.
    if(phi.abs_norm() < 1) return true;

    // If that didn't work then we're stuck finding roots.

    // TODO(stevescott): Really we just need to check the smallest root.  If we
    // had a cheap way of finding just the smallest root then that would be more
    // efficient than finding them all.
    Vector coefficients = concat(1, -1 * phi);

    Polynomial polynomial(coefficients);
    std::vector<std::complex<double> > roots(polynomial.roots());
    for (int i = 0; i < roots.size(); ++i) {
      if (abs(roots[i]) <= 1) return false;
    }
    return true;
  }

  Vector ArModel::autocovariance(int number_of_lags)const{
    set_filter_coefficients();
    Vector ans(number_of_lags + 1);
    for(int lag = 0; lag <= number_of_lags; ++lag){
      int n = filter_coefficients_.size() - lag;
      const ConstVectorView psi(filter_coefficients_, 0, n);
      const ConstVectorView lag_psi(filter_coefficients_, lag, n);
      ans[lag] = psi.dot(lag_psi);
    }
    return ans * sigsq();
  }

  Vector ArModel::simulate(int n, RNG &rng) const {
    int p = number_of_lags();
    Vector acf = autocovariance(p);
    SpdMatrix Sigma(p);
    Sigma.diag() = acf[0];
    for(int i = 1; i < p; ++i) {
      Sigma.subdiag(i) = acf[i];
      Sigma.superdiag(i) = acf[i];
    }
    Vector zero(p, 0.0);
    Vector y0 = rmvn(zero, Sigma);
    return simulate(n, y0, rng);
  }

  Vector ArModel::simulate(int n, const Vector &y0, RNG &rng) const {
    if(y0.size() != number_of_lags()){
      ostringstream err;
      err << "Error in ArModel::simulate." << endl
          << "Initial state value y0 was size " << y0.size()
          << ", but the model has " << number_of_lags() << " lags."
          << endl;
      report_error(err.str());
    }
    const Vector &phi(this->phi());
    std::deque<double> lags(y0.rbegin(), y0.rend());
    Vector ans;
    ans.reserve(n);
    for(int i = 0; i < n; ++i) {
      double mu = 0;
      for(int lag = 0; lag < number_of_lags(); ++lag) {
        mu += phi[lag] * lags[lag];
      }
      double y = rnorm_mt(rng, mu, sigma());
      lags.push_front(y);
      lags.pop_back();
      ans.push_back(y);
    }
    return ans;
  }

  // Determine the MA filter coefficients from the AR coefficients by
  // equating coefficients in the polynomial phi(z)*psi(z) = 1.
  // phi(z) = 1 - phi_1 z - phi_2 z^2 - ... - phi_p z^p.  This implies
  // that psi[0] = 1.  The coefficient of z^n is
  //
  // psi[n] - psi[n-1]*phi_1 - psi[n-2]*phi_2 - ... = 0
  // implying
  // psi[n] = psi[n-1]*phi_1 + ...
  //
  // The preceding math is unit-offset for phi, but zero-offset for
  // psi.
  void ArModel::set_filter_coefficients()const{
    if (filter_coefficients_current_) return;
    const Vector &phi(this->phi());
    int p = phi.size();

    filter_coefficients_.resize(2);
    filter_coefficients_[0] = 1.0;
    if(phi.empty()) return;
    filter_coefficients_[1] = phi[0];
    bool done = false;

    for(int n = 2; ; ++n){
      if (n <= phi.size()) {
        ConstVectorView phi_view(phi, 0, n);
        ConstVectorView psi(filter_coefficients_, 0, n);
        double value = phi_view.dot(psi.reverse());
        filter_coefficients_.push_back(value);
      } else {
        ConstVectorView psi(filter_coefficients_, n-p, p);
        double value = phi.dot(psi.reverse());
        filter_coefficients_.push_back(value);
        ConstVectorView psi_tail(filter_coefficients_, n-p, p);
        // You're done when the last p elements of the vector are all
        // small.
        done = psi_tail.abs_norm() < 1e-6;
      }
      if(done) break;
    }
    filter_coefficients_current_ = true;
  }

}
<commit_msg>Removed unnecessary dependency on Eigen.hpp<commit_after>/*
  Copyright (C) 2005-2012 Steven L. Scott

  This library 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 (at your option) any later version.

  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.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
*/

#include "Models/TimeSeries/ArModel.hpp"
#include <complex>
#include <functional>
#include "Models/SufstatAbstractCombineImpl.hpp"
#include "cpputil/Polynomial.hpp"
#include "cpputil/report_error.hpp"
#include "distributions.hpp"

namespace BOOM{

  ArSuf::ArSuf(int number_of_lags)
      : reg_suf_(new NeRegSuf(number_of_lags)),
        x_(number_of_lags)
  {}

  ArSuf * ArSuf::clone()const{return new ArSuf(*this);}

  void ArSuf::clear(){
    lags_.clear();
    reg_suf_->clear();
  }

  void ArSuf::Update(const DoubleData &y) {
    double yvalue = y.value();
    if (lags_.size() == reg_suf_->size()) {
      x_.assign(lags_.begin(), lags_.end());
      reg_suf_->add_mixture_data(yvalue, x_, 1.0);
      lags_.push_front(yvalue);
      lags_.pop_back();
    } else if (lags_.size() < reg_suf_->size()) {
      lags_.push_front(yvalue);
    } else {
      report_error("Vector of lags is larger than the AR(p) dimension.");
    }
  }

  void ArSuf::add_mixture_data(double y, const Vector &x, double weight){
    reg_suf_->add_mixture_data(y, x, weight);
  }

  void ArSuf::combine(const Ptr<ArSuf> & s){
    reg_suf_->combine(s->reg_suf_);
  }

  void ArSuf::combine(const ArSuf &s){
    reg_suf_->combine(*s.reg_suf_);
  }

  ArSuf * ArSuf::abstract_combine(Sufstat *s) {
    return abstract_combine_impl<ArSuf>(this, s);
  }

  Vector ArSuf::vectorize(bool minimal)const{
    return reg_suf_->vectorize(minimal);
  }

  Vector::const_iterator ArSuf::unvectorize(Vector::const_iterator &v,
                                         bool minimal){
    return reg_suf_->unvectorize(v, minimal);
  }

  Vector::const_iterator ArSuf::unvectorize(const Vector &v,
                                         bool minimal){
    return reg_suf_->unvectorize(v, minimal);
  }

  ostream & ArSuf::print(ostream &out)const{
    reg_suf_->print(out);
    out << "lags:" << endl;
    for(int i = 0; i < lags_.size(); ++i) {
      out << i+1 << ":  " << lags_[i] << endl;
    }
    return out;
  }

  //======================================================================
  ArModel::ArModel(int number_of_lags)
      : ParamPolicy(new GlmCoefs(Vector(number_of_lags, 0.0),
                                 true),
                    new UnivParams(1.0)),
        DataPolicy(new ArSuf(number_of_lags)),
        filter_coefficients_current_(false)
  {
    Phi_prm()->add_observer([this](){this->observe_phi();});
  }

  ArModel::ArModel(const Ptr<GlmCoefs> &autoregression_coefficients,
                   const Ptr<UnivParams> &innovation_variance)
      : ParamPolicy(autoregression_coefficients, innovation_variance),
        DataPolicy(new ArSuf(autoregression_coefficients->size())),
        filter_coefficients_current_(false)
  {
    bool ok = check_stationary(autoregression_coefficients->value());
    if (!ok) {
      report_error("Attempt to initialize ArModel with an illegal value "
                   "of the autoregression coefficients.");
    }
    Phi_prm()->add_observer([this](){this->observe_phi();});
  }

  ArModel * ArModel::clone()const{return new ArModel(*this);}

  int ArModel::number_of_lags()const{return phi().size();}

  double ArModel::sigma()const{
    return sqrt(Sigsq_prm()->value());
  }

  double ArModel::sigsq()const{
    return Sigsq_prm()->value();
  }

  const Vector &ArModel::phi()const{
    return Phi_prm()->value();
  }

  void ArModel::set_sigma(double sigma){
    Sigsq_prm()->set(sigma * sigma);
  }

  void ArModel::set_sigsq(double sigsq){
    Sigsq_prm()->set(sigsq);
  }

  void ArModel::set_phi(const Vector &phi){
    Phi_prm()->set(phi);
  }

  Ptr<GlmCoefs> ArModel::Phi_prm(){ return prm1(); }
  const Ptr<GlmCoefs> ArModel::Phi_prm()const{ return prm1(); }
  Ptr<UnivParams> ArModel::Sigsq_prm(){ return prm2(); }
  const Ptr<UnivParams> ArModel::Sigsq_prm()const{ return prm2(); }

  const GlmCoefs &ArModel::coef() const { return prm1_ref(); }
  GlmCoefs &ArModel::coef() { return prm1_ref(); }

  bool ArModel::check_stationary(const Vector &phi){
    // The process is stationary if the roots of the polynomial
    //
    // 1 - phi[0]*z - ... - phi[p-1]*z^p.
    //
    // all lie outside the unit circle.  We can do that by explicitly finding
    // and checking the roots, but that's kind of expensive.  Before doing that
    // we can do a quick check to see if the coefficients are within a loose
    // bound.
    //
    // Based on Rouche's theorem:
    // http://en.wikipedia.org/wiki/Properties_of_polynomial_roots#Based_on_the_Rouch.C3.A9_theorem
    // All the roots will be at least 1 in absolute value as long as
    // sum(abs(phi)) < 1.
    if(phi.abs_norm() < 1) return true;

    // If that didn't work then we're stuck finding roots.

    // TODO(stevescott): Really we just need to check the smallest root.  If we
    // had a cheap way of finding just the smallest root then that would be more
    // efficient than finding them all.
    Vector coefficients = concat(1, -1 * phi);

    Polynomial polynomial(coefficients);
    std::vector<std::complex<double> > roots(polynomial.roots());
    for (int i = 0; i < roots.size(); ++i) {
      if (abs(roots[i]) <= 1) return false;
    }
    return true;
  }

  Vector ArModel::autocovariance(int number_of_lags)const{
    set_filter_coefficients();
    Vector ans(number_of_lags + 1);
    for(int lag = 0; lag <= number_of_lags; ++lag){
      int n = filter_coefficients_.size() - lag;
      const ConstVectorView psi(filter_coefficients_, 0, n);
      const ConstVectorView lag_psi(filter_coefficients_, lag, n);
      ans[lag] = psi.dot(lag_psi);
    }
    return ans * sigsq();
  }

  Vector ArModel::simulate(int n, RNG &rng) const {
    int p = number_of_lags();
    Vector acf = autocovariance(p);
    SpdMatrix Sigma(p);
    Sigma.diag() = acf[0];
    for(int i = 1; i < p; ++i) {
      Sigma.subdiag(i) = acf[i];
      Sigma.superdiag(i) = acf[i];
    }
    Vector zero(p, 0.0);
    Vector y0 = rmvn(zero, Sigma);
    return simulate(n, y0, rng);
  }

  Vector ArModel::simulate(int n, const Vector &y0, RNG &rng) const {
    if(y0.size() != number_of_lags()){
      ostringstream err;
      err << "Error in ArModel::simulate." << endl
          << "Initial state value y0 was size " << y0.size()
          << ", but the model has " << number_of_lags() << " lags."
          << endl;
      report_error(err.str());
    }
    const Vector &phi(this->phi());
    std::deque<double> lags(y0.rbegin(), y0.rend());
    Vector ans;
    ans.reserve(n);
    for(int i = 0; i < n; ++i) {
      double mu = 0;
      for(int lag = 0; lag < number_of_lags(); ++lag) {
        mu += phi[lag] * lags[lag];
      }
      double y = rnorm_mt(rng, mu, sigma());
      lags.push_front(y);
      lags.pop_back();
      ans.push_back(y);
    }
    return ans;
  }

  // Determine the MA filter coefficients from the AR coefficients by
  // equating coefficients in the polynomial phi(z)*psi(z) = 1.
  // phi(z) = 1 - phi_1 z - phi_2 z^2 - ... - phi_p z^p.  This implies
  // that psi[0] = 1.  The coefficient of z^n is
  //
  // psi[n] - psi[n-1]*phi_1 - psi[n-2]*phi_2 - ... = 0
  // implying
  // psi[n] = psi[n-1]*phi_1 + ...
  //
  // The preceding math is unit-offset for phi, but zero-offset for
  // psi.
  void ArModel::set_filter_coefficients()const{
    if (filter_coefficients_current_) return;
    const Vector &phi(this->phi());
    int p = phi.size();

    filter_coefficients_.resize(2);
    filter_coefficients_[0] = 1.0;
    if(phi.empty()) return;
    filter_coefficients_[1] = phi[0];
    bool done = false;

    for(int n = 2; ; ++n){
      if (n <= phi.size()) {
        ConstVectorView phi_view(phi, 0, n);
        ConstVectorView psi(filter_coefficients_, 0, n);
        double value = phi_view.dot(psi.reverse());
        filter_coefficients_.push_back(value);
      } else {
        ConstVectorView psi(filter_coefficients_, n-p, p);
        double value = phi.dot(psi.reverse());
        filter_coefficients_.push_back(value);
        ConstVectorView psi_tail(filter_coefficients_, n-p, p);
        // You're done when the last p elements of the vector are all
        // small.
        done = psi_tail.abs_norm() < 1e-6;
      }
      if(done) break;
    }
    filter_coefficients_current_ = true;
  }

}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "config.h"
#include "NetworkStateNotifier.h"

namespace WebCore {

// Chromium doesn't currently support network state notifications. This causes
// an extra DLL to get loaded into the renderer which can slow things down a
// bit. We may want an alternate design.

void NetworkStateNotifier::updateState()
{
}

// TODO(darin): Kill this once we stop defining PLATFORM(MAC)
#if PLATFORM(MAC)
void NetworkStateNotifier::networkStateChangeTimerFired(Timer<NetworkStateNotifier>*)
{
}
#endif

#if PLATFORM(OS_WIN) || PLATFORM(MAC)
NetworkStateNotifier::NetworkStateNotifier()
    : m_isOnLine(true)
#if PLATFORM(MAC)
    , m_networkStateChangeTimer(this, &NetworkStateNotifier::networkStateChangeTimerFired)
#endif
{
}
#endif

}
<commit_msg>fix build take 2<commit_after>/*
 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "config.h"
#include "NetworkStateNotifier.h"

namespace WebCore {

// Chromium doesn't currently support network state notifications. This causes
// an extra DLL to get loaded into the renderer which can slow things down a
// bit. We may want an alternate design.

void NetworkStateNotifier::updateState()
{
}

// TODO(darin): Kill this once we stop defining PLATFORM(MAC)
#if PLATFORM(MAC)
void NetworkStateNotifier::networkStateChangeTimerFired(Timer<NetworkStateNotifier>*)
{
}
#endif

#if PLATFORM(WIN_OS) || PLATFORM(MAC)
NetworkStateNotifier::NetworkStateNotifier()
    : m_isOnLine(true)
#if PLATFORM(MAC)
    , m_networkStateChangeTimer(this, &NetworkStateNotifier::networkStateChangeTimerFired)
#endif
{
}
#endif

}
<|endoftext|>


<commit_before>#line 2 "togo/memory.hpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file memory.hpp
@brief Memory interface.
@ingroup memory
*/

#pragma once

#include <togo/config.hpp>
#include <togo/types.hpp>
#include <togo/memory_types.hpp>

#include <type_traits>
#include <new>
#include <cstdlib>

namespace togo {

/**
	@addtogroup memory
	@{
*/

namespace {
	template<class T>
	using pointer_type = typename std::remove_const<
		typename std::remove_pointer<T>::type
	>::type;
}

/// Construct an object with an allocator.
#define TOGO_CONSTRUCT(a, T, ...) \
	(new ((a).allocate(sizeof(T), alignof(T))) T(__VA_ARGS__))

/// Construct an object with an allocator and no alignment.
#define TOGO_CONSTRUCT_NA(a, T, ...) \
	(new ((a).allocate(sizeof(T), 0)) T(__VA_ARGS__))

/// Construct an object with an allocator and no initialization parameters.
/// This calls the default constructor.
#define TOGO_CONSTRUCT_DEFAULT(a, T) \
	(new ((a).allocate(sizeof(T), alignof(T))) T())

/// Construct an object with an allocator, no initialization parameters, and no alignment.
/// This calls the default constructor.
#define TOGO_CONSTRUCT_DEFAULT_NA(a, T) \
	(new ((a).allocate(sizeof(T), 0)) T())

/// Destroy an object with an allocator.
/// Does nothing if p is nullptr. Calls destructor p->~T(); and
/// deallocates the object.
// Oh C++.
#define TOGO_DESTROY(a, p) \
	do { if (p) { \
		(p)->~pointer_type<decltype(p)>(); (a).deallocate(p); \
	} } while (false)

/**
	%Allocator base class.
*/
class Allocator {
public:
	static constexpr u32 const
	/// Default allocation alignment.
	DEFAULT_ALIGNMENT = 4,
	/// Size value returned by unsupported operations.
	SIZE_NOT_TRACKED = static_cast<u32>(-1);

	Allocator() = default;
	Allocator(Allocator&&) = default;
	Allocator& operator=(Allocator&&) = default;

	Allocator(Allocator const&) = delete;
	Allocator& operator=(Allocator const&) = delete;

	/// Allocators should assert that they have no active allocations
	/// in the destructor.
	virtual ~Allocator() = 0;

	/// Get number of active allocations.
	virtual u32 num_allocations() const = 0;

	/// Get total number of bytes allocated by the allocator.
	/// If an allocator does not support this operation, it shall
	/// return SIZE_NOT_TRACKED.
	virtual u32 total_size() const = 0;

	/// Get size of block allocated for p.
	///
	/// This may be greater than the actual size of the object type
	/// due to internal state and alignment. If an allocator does not
	/// support this operation, it shall return SIZE_NOT_TRACKED.
	virtual u32 allocation_size(void const* p) const = 0;

	/// Allocate a chunk of memory.
	/// If align is 0, no alignment is used.
	virtual void* allocate(u32 size, u32 align = DEFAULT_ALIGNMENT) = 0;

	/// Deallocate a pointer.
	/// Does nothing if p is nullptr.
	virtual void deallocate(void* p) = 0;
};
inline Allocator::~Allocator() = default;

/** @} */ // end of doc-group memory

namespace memory {

/**
	@addtogroup memory
	@{
*/

static constexpr u32 const
	/// Minimum scratch size (8K).
	SCRATCH_SIZE_MINIMUM = 8 * 1024,
	/// Default scratch size (4MB).
	SCRATCH_SIZE_DEFAULT = 4 * 1024 * 1024
;

/// Initialize global allocators.
/// scratch_size is size of the scratch space block to pre-allocate.
/// If scratch_size < SCRATCH_SIZE_MINIMUM, an assertion will trigger.
void init(u32 const scratch_size = SCRATCH_SIZE_MINIMUM);

/// Shutdown allocators created by init().
void shutdown();

/// Get the default allocator.
///
/// This is a thread-safe growing heap allocator.
Allocator& default_allocator();

/// Get the scratch allocator.
///
/// This is a thread-safe allocator.
/// This should *only* be used for temporary memory. It uses a ring
/// buffer for allocations, backed by a block of memory from the
/// default allocator.
Allocator& scratch_allocator();

/** @} */ // end of doc-group memory

} // namespace memory

} // namespace togo
<commit_msg>memory: doc tidy.<commit_after>#line 2 "togo/memory.hpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file memory.hpp
@brief Memory interface.
@ingroup memory
*/

#pragma once

#include <togo/config.hpp>
#include <togo/types.hpp>
#include <togo/memory_types.hpp>

#include <type_traits>
#include <new>
#include <cstdlib>

namespace togo {

/**
	@addtogroup memory
	@{
*/

namespace {
	template<class T>
	using pointer_type = typename std::remove_const<
		typename std::remove_pointer<T>::type
	>::type;
}

/// Construct an object with an allocator.
#define TOGO_CONSTRUCT(a, T, ...) \
	(new ((a).allocate(sizeof(T), alignof(T))) T(__VA_ARGS__))

/// Construct an object with an allocator and no alignment.
#define TOGO_CONSTRUCT_NA(a, T, ...) \
	(new ((a).allocate(sizeof(T), 0)) T(__VA_ARGS__))

/// Construct an object with an allocator and no initialization parameters.
/// This calls the default constructor.
#define TOGO_CONSTRUCT_DEFAULT(a, T) \
	(new ((a).allocate(sizeof(T), alignof(T))) T())

/// Construct an object with an allocator, no initialization parameters,
/// and no alignment.
///
/// This calls the default constructor.
#define TOGO_CONSTRUCT_DEFAULT_NA(a, T) \
	(new ((a).allocate(sizeof(T), 0)) T())

/// Destroy an object with an allocator.
///
/// Does nothing if p is nullptr. Calls destructor p->~T(); and
/// deallocates the object.
// Oh C++.
#define TOGO_DESTROY(a, p) \
	do { if (p) { \
		(p)->~pointer_type<decltype(p)>(); (a).deallocate(p); \
	} } while (false)

/**
	%Allocator base class.
*/
class Allocator {
public:
	static constexpr u32 const
	/// Default allocation alignment.
	DEFAULT_ALIGNMENT = 4,
	/// Size value returned by unsupported operations.
	SIZE_NOT_TRACKED = static_cast<u32>(-1);

	Allocator() = default;
	Allocator(Allocator&&) = default;
	Allocator& operator=(Allocator&&) = default;

	Allocator(Allocator const&) = delete;
	Allocator& operator=(Allocator const&) = delete;

	/// Allocators should assert that they have no active allocations
	/// in the destructor.
	virtual ~Allocator() = 0;

	/// Get number of active allocations.
	virtual u32 num_allocations() const = 0;

	/// Get total number of bytes allocated by the allocator.
	///
	/// If an allocator does not support this operation, it shall
	/// return SIZE_NOT_TRACKED.
	virtual u32 total_size() const = 0;

	/// Get size of block allocated for p.
	///
	/// This may be greater than the actual size of the object type
	/// due to internal state and alignment. If an allocator does not
	/// support this operation, it shall return SIZE_NOT_TRACKED.
	virtual u32 allocation_size(void const* p) const = 0;

	/// Allocate a chunk of memory.
	///
	/// If align is 0, no alignment is used.
	virtual void* allocate(u32 size, u32 align = DEFAULT_ALIGNMENT) = 0;

	/// Deallocate a pointer.
	///
	/// Does nothing if p is nullptr.
	virtual void deallocate(void* p) = 0;
};
inline Allocator::~Allocator() = default;

/** @} */ // end of doc-group memory

namespace memory {

/**
	@addtogroup memory
	@{
*/

static constexpr u32 const
	/// Minimum scratch size (8K).
	SCRATCH_SIZE_MINIMUM = 8 * 1024,
	/// Default scratch size (4MB).
	SCRATCH_SIZE_DEFAULT = 4 * 1024 * 1024
;

/// Initialize global allocators.
///
/// scratch_size is size of the scratch space block to pre-allocate.
/// If scratch_size < SCRATCH_SIZE_MINIMUM, an assertion will trigger.
void init(u32 const scratch_size = SCRATCH_SIZE_MINIMUM);

/// Shutdown allocators created by init().
void shutdown();

/// Get the default allocator.
///
/// This is a thread-safe growing heap allocator.
Allocator& default_allocator();

/// Get the scratch allocator.
///
/// This is a thread-safe allocator.
/// This should *only* be used for temporary memory. It uses a ring
/// buffer for allocations, backed by a block of memory from the
/// default allocator.
Allocator& scratch_allocator();

/** @} */ // end of doc-group memory

} // namespace memory

} // namespace togo
<|endoftext|>