<commit_before>// reimplementation of kerninhanlin in
// https://github.com/bjoern-andres/graph

#pragma once
#ifndef NIFTY_GRAPH_OPTIMIZATION_LIFTED_MULTICUT_LIFTED_MULTICUT_ANDRES_KERNIGHAN_LIN_HXX
#define NIFTY_GRAPH_OPTIMIZATION_LIFTED_MULTICUT_LIFTED_MULTICUT_ANDRES_KERNIGHAN_LIN_HXX

#include <iomanip>
#include <algorithm>
#include <unordered_set>
#include <vector>
#include <stack>

#include "vigra/priority_queue.hxx"

#include "nifty/tools/runtime_check.hxx"
#include "nifty/ufd/ufd.hxx"
#include "nifty/graph/detail/adjacency.hxx"
#include "nifty/graph/optimization/lifted_multicut/lifted_multicut_base.hxx"
#include "nifty/graph/edge_contraction_graph.hxx"
#include "nifty/graph/components.hxx"

#include "andres/graph/graph.hxx"
#include "andres/graph/multicut-lifted/kernighan-lin.hxx"

namespace nifty{
namespace graph{
namespace lifted_multicut{

    template<class OBJECTIVE>
    class LiftedMulticutAndresKernighanLin : public LiftedMulticutBase<OBJECTIVE>
    {
    public:

        typedef OBJECTIVE ObjectiveType;
        typedef LiftedMulticutBase<ObjectiveType> BaseType;
        typedef typename ObjectiveType::GraphType GraphType;
        typedef typename ObjectiveType::LiftedGraphType LiftedGraphType;

        typedef typename BaseType::VisitorBase VisitorBase;
        typedef typename BaseType::VisitorProxy VisitorProxy;
        typedef typename BaseType::NodeLabels NodeLabels;

    private:

    public:

        typedef andres::graph::multicut_lifted::KernighanLinSettings Settings;

        virtual ~LiftedMulticutAndresKernighanLin(){}
        LiftedMulticutAndresKernighanLin(const ObjectiveType & objective, const Settings & settings = Settings());
        virtual void optimize(NodeLabels & nodeLabels, VisitorBase * visitor);
        virtual const ObjectiveType & objective() const;

        virtual const NodeLabels & currentBestNodeLabels( ){
            return *currentBest_;
        }

        virtual std::string name()const{
            return std::string("LiftedMulticutAndresKernighanLin");
        }

    private:

        const ObjectiveType & objective_;
        Settings settings_;
        const GraphType & graph_;
        const LiftedGraphType & liftedGraph_;
        NodeLabels * currentBest_;

        andres::graph::Graph<> aGraph_;
        andres::graph::Graph<> aLiftedGraph_;
        std::vector<double> edgeCosts_;
    };

    template<class OBJECTIVE>
    LiftedMulticutAndresKernighanLin<OBJECTIVE>::
    LiftedMulticutAndresKernighanLin(
        const ObjectiveType & objective,
        const Settings & settings
    )
    :   objective_(objective),
        settings_(settings),
        graph_(objective.graph()),
        liftedGraph_(objective.liftedGraph()),
        currentBest_(nullptr),
        aGraph_(objective.graph().nodeIdUpperBound()+1),
        aLiftedGraph_(objective.graph().nodeIdUpperBound()+1),
        edgeCosts_(objective.liftedGraph().numberOfEdges(),0)
    {
        for(const auto edge : graph_.edges()){
            const auto uv = graph_.uv(edge);
            aGraph_.insertEdge(uv.first, uv.second);
        }

        auto c = 0;
        for(const auto edge : liftedGraph_.edges()){
            const auto uv = liftedGraph_.uv(edge);
            aLiftedGraph_.insertEdge(uv.first, uv.second);
            edgeCosts_[c] = objective_.weights()[edge];
            ++c;
        }
    }

    template<class OBJECTIVE>
    void LiftedMulticutAndresKernighanLin<OBJECTIVE>::
    optimize(
        NodeLabels & nodeLabels,  VisitorBase * visitor
    ){

        currentBest_ = &nodeLabels;

        VisitorProxy visitorProxy(visitor);
        //visitorProxy.addLogNames({"violatedCycleConstraints","violatedCutConstraints"});
        visitorProxy.begin(this);

        typedef std::vector<uint8_t> ELA;

        std::vector<uint8_t> ioLabels(aLiftedGraph_.numberOfEdges());

        std::vector<std::size_t> edegInALiftedGraph(aGraph_.numberOfEdges());

        for (std::size_t i = 0; i < aGraph_.numberOfEdges(); ++i){
            const auto v0 = aGraph_.vertexOfEdge(i, 0);
            const auto v1 = aGraph_.vertexOfEdge(i, 1);
            edegInALiftedGraph[i] = aLiftedGraph_.findEdge(v0, v1).second;
        }

        for (std::size_t i = 0; i < aLiftedGraph_.numberOfEdges(); ++i){
            const auto v0 = aLiftedGraph_.vertexOfEdge(i, 0);
            const auto v1 = aLiftedGraph_.vertexOfEdge(i, 1);
            ioLabels[i] = nodeLabels[v0] != nodeLabels[v1] ? 1 : 0;
        }

        settings_.verbose = false;

        andres::graph::multicut_lifted::kernighanLin(
            aGraph_,
            aLiftedGraph_,
            edgeCosts_,
            ioLabels,
            ioLabels,
            settings_
        );

        struct SubgraphWithCut { // a subgraph with cut mask
            SubgraphWithCut(const ELA& labels, std::vector<std::size_t> const& edegInALiftedGraph)
                : labels_(labels), edegInALiftedGraph_(edegInALiftedGraph)
                {}
            bool vertex(const std::size_t v) const
                { return true; }
            bool edge(const std::size_t e) const
                { return labels_[edegInALiftedGraph_[e]] == 0; }

            std::vector<std::size_t> const& edegInALiftedGraph_;
            const ELA& labels_;
        };

        // build decomposition based on the current multicut
        andres::graph::ComponentsByPartition<andres::graph::Graph<> > components;
        components.build(aGraph_, SubgraphWithCut(ioLabels, edegInALiftedGraph));

        for(const auto node : graph_.nodes()){
            nodeLabels[node] = components.partition_.find(node);
        }

        visitorProxy.end(this);
    }

    template<class OBJECTIVE>
    const typename LiftedMulticutAndresKernighanLin<OBJECTIVE>::ObjectiveType &
    LiftedMulticutAndresKernighanLin<OBJECTIVE>::
    objective()const{
        return objective_;
    }

} // lifted_multicut
} // namespace nifty::graph
} // namespace nifty

#endif  // NIFTY_GRAPH_OPTIMIZATION_LIFTED_MULTICUT_LIFTED_MULTICUT_ANDRES_KERNIGHAN_LIN_HXX
<commit_msg>fixed minor bug<commit_after>// reimplementation of kerninhanlin in
// https://github.com/bjoern-andres/graph

#pragma once
#ifndef NIFTY_GRAPH_OPTIMIZATION_LIFTED_MULTICUT_LIFTED_MULTICUT_ANDRES_KERNIGHAN_LIN_HXX
#define NIFTY_GRAPH_OPTIMIZATION_LIFTED_MULTICUT_LIFTED_MULTICUT_ANDRES_KERNIGHAN_LIN_HXX

#include <iomanip>
#include <algorithm>
#include <unordered_set>
#include <vector>
#include <stack>

#include "vigra/priority_queue.hxx"

#include "nifty/tools/runtime_check.hxx"
#include "nifty/ufd/ufd.hxx"
#include "nifty/graph/detail/adjacency.hxx"
#include "nifty/graph/optimization/lifted_multicut/lifted_multicut_base.hxx"
#include "nifty/graph/edge_contraction_graph.hxx"
#include "nifty/graph/components.hxx"

#include "andres/graph/graph.hxx"
#include "andres/graph/multicut-lifted/kernighan-lin.hxx"

namespace nifty{
namespace graph{
namespace lifted_multicut{

    template<class OBJECTIVE>
    class LiftedMulticutAndresKernighanLin : public LiftedMulticutBase<OBJECTIVE>
    {
    public:

        typedef OBJECTIVE ObjectiveType;
        typedef LiftedMulticutBase<ObjectiveType> BaseType;
        typedef typename ObjectiveType::GraphType GraphType;
        typedef typename ObjectiveType::LiftedGraphType LiftedGraphType;

        typedef typename BaseType::VisitorBase VisitorBase;
        typedef typename BaseType::VisitorProxy VisitorProxy;
        typedef typename BaseType::NodeLabels NodeLabels;

    private:

    public:

        struct Settings {
            std::size_t numberOfInnerIterations { std::numeric_limits<std::size_t>::max() };
            std::size_t numberOfOuterIterations { 100 };
            double epsilon { 1e-7 };
        };

        virtual ~LiftedMulticutAndresKernighanLin(){}
        LiftedMulticutAndresKernighanLin(const ObjectiveType & objective, const Settings & settings = Settings());
        virtual void optimize(NodeLabels & nodeLabels, VisitorBase * visitor);
        virtual const ObjectiveType & objective() const;

        virtual const NodeLabels & currentBestNodeLabels( ){
            return *currentBest_;
        }

        virtual std::string name()const{
            return std::string("LiftedMulticutAndresKernighanLin");
        }

    private:

        const ObjectiveType & objective_;
        Settings settings_;
        const GraphType & graph_;
        const LiftedGraphType & liftedGraph_;
        NodeLabels * currentBest_;

        andres::graph::Graph<> aGraph_;
        andres::graph::Graph<> aLiftedGraph_;
        std::vector<double> edgeCosts_;
    };

    template<class OBJECTIVE>
    LiftedMulticutAndresKernighanLin<OBJECTIVE>::
    LiftedMulticutAndresKernighanLin(
        const ObjectiveType & objective,
        const Settings & settings
    )
    :   objective_(objective),
        settings_(settings),
        graph_(objective.graph()),
        liftedGraph_(objective.liftedGraph()),
        currentBest_(nullptr),
        aGraph_(objective.graph().nodeIdUpperBound()+1),
        aLiftedGraph_(objective.graph().nodeIdUpperBound()+1),
        edgeCosts_(objective.liftedGraph().numberOfEdges(),0)
    {
        for(const auto edge : graph_.edges()){
            const auto uv = graph_.uv(edge);
            aGraph_.insertEdge(uv.first, uv.second);
        }

        auto c = 0;
        for(const auto edge : liftedGraph_.edges()){
            const auto uv = liftedGraph_.uv(edge);
            aLiftedGraph_.insertEdge(uv.first, uv.second);
            edgeCosts_[c] = objective_.weights()[edge];
            ++c;
        }
    }

    template<class OBJECTIVE>
    void LiftedMulticutAndresKernighanLin<OBJECTIVE>::
    optimize(
        NodeLabels & nodeLabels,  VisitorBase * visitor
    ){

        currentBest_ = &nodeLabels;

        VisitorProxy visitorProxy(visitor);
        //visitorProxy.addLogNames({"violatedCycleConstraints","violatedCutConstraints"});
        visitorProxy.begin(this);

        typedef std::vector<uint8_t> ELA;

        std::vector<uint8_t> ioLabels(aLiftedGraph_.numberOfEdges());

        std::vector<std::size_t> edegInALiftedGraph(aGraph_.numberOfEdges());

        for (std::size_t i = 0; i < aGraph_.numberOfEdges(); ++i){
            const auto v0 = aGraph_.vertexOfEdge(i, 0);
            const auto v1 = aGraph_.vertexOfEdge(i, 1);
            edegInALiftedGraph[i] = aLiftedGraph_.findEdge(v0, v1).second;
        }

        for (std::size_t i = 0; i < aLiftedGraph_.numberOfEdges(); ++i){
            const auto v0 = aLiftedGraph_.vertexOfEdge(i, 0);
            const auto v1 = aLiftedGraph_.vertexOfEdge(i, 1);
            ioLabels[i] = nodeLabels[v0] != nodeLabels[v1] ? 1 : 0;
        }

        andres::graph::multicut_lifted::KernighanLinSettings klSettings_;
        klSettings_.numberOfInnerIterations = settings_.numberOfInnerIterations;
        klSettings_.numberOfOuterIterations = settings_.numberOfOuterIterations;
        klSettings_.epsilon = settings_.epsilon;
        klSettings_.verbose = false;

        andres::graph::multicut_lifted::kernighanLin(
            aGraph_,
            aLiftedGraph_,
            edgeCosts_,
            ioLabels,
            ioLabels,
            klSettings_
        );

        struct SubgraphWithCut { // a subgraph with cut mask
            SubgraphWithCut(const ELA& labels, std::vector<std::size_t> const& edegInALiftedGraph)
                : labels_(labels), edegInALiftedGraph_(edegInALiftedGraph)
                {}
            bool vertex(const std::size_t v) const
                { return true; }
            bool edge(const std::size_t e) const
                { return labels_[edegInALiftedGraph_[e]] == 0; }

            std::vector<std::size_t> const& edegInALiftedGraph_;
            const ELA& labels_;
        };

        // build decomposition based on the current multicut
        andres::graph::ComponentsByPartition<andres::graph::Graph<> > components;
        components.build(aGraph_, SubgraphWithCut(ioLabels, edegInALiftedGraph));

        for(const auto node : graph_.nodes()){
            nodeLabels[node] = components.partition_.find(node);
        }

        visitorProxy.end(this);
    }

    template<class OBJECTIVE>
    const typename LiftedMulticutAndresKernighanLin<OBJECTIVE>::ObjectiveType &
    LiftedMulticutAndresKernighanLin<OBJECTIVE>::
    objective()const{
        return objective_;
    }

} // lifted_multicut
} // namespace nifty::graph
} // namespace nifty

#endif  // NIFTY_GRAPH_OPTIMIZATION_LIFTED_MULTICUT_LIFTED_MULTICUT_ANDRES_KERNIGHAN_LIN_HXX
<|endoftext|>


<commit_before>///
/// @file  S2LoadBalancer.cpp
/// @brief The S2LoadBalancer evenly distributes the work load between
///        the threads in the computation of the special leaves.
///
/// Simply parallelizing the computation of the special leaves in the
/// Lagarias-Miller-Odlyzko and Deleglise-Rivat algorithms by
/// subdividing the sieve interval by the number of threads into
/// equally sized subintervals does not scale because the distribution
/// of the special leaves is highly skewed and most special leaves are
/// in the first few segments whereas later on there are very few
/// special leaves.
///
/// Based on the above observations it is clear that we need some kind
/// of load balancing in order to scale our parallel algorithm for
/// computing special leaves. Below are the ideas I used to develop a
/// load balancing algorithm that achieves a high load balance by
/// dynamically increasing or decreasing the interval size based on
/// the relative standard deviation of the thread run-times.
///
/// 1) Start with a tiny segment size of x^(1/3) / (log x * log log x)
///    and one segment per thread. Our algorithm uses equally sized
///    intervals, for each thread the interval_size is
///    segment_size * segments_per_thread and the threads process
///    adjacent intervals i.e.
///    [base + interval_size * thread_id, base + interval_size * (thread_id + 1)].
///
/// 2) If the relative standard deviation of the thread run-times is
///    large then we know the special leaves are distributed unevenly,
///    else if the relative standard deviation is low the special
///    leaves are more evenly distributed.
///
/// 3) If the special leaves are distributed unevenly then we can
///    increase the load balance by decreasing the interval_size.
///    Contrary if the special leaves are more evenly distributed
///    we can increase the interval_size in order to improve the
///    algorithm's efficiency.
///
/// 4) We can't use a static threshold for as to when the relative
///    standard deviation is low or large as this threshold varies for
///    different PC architectures. So instead we compare the current
///    relative standard deviation to the previous one in order to
///    decide whether to increase or decrease the interval_size.
///
/// Copyright (C) 2016 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <S2LoadBalancer.hpp>
#include <primecount-internal.hpp>
#include <aligned_vector.hpp>
#include <pmath.hpp>
#include <int128.hpp>

#include <stdint.h>
#include <algorithm>
#include <cmath>

using namespace std;
using namespace primecount;

namespace {

double get_average(aligned_vector<double>& timings)
{
  size_t n = timings.size();
  double sum = 0;

  for (size_t i = 0; i < n; i++)
    sum += timings[i];

  return sum / n;
}

double relative_standard_deviation(aligned_vector<double>& timings)
{
  size_t n = timings.size();
  double average = get_average(timings);
  double sum = 0;

  if (average == 0)
    return 0;

  for (size_t i = 0; i < n; i++)
  {
    double mean = timings[i] - average;
    sum += mean * mean;
  }

  double std_dev = sqrt(sum / max(1.0, n - 1.0));
  double rsd = 100 * std_dev / average;

  return rsd;
}

} // namespace

namespace primecount {

S2LoadBalancer::S2LoadBalancer(maxint_t x,
                               int64_t y,
                               int64_t z,
                               int64_t threads) :
  x_((double) x),
  y_((double) y),
  z_((double) z),
  rsd_(40),
  avg_seconds_(0),
  count_(0),
  sqrtz_(isqrt(z))
{
  init(threads);
}

S2LoadBalancer::S2LoadBalancer(maxint_t x,
                               int64_t y,
                               int64_t z,
                               int64_t threads,
                               double rsd) :
  x_((double) x),
  y_((double) y),
  z_((double) z),
  rsd_(rsd),
  avg_seconds_(0),
  count_(0),
  sqrtz_(isqrt(z))
{
  init(threads);
}

void S2LoadBalancer::init(int64_t threads)
{
  // determined by benchmarking
  double log_threads = max(1.0, log((double) threads));
  decrease_dividend_ = max(0.5, log_threads / 3);
  min_seconds_ = 0.02 * log_threads;
  update_min_size(log(x_) * log(log(x_)));

  double alpha = get_alpha(x_, y_);
  smallest_hard_leaf_ = (int64_t) (x_ / (y_ * sqrt(alpha) * iroot<6>(x_)));
}

double S2LoadBalancer::get_rsd() const
{
  return rsd_;
}

int64_t S2LoadBalancer::get_min_segment_size() const
{
  return min_size_;
}

bool S2LoadBalancer::decrease_size(double seconds,
                                   double decrease) const
{
  return seconds > min_seconds_ &&
         rsd_ > decrease;
}

bool S2LoadBalancer::increase_size(double seconds,
                                   double decrease) const
{
  return seconds < avg_seconds_ &&
        !decrease_size(seconds, decrease);
}

/// Used to decide whether to use a smaller or larger
/// segment_size and/or segments_per_thread.
///
double S2LoadBalancer::get_decrease_threshold(double seconds) const
{
  double log_seconds = max(min_seconds_, log(seconds));
  double dont_decrease = min(decrease_dividend_ / (seconds * log_seconds), rsd_);
  return rsd_ + dont_decrease;
}

void S2LoadBalancer::update_avg_seconds(double seconds)
{
  seconds = max(seconds, min_seconds_);
  double dividend = avg_seconds_ * count_ + seconds;
  avg_seconds_ = dividend / ++count_;
}

void S2LoadBalancer::update_min_size(double divisor)
{
  int64_t size = (int64_t) (sqrt(z_) / max(1.0, divisor));
  int64_t min_size = 1 << 9;
  min_size_ = max(size, min_size);
  min_size_ = next_power_of_2(min_size_);
}

/// Balance the load in the computation of the special leaves
/// by dynamically adjusting the segment_size and segments_per_thread.
/// @param timings  Timings of the threads.
///
void S2LoadBalancer::update(int64_t low,
                            int64_t threads,
                            int64_t* segment_size,
                            int64_t* segments_per_thread,
                            aligned_vector<double>& timings)
{
  double seconds = get_average(timings);
  update_avg_seconds(seconds);
  double decrease_threshold = get_decrease_threshold(seconds);
  rsd_ = max(0.1, relative_standard_deviation(timings));

  // 1 segment per thread
  if (*segment_size < sqrtz_)
  {
    if (increase_size(seconds, decrease_threshold))
      *segment_size <<= 1;
    else if (decrease_size(seconds, decrease_threshold))
      if (*segment_size > min_size_)
        *segment_size >>= 1;
  }
  // many segments per thread
  else if (low > smallest_hard_leaf_)
  {
    double factor = decrease_threshold / rsd_;
    factor = in_between(0.5, factor, 2);
    double n = *segments_per_thread * factor;
    n = max(1.0, n);

    if ((n < *segments_per_thread && seconds > min_seconds_) ||
        (n > *segments_per_thread && seconds < avg_seconds_))
    {
      *segments_per_thread = (int) n;
    }
  }

  int64_t high = low + *segment_size * *segments_per_thread * threads;

  // near smallest_hard_leaf_ the hard special leaves
  // are distributed unevenly so use min_size_
  if (low <= smallest_hard_leaf_ &&
      high > smallest_hard_leaf_)
  {
    *segment_size = min_size_;
  }

  high = low + *segment_size * *segments_per_thread * threads;

  // slightly increase min_size_
  if (high >= smallest_hard_leaf_)
  {
    update_min_size(log(y_));
    *segment_size = max(min_size_, *segment_size);
  }
}

} // namespace
<commit_msg>Refactoring<commit_after>///
/// @file  S2LoadBalancer.cpp
/// @brief The S2LoadBalancer evenly distributes the work load between
///        the threads in the computation of the special leaves.
///
/// Simply parallelizing the computation of the special leaves in the
/// Lagarias-Miller-Odlyzko and Deleglise-Rivat algorithms by
/// subdividing the sieve interval by the number of threads into
/// equally sized subintervals does not scale because the distribution
/// of the special leaves is highly skewed and most special leaves are
/// in the first few segments whereas later on there are very few
/// special leaves.
///
/// Based on the above observations it is clear that we need some kind
/// of load balancing in order to scale our parallel algorithm for
/// computing special leaves. Below are the ideas I used to develop a
/// load balancing algorithm that achieves a high load balance by
/// dynamically increasing or decreasing the interval size based on
/// the relative standard deviation of the thread run-times.
///
/// 1) Start with a tiny segment size of x^(1/3) / (log x * log log x)
///    and one segment per thread. Our algorithm uses equally sized
///    intervals, for each thread the interval_size is
///    segment_size * segments_per_thread and the threads process
///    adjacent intervals i.e.
///    [base + interval_size * thread_id, base + interval_size * (thread_id + 1)].
///
/// 2) If the relative standard deviation of the thread run-times is
///    large then we know the special leaves are distributed unevenly,
///    else if the relative standard deviation is low the special
///    leaves are more evenly distributed.
///
/// 3) If the special leaves are distributed unevenly then we can
///    increase the load balance by decreasing the interval_size.
///    Contrary if the special leaves are more evenly distributed
///    we can increase the interval_size in order to improve the
///    algorithm's efficiency.
///
/// 4) We can't use a static threshold for as to when the relative
///    standard deviation is low or large as this threshold varies for
///    different PC architectures. So instead we compare the current
///    relative standard deviation to the previous one in order to
///    decide whether to increase or decrease the interval_size.
///
/// Copyright (C) 2016 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <S2LoadBalancer.hpp>
#include <primecount-internal.hpp>
#include <aligned_vector.hpp>
#include <pmath.hpp>
#include <int128.hpp>

#include <stdint.h>
#include <algorithm>
#include <cmath>

using namespace std;
using namespace primecount;

namespace {

double get_average(aligned_vector<double>& timings)
{
  size_t n = timings.size();
  double sum = 0;

  for (size_t i = 0; i < n; i++)
    sum += timings[i];

  return sum / n;
}

double relative_standard_deviation(aligned_vector<double>& timings)
{
  size_t n = timings.size();
  double average = get_average(timings);
  double sum = 0;

  if (average == 0)
    return 0;

  for (size_t i = 0; i < n; i++)
  {
    double mean = timings[i] - average;
    sum += mean * mean;
  }

  double std_dev = sqrt(sum / max(1.0, n - 1.0));
  double rsd = 100 * std_dev / average;

  return rsd;
}

} // namespace

namespace primecount {

S2LoadBalancer::S2LoadBalancer(maxint_t x,
                               int64_t y,
                               int64_t z,
                               int64_t threads) :
  x_((double) x),
  y_((double) y),
  z_((double) z),
  rsd_(40),
  avg_seconds_(0),
  count_(0),
  sqrtz_(isqrt(z))
{
  init(threads);
}

S2LoadBalancer::S2LoadBalancer(maxint_t x,
                               int64_t y,
                               int64_t z,
                               int64_t threads,
                               double rsd) :
  x_((double) x),
  y_((double) y),
  z_((double) z),
  rsd_(rsd),
  avg_seconds_(0),
  count_(0),
  sqrtz_(isqrt(z))
{
  init(threads);
}

void S2LoadBalancer::init(int64_t threads)
{
  // determined by benchmarking
  double log_threads = max(1.0, log((double) threads));
  decrease_dividend_ = max(0.5, log_threads / 3);
  min_seconds_ = 0.02 * log_threads;
  update_min_size(log(x_) * log(log(x_)));

  double alpha = get_alpha(x_, y_);
  smallest_hard_leaf_ = (int64_t) (x_ / (y_ * sqrt(alpha) * iroot<6>(x_)));
}

double S2LoadBalancer::get_rsd() const
{
  return rsd_;
}

int64_t S2LoadBalancer::get_min_segment_size() const
{
  return min_size_;
}

bool S2LoadBalancer::decrease_size(double seconds,
                                   double decrease) const
{
  return seconds > min_seconds_ &&
         rsd_ > decrease;
}

bool S2LoadBalancer::increase_size(double seconds,
                                   double decrease) const
{
  return seconds < avg_seconds_ &&
        !decrease_size(seconds, decrease);
}

/// Used to decide whether to use a smaller or larger
/// segment_size and/or segments_per_thread.
///
double S2LoadBalancer::get_decrease_threshold(double seconds) const
{
  double log_seconds = max(min_seconds_, log(seconds));
  double dont_decrease = min(decrease_dividend_ / (seconds * log_seconds), rsd_);
  return rsd_ + dont_decrease;
}

void S2LoadBalancer::update_avg_seconds(double seconds)
{
  seconds = max(seconds, min_seconds_);
  double dividend = avg_seconds_ * count_ + seconds;
  avg_seconds_ = dividend / ++count_;
}

void S2LoadBalancer::update_min_size(double divisor)
{
  int64_t size = (int64_t) (sqrtz_ / max(1.0, divisor));
  int64_t min_size = 1 << 9;
  min_size_ = max(size, min_size);
  min_size_ = next_power_of_2(min_size_);
}

/// Balance the load in the computation of the special leaves
/// by dynamically adjusting the segment_size and segments_per_thread.
/// @param timings  Timings of the threads.
///
void S2LoadBalancer::update(int64_t low,
                            int64_t threads,
                            int64_t* segment_size,
                            int64_t* segments_per_thread,
                            aligned_vector<double>& timings)
{
  double seconds = get_average(timings);
  update_avg_seconds(seconds);
  double decrease_threshold = get_decrease_threshold(seconds);
  rsd_ = max(0.1, relative_standard_deviation(timings));

  // 1 segment per thread
  if (*segment_size < sqrtz_)
  {
    if (increase_size(seconds, decrease_threshold))
      *segment_size <<= 1;
    else if (decrease_size(seconds, decrease_threshold))
      if (*segment_size > min_size_)
        *segment_size >>= 1;
  }
  // many segments per thread
  else if (low > smallest_hard_leaf_)
  {
    double factor = decrease_threshold / rsd_;
    factor = in_between(0.5, factor, 2);
    double n = *segments_per_thread * factor;
    n = max(1.0, n);

    if ((n < *segments_per_thread && seconds > min_seconds_) ||
        (n > *segments_per_thread && seconds < avg_seconds_))
    {
      *segments_per_thread = (int) n;
    }
  }

  int64_t high = low + *segment_size * *segments_per_thread * threads;

  // near smallest_hard_leaf_ the hard special leaves
  // are distributed unevenly so use min_size_
  if (low <= smallest_hard_leaf_ &&
      high > smallest_hard_leaf_)
  {
    *segment_size = min_size_;
  }

  high = low + *segment_size * *segments_per_thread * threads;

  // slightly increase min_size_
  if (high >= smallest_hard_leaf_)
  {
    update_min_size(log(y_));
    *segment_size = max(min_size_, *segment_size);
  }
}

} // namespace
<|endoftext|>


<commit_before>/*
 Library written for use with Common-Anode 7-Segment Display. For more information on how to use this library,
 please refer to the github README.

 Written by: Derek Duncan
 Data: 2/4/2016
*/

#include "Arduino.h"
#include "SegmentDisplay.h"

int pins[8];

SegmentDisplay::SegmentDisplay(int pin1, int pin2, int pin4, int pin5, int pin6, int pin7, int pin9, int pin10)
{
    _pin1 = pin1;
    _pin2 = pin2;
    _pin4 = pin4;
    _pin5 = pin5;
    _pin6 = pin6;
    _pin7 = pin7;
    _pin9 = pin9;
    _pin10 = pin10;

    pins[0] = _pin1;
    pins[1] = _pin2;
    pins[2] = _pin4;
    pins[3] = _pin5;
    pins[4] = _pin6;
    pins[5] = _pin7;
    pins[6] = _pin9;
    pins[7] = _pin10;

    for(int i = 0; i < 8; i++)
    {
        pinMode(pins[i], OUTPUT);
        digitalWrite(pins[i], HIGH);
    }

}

void SegmentDisplay::displayHex(int number, boolean decimalPointFlag)
{

    byte numbersToDisplay[] =
    {
        B10001000,  //  0
        B11101011,  //  1
        B01001100,  //  2
        B01001001,  //  3
        B00101011,  //  4
        B00011001,  //  5
        B00011000,  //  6
        B11001011,  //  7
        B00001000,  //  8
        B00001011,  //  9
        B00001010,  //  A
        B00111000,  //  B
        B10011100,  //  C
        B01101000,  //  D
        B00011100,  //  E
        B00011110,  //  F
        B01011101  //  Error

    };

    boolean bitToWrite;

    for(int segment = 0; segment < 8; segment++)
    {
        if(number < 0 || number > 15)
        {
            bitToWrite = bitRead(numbersToDisplay[16], segment);
        }

        else if(segment == 3 && decimalPointFlag)
        {
            bitToWrite = 0;
        }

        else
        {
            bitToWrite = bitRead(numbersToDisplay[number], segment);
        }

        digitalWrite(pins[segment], bitToWrite);

    }
}

void SegmentDisplay::displayDecimalPoint()
{
    digitalWrite(_pin1, HIGH);
    digitalWrite(_pin2, HIGH);
    digitalWrite(_pin4, HIGH);
    digitalWrite(_pin5, LOW);
    digitalWrite(_pin6, HIGH);
    digitalWrite(_pin7, HIGH);
    digitalWrite(_pin9, HIGH);
    digitalWrite(_pin10, HIGH);

}

void SegmentDisplay::testDisplay()
{
	for(int i = 0; i <= 15; i++)
	{
		displayHex(i, false);
		delay(500);
	}
}

<commit_msg>cleaned up displayDecimalPoint()<commit_after>/*
 Library written for use with Common-Anode 7-Segment Display. For more information on how to use this library,
 please refer to the github README.

 Written by: Derek Duncan
 Data: 2/4/2016
*/

#include "Arduino.h"
#include "SegmentDisplay.h"

int pins[8];

SegmentDisplay::SegmentDisplay(int pin1, int pin2, int pin4, int pin5, int pin6, int pin7, int pin9, int pin10)
{
    _pin1 = pin1;
    _pin2 = pin2;
    _pin4 = pin4;
    _pin5 = pin5;
    _pin6 = pin6;
    _pin7 = pin7;
    _pin9 = pin9;
    _pin10 = pin10;

    pins[0] = _pin1;
    pins[1] = _pin2;
    pins[2] = _pin4;
    pins[3] = _pin5;
    pins[4] = _pin6;
    pins[5] = _pin7;
    pins[6] = _pin9;
    pins[7] = _pin10;

    for(int i = 0; i < 8; i++)
    {
        pinMode(pins[i], OUTPUT);
        digitalWrite(pins[i], HIGH);
    }

}

void SegmentDisplay::displayHex(int number, boolean decimalPointFlag)
{

    byte numbersToDisplay[] =
    {
        B10001000,  //  0
        B11101011,  //  1
        B01001100,  //  2
        B01001001,  //  3
        B00101011,  //  4
        B00011001,  //  5
        B00011000,  //  6
        B11001011,  //  7
        B00001000,  //  8
        B00001011,  //  9
        B00001010,  //  A
        B00111000,  //  B
        B10011100,  //  C
        B01101000,  //  D
        B00011100,  //  E
        B00011110,  //  F
        B01011101  //  Error

    };

    boolean bitToWrite;

    for(int segment = 0; segment < 8; segment++)
    {
        if(number < 0 || number > 15)
        {
            bitToWrite = bitRead(numbersToDisplay[16], segment);
        }

        else if(segment == 3 && decimalPointFlag)
        {
            bitToWrite = 0;
        }

        else
        {
            bitToWrite = bitRead(numbersToDisplay[number], segment);
        }

        digitalWrite(pins[segment], bitToWrite);

    }
}

void SegmentDisplay::displayDecimalPoint()
{
    for(int i = 0; i < 8; i++)
    {
        if(i == 3)
        {
            digitalWrite(pins[i], 0);
        }
        else
        {
            digitalWrite(pins[i], 1);
        }
    }

}

void SegmentDisplay::testDisplay()
{
	for(int i = 0; i <= 15; i++)
	{
		displayHex(i, false);
		delay(500);
	}
}

<|endoftext|>


<commit_before>/* mbino - basic mbed APIs for the Arduino platform
 * Copyright (c) 2017 Thomas Kemmer
 *
 * mbed Microcontroller Library
 * Copyright (c) 2006-2013 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.  See the License for the specific language governing
 * permissions and limitations under the License.
 */
#include "RawSerial.h"

#include <stdio.h>
#include <stdarg.h>

#define STRING_STACK_LIMIT 80

namespace mbino {
    int RawSerial::printf(const char *format, ...) {
        va_list arg;
        va_start(arg, format);
        // TODO: always try with STRING_STACK_LIMIT first?
        char dummy_buf[1];
        int len = vsnprintf(dummy_buf, sizeof(dummy_buf), format, arg);
        if (len < STRING_STACK_LIMIT) {
            char temp[STRING_STACK_LIMIT];
            vsprintf(temp, format, arg);
            puts(temp);
        } else {
            char *temp = new char[len + 1];
            vsprintf(temp, format, arg);
            puts(temp);
            delete[] temp;
        }
        va_end(arg);
        return len;
    }
}
<commit_msg>Improve RawSerial::printf() implementation.<commit_after>/* mbino - basic mbed APIs for the Arduino platform
 * Copyright (c) 2017 Thomas Kemmer
 *
 * mbed Microcontroller Library
 * Copyright (c) 2006-2013 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.  See the License for the specific language governing
 * permissions and limitations under the License.
 */
#include "RawSerial.h"

#include <alloca.h>
#include <stdio.h>
#include <stdarg.h>

#define OPTIMISTIC_STRING_STACK_LIMIT 80

namespace mbino {
    static int vnprintf(RawSerial* obj, size_t n, const char* format, va_list arg)
    {
        char* buf = alloca(n);
        int len = vsnprintf(buf, n, format, arg);
        if (len >= 0 && size_t(len) < n) {
            obj->puts(buf);
        }
        return len;
    }

    int RawSerial::printf(const char *format, ...) {
        va_list arg;
        va_start(arg, format);
        int n = vnprintf(this, OPTIMISTIC_STRING_STACK_LIMIT, format, arg);
        if (n < OPTIMISTIC_STRING_STACK_LIMIT) {
            return n;
        } else {
            return vnprintf(this, n + 1, format, arg);
        }
    }
}
<|endoftext|>


<commit_before>/*
 * ServalCommunication.cpp
 *
 *  Created on: Apr 15, 2016
 *      Author: sni
 */

#include "ServalCommunication.h"

#include <chrono>

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <ice/communication/messages/Message.h>
#include <serval_interface.h>
#include <serval_wrapper/MDPSocket.h>

#include "ice/Entity.h"
#include "IceServalBridge.h"

// Short alias for this namespace
namespace pt = boost::property_tree;

namespace ice
{

ServalCommunication::ServalCommunication(std::weak_ptr<ICEngine> engine, std::string configPath, std::string const host,
                                         int const port, std::string const authName, std::string const authPass,
                                         bool const local) :
    CommunicationInterface(engine), configPath(configPath), host(host), port(port), authName(authName),
    authPass(authPass), serval(nullptr), local(local), running (false)
{
  _log = el::Loggers::getLogger("ServalCommunication");
  this->maxMessageSend = 10;
}

ServalCommunication::~ServalCommunication()
{
  if (this->running)
  {
    this->running = false;
  }
}

std::shared_ptr<serval_interface> ServalCommunication::getServalInterface()
{
  return this->serval;
}

void ServalCommunication::setOwnSid(std::string const &sid)
{
  this->ownSid = sid;
}

void ServalCommunication::initInternal()
{
  // create interface
  this->serval = std::make_shared<serval_interface>(this->configPath, this->host, this->port, this->authName, this->authPass);

  // get own id
  if (local)
  {
    auto oid = this->serval->keyring.addIdentity();

    if (oid == nullptr)
    {
      // error case, own id could not be determined
      throw(std::runtime_error("Own serval id could not be determined"));
    }

    this->ownSid = oid->sid;
    this->self->addId(EntityDirectory::ID_SERVAL, this->ownSid);
  }
  else
  {
    if (this->ownSid == "")
    {
      auto id = this->serval->keyring.getSelf();
      if (id == nullptr || id->size() == 0)
      {
        // error case, own id could not be determined
        throw(std::runtime_error("Own serval id could not be determined"));
      }

      this->ownSid = id->at(0).sid;
      this->self->addId(EntityDirectory::ID_SERVAL, this->ownSid);
    }
  }

  // create socket
  this->socket = this->serval->createSocket(SERVAL_PORT, this->ownSid);

  if (this->socket == nullptr)
  {
    throw (std::runtime_error("MDP socket could not be created"));
    return;
  }

  // init read thread
  this->running = true;
  this->worker = std::thread(&ServalCommunication::read, this);
  this->worker.detach();
}

void ServalCommunication::cleanUpInternal()
{
  this->running = false;

  if (this->serval != nullptr)
  {
    this->serval->cleanUp();
    this->serval = nullptr;
  }
}

void ServalCommunication::read()
{
  uint8_t buffer[4096];
  std::string sid;

  while (this->running)
  {
    int recCount = this->socket->receive(sid, buffer, 4096);

    if (false == this->running)
      return;

    if (recCount == 0)
    {
      // huge amount of emtpy messages, will be skipped
//      _log->debug("Received empty message from sid %v", sid);
      continue;
    }

    if (recCount < 0)
    {
      _log->info("Received broken message from sid %v", sid);
      continue;
    }

    auto entity = this->directory->lookup(EntityDirectory::ID_SERVAL, sid, false);

    if (entity == nullptr)
    {
      this->_log->info("Received message from unknown serval node '%v'", sid);

      // Create new instance and request ids
      entity = this->directory->create(EntityDirectory::ID_SERVAL, sid);
      // At the beginning each discovered node is expected to be an ice node
      entity->setAvailable(true);
      this->discoveredEntity(entity);
    }
    else if (sid == this->ownSid)
    {
      // own message, will not be processed
      this->_log->debug("Received own message, will be skipped");
      continue;
    }

    this->traffic.receivedBytes += recCount;
    ++this->traffic.messageReceivedCount;
    std::string json(buffer+3, buffer+recCount);

    auto message = Message::parse(buffer[0], json, this->containerFactory);
    message->setJobId(buffer[1]);
    message->setJobIndex(buffer[2]);

    if (message == nullptr)
    {
      this->_log->info("Received unknown or broken message from serval node '%v'", sid);

      continue;
    }

    message->setEntity(entity);
//    m.command = buffer[0];
//    m.payload.clear();
//    m.payload.reserve(recCount-1);
//    std::copy(buffer + 1, buffer + recCount, std::back_inserter(m.payload));

    this->handleMessage(message);
  }
}

void ServalCommunication::discover()
{
  std::unique_ptr<std::vector<serval_identity>> peers;
  if (this->local)
  {
    peers = this->serval->keyring.getSelf();
  }
  else
  {
    peers = this->serval->keyring.getPeerIdentities();
  }

  for (auto &sid : *peers)
  {
    auto entity = this->directory->lookup(EntityDirectory::ID_SERVAL, sid.sid);

    if (entity == nullptr)
    {
      // Create new instance and request ids
      entity = this->directory->create(EntityDirectory::ID_SERVAL, sid.sid);
      // At the beginning each discovered node is expected to be an ice node
      entity->setAvailable(true);
      this->discoveredEntity(entity);

      _log->info("New ID discovered: %v", entity->toString());
    }

    entity->setActiveTimestamp();
  }
}

int ServalCommunication::readMessage(std::vector<std::shared_ptr<Message>> &outMessages)
{
  return 0; // reading messages is done in own thread
}

void ServalCommunication::sendMessage(std::shared_ptr<Message> msg)
{
  std::string sid;

  if (false == msg->getEntity()->getId(EntityDirectory::ID_SERVAL, sid))
  {
    this->_log->error("Trying to send message with serval to none serval instance %v", msg->getEntity()->toString());
    return;
  }

  int size = 3;
  if (msg->isPayload())
  {
    std::string json = msg->toJson();
    size = json.size() + 3;

    if (size > 1024)
    {
      this->_log->error("Message could not be send to instance '%v', to large '%v' byte", msg->getEntity()->toString(), size);
      return;
    }

    std::lock_guard<std::mutex> guard(_mtxSend);
    std::copy(json.begin(), json.end(), this->buffer + 3);
  }

  buffer[0] = msg->getId();
  buffer[1] = msg->getJobId();
  buffer[2] = msg->getJobIndex();

  this->traffic.sendBytes += size;
  ++this->traffic.messageSendCount;
  this->socket->send(sid, buffer, size);
//  std::cout << size << std::endl;
}

std::shared_ptr<BaseInformationSender> ServalCommunication::createSender(std::shared_ptr<BaseInformationStream> stream)
{
  return nullptr;
}

std::shared_ptr<InformationReceiver> ServalCommunication::createReceiver(std::shared_ptr<BaseInformationStream> stream)
{
  return nullptr;
}

} /* namespace ice */
<commit_msg>testing<commit_after>/*
 * ServalCommunication.cpp
 *
 *  Created on: Apr 15, 2016
 *      Author: sni
 */

#include "ServalCommunication.h"

#include <chrono>

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <ice/communication/messages/Message.h>
#include <serval_interface.h>
#include <serval_wrapper/MDPSocket.h>

#include "ice/Entity.h"
#include "IceServalBridge.h"

// Short alias for this namespace
namespace pt = boost::property_tree;

namespace ice
{

ServalCommunication::ServalCommunication(std::weak_ptr<ICEngine> engine, std::string configPath, std::string const host,
                                         int const port, std::string const authName, std::string const authPass,
                                         bool const local) :
    CommunicationInterface(engine), configPath(configPath), host(host), port(port), authName(authName),
    authPass(authPass), serval(nullptr), local(local), running (false)
{
  _log = el::Loggers::getLogger("ServalCommunication");
  this->maxMessageSend = 5;
}

ServalCommunication::~ServalCommunication()
{
  if (this->running)
  {
    this->running = false;
  }
}

std::shared_ptr<serval_interface> ServalCommunication::getServalInterface()
{
  return this->serval;
}

void ServalCommunication::setOwnSid(std::string const &sid)
{
  this->ownSid = sid;
}

void ServalCommunication::initInternal()
{
  // create interface
  this->serval = std::make_shared<serval_interface>(this->configPath, this->host, this->port, this->authName, this->authPass);

  // get own id
  if (local)
  {
    auto oid = this->serval->keyring.addIdentity();

    if (oid == nullptr)
    {
      // error case, own id could not be determined
      throw(std::runtime_error("Own serval id could not be determined"));
    }

    this->ownSid = oid->sid;
    this->self->addId(EntityDirectory::ID_SERVAL, this->ownSid);
  }
  else
  {
    if (this->ownSid == "")
    {
      auto id = this->serval->keyring.getSelf();
      if (id == nullptr || id->size() == 0)
      {
        // error case, own id could not be determined
        throw(std::runtime_error("Own serval id could not be determined"));
      }

      this->ownSid = id->at(0).sid;
      this->self->addId(EntityDirectory::ID_SERVAL, this->ownSid);
    }
  }

  // create socket
  this->socket = this->serval->createSocket(SERVAL_PORT, this->ownSid);

  if (this->socket == nullptr)
  {
    throw (std::runtime_error("MDP socket could not be created"));
    return;
  }

  // init read thread
  this->running = true;
  this->worker = std::thread(&ServalCommunication::read, this);
  this->worker.detach();
}

void ServalCommunication::cleanUpInternal()
{
  this->running = false;

  if (this->serval != nullptr)
  {
    this->serval->cleanUp();
    this->serval = nullptr;
  }
}

void ServalCommunication::read()
{
  uint8_t buffer[4096];
  std::string sid;

  while (this->running)
  {
    int recCount = this->socket->receive(sid, buffer, 4096);

    if (false == this->running)
      return;

    if (recCount == 0)
    {
      // huge amount of emtpy messages, will be skipped
//      _log->debug("Received empty message from sid %v", sid);
      continue;
    }

    if (recCount < 0)
    {
      _log->info("Received broken message from sid %v", sid);
      continue;
    }

    auto entity = this->directory->lookup(EntityDirectory::ID_SERVAL, sid, false);

    if (entity == nullptr)
    {
      this->_log->info("Received message from unknown serval node '%v'", sid);

      // Create new instance and request ids
      entity = this->directory->create(EntityDirectory::ID_SERVAL, sid);
      // At the beginning each discovered node is expected to be an ice node
      entity->setAvailable(true);
      this->discoveredEntity(entity);
    }
    else if (sid == this->ownSid)
    {
      // own message, will not be processed
      this->_log->debug("Received own message, will be skipped");
      continue;
    }

    this->traffic.receivedBytes += recCount;
    ++this->traffic.messageReceivedCount;
    std::string json(buffer+3, buffer+recCount);

    auto message = Message::parse(buffer[0], json, this->containerFactory);
    message->setJobId(buffer[1]);
    message->setJobIndex(buffer[2]);

    if (message == nullptr)
    {
      this->_log->info("Received unknown or broken message from serval node '%v'", sid);

      continue;
    }

    message->setEntity(entity);
//    m.command = buffer[0];
//    m.payload.clear();
//    m.payload.reserve(recCount-1);
//    std::copy(buffer + 1, buffer + recCount, std::back_inserter(m.payload));

    this->handleMessage(message);
  }
}

void ServalCommunication::discover()
{
  std::unique_ptr<std::vector<serval_identity>> peers;
  if (this->local)
  {
    peers = this->serval->keyring.getSelf();
  }
  else
  {
    peers = this->serval->keyring.getPeerIdentities();
  }

  for (auto &sid : *peers)
  {
    auto entity = this->directory->lookup(EntityDirectory::ID_SERVAL, sid.sid);

    if (entity == nullptr)
    {
      // Create new instance and request ids
      entity = this->directory->create(EntityDirectory::ID_SERVAL, sid.sid);
      // At the beginning each discovered node is expected to be an ice node
      entity->setAvailable(true);
      this->discoveredEntity(entity);

      _log->info("New ID discovered: %v", entity->toString());
    }

    entity->setActiveTimestamp();
  }
}

int ServalCommunication::readMessage(std::vector<std::shared_ptr<Message>> &outMessages)
{
  return 0; // reading messages is done in own thread
}

void ServalCommunication::sendMessage(std::shared_ptr<Message> msg)
{
  std::string sid;

  if (false == msg->getEntity()->getId(EntityDirectory::ID_SERVAL, sid))
  {
    this->_log->error("Trying to send message with serval to none serval instance %v", msg->getEntity()->toString());
    return;
  }

  int size = 3;
  if (msg->isPayload())
  {
    std::string json = msg->toJson();
    size = json.size() + 3;

    if (size > 1024)
    {
      this->_log->error("Message could not be send to instance '%v', to large '%v' byte", msg->getEntity()->toString(), size);
      return;
    }

    std::lock_guard<std::mutex> guard(_mtxSend);
    std::copy(json.begin(), json.end(), this->buffer + 3);
  }

  buffer[0] = msg->getId();
  buffer[1] = msg->getJobId();
  buffer[2] = msg->getJobIndex();

  this->traffic.sendBytes += size;
  ++this->traffic.messageSendCount;
  this->socket->send(sid, buffer, size);
//  std::cout << size << std::endl;
}

std::shared_ptr<BaseInformationSender> ServalCommunication::createSender(std::shared_ptr<BaseInformationStream> stream)
{
  return nullptr;
}

std::shared_ptr<InformationReceiver> ServalCommunication::createReceiver(std::shared_ptr<BaseInformationStream> stream)
{
  return nullptr;
}

} /* namespace ice */
<|endoftext|>


<commit_before>#include "SparkFunCCS811.hpp"
#include "cox.h"

CCS811Core::CCS811Core(TwoWire &W, uint8_t addr) : Wire(W), I2CAddress(addr) {
}

CCS811Core::status CCS811Core::readRegister(uint8_t offset, uint8_t* outputPointer){
	//Return value
	uint8_t result=0;
	uint8_t numBytes = 1;

	this->Wire.beginTransmission(I2CAddress);
	this->Wire.write(offset);
	this->Wire.endTransmission();
	// slave may send less than requeste
	// receive a byte as a proper uint8_t
	this->Wire.requestFrom(I2CAddress, numBytes);
	while(this->Wire.available()){
		result = this->Wire.read();
	}
	*outputPointer = result;

	return SENSOR_SUCCESS;
}

CCS811Core::status CCS811Core::multiReadRegister(uint8_t offset, uint8_t *outputPointer, uint8_t length){
	//define pointer that will point to the external space
	uint8_t i = 0;
	uint8_t c = 0;
	//Set the address
	this->Wire.beginTransmission(I2CAddress);
	this->Wire.write(offset);
	this->Wire.endTransmission();
	// request 6 bytes from slave device
	this->Wire.requestFrom(I2CAddress, 4);
	while ((this->Wire.available()) && (i < length)){
	// slave may send less than requested
	// receive a byte as character
		c = this->Wire.read();
		*outputPointer = c;
		outputPointer++;
		i++;
	}
	return SENSOR_SUCCESS;
}

CCS811Core::status CCS811Core::writeRegister(uint8_t offset, uint8_t dataToWrite) {
	//offset -- register to write
	//dataToWrite -- 8 bit data to write to register
	this->Wire.beginTransmission(I2CAddress);
	this->Wire.write(offset);
	this->Wire.write(dataToWrite);
	this->Wire.endTransmission();

	return SENSOR_SUCCESS;
}

CCS811Core::status CCS811Core::multiWriteRegister(uint8_t offset, uint8_t *inputPointer, uint8_t length){
	//offset -- register to read
	//*inputPointer -- Pass &variable (base address of) to save read data to
	//length -- number of bytes to read
	//define pointer that will point to the external space
	uint8_t i = 0;
	//Set the address
	this->Wire.beginTransmission(I2CAddress);
	this->Wire.write(offset);
	// receive a byte as character
	while ( i < length ){
		this->Wire.write(*inputPointer);
		inputPointer++;
		i++;
	}
	this->Wire.endTransmission();

	return SENSOR_SUCCESS;
}

CCS811::CCS811(TwoWire &W, uint8_t addr) : CCS811Core(W, addr){
	refResistance = 10000;
	resistance = 0;
	temperature = 0;
	tVOC = 0;
	CO2 = 0;
}

CCS811Core::status CCS811::begin( void ){
	//Reset key
	uint8_t data[4] = {0x11,0xE5,0x72,0x8A};

	multiWriteRegister(CSS811_SW_RESET, data, 4);

	delay(20);
	//Write 0 bytes to this register to start app
	this->Wire.beginTransmission(I2CAddress);
	this->Wire.write(CSS811_APP_START);
	this->Wire.endTransmission();
	//Read every second
	setDriveMode(1);

	return SENSOR_SUCCESS;
}

CCS811Core::status CCS811::readAlgorithmResults( void ){
	uint8_t data[4];
	uint8_t i = 0;
	//Set the address
	this->Wire.beginTransmission(I2CAddress);
	this->Wire.write(CSS811_ALG_RESULT_DATA);
	this->Wire.endTransmission();
	this->Wire.requestFrom(I2CAddress, 4);
	while (  i < 4){
		data[i] = this->Wire.read();
		i++;
	}
	// data : co2MSB, co2LSB, tvocMSB, tvocLSB
	CO2  = ((uint16_t)data[0] << 8) | data[1];
	tVOC = ((uint16_t)data[2] << 8) | data[3];

	return SENSOR_SUCCESS;
}

	//Mode 0 = Idle
	//Mode 1 = read every 1s
	//Mode 2 = every 10s
	//Mode 3 = every 60s
	//Mode 4 = RAW mode
CCS811Core::status CCS811::setDriveMode( uint8_t mode ){
	//sanitize input
	if (mode > 4) mode = 4;

	uint8_t value;
	//Read what's currently there
	//Clear DRIVE_MODE bits
	//Mask in mode
	CCS811Core::status returnError = readRegister( CSS811_MEAS_MODE, &value );
	value &= ~(0b00000111 << 4);
	value |= (mode << 4);
	returnError = writeRegister(CSS811_MEAS_MODE, value);

	return returnError;
}

uint16_t CCS811::getTVOC( void ){
	return tVOC;
}

uint16_t CCS811::getCO2( void ){
	return CO2;
}
<commit_msg>Added Wire.begin()<commit_after>#include "SparkFunCCS811.hpp"
#include "cox.h"

CCS811Core::CCS811Core(TwoWire &W, uint8_t addr) : Wire(W), I2CAddress(addr) {
}

CCS811Core::status CCS811Core::readRegister(uint8_t offset, uint8_t* outputPointer){
	//Return value
	uint8_t result=0;
	uint8_t numBytes = 1;

	this->Wire.beginTransmission(I2CAddress);
	this->Wire.write(offset);
	this->Wire.endTransmission();
	// slave may send less than requeste
	// receive a byte as a proper uint8_t
	this->Wire.requestFrom(I2CAddress, numBytes);
	while(this->Wire.available()){
		result = this->Wire.read();
	}
	*outputPointer = result;

	return SENSOR_SUCCESS;
}

CCS811Core::status CCS811Core::multiReadRegister(uint8_t offset, uint8_t *outputPointer, uint8_t length){
	//define pointer that will point to the external space
	uint8_t i = 0;
	uint8_t c = 0;
	//Set the address
	this->Wire.beginTransmission(I2CAddress);
	this->Wire.write(offset);
	this->Wire.endTransmission();
	// request 6 bytes from slave device
	this->Wire.requestFrom(I2CAddress, 4);
	while ((this->Wire.available()) && (i < length)){
	// slave may send less than requested
	// receive a byte as character
		c = this->Wire.read();
		*outputPointer = c;
		outputPointer++;
		i++;
	}
	return SENSOR_SUCCESS;
}

CCS811Core::status CCS811Core::writeRegister(uint8_t offset, uint8_t dataToWrite) {
	//offset -- register to write
	//dataToWrite -- 8 bit data to write to register
	this->Wire.beginTransmission(I2CAddress);
	this->Wire.write(offset);
	this->Wire.write(dataToWrite);
	this->Wire.endTransmission();

	return SENSOR_SUCCESS;
}

CCS811Core::status CCS811Core::multiWriteRegister(uint8_t offset, uint8_t *inputPointer, uint8_t length){
	//offset -- register to read
	//*inputPointer -- Pass &variable (base address of) to save read data to
	//length -- number of bytes to read
	//define pointer that will point to the external space
	uint8_t i = 0;
	//Set the address
	this->Wire.beginTransmission(I2CAddress);
	this->Wire.write(offset);
	// receive a byte as character
	while ( i < length ){
		this->Wire.write(*inputPointer);
		inputPointer++;
		i++;
	}
	this->Wire.endTransmission();

	return SENSOR_SUCCESS;
}

CCS811::CCS811(TwoWire &W, uint8_t addr) : CCS811Core(W, addr){
	refResistance = 10000;
	resistance = 0;
	temperature = 0;
	tVOC = 0;
	CO2 = 0;
}

CCS811Core::status CCS811::begin( void ){
	//Reset key
	this->Wire.begin();
	uint8_t data[4] = {0x11,0xE5,0x72,0x8A};

	multiWriteRegister(CSS811_SW_RESET, data, 4);

	delay(20);
	//Write 0 bytes to this register to start app
	this->Wire.beginTransmission(I2CAddress);
	this->Wire.write(CSS811_APP_START);
	this->Wire.endTransmission();
	//Read every second
	setDriveMode(1);

	return SENSOR_SUCCESS;
}

CCS811Core::status CCS811::readAlgorithmResults( void ){
	uint8_t data[4];
	uint8_t i = 0;
	//Set the address
	this->Wire.beginTransmission(I2CAddress);
	this->Wire.write(CSS811_ALG_RESULT_DATA);
	this->Wire.endTransmission();
	this->Wire.requestFrom(I2CAddress, 4);
	while (  i < 4){
		data[i] = this->Wire.read();
		i++;
	}
	// data : co2MSB, co2LSB, tvocMSB, tvocLSB
	CO2  = ((uint16_t)data[0] << 8) | data[1];
	tVOC = ((uint16_t)data[2] << 8) | data[3];

	return SENSOR_SUCCESS;
}

	//Mode 0 = Idle
	//Mode 1 = read every 1s
	//Mode 2 = every 10s
	//Mode 3 = every 60s
	//Mode 4 = RAW mode
CCS811Core::status CCS811::setDriveMode( uint8_t mode ){
	//sanitize input
	if (mode > 4) mode = 4;

	uint8_t value;
	//Read what's currently there
	//Clear DRIVE_MODE bits
	//Mask in mode
	CCS811Core::status returnError = readRegister( CSS811_MEAS_MODE, &value );
	value &= ~(0b00000111 << 4);
	value |= (mode << 4);
	returnError = writeRegister(CSS811_MEAS_MODE, value);

	return returnError;
}

uint16_t CCS811::getTVOC( void ){
	return tVOC;
}

uint16_t CCS811::getCO2( void ){
	return CO2;
}
<|endoftext|>


<commit_before>#ifndef ecmdStructs_H
#define ecmdStructs_H
// Copyright **********************************************************
//
// File ecmdStructs.H
//
// IBM Confidential
// OCO Source Materials
// 9400 Licensed Internal Code
// (C) COPYRIGHT IBM CORP. 2003
//
// The source code for this program is not published or otherwise
// divested of its trade secrets, irrespective of what has been
// deposited with the U.S. Copyright Office.
//
// End Copyright ******************************************************
/**
  @file ecmdStructs.H
  @brief All the Structures required for the eCMD Capi
*/

//--------------------------------------------------------------------
// Includes
//--------------------------------------------------------------------
#include <stdint.h>

//--------------------------------------------------------------------
//  Forward References
//--------------------------------------------------------------------

//--------------------------------------------------------------------
//  Defines
//--------------------------------------------------------------------

#define ECMD_CAPI_VERSION ".1"

#define ECMD_MAX_CHIP_TYPE_LENGTH 15  ///< @see ecmdChipTarget

// Change Log *********************************************************
//
//  Flag Reason   Vers Date     Coder  Description
//  ---- -------- ---- -------- -----  -------------------------------
//                              willsj Initial Creation
//
// End Change Log *****************************************************

/**
 @brief Structure used to designate which cec object you would like the function to operate on

*/
struct ecmdChipTarget {

  char chipType[ECMD_MAX_CHIP_TYPE_LENGTH];  ///< name of chip to access

  uint32_t cage;  ///< cage that contains node with chip
  uint32_t node;  ///< node that contains chip
  uint32_t pos;   ///< position of chip within node
  uint32_t core;  ///< which core on chip to access, if chip is multi-core
  uint32_t thread; ///< which thread on chip to access, if chip is multi-threaded

  uint8_t cageLoopValid;  ///< Tell the calling function that this function operates at a cage level
  uint8_t nodeLoopValid;  ///< Tell the calling function that this function operates at a node level
  uint8_t posLoopValid;   ///< Tell the calling function that this function operates at a pos level
  uint8_t coreLoopValid;  ///< Tell the calling function that this function operates at a core level
  uint8_t threadLoopValid; ///< Tell the calling function that this function operates at a thread level

};

#endif
<commit_msg>friday changes- added loopValidChecked flag to ecmdChipTarget<commit_after>#ifndef ecmdStructs_H
#define ecmdStructs_H
// Copyright **********************************************************
//
// File ecmdStructs.H
//
// IBM Confidential
// OCO Source Materials
// 9400 Licensed Internal Code
// (C) COPYRIGHT IBM CORP. 2003
//
// The source code for this program is not published or otherwise
// divested of its trade secrets, irrespective of what has been
// deposited with the U.S. Copyright Office.
//
// End Copyright ******************************************************
/**
  @file ecmdStructs.H
  @brief All the Structures required for the eCMD Capi
*/

//--------------------------------------------------------------------
// Includes
//--------------------------------------------------------------------
#include <stdint.h>

//--------------------------------------------------------------------
//  Forward References
//--------------------------------------------------------------------

//--------------------------------------------------------------------
//  Defines
//--------------------------------------------------------------------

#define ECMD_CAPI_VERSION ".1"

#define ECMD_MAX_CHIP_TYPE_LENGTH 15  ///< @see ecmdChipTarget

// Change Log *********************************************************
//
//  Flag Reason   Vers Date     Coder  Description
//  ---- -------- ---- -------- -----  -------------------------------
//                              willsj Initial Creation
//
// End Change Log *****************************************************

/**
 @brief Structure used to designate which cec object you would like the function to operate on

*/
struct ecmdChipTarget {

  char chipType[ECMD_MAX_CHIP_TYPE_LENGTH];  ///< name of chip to access

  uint32_t cage;  ///< cage that contains node with chip
  uint32_t node;  ///< node that contains chip
  uint32_t pos;   ///< position of chip within node
  uint32_t core;  ///< which core on chip to access, if chip is multi-core
  uint32_t thread; ///< which thread on chip to access, if chip is multi-threaded

  uint8_t cageLoopValid;  ///< Tell the calling function that this function operates at a cage level
  uint8_t nodeLoopValid;  ///< Tell the calling function that this function operates at a node level
  uint8_t posLoopValid;   ///< Tell the calling function that this function operates at a pos level
  uint8_t coreLoopValid;  ///< Tell the calling function that this function operates at a core level
  uint8_t threadLoopValid; ///< Tell the calling function that this function operates at a thread level
  uint8_t loopValidChecked;  ///< Flag that indicates that we have signaled to the user level how to loop
};

#endif
<|endoftext|>


<commit_before>//----------------------------  multiple_parameter_loop_01.cc  ---------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 2002, 2003, 2004, 2005, 2010 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  multiple_parameter_loop_01.cc  ---------------------------

// check the MultipleParameterLoop class

#include "../tests.h"
#include <base/logstream.h>
#include <base/parameter_handler.h>
#include <fstream>

				 // Take the example from the
				 // documentation but instead of
				 // running anything simply print
				 // parameters
class HelperClass : public MultipleParameterLoop::UserClass
{
  public:
    virtual void create_new (unsigned int run_no)
      { this->run_no = run_no; }
    virtual void declare_parameters (ParameterHandler &prm);
    virtual void run (ParameterHandler &prm);
    unsigned int run_no;
};

void HelperClass::declare_parameters (ParameterHandler &prm)
{
  prm.enter_subsection ("Testing");
  prm.declare_entry ("string list",
		     "a",
		     Patterns::List(Patterns::Selection("a|b|c|d|e|f|g|h")),
		     "docs 1");
  prm.declare_entry ("int",
		     "1",
		     Patterns::Integer());
  prm.declare_entry ("double",
		     "3.1415926",
		     Patterns::Double(),
		     "docs 3");
  prm.leave_subsection ();
}

void HelperClass::run (ParameterHandler &prm)
{
  deallog << "Number of run: " << run_no << std::endl;

  prm.print_parameters (deallog.get_file_stream(), ParameterHandler::Text);
}

void check (const char *p)
{
  class MultipleParameterLoop prm;
  HelperClass h;

  h.declare_parameters (prm);
  prm.read_input ("multiple_parameter_loop_01/prm");
  prm.loop (h);
}

int main ()
{
  std::ofstream logfile("multiple_parameter_loop_01/output");
  deallog.attach(logfile);
  deallog.depth_console(0);
  deallog.threshold_double(1.e-10);

  check ("multiple_parameter_loop_01/prm");

  return 0;
}
<commit_msg>Remove unnecessary parameter.<commit_after>//----------------------------  multiple_parameter_loop_01.cc  ---------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 2002, 2003, 2004, 2005, 2010 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  multiple_parameter_loop_01.cc  ---------------------------

// check the MultipleParameterLoop class

#include "../tests.h"
#include <base/logstream.h>
#include <base/parameter_handler.h>
#include <fstream>

				 // Take the example from the
				 // documentation but instead of
				 // running anything simply print
				 // parameters
class HelperClass : public MultipleParameterLoop::UserClass
{
  public:
    virtual void create_new (unsigned int run_no)
      { this->run_no = run_no; }
    virtual void declare_parameters (ParameterHandler &prm);
    virtual void run (ParameterHandler &prm);
    unsigned int run_no;
};

void HelperClass::declare_parameters (ParameterHandler &prm)
{
  prm.enter_subsection ("Testing");
  prm.declare_entry ("string list",
		     "a",
		     Patterns::List(Patterns::Selection("a|b|c|d|e|f|g|h")),
		     "docs 1");
  prm.declare_entry ("int",
		     "1",
		     Patterns::Integer());
  prm.declare_entry ("double",
		     "3.1415926",
		     Patterns::Double(),
		     "docs 3");
  prm.leave_subsection ();
}

void HelperClass::run (ParameterHandler &prm)
{
  deallog << "Number of run: " << run_no << std::endl;

  prm.print_parameters (deallog.get_file_stream(), ParameterHandler::Text);
}

void check ()
{
  class MultipleParameterLoop prm;
  HelperClass h;

  h.declare_parameters (prm);
  prm.read_input ("multiple_parameter_loop_01/prm");
  prm.loop (h);
}

int main ()
{
  std::ofstream logfile("multiple_parameter_loop_01/output");
  deallog.attach(logfile);
  deallog.depth_console(0);
  deallog.threshold_double(1.e-10);

  check ();

  return 0;
}
<|endoftext|>


<commit_before>/*
  Hume Library
  Copyright (C) 2015 Marshall Clyburn

  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 "Graphics.h"

namespace hume
{
	Graphics::Graphics() : window(nullptr)
	{
		draw_color.r = draw_color.g = draw_color.b = 0;
		draw_color.a = SDL_ALPHA_OPAQUE;
	}

	Graphics::~Graphics()
	{
		if(window) delete window;
	}

	void Graphics::initialize()
	{
		const int types = IMG_INIT_JPG | IMG_INIT_PNG;
		int result = IMG_Init(types);
		if(result != types) throw SDLException();

		result = TTF_Init();
		if(result != 0) throw SDLTTFException();

		return;
	}

	void Graphics::shutdown()
	{
		IMG_Quit();
		TTF_Quit();

		return;
	}

	void Graphics::set_window(Window* const w)
	{
		window = w;
		return;
	}

	Window* Graphics::get_window() const
	{
		return window;
	}

	void Graphics::set_color(const uint8_t r, const uint8_t g, const uint8_t b, const uint8_t a)
	{
		draw_color.r = r;
		draw_color.g = g;
		draw_color.b = b;
		draw_color.a = a;

		return;
	}

	void Graphics::set_color(const Color& color)
	{
		this->draw_color = color;
		return;
	}

	Color Graphics::get_color() const
	{
		return draw_color;
	}

	Image* Graphics::load_image(const std::string& filename)
	{
		Image* image = new Image();
		image->open(filename, window->get_renderer());

		return image;
	}

	Image* Graphics::load_image(const std::string& filename, const Uint8 r, const Uint8 g, const Uint8 b)
	{
		Image* image = new Image(r, g, b);
		image->open(filename, window->get_renderer());

		return image;
	}

	void Graphics::draw(const Blittable* const b, const Properties& p)
	{
		window->draw(b, p);
		return;
	}

	void Graphics::draw_rect(const Properties& p, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
	{
		draw_rect(p.x, p.y, p.w, p.h, r, g, b, a);
		return;
	}

	void Graphics::draw_rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
	{
		SDL_Renderer* const renderer = window->get_renderer();

		// We'll be restoring the blend mode and colors back to what they were.
		SDL_BlendMode previous;
		uint8_t rgba[4];
		if(SDL_GetRenderDrawBlendMode(renderer, &previous) != 0) throw SDLException();
		if(SDL_GetRenderDrawColor(renderer, &rgba[0], &rgba[1], &rgba[2], &rgba[3]) != 0) throw SDLException();
		if(SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND) != 0) throw SDLException();
		if(SDL_SetRenderDrawColor(renderer, r, g, b, a) != 0) throw SDLException();

		SDL_Rect rect;
		rect.x = x;
		rect.y = y;
		rect.w = w;
		rect.h = h;
		if(SDL_RenderFillRect(renderer, &rect) != 0) throw SDLException();

		// Restore blend mode.
		if(SDL_SetRenderDrawBlendMode(renderer, previous) != 0) throw SDLException();
		if(SDL_SetRenderDrawColor(renderer, rgba[0], rgba[1], rgba[2], rgba[3]) != 0) throw SDLException();

		return;
	}

	void Graphics::clear()
	{
		window->clear();
		return;
	}

	void Graphics::refresh()
	{
		window->present();
		return;
	}
}
<commit_msg>Call SDL to change color.<commit_after>/*
  Hume Library
  Copyright (C) 2015 Marshall Clyburn

  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 "Graphics.h"

namespace hume
{
	Graphics::Graphics() : window(nullptr)
	{
		draw_color.r = draw_color.g = draw_color.b = 0;
		draw_color.a = SDL_ALPHA_OPAQUE;
	}

	Graphics::~Graphics()
	{
		if(window) delete window;
	}

	void Graphics::initialize()
	{
		const int types = IMG_INIT_JPG | IMG_INIT_PNG;
		int result = IMG_Init(types);
		if(result != types) throw SDLException();

		result = TTF_Init();
		if(result != 0) throw SDLTTFException();

		return;
	}

	void Graphics::shutdown()
	{
		IMG_Quit();
		TTF_Quit();

		return;
	}

	void Graphics::set_window(Window* const w)
	{
		window = w;
		return;
	}

	Window* Graphics::get_window() const
	{
		return window;
	}

	void Graphics::set_color(const uint8_t r, const uint8_t g, const uint8_t b, const uint8_t a)
	{
		draw_color.r = r;
		draw_color.g = g;
		draw_color.b = b;
		draw_color.a = a;

		if(SDL_SetRenderDrawColor(window->get_renderer(), r, g, b, a) != 0) throw SDLException();

		return;
	}

	void Graphics::set_color(const Color& color)
	{
		this->draw_color = color;
		if(SDL_SetRenderDrawColor(window->get_renderer(), color.r, color.g, color.b, color.a) != 0) throw SDLException();

		return;
	}

	Color Graphics::get_color() const
	{
		return draw_color;
	}

	Image* Graphics::load_image(const std::string& filename)
	{
		Image* image = new Image();
		image->open(filename, window->get_renderer());

		return image;
	}

	Image* Graphics::load_image(const std::string& filename, const Uint8 r, const Uint8 g, const Uint8 b)
	{
		Image* image = new Image(r, g, b);
		image->open(filename, window->get_renderer());

		return image;
	}

	void Graphics::draw(const Blittable* const b, const Properties& p)
	{
		window->draw(b, p);
		return;
	}

	void Graphics::draw_rect(const Properties& p, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
	{
		draw_rect(p.x, p.y, p.w, p.h, r, g, b, a);
		return;
	}

	void Graphics::draw_rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
	{
		SDL_Renderer* const renderer = window->get_renderer();

		// We'll be restoring the blend mode and colors back to what they were.
		SDL_BlendMode previous;
		uint8_t rgba[4];
		if(SDL_GetRenderDrawBlendMode(renderer, &previous) != 0) throw SDLException();
		if(SDL_GetRenderDrawColor(renderer, &rgba[0], &rgba[1], &rgba[2], &rgba[3]) != 0) throw SDLException();
		if(SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND) != 0) throw SDLException();
		if(SDL_SetRenderDrawColor(renderer, r, g, b, a) != 0) throw SDLException();

		SDL_Rect rect;
		rect.x = x;
		rect.y = y;
		rect.w = w;
		rect.h = h;
		if(SDL_RenderFillRect(renderer, &rect) != 0) throw SDLException();

		// Restore blend mode.
		if(SDL_SetRenderDrawBlendMode(renderer, previous) != 0) throw SDLException();
		if(SDL_SetRenderDrawColor(renderer, rgba[0], rgba[1], rgba[2], rgba[3]) != 0) throw SDLException();

		return;
	}

	void Graphics::clear()
	{
		window->clear();
		return;
	}

	void Graphics::refresh()
	{
		window->present();
		return;
	}
}
<|endoftext|>


<commit_before>//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//

#include "sys_dev_i2c_native_target.h"

// copied from esp-idf\components\driver\test\test_i2c.c because they aren't made available on a header
#define I2C_MASTER_TX_BUF_DISABLE 0
#define I2C_MASTER_RX_BUF_DISABLE 0
// I2C master will check ack from slave
#define ACK_CHECK_EN 0x1

typedef Library_sys_dev_i2c_native_System_Device_I2c_I2cConnectionSettings I2cConnectionSettings;
typedef Library_sys_dev_i2c_native_System_Device_I2c_I2cTransferResult I2cTransferResult;
typedef Library_corlib_native_System_SpanByte SpanByte;

static char Esp_I2C_Initialised_Flag[I2C_NUM_MAX] = {0, 0};

// need to declare these as external
// TODO move them here after Windows.Devices.I2c is removed
extern void Esp32_I2c_UnitializeAll();
extern bool SetConfig(i2c_port_t bus, CLR_RT_HeapBlock *config);

HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice::NativeInit___VOID(CLR_RT_StackFrame &stack)
{
    NANOCLR_HEADER();
    {
        CLR_RT_HeapBlock *pConfig;

        // get a pointer to the managed object instance and check that it's not NULL
        CLR_RT_HeapBlock *pThis = stack.This();
        FAULT_ON_NULL(pThis);

        // get a pointer to the managed spi connectionSettings object instance
        pConfig = pThis[FIELD___connectionSettings].Dereference();

        // get bus index
        // subtract 1 to get ESP32 bus number
        i2c_port_t bus = (i2c_port_t)(pConfig[I2cConnectionSettings::FIELD___busId].NumericByRef().s4 - 1);

        if (bus != I2C_NUM_0 && bus != I2C_NUM_1)
        {
            NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
        }

        // Set the Bus parameters
        if (!SetConfig(bus, pConfig))
        {
            NANOCLR_SET_AND_LEAVE(CLR_E_FAIL);
        }

        // If this is first device on Bus then init driver
        if (Esp_I2C_Initialised_Flag[bus] == 0)
        {
            // install driver in RAM to prevent issues with PSRAM cache
            esp_err_t res = i2c_driver_install(
                bus,
                I2C_MODE_MASTER,
                I2C_MASTER_RX_BUF_DISABLE,
                I2C_MASTER_TX_BUF_DISABLE,
                ESP_INTR_FLAG_IRAM);

            if (res != ESP_OK)
            {
                NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
            }

            // Ensure driver gets uninitialized during soft reboot
            HAL_AddSoftRebootHandler(Esp32_I2c_UnitializeAll);

            Esp_I2C_Initialised_Flag[bus]++;
        }
    }
    NANOCLR_NOCLEANUP();
}

HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice::NativeDispose___VOID(CLR_RT_StackFrame &stack)
{
    NANOCLR_HEADER();

    CLR_RT_HeapBlock *pConfig;
    i2c_port_t bus;

    // get a pointer to the managed object instance and check that it's not NULL
    CLR_RT_HeapBlock *pThis = stack.This();
    FAULT_ON_NULL(pThis);

    // get a pointer to the managed I2C connectionSettings object instance
    pConfig = pThis[FIELD___connectionSettings].Dereference();

    // get bus index
    // subtract 1 to get ESP32 bus number
    bus = (i2c_port_t)(pConfig[I2cConnectionSettings::FIELD___busId].NumericByRef().s4 - 1);

    Esp_I2C_Initialised_Flag[bus]--;

    if (Esp_I2C_Initialised_Flag[bus] <= 0)
    {
        i2c_driver_delete(bus);

        Esp_I2C_Initialised_Flag[bus] = 0;
    }

    NANOCLR_NOCLEANUP();
}

HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice::
    NativeTransmit___SystemDeviceI2cI2cTransferResult__SystemSpanByte__SystemSpanByte(CLR_RT_StackFrame &stack)
{
    NANOCLR_HEADER();

    uint8_t *writeBuffer = NULL;
    uint8_t *readBuffer = NULL;
    int writeOffset = 0;
    int writeSize = 0;
    int readOffset = 0;
    int readSize = 0;
    esp_err_t opResult;
    uint32_t transferResult;
    i2c_port_t bus;
    int slaveAddress;
    i2c_cmd_handle_t cmd;

    CLR_RT_HeapBlock *result;
    CLR_RT_HeapBlock *writeSpanByte;
    CLR_RT_HeapBlock *readSpanByte;
    CLR_RT_HeapBlock_Array *writeData = NULL;
    CLR_RT_HeapBlock_Array *readData = NULL;
    CLR_RT_HeapBlock *pConfig = NULL;

    // create the return object (I2cTransferResult)
    CLR_RT_HeapBlock &top = stack.PushValueAndClear();

    // get a pointer to the managed object instance and check that it's not NULL
    CLR_RT_HeapBlock *pThis = stack.This();
    FAULT_ON_NULL(pThis);

    // get a pointer to the managed I2C connectionSettings object instance
    pConfig = pThis[FIELD___connectionSettings].Dereference();

    // get bus index
    // subtract 1 to get ESP32 bus number
    bus = (i2c_port_t)(pConfig[I2cConnectionSettings::FIELD___busId].NumericByRef().s4 - 1);

    slaveAddress = pConfig[I2cConnectionSettings::FIELD___deviceAddress].NumericByRef().s4;

    // dereference the write and read SpanByte from the arguments
    writeSpanByte = stack.Arg1().Dereference();
    if (writeSpanByte != NULL)
    {
        writeData = writeSpanByte[SpanByte::FIELD___array].DereferenceArray();

        if (writeData != NULL)
        {
            // Get the write offset, only the elements defined by the span must be written, not the whole array
            writeOffset = writeSpanByte[SpanByte::FIELD___start].NumericByRef().s4;

            // use the span length as write size, only the elements defined by the span must be written
            writeSize = writeSpanByte[SpanByte::FIELD___length].NumericByRef().s4;

            // grab the pointer to the array by starting and the offset specified in the span
            writeBuffer = (uint8_t *)writeData->GetElement(writeOffset);
        }
    }

    readSpanByte = stack.Arg2().Dereference();
    if (readSpanByte != 0)
    {
        readData = readSpanByte[SpanByte::FIELD___array].DereferenceArray();

        if (readData != NULL)
        {
            // Get the read offset, only the elements defined by the span must be read, not the whole array
            readOffset = readSpanByte[SpanByte::FIELD___start].NumericByRef().s4;

            // use the span length as read size, only the elements defined by the span must be read
            readSize = readSpanByte[SpanByte::FIELD___length].NumericByRef().s4;

            // need to allocate buffer from internal memory to prevent
            readBuffer = (uint8_t *)heap_caps_malloc(readSize, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);

            if (readBuffer == NULL)
            {
                NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_MEMORY);
            }

            memset(readBuffer, 0, readSize);
        }
    }

    cmd = i2c_cmd_link_create();

    // handle write transaction,if any
    if (writeSize != 0)
    {
        i2c_master_start(cmd);
        i2c_master_write_byte(cmd, (slaveAddress << 1) | I2C_MASTER_WRITE, ACK_CHECK_EN);
        opResult = i2c_master_write(cmd, &writeBuffer[0], writeSize, true);

        ASSERT(opResult == ESP_OK);
    }

    // setup read transaction, if any
    if (readSize != 0)
    {
        i2c_master_start(cmd);
        i2c_master_write_byte(cmd, (slaveAddress << 1) | I2C_MASTER_READ, ACK_CHECK_EN);

        // read all bytes with ACK except the last one
        opResult = i2c_master_read(cmd, readBuffer, readSize, I2C_MASTER_LAST_NACK);

        ASSERT(opResult == ESP_OK);
    }

    i2c_master_stop(cmd);

    opResult = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);

    // create return object
    NANOCLR_CHECK_HRESULT(
        g_CLR_RT_ExecutionEngine.NewObjectFromIndex(top, g_CLR_RT_WellKnownTypes.m_I2cTransferResult));

    result = top.Dereference();

    FAULT_ON_NULL(result);

    if (opResult != ESP_OK)
    {
        transferResult = I2cTransferStatus_FullTransfer;

        // set the result field
        if (opResult == ESP_FAIL)
        {
            transferResult = I2cTransferStatus_SlaveAddressNotAcknowledged;
        }
        else if (opResult == ESP_ERR_TIMEOUT)
        {
            transferResult = I2cTransferStatus_ClockStretchTimeout;
        }
        else
        {
            transferResult = I2cTransferStatus_UnknownError;
        }

        result[I2cTransferResult::FIELD___status].SetInteger((CLR_UINT32)transferResult);

        // set the bytes transferred field
        result[I2cTransferResult::FIELD___bytesTransferred].SetInteger(0);
    }
    else
    {
        // was there a read operation?
        if (readSize > 0)
        {
            // grab the pointer to the array by starting and the offset specified in the span
            memcpy(readData->GetElement(readOffset), readBuffer, readSize);
        }

        result[I2cTransferResult::FIELD___status].SetInteger((CLR_UINT32)I2cTransferStatus_FullTransfer);

        // set the bytes transferred field
        result[I2cTransferResult::FIELD___bytesTransferred].SetInteger((CLR_UINT32)(writeSize + readSize));
    }

    NANOCLR_CLEANUP();

    if (readBuffer)
    {
        platform_free(readBuffer);
    }

    NANOCLR_CLEANUP_END();
}
<commit_msg>Improvements in I2C handling (#2106)<commit_after>//
// Copyright (c) .NET Foundation and Contributors
// See LICENSE file in the project root for full license information.
//

#include "sys_dev_i2c_native_target.h"

// copied from esp-idf\components\driver\test\test_i2c.c because they aren't made available on a header
#define I2C_MASTER_TX_BUF_DISABLE 0
#define I2C_MASTER_RX_BUF_DISABLE 0
// I2C master will check ack from slave
#define ACK_CHECK_EN 0x1

typedef Library_sys_dev_i2c_native_System_Device_I2c_I2cConnectionSettings I2cConnectionSettings;
typedef Library_sys_dev_i2c_native_System_Device_I2c_I2cTransferResult I2cTransferResult;
typedef Library_corlib_native_System_SpanByte SpanByte;

static char Esp_I2C_Initialised_Flag[I2C_NUM_MAX] = {0, 0};

// need to declare these as external
// TODO move them here after Windows.Devices.I2c is removed
extern void Esp32_I2c_UnitializeAll();
extern bool SetConfig(i2c_port_t bus, CLR_RT_HeapBlock *config);

HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice::NativeInit___VOID(CLR_RT_StackFrame &stack)
{
    NANOCLR_HEADER();
    {
        CLR_RT_HeapBlock *pConfig;

        // get a pointer to the managed object instance and check that it's not NULL
        CLR_RT_HeapBlock *pThis = stack.This();
        FAULT_ON_NULL(pThis);

        // get a pointer to the managed spi connectionSettings object instance
        pConfig = pThis[FIELD___connectionSettings].Dereference();

        // get bus index
        // subtract 1 to get ESP32 bus number
        i2c_port_t bus = (i2c_port_t)(pConfig[I2cConnectionSettings::FIELD___busId].NumericByRef().s4 - 1);

        if (bus != I2C_NUM_0 && bus != I2C_NUM_1)
        {
            NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
        }

        // Set the Bus parameters
        if (!SetConfig(bus, pConfig))
        {
            NANOCLR_SET_AND_LEAVE(CLR_E_FAIL);
        }

        // If this is first device on Bus then init driver
        if (Esp_I2C_Initialised_Flag[bus] == 0)
        {
            // install driver in RAM to prevent issues with PSRAM cache
            esp_err_t res = i2c_driver_install(
                bus,
                I2C_MODE_MASTER,
                I2C_MASTER_RX_BUF_DISABLE,
                I2C_MASTER_TX_BUF_DISABLE,
                ESP_INTR_FLAG_IRAM);

            if (res != ESP_OK)
            {
                NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
            }

            // Ensure driver gets uninitialized during soft reboot
            HAL_AddSoftRebootHandler(Esp32_I2c_UnitializeAll);

            Esp_I2C_Initialised_Flag[bus]++;
        }
    }
    NANOCLR_NOCLEANUP();
}

HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice::NativeDispose___VOID(CLR_RT_StackFrame &stack)
{
    NANOCLR_HEADER();

    CLR_RT_HeapBlock *pConfig;
    i2c_port_t bus;

    // get a pointer to the managed object instance and check that it's not NULL
    CLR_RT_HeapBlock *pThis = stack.This();
    FAULT_ON_NULL(pThis);

    // get a pointer to the managed I2C connectionSettings object instance
    pConfig = pThis[FIELD___connectionSettings].Dereference();

    // get bus index
    // subtract 1 to get ESP32 bus number
    bus = (i2c_port_t)(pConfig[I2cConnectionSettings::FIELD___busId].NumericByRef().s4 - 1);

    Esp_I2C_Initialised_Flag[bus]--;

    if (Esp_I2C_Initialised_Flag[bus] <= 0)
    {
        i2c_driver_delete(bus);

        Esp_I2C_Initialised_Flag[bus] = 0;
    }

    NANOCLR_NOCLEANUP();
}

HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice::
    NativeTransmit___SystemDeviceI2cI2cTransferResult__SystemSpanByte__SystemSpanByte(CLR_RT_StackFrame &stack)
{
    NANOCLR_HEADER();

    uint8_t *writeBuffer = NULL;
    uint8_t *readBuffer = NULL;
    int writeOffset = 0;
    int writeSize = 0;
    int readOffset = 0;
    int readSize = 0;
    esp_err_t opResult;
    uint32_t transferResult;
    i2c_port_t bus;
    int slaveAddress;
    i2c_cmd_handle_t cmd;

    CLR_RT_HeapBlock *result;
    CLR_RT_HeapBlock *writeSpanByte;
    CLR_RT_HeapBlock *readSpanByte;
    CLR_RT_HeapBlock_Array *writeData = NULL;
    CLR_RT_HeapBlock_Array *readData = NULL;
    CLR_RT_HeapBlock *pConfig = NULL;

    // create the return object (I2cTransferResult)
    CLR_RT_HeapBlock &top = stack.PushValueAndClear();

    // get a pointer to the managed object instance and check that it's not NULL
    CLR_RT_HeapBlock *pThis = stack.This();
    FAULT_ON_NULL(pThis);

    // get a pointer to the managed I2C connectionSettings object instance
    pConfig = pThis[FIELD___connectionSettings].Dereference();

    // get bus index
    // subtract 1 to get ESP32 bus number
    bus = (i2c_port_t)(pConfig[I2cConnectionSettings::FIELD___busId].NumericByRef().s4 - 1);

    slaveAddress = pConfig[I2cConnectionSettings::FIELD___deviceAddress].NumericByRef().s4;

    cmd = i2c_cmd_link_create();

    // dereference the write and read SpanByte from the arguments
    writeSpanByte = stack.Arg1().Dereference();
    if (writeSpanByte != NULL)
    {
        writeData = writeSpanByte[SpanByte::FIELD___array].DereferenceArray();

        if (writeData != NULL)
        {
            // Get the write offset, only the elements defined by the span must be written, not the whole array
            writeOffset = writeSpanByte[SpanByte::FIELD___start].NumericByRef().s4;

            // use the span length as write size, only the elements defined by the span must be written
            writeSize = writeSpanByte[SpanByte::FIELD___length].NumericByRef().s4;

            if (writeSize > 0)
            {
                // need to allocate buffer from internal memory
                writeBuffer = (uint8_t *)heap_caps_malloc(writeSize, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);

                if (writeBuffer == NULL)
                {
                    NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_MEMORY);
                }

                // copy buffer content
                memcpy(writeBuffer, (uint8_t *)writeData->GetElement(writeOffset), writeSize);

                // setup write transaction
                i2c_master_start(cmd);
                i2c_master_write_byte(cmd, (slaveAddress << 1) | I2C_MASTER_WRITE, ACK_CHECK_EN);
                opResult = i2c_master_write(cmd, writeBuffer, writeSize, true);

                ASSERT(opResult == ESP_OK);
            }
        }
    }

    readSpanByte = stack.Arg2().Dereference();
    if (readSpanByte != 0)
    {
        readData = readSpanByte[SpanByte::FIELD___array].DereferenceArray();

        if (readData != NULL)
        {
            // Get the read offset, only the elements defined by the span must be read, not the whole array
            readOffset = readSpanByte[SpanByte::FIELD___start].NumericByRef().s4;

            // use the span length as read size, only the elements defined by the span must be read
            readSize = readSpanByte[SpanByte::FIELD___length].NumericByRef().s4;

            if (readSize > 0)
            {
                // need to allocate buffer from internal memory
                readBuffer = (uint8_t *)heap_caps_malloc(readSize, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);

                if (readBuffer == NULL)
                {
                    NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_MEMORY);
                }

                // clear allocated buffer
                memset(readBuffer, 0, readSize);

                // setup read transaction
                i2c_master_start(cmd);
                i2c_master_write_byte(cmd, (slaveAddress << 1) | I2C_MASTER_READ, ACK_CHECK_EN);

                // read all bytes with ACK except the last one
                opResult = i2c_master_read(cmd, readBuffer, readSize, I2C_MASTER_LAST_NACK);

                ASSERT(opResult == ESP_OK);
            }
        }
    }

    i2c_master_stop(cmd);

    opResult = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);

    // create return object
    NANOCLR_CHECK_HRESULT(
        g_CLR_RT_ExecutionEngine.NewObjectFromIndex(top, g_CLR_RT_WellKnownTypes.m_I2cTransferResult));

    result = top.Dereference();

    FAULT_ON_NULL(result);

    if (opResult != ESP_OK)
    {
        // set the result field
        if (opResult == ESP_FAIL)
        {
            transferResult = I2cTransferStatus_SlaveAddressNotAcknowledged;
        }
        else if (opResult == ESP_ERR_TIMEOUT)
        {
            transferResult = I2cTransferStatus_ClockStretchTimeout;
        }
        else
        {
            transferResult = I2cTransferStatus_UnknownError;
        }

        result[I2cTransferResult::FIELD___status].SetInteger((CLR_UINT32)transferResult);

        // set the bytes transferred field
        result[I2cTransferResult::FIELD___bytesTransferred].SetInteger(0);
    }
    else
    {
        // was there a read operation?
        if (readSize > 0)
        {
            // grab the pointer to the array by starting and the offset specified in the span
            memcpy(readData->GetElement(readOffset), readBuffer, readSize);
        }

        result[I2cTransferResult::FIELD___status].SetInteger((CLR_UINT32)I2cTransferStatus_FullTransfer);

        // set the bytes transferred field
        result[I2cTransferResult::FIELD___bytesTransferred].SetInteger((CLR_UINT32)(writeSize + readSize));
    }

    NANOCLR_CLEANUP();

    if (writeBuffer)
    {
        platform_free(writeBuffer);
    }

    if (readBuffer)
    {
        platform_free(readBuffer);
    }

    NANOCLR_CLEANUP_END();
}
<|endoftext|>