<commit_before>/*

Copyright (c) 2006, Arvid Norberg & Daniel Wallin
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 the author 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 THE COPYRIGHT OWNER 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 "libtorrent/pch.hpp"

#include <libtorrent/kademlia/closest_nodes.hpp>
#include <libtorrent/kademlia/routing_table.hpp>
#include <libtorrent/kademlia/rpc_manager.hpp>
#include "libtorrent/assert.hpp"

namespace libtorrent { namespace dht
{

using asio::ip::udp;

closest_nodes_observer::~closest_nodes_observer()
{
	if (m_algorithm) m_algorithm->failed(m_self, true);
}

void closest_nodes_observer::reply(msg const& in)
{
	if (!m_algorithm)
	{
		TORRENT_ASSERT(false);
		return;
	}

	if (!in.nodes.empty())
	{
		for (msg::nodes_t::const_iterator i = in.nodes.begin()
			, end(in.nodes.end()); i != end; ++i)
		{
			m_algorithm->traverse(i->id, i->addr);
		}
	}
	m_algorithm->finished(m_self);
	m_algorithm = 0;
}

void closest_nodes_observer::timeout()
{
	if (!m_algorithm) return;
	m_algorithm->failed(m_self);
	m_algorithm = 0;
}

closest_nodes::closest_nodes(
	node_id target
	, int branch_factor
	, int max_results
	, routing_table& table
	, rpc_manager& rpc
	, done_callback const& callback
)
	: traversal_algorithm(
		target
		, branch_factor
		, max_results
		, table
		, rpc
		, table.begin()
		, table.end()
	)
	, m_done_callback(callback)
{
	boost::intrusive_ptr<closest_nodes> self(this);
	add_requests();
}

void closest_nodes::invoke(node_id const& id, udp::endpoint addr)
{
	TORRENT_ASSERT(m_rpc.allocation_size() >= sizeof(closest_nodes_observer));
	observer_ptr o(new (m_rpc.allocator().malloc()) closest_nodes_observer(this, id, m_target));
#ifndef NDEBUG
	o->m_in_constructor = false;
#endif
	m_rpc.invoke(messages::find_node, addr, o);
}

void closest_nodes::done()
{
	std::vector<node_entry> results;
	int num_results = m_max_results;
	for (std::vector<result>::iterator i = m_results.begin()
		, end(m_results.end()); i != end && num_results >= 0; ++i)
	{
		if (i->flags & result::no_id) continue;
		if ((i->flags & result::queried) == 0) continue;
		results.push_back(node_entry(i->id, i->addr));
		--num_results;
	}
	m_done_callback(results);
}

void closest_nodes::initiate(
	node_id target
	, int branch_factor
	, int max_results
	, routing_table& table
	, rpc_manager& rpc
	, done_callback const& callback
)
{
	new closest_nodes(target, branch_factor, max_results, table, rpc, callback);
}

} } // namespace libtorrent::dht

<commit_msg>minor dht fix<commit_after>/*

Copyright (c) 2006, Arvid Norberg & Daniel Wallin
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 the author 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 THE COPYRIGHT OWNER 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 "libtorrent/pch.hpp"

#include <libtorrent/kademlia/closest_nodes.hpp>
#include <libtorrent/kademlia/routing_table.hpp>
#include <libtorrent/kademlia/rpc_manager.hpp>
#include "libtorrent/assert.hpp"

namespace libtorrent { namespace dht
{

using asio::ip::udp;

closest_nodes_observer::~closest_nodes_observer()
{
	if (m_algorithm) m_algorithm->failed(m_self, true);
}

void closest_nodes_observer::reply(msg const& in)
{
	if (!m_algorithm)
	{
		TORRENT_ASSERT(false);
		return;
	}

	if (!in.nodes.empty())
	{
		for (msg::nodes_t::const_iterator i = in.nodes.begin()
			, end(in.nodes.end()); i != end; ++i)
		{
			m_algorithm->traverse(i->id, i->addr);
		}
	}
	m_algorithm->finished(m_self);
	m_algorithm = 0;
}

void closest_nodes_observer::timeout()
{
	if (!m_algorithm) return;
	m_algorithm->failed(m_self);
	m_algorithm = 0;
}

closest_nodes::closest_nodes(
	node_id target
	, int branch_factor
	, int max_results
	, routing_table& table
	, rpc_manager& rpc
	, done_callback const& callback
)
	: traversal_algorithm(
		target
		, branch_factor
		, max_results
		, table
		, rpc
		, table.begin()
		, table.end()
	)
	, m_done_callback(callback)
{
	boost::intrusive_ptr<closest_nodes> self(this);
	add_requests();
}

void closest_nodes::invoke(node_id const& id, udp::endpoint addr)
{
	TORRENT_ASSERT(m_rpc.allocation_size() >= sizeof(closest_nodes_observer));
	observer_ptr o(new (m_rpc.allocator().malloc()) closest_nodes_observer(this, id, m_target));
#ifndef NDEBUG
	o->m_in_constructor = false;
#endif
	m_rpc.invoke(messages::find_node, addr, o);
}

void closest_nodes::done()
{
	std::vector<node_entry> results;
	int num_results = m_max_results;
	for (std::vector<result>::iterator i = m_results.begin()
		, end(m_results.end()); i != end && num_results > 0; ++i)
	{
		if (i->flags & result::no_id) continue;
		if ((i->flags & result::queried) == 0) continue;
		results.push_back(node_entry(i->id, i->addr));
		--num_results;
	}
	m_done_callback(results);
}

void closest_nodes::initiate(
	node_id target
	, int branch_factor
	, int max_results
	, routing_table& table
	, rpc_manager& rpc
	, done_callback const& callback
)
{
	new closest_nodes(target, branch_factor, max_results, table, rpc, callback);
}

} } // namespace libtorrent::dht

<|endoftext|>


<commit_before><commit_msg>Changed mail -> messages where appropriate. I didn't change the "mail"s in the DnD configuration as those will be removed anyway.<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.

#include "util/arena.h"

#include "util/random.h"
#include "util/testharness.h"

namespace leveldb {

class ArenaTest { };

TEST(ArenaTest, Empty) {
  Arena arena;
}

TEST(ArenaTest, Simple) {
  std::vector<std::pair<size_t, char*> > allocated;
  Arena arena;
  const int N = 100000;
  size_t bytes = 0;
  Random rnd(301);
  for (int i = 0; i < N; i++) {
    size_t s;
    if (i % (N / 10) == 0) {
      s = i;
    } else {
      s = rnd.OneIn(4000) ? rnd.Uniform(6000) :
          (rnd.OneIn(10) ? rnd.Uniform(100) : rnd.Uniform(20));
    }
    if (s == 0) {
      // Our arena disallows size 0 allocations.
      s = 1;
    }
    char* r;
    if (rnd.OneIn(10)) {
      r = arena.AllocateAligned(s);
    } else {
      r = arena.Allocate(s);
    }

    for (size_t b = 0; b < s; b++) {
      // Fill the "i"th allocation with a known bit pattern
      r[b] = i % 256;
    }
    bytes += s;
    allocated.push_back(std::make_pair(s, r));
    ASSERT_GE(arena.MemoryUsage(), bytes);
    if (i > N/10) {
      ASSERT_LE(arena.MemoryUsage(), bytes * 1.10);
    }
  }
  for (size_t i = 0; i < allocated.size(); i++) {
    size_t num_bytes = allocated[i].first;
    const char* p = allocated[i].second;
    for (size_t b = 0; b < num_bytes; b++) {
      // Check the "i"th allocation for the known bit pattern
      ASSERT_EQ(int(p[b]) & 0xff, i % 256);
    }
  }
}

}  // namespace leveldb

int main(int argc, char** argv) {
  return leveldb::test::RunAllTests();
}
<commit_msg>Update arena_test.cc<commit_after>// Copyright (c) 2017 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.

#include "util/arena.h"

#include "util/random.h"
#include "util/testharness.h"

namespace leveldb {

class ArenaTest { };

TEST(ArenaTest, Empty) {
  Arena arena;
}

TEST(ArenaTest, Simple) {
  std::vector<std::pair<size_t, char*> > allocated;
  Arena arena;
  const int N = 100000;
  size_t bytes = 0;
  Random rnd(301);
  for (int i = 0; i < N; i++) {
    size_t s;
    if (i % (N / 10) == 0) {
      s = i;
    } else {
      s = rnd.OneIn(4000) ? rnd.Uniform(6000) :
          (rnd.OneIn(10) ? rnd.Uniform(100) : rnd.Uniform(20));
    }
    if (s == 0) {
      // Our arena disallows size 0 allocations.
      s = 1;
    }
    char* r;
    if (rnd.OneIn(10)) {
      r = arena.AllocateAligned(s);
    } else {
      r = arena.Allocate(s);
    }

    for (size_t b = 0; b < s; b++) {
      // Fill the "i"th allocation with a known bit pattern
      r[b] = i % 256;
    }
    bytes += s;
    allocated.push_back(std::make_pair(s, r));
    ASSERT_GE(arena.MemoryUsage(), bytes);
    if (i > N/10) {
      ASSERT_LE(arena.MemoryUsage(), bytes * 1.10);
    }
  }
  for (size_t i = 0; i < allocated.size(); i++) {
    size_t num_bytes = allocated[i].first;
    const char* p = allocated[i].second;
    for (size_t b = 0; b < num_bytes; b++) {
      // Check the "i"th allocation for the known bit pattern
      ASSERT_EQ(int(p[b]) & 0xff, i % 256);
    }
  }
}

}  // namespace leveldb

int main(int argc, char** argv) {
  return leveldb::test::RunAllTests();
}
<|endoftext|>


<commit_before>#include "LiveMediaExtPch.h"
#include <LiveMediaExt/LiveH264Subsession.h>
#include <LiveMediaExt/LiveDeviceSource.h>
#include <LiveMediaExt/LiveH264VideoDeviceSource.h>
#include <H264VideoRTPSink.hh>
#include "Base64.hh"
#include "H264VideoStreamDiscreteFramer.hh"

namespace lme
{

LiveH264Subsession::LiveH264Subsession( UsageEnvironment& env, LiveRtspServer& rParent,
                                        const unsigned uiChannelId, unsigned uiSourceId,
                                        const std::string& sSessionName,
                                        const std::string& sSps, const std::string& sPps,
                                        IRateAdaptationFactory* pFactory,
                                        IRateController* pGlobalRateControl)
  :LiveMediaSubsession(env, rParent, uiChannelId, uiSourceId, sSessionName, true, 1, pFactory, pGlobalRateControl),
  m_sSps(sSps),
  m_sPps(sPps),
  fAuxSDPLine(NULL),
  fFmtpSDPLine(NULL)
{
  VLOG(2) << "LiveH264Subsession() SPS: " << m_sSps << " PPS: " << m_sPps;
}

LiveH264Subsession::~LiveH264Subsession()
{
  delete[] fAuxSDPLine;
  delete[] fFmtpSDPLine;
}

FramedSource* LiveH264Subsession::createSubsessionSpecificSource(unsigned clientSessionId,
                                                                 IMediaSampleBuffer* pMediaSampleBuffer,
                                                                 IRateAdaptationFactory* pRateAdaptationFactory,
                                                                 IRateController* pRateControl)
{
  FramedSource* pLiveDeviceSource = LiveH264VideoDeviceSource::createNew(envir(), clientSessionId, this, m_sSps, m_sPps,
                                                                         pMediaSampleBuffer, pRateAdaptationFactory, pRateControl);
  // wrap framer around our device source
  H264VideoStreamDiscreteFramer* pFramer = H264VideoStreamDiscreteFramer::createNew(envir(), pLiveDeviceSource);
  return pFramer;
}

void LiveH264Subsession::setEstimatedBitRate(unsigned& estBitrate)
{
	// Set estimated session band width
	estBitrate = 1000;
}

RTPSink* LiveH264Subsession::createSubsessionSpecificRTPSink( Groupsock* rtpGroupsock, unsigned char rtpPayloadTypeIfDynamic, FramedSource* inputSource )
{
  // HACKERY
  std::string sPropParameterSets = m_sSps + "," + m_sPps;
  H264VideoRTPSink* pSink = H264VideoRTPSink::createNew(envir(), rtpGroupsock, rtpPayloadTypeIfDynamic, sPropParameterSets.c_str());
	pSink->setPacketSizes(1000, 1400);
	return pSink;
}

char const* LiveH264Subsession::getAuxSDPLine( RTPSink* rtpSink, FramedSource* inputSource )
{
  const char* sps = m_sSps.c_str();
  unsigned spsSize = m_sSps.length();

  const char* pps = m_sPps.c_str();
  unsigned ppsSize = m_sPps.length();

  u_int32_t profile_level_id;
  if (spsSize < 4) { // sanity check
    profile_level_id = 0;
  } else {
    profile_level_id = (sps[1]<<16)|(sps[2]<<8)|sps[3]; // profile_idc|constraint_setN_flag|level_idc
  }

  // The parameter sets are base64 encoded already
  // Set up the "a=fmtp:" SDP line for this stream:
  char const* fmtpFmt =
    "a=fmtp:%d packetization-mode=1"
    ";profile-level-id=%06X"
    ";sprop-parameter-sets=%s,%s\r\n";
  unsigned fmtpFmtSize = strlen(fmtpFmt)
    + 3 /* max char len */
    + 6 /* 3 bytes in hex */
    + spsSize + ppsSize;
  char* fmtp = new char[fmtpFmtSize];
  sprintf(fmtp, fmtpFmt,
    rtpSink->rtpPayloadType(),
    profile_level_id,
    sps, pps);

  delete[] fFmtpSDPLine; fFmtpSDPLine = fmtp;
  return fFmtpSDPLine;
}

} // lme
<commit_msg>Reduced est bitrate to 500kbps<commit_after>#include "LiveMediaExtPch.h"
#include <LiveMediaExt/LiveH264Subsession.h>
#include <LiveMediaExt/LiveDeviceSource.h>
#include <LiveMediaExt/LiveH264VideoDeviceSource.h>
#include <H264VideoRTPSink.hh>
#include "Base64.hh"
#include "H264VideoStreamDiscreteFramer.hh"

namespace lme
{

LiveH264Subsession::LiveH264Subsession( UsageEnvironment& env, LiveRtspServer& rParent,
                                        const unsigned uiChannelId, unsigned uiSourceId,
                                        const std::string& sSessionName,
                                        const std::string& sSps, const std::string& sPps,
                                        IRateAdaptationFactory* pFactory,
                                        IRateController* pGlobalRateControl)
  :LiveMediaSubsession(env, rParent, uiChannelId, uiSourceId, sSessionName, true, 1, pFactory, pGlobalRateControl),
  m_sSps(sSps),
  m_sPps(sPps),
  fAuxSDPLine(NULL),
  fFmtpSDPLine(NULL)
{
  VLOG(2) << "LiveH264Subsession() SPS: " << m_sSps << " PPS: " << m_sPps;
}

LiveH264Subsession::~LiveH264Subsession()
{
  delete[] fAuxSDPLine;
  delete[] fFmtpSDPLine;
}

FramedSource* LiveH264Subsession::createSubsessionSpecificSource(unsigned clientSessionId,
                                                                 IMediaSampleBuffer* pMediaSampleBuffer,
                                                                 IRateAdaptationFactory* pRateAdaptationFactory,
                                                                 IRateController* pRateControl)
{
  FramedSource* pLiveDeviceSource = LiveH264VideoDeviceSource::createNew(envir(), clientSessionId, this, m_sSps, m_sPps,
                                                                         pMediaSampleBuffer, pRateAdaptationFactory, pRateControl);
  // wrap framer around our device source
  H264VideoStreamDiscreteFramer* pFramer = H264VideoStreamDiscreteFramer::createNew(envir(), pLiveDeviceSource);
  return pFramer;
}

void LiveH264Subsession::setEstimatedBitRate(unsigned& estBitrate)
{
	// Set estimated bitrate in kbps
	estBitrate = 500;
}

RTPSink* LiveH264Subsession::createSubsessionSpecificRTPSink( Groupsock* rtpGroupsock, unsigned char rtpPayloadTypeIfDynamic, FramedSource* inputSource )
{
  // HACKERY
  std::string sPropParameterSets = m_sSps + "," + m_sPps;
  H264VideoRTPSink* pSink = H264VideoRTPSink::createNew(envir(), rtpGroupsock, rtpPayloadTypeIfDynamic, sPropParameterSets.c_str());
	pSink->setPacketSizes(1000, 1400);
	return pSink;
}

char const* LiveH264Subsession::getAuxSDPLine( RTPSink* rtpSink, FramedSource* inputSource )
{
  const char* sps = m_sSps.c_str();
  unsigned spsSize = m_sSps.length();

  const char* pps = m_sPps.c_str();
  unsigned ppsSize = m_sPps.length();

  u_int32_t profile_level_id;
  if (spsSize < 4) { // sanity check
    profile_level_id = 0;
  } else {
    profile_level_id = (sps[1]<<16)|(sps[2]<<8)|sps[3]; // profile_idc|constraint_setN_flag|level_idc
  }

  // The parameter sets are base64 encoded already
  // Set up the "a=fmtp:" SDP line for this stream:
  char const* fmtpFmt =
    "a=fmtp:%d packetization-mode=1"
    ";profile-level-id=%06X"
    ";sprop-parameter-sets=%s,%s\r\n";
  unsigned fmtpFmtSize = strlen(fmtpFmt)
    + 3 /* max char len */
    + 6 /* 3 bytes in hex */
    + spsSize + ppsSize;
  char* fmtp = new char[fmtpFmtSize];
  sprintf(fmtp, fmtpFmt,
    rtpSink->rtpPayloadType(),
    profile_level_id,
    sps, pps);

  delete[] fFmtpSDPLine; fFmtpSDPLine = fmtp;
  return fFmtpSDPLine;
}

} // lme
<|endoftext|>


<commit_before>/**
\file ll_translation_control.hpp
\brief Defines class LLTranslationControl and defines its methods.
\author Radek Vít
*/
#ifndef CTF_LL_TRANSLATION_CONTROL_H
#define CTF_LL_TRANSLATION_CONTROL_H

#include "translation_control.hpp"

namespace ctf {

/**
\brief Implements LL top down translation control.
*/
class LLTranslationControl : public TranslationControl {
 protected:
  /**
  \brief Empty set for each nonterminal.
  */
  vector<bool> empty_;
  /**
  \brief First set for each nonterminal.
  */
  vector<vector<Symbol>> first_;
  /**
  \brief Follow set for each nonterminal.
  */
  vector<vector<Symbol>> follow_;
  /**
  \brief Predict set for each nonterminal.
  */
  vector<vector<Symbol>> predict_;

  /**
  \brief LL table used to control the translation.
  */
  LLTable llTable_;

  /**
  \brief Error message string.
  */
  string errorString_;

  /**
  \brief The last expanded nonterminal.
  */
  Symbol lastNonterminal_ = Symbol::eof();

  /**
  Creates all predictive sets and creates a new LL table.
  */
  void create_ll_table() {
    create_empty();
    create_first();
    create_follow();
    create_predict();

    llTable_ = LLTable(*translationGrammar_, predict_);
  }

  /**
  \brief Creates Empty set for each nonterminal.

  Empty is true if a series of productions from the nonterminal can result in an
  empty string.
  */
  void create_empty() {
    const TranslationGrammar &tg = *translationGrammar_;
    empty_ = vector<bool>(tg.nonterminals().size(), false);

    for (auto &r : tg.rules()) {
      if (r.input().size() == 0) {
        empty_[tg.nonterminal_index(r.nonterminal())] = true;
      }
    }

    bool changed = false;
    do {
      changed = false;
      for (auto &r : tg.rules()) {
        bool isempty = true;
        for (auto &s : r.input()) {
          switch (s.type()) {
            case Symbol::Type::TERMINAL:
              isempty = false;
              break;
            case Symbol::Type::NONTERMINAL:
              if (empty_[tg.nonterminal_index(s)] == false) {
                isempty = false;
              }
              break;
            default:
              break;
          }
        }
        if (isempty) {
          if (!empty_[tg.nonterminal_index(r.nonterminal())]) {
            changed = true;
            empty_[tg.nonterminal_index(r.nonterminal())] = true;
          }
        }
      }
    } while (changed);
  }
  /**
  \brief Creates First set for each nonterminal.

  First contains all characters that can be at the first position of any string
  derived from this nonterminal.
  */
  void create_first() {
    const TranslationGrammar &tg = *translationGrammar_;
    first_ = {tg.nonterminals().size(), vector<Symbol>{}};

    bool changed = false;
    do {
      changed = false;
      for (auto &r : tg.rules()) {
        size_t i = tg.nonterminal_index(r.nonterminal());
        bool empty = true;
        for (auto &symbol : r.input()) {
          if (!empty)
            break;
          size_t nonterm_i;
          switch (symbol.type()) {
            case Symbol::Type::NONTERMINAL:
              nonterm_i = tg.nonterminal_index(symbol);
              if (modify_set(first_[i], first_[nonterm_i]))
                changed = true;
              empty = empty_[nonterm_i];
              break;
            case Symbol::Type::TERMINAL:
              if (modify_set(first_[i], vector<Symbol>({symbol})))
                changed = true;
              empty = false;
              break;
            default:
              break;
          }
        }
      }
    } while (changed);
  }
  /**
  \brief Creates Follow set for each nonterminal.

  Follow contains all characters that may follow that nonterminal in a
  sentential form from the starting nonterminal.
  */
  void create_follow() {
    const TranslationGrammar &tg = *translationGrammar_;
    follow_ = {tg.nonterminals().size(), vector<Symbol>{}};
    follow_[tg.nonterminal_index(tg.starting_symbol())].push_back(
        Symbol::eof());

    bool changed = false;
    do {
      changed = false;
      for (auto &r : tg.rules()) {
        // index of origin nonterminal
        size_t i = tg.nonterminal_index(r.nonterminal());
        /* empty set of all symbols to the right of the current one */
        bool compoundEmpty = true;
        /* first set of all symbols to the right of the current symbol */
        vector<Symbol> compoundFirst;
        /* track symbols from back */
        for (auto &s : reverse(r.input())) {
          // index of nonterminal in input string, only valid with
          // nonterminal symbol
          size_t ti = 0;
          switch (s.type()) {
            case Symbol::Type::NONTERMINAL:
              ti = tg.nonterminal_index(s);
              if (modify_set(follow_[ti], compoundFirst))
                changed = true;
              if (compoundEmpty && modify_set(follow_[ti], follow_[i]))
                changed = true;
              break;
            default:
              break;
          }
          /* if empty = false */
          if (s.type() != Symbol::Type::NONTERMINAL ||
              !empty_[tg.nonterminal_index(s)]) {
            compoundEmpty = false;
            switch (s.type()) {
              case Symbol::Type::NONTERMINAL:
                compoundFirst = first_[ti];
                break;
              case Symbol::Type::TERMINAL:
                compoundFirst = {s};
                break;
              default:
                break;
            }
          }
          /* empty = true, nonterminal*/
          else {
            modify_set(compoundFirst, first_[ti]);
          }
        }  // for all reverse input
      }    // for all rules
    } while (changed);
  }
  /**
  \brief Creates Predict set for each nonterminal.

  Predict contains all Terminals that may be the first terminal read in a
  sentential form from that nonterminal.
  */
  void create_predict() {
    predict_.clear();
    const TranslationGrammar &tg = *translationGrammar_;
    for (auto &r : tg.rules()) {
      vector<Symbol> compoundFirst;
      vector<Symbol> rfollow = follow_[tg.nonterminal_index(r.nonterminal())];
      bool compoundEmpty = true;
      for (auto &s : reverse(r.input())) {
        size_t i;
        switch (s.type()) {
          case Symbol::Type::TERMINAL:
            compoundEmpty = false;
            compoundFirst = vector<Symbol>({s});
            break;
          case Symbol::Type::NONTERMINAL:
            i = tg.nonterminal_index(s);
            if (!empty_[i]) {
              compoundEmpty = false;
              compoundFirst = first_[i];
            } else {
              modify_set(compoundFirst, first_[i]);
            }
          default:
            break;
        }
      }
      predict_.push_back(compoundFirst);

      if (compoundEmpty) {
        modify_set(predict_.back(), rfollow);
      }
    }  // for all rules
  }

  /**
  \brief Creates iterator attribute actions for incoming terminals.

  \param[in] obegin Iterator to the first Symbol of the output of the applied
  Rule.
  \param[in] targets Indices of the target actions for all input terminals.
  \param[out] attributeActions Targets to append incoming terminal's attributes.

  The added iterators point to input terminal attribute targets.
  */
  void create_attibute_actions(
      tstack<Symbol>::iterator obegin, const vector<set<size_t>> &targets,
      tstack<vector<tstack<Symbol>::iterator>> &attributeActions) {
    for (auto &target : reverse(targets)) {
      vector<tstack<Symbol>::iterator> iterators;
      for (auto &i : target) {
        auto oit = obegin;
        for (size_t x = 0; x < i; ++x)
          ++oit;
        if (oit->type() == Symbol::Type::TERMINAL)
          iterators.push_back(oit);
      }
      attributeActions.push(iterators);
    }
  }

 public:
  /**
  \brief Constructs a LLTranslationControl.
  */
  LLTranslationControl() = default;
  /**
  \brief Default destructor.
  */
  virtual ~LLTranslationControl() = default;
  /**
  \brief Constructs LLTranslationControl with a LexicalAnalyzer and
  TranslationGrammar.

  \param[in] la A reference to the lexical analyzer to be used to get tokens.
  \param[in] tg The translation grammar for this translation.
  */
  LLTranslationControl(LexicalAnalyzer &la, TranslationGrammar &tg) {
    set_grammar(tg);
    set_lexical_analyzer(la);
  }

  /**
  \brief Sets translation grammar.

  \param[in] tg The translation grammar for this translation.
  */
  virtual void set_grammar(const TranslationGrammar &tg) {
    translationGrammar_ = &tg;
    create_ll_table();
  }

  /**
  \brief Runs the translation. Output symbols are stored in output_.
  */
  virtual void run() {
    using Type = Symbol::Type;

    if (!lexicalAnalyzer_)
      throw TranslationException("No lexical analyzer was attached.");
    else if (!translationGrammar_)
      throw TranslationException("No translation grammar was attached.");

    input_.clear();
    output_.clear();
    tstack<vector<tstack<Symbol>::iterator>> attributeActions;

    Symbol token = next_token();

    input_.push(Symbol::eof());
    output_.push(Symbol::eof());
    input_.push(translationGrammar_->starting_symbol());
    output_.push(translationGrammar_->starting_symbol());

    // iterator to the first symbol of the last inserted string
    // used to speed up output_ linear search
    auto obegin = output_.begin();

    while (1) {
      Symbol &top = input_.top();
      size_t ruleIndex;
      switch (top.type()) {
        case Type::EOI:
          if (token == Symbol::eof()) {
            return;
          } else {
            add_error(top, token);
            return;
          }
          break;
        case Type::TERMINAL:
          if (top == token) {
            for (auto it : attributeActions.pop()) {
              it->set_attribute(token);
            }
            input_.pop();
            token = next_token();
          } else {
            add_error(top, token);
            if (!error_recovery(token))
              return;
          }
          break;
        case Type::NONTERMINAL:
          lastNonterminal_ = top;
          ruleIndex = llTable_.rule_index(top, token);
          if (ruleIndex < translationGrammar_->rules().size()) {
            auto &rule = translationGrammar_->rules()[ruleIndex];

            obegin = output_.replace(top, rule.output(), obegin);
            input_.replace(input_.begin(), rule.input());
            create_attibute_actions(obegin, rule.actions(), attributeActions);
          } else {
            add_error(top, token);
            if (!error_recovery(token))
              return;
          }
          break;
        default:
          // unexpected symbol type on input stack
          input_.pop();
          break;
      }
    }
  }

  /**
  \brief Adds error message caused by a top symbol and incoming token
  combination.

  \param[in] top The current top symbol.
  \param[in] token The incoming token.
  */
  virtual void add_error(const Symbol &top, const Symbol &token) {
    using Type = Symbol::Type;

    errorFlag_ = true;
    errorString_ += token.location().to_string() + ": ";
    switch (top.type()) {
      case Type::EOI:
        errorString_ += "Unexpected token '" + token.name() +
                        "' after translation has finished.";
        break;
      case Type::TERMINAL:
        errorString_ += "Unexpected token '" + token.name() + "'; expected '" +
                        top.name() + "'";
        break;
      case Type::NONTERMINAL:
        // TODO list expected tokens
        errorString_ += "Unexpected token '" + token.name() +
                        "', nonterminal '" + top.name() + "'";
        break;
      default:
        break;
    }
    errorString_ += "\n";
  }

  /**
  \brief Hartmann error recovery.

  \param[out] token The next valid token.
  \returns True if the error recovery succeeded.
  */
  virtual bool error_recovery(Symbol& token) {
    size_t ruleIndex = 0;
    size_t ntIndex = translationGrammar_.nonterminal_index(lastNonterminal_);
    auto& ntFollow = follow_[ntIndex];
    // get a token from follow(lastNonterminal_)
    while(!is_in(ntFollow, token)) {
      token = next_token();
    }
    // pop stack until a rule is applicable or the same token is on top
    while(true) {
      Symbol& top = input_.top();
      switch(top.type()) {
        case Type::EOI:
          return true;
        case Type::TERMINAL:
          if (top == token)
            return true;
          break;
        case Type::NONTERMINAL:
          ruleIndex = llTable_.rule_index(top, token);
          if (ruleIndex < translationGrammar_->rules().size()) {
            return true;
          }
          break;
        default:
          break;
      }
      input_.pop();
    }

  }
  /**
  \brief Get error message.

  \returns The error message string.
  */
  string error_message() { return errorString_; }
};
}  // namespace ctf
#endif
/*** End of file ll_translation_control.hpp ***/<commit_msg>fix compilation errors<commit_after>/**
\file ll_translation_control.hpp
\brief Defines class LLTranslationControl and defines its methods.
\author Radek Vít
*/
#ifndef CTF_LL_TRANSLATION_CONTROL_H
#define CTF_LL_TRANSLATION_CONTROL_H

#include "translation_control.hpp"

namespace ctf {

/**
\brief Implements LL top down translation control.
*/
class LLTranslationControl : public TranslationControl {
 protected:
  /**
  \brief Empty set for each nonterminal.
  */
  vector<bool> empty_;
  /**
  \brief First set for each nonterminal.
  */
  vector<vector<Symbol>> first_;
  /**
  \brief Follow set for each nonterminal.
  */
  vector<vector<Symbol>> follow_;
  /**
  \brief Predict set for each nonterminal.
  */
  vector<vector<Symbol>> predict_;

  /**
  \brief LL table used to control the translation.
  */
  LLTable llTable_;

  /**
  \brief Error message string.
  */
  string errorString_;

  /**
  \brief The last expanded nonterminal.
  */
  Symbol lastNonterminal_ = Symbol::eof();

  /**
  Creates all predictive sets and creates a new LL table.
  */
  void create_ll_table() {
    create_empty();
    create_first();
    create_follow();
    create_predict();

    llTable_ = LLTable(*translationGrammar_, predict_);
  }

  /**
  \brief Creates Empty set for each nonterminal.

  Empty is true if a series of productions from the nonterminal can result in an
  empty string.
  */
  void create_empty() {
    const TranslationGrammar &tg = *translationGrammar_;
    empty_ = vector<bool>(tg.nonterminals().size(), false);

    for (auto &r : tg.rules()) {
      if (r.input().size() == 0) {
        empty_[tg.nonterminal_index(r.nonterminal())] = true;
      }
    }

    bool changed = false;
    do {
      changed = false;
      for (auto &r : tg.rules()) {
        bool isempty = true;
        for (auto &s : r.input()) {
          switch (s.type()) {
            case Symbol::Type::TERMINAL:
              isempty = false;
              break;
            case Symbol::Type::NONTERMINAL:
              if (empty_[tg.nonterminal_index(s)] == false) {
                isempty = false;
              }
              break;
            default:
              break;
          }
        }
        if (isempty) {
          if (!empty_[tg.nonterminal_index(r.nonterminal())]) {
            changed = true;
            empty_[tg.nonterminal_index(r.nonterminal())] = true;
          }
        }
      }
    } while (changed);
  }
  /**
  \brief Creates First set for each nonterminal.

  First contains all characters that can be at the first position of any string
  derived from this nonterminal.
  */
  void create_first() {
    const TranslationGrammar &tg = *translationGrammar_;
    first_ = {tg.nonterminals().size(), vector<Symbol>{}};

    bool changed = false;
    do {
      changed = false;
      for (auto &r : tg.rules()) {
        size_t i = tg.nonterminal_index(r.nonterminal());
        bool empty = true;
        for (auto &symbol : r.input()) {
          if (!empty)
            break;
          size_t nonterm_i;
          switch (symbol.type()) {
            case Symbol::Type::NONTERMINAL:
              nonterm_i = tg.nonterminal_index(symbol);
              if (modify_set(first_[i], first_[nonterm_i]))
                changed = true;
              empty = empty_[nonterm_i];
              break;
            case Symbol::Type::TERMINAL:
              if (modify_set(first_[i], vector<Symbol>({symbol})))
                changed = true;
              empty = false;
              break;
            default:
              break;
          }
        }
      }
    } while (changed);
  }
  /**
  \brief Creates Follow set for each nonterminal.

  Follow contains all characters that may follow that nonterminal in a
  sentential form from the starting nonterminal.
  */
  void create_follow() {
    const TranslationGrammar &tg = *translationGrammar_;
    follow_ = {tg.nonterminals().size(), vector<Symbol>{}};
    follow_[tg.nonterminal_index(tg.starting_symbol())].push_back(
        Symbol::eof());

    bool changed = false;
    do {
      changed = false;
      for (auto &r : tg.rules()) {
        // index of origin nonterminal
        size_t i = tg.nonterminal_index(r.nonterminal());
        /* empty set of all symbols to the right of the current one */
        bool compoundEmpty = true;
        /* first set of all symbols to the right of the current symbol */
        vector<Symbol> compoundFirst;
        /* track symbols from back */
        for (auto &s : reverse(r.input())) {
          // index of nonterminal in input string, only valid with
          // nonterminal symbol
          size_t ti = 0;
          switch (s.type()) {
            case Symbol::Type::NONTERMINAL:
              ti = tg.nonterminal_index(s);
              if (modify_set(follow_[ti], compoundFirst))
                changed = true;
              if (compoundEmpty && modify_set(follow_[ti], follow_[i]))
                changed = true;
              break;
            default:
              break;
          }
          /* if empty = false */
          if (s.type() != Symbol::Type::NONTERMINAL ||
              !empty_[tg.nonterminal_index(s)]) {
            compoundEmpty = false;
            switch (s.type()) {
              case Symbol::Type::NONTERMINAL:
                compoundFirst = first_[ti];
                break;
              case Symbol::Type::TERMINAL:
                compoundFirst = {s};
                break;
              default:
                break;
            }
          }
          /* empty = true, nonterminal*/
          else {
            modify_set(compoundFirst, first_[ti]);
          }
        }  // for all reverse input
      }    // for all rules
    } while (changed);
  }
  /**
  \brief Creates Predict set for each nonterminal.

  Predict contains all Terminals that may be the first terminal read in a
  sentential form from that nonterminal.
  */
  void create_predict() {
    predict_.clear();
    const TranslationGrammar &tg = *translationGrammar_;
    for (auto &r : tg.rules()) {
      vector<Symbol> compoundFirst;
      vector<Symbol> rfollow = follow_[tg.nonterminal_index(r.nonterminal())];
      bool compoundEmpty = true;
      for (auto &s : reverse(r.input())) {
        size_t i;
        switch (s.type()) {
          case Symbol::Type::TERMINAL:
            compoundEmpty = false;
            compoundFirst = vector<Symbol>({s});
            break;
          case Symbol::Type::NONTERMINAL:
            i = tg.nonterminal_index(s);
            if (!empty_[i]) {
              compoundEmpty = false;
              compoundFirst = first_[i];
            } else {
              modify_set(compoundFirst, first_[i]);
            }
          default:
            break;
        }
      }
      predict_.push_back(compoundFirst);

      if (compoundEmpty) {
        modify_set(predict_.back(), rfollow);
      }
    }  // for all rules
  }

  /**
  \brief Creates iterator attribute actions for incoming terminals.

  \param[in] obegin Iterator to the first Symbol of the output of the applied
  Rule.
  \param[in] targets Indices of the target actions for all input terminals.
  \param[out] attributeActions Targets to append incoming terminal's attributes.

  The added iterators point to input terminal attribute targets.
  */
  void create_attibute_actions(
      tstack<Symbol>::iterator obegin, const vector<set<size_t>> &targets,
      tstack<vector<tstack<Symbol>::iterator>> &attributeActions) {
    for (auto &target : reverse(targets)) {
      vector<tstack<Symbol>::iterator> iterators;
      for (auto &i : target) {
        auto oit = obegin;
        for (size_t x = 0; x < i; ++x)
          ++oit;
        if (oit->type() == Symbol::Type::TERMINAL)
          iterators.push_back(oit);
      }
      attributeActions.push(iterators);
    }
  }

 public:
  /**
  \brief Constructs a LLTranslationControl.
  */
  LLTranslationControl() = default;
  /**
  \brief Default destructor.
  */
  virtual ~LLTranslationControl() = default;
  /**
  \brief Constructs LLTranslationControl with a LexicalAnalyzer and
  TranslationGrammar.

  \param[in] la A reference to the lexical analyzer to be used to get tokens.
  \param[in] tg The translation grammar for this translation.
  */
  LLTranslationControl(LexicalAnalyzer &la, TranslationGrammar &tg) {
    set_grammar(tg);
    set_lexical_analyzer(la);
  }

  /**
  \brief Sets translation grammar.

  \param[in] tg The translation grammar for this translation.
  */
  virtual void set_grammar(const TranslationGrammar &tg) {
    translationGrammar_ = &tg;
    create_ll_table();
  }

  /**
  \brief Runs the translation. Output symbols are stored in output_.
  */
  virtual void run() {
    using Type = Symbol::Type;

    if (!lexicalAnalyzer_)
      throw TranslationException("No lexical analyzer was attached.");
    else if (!translationGrammar_)
      throw TranslationException("No translation grammar was attached.");

    input_.clear();
    output_.clear();
    tstack<vector<tstack<Symbol>::iterator>> attributeActions;

    Symbol token = next_token();

    input_.push(Symbol::eof());
    output_.push(Symbol::eof());
    input_.push(translationGrammar_->starting_symbol());
    output_.push(translationGrammar_->starting_symbol());

    // iterator to the first symbol of the last inserted string
    // used to speed up output_ linear search
    auto obegin = output_.begin();

    while (1) {
      Symbol &top = input_.top();
      size_t ruleIndex;
      switch (top.type()) {
        case Symbol::Type::EOI:
          if (token == Symbol::eof()) {
            return;
          } else {
            add_error(top, token);
            return;
          }
          break;
        case Symbol::Type::TERMINAL:
          if (top == token) {
            for (auto it : attributeActions.pop()) {
              it->set_attribute(token);
            }
            input_.pop();
            token = next_token();
          } else {
            add_error(top, token);
            if (!error_recovery(token))
              return;
          }
          break;
        case Symbol::Type::NONTERMINAL:
          lastNonterminal_ = top;
          ruleIndex = llTable_.rule_index(top, token);
          if (ruleIndex < translationGrammar_->rules().size()) {
            auto &rule = translationGrammar_->rules()[ruleIndex];

            obegin = output_.replace(top, rule.output(), obegin);
            input_.replace(input_.begin(), rule.input());
            create_attibute_actions(obegin, rule.actions(), attributeActions);
          } else {
            add_error(top, token);
            if (!error_recovery(token))
              return;
          }
          break;
        default:
          // unexpected symbol type on input stack
          input_.pop();
          break;
      }
    }
  }

  /**
  \brief Adds error message caused by a top symbol and incoming token
  combination.

  \param[in] top The current top symbol.
  \param[in] token The incoming token.
  */
  virtual void add_error(const Symbol &top, const Symbol &token) {
    using Type = Symbol::Type;

    errorFlag_ = true;
    errorString_ += token.location().to_string() + ": ";
    switch (top.type()) {
      case Type::EOI:
        errorString_ += "Unexpected token '" + token.name() +
                        "' after translation has finished.";
        break;
      case Type::TERMINAL:
        errorString_ += "Unexpected token '" + token.name() + "'; expected '" +
                        top.name() + "'";
        break;
      case Type::NONTERMINAL:
        // TODO list expected tokens
        errorString_ += "Unexpected token '" + token.name() +
                        "', nonterminal '" + top.name() + "'";
        break;
      default:
        break;
    }
    errorString_ += "\n";
  }

  /**
  \brief Hartmann error recovery.

  \param[out] token The next valid token.
  \returns True if the error recovery succeeded.
  */
  virtual bool error_recovery(Symbol& token) {
    size_t ruleIndex = 0;
    size_t ntIndex = translationGrammar_->nonterminal_index(lastNonterminal_);
    auto& ntFollow = follow_[ntIndex];
    // get a token from follow(lastNonterminal_)
    while(!is_in(ntFollow, token)) {
      token = next_token();
    }
    // pop stack until a rule is applicable or the same token is on top
    while(true) {
      Symbol& top = input_.top();
      switch(top.type()) {
        case Type::EOI:
          return true;
        case Type::TERMINAL:
          if (top == token)
            return true;
          break;
        case Type::NONTERMINAL:
          ruleIndex = llTable_.rule_index(top, token);
          if (ruleIndex < translationGrammar_->rules().size()) {
            return true;
          }
          break;
        default:
          break;
      }
      input_.pop();
    }

  }
  /**
  \brief Get error message.

  \returns The error message string.
  */
  string error_message() { return errorString_; }
};
}  // namespace ctf
#endif
/*** End of file ll_translation_control.hpp ***/<|endoftext|>


<commit_before><commit_msg>layers: Fix incorrect feature protect for KHX ext<commit_after><|endoftext|>


<commit_before>/* --
 * Copyright (C) 2013, George Makrydakis <irrequietus@gmail.com>
 *
 * This file is part of odreex.
 *
 * odreex is free software: you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * odreex 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 General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * odreex. If not, see http://www.gnu.org/licenses/.
 *
 */

#ifndef _ODREEX_PPMPF_TUPLE_FUNCTIONS_HH_
#define _ODREEX_PPMPF_TUPLE_FUNCTIONS_HH_

#include <odreex/ppmpf/base.hh>
#include <odreex/ppmpf/core.hh>
#include <odreex/ppmpf/tupseq.hh>
#include <odreex/ppmpf/fold.hh>
#include <odreex/ppmpf/tuple/atpos.hh>

/* NOTE: PPMPF_TUP2SEQ: convert a ppmpf tuple to a ppmpf sequence, preserving
 * the original order of elements. */
#define PPMPF_TUP2SEQ(tup) \
        PPMPF_DREF( \
            PPMPF_TUP_FOLDL( PPMPF_T2S_ \
                           , (PPMPF_TUP_GET(tup)) \
                           , PPMPF_TUP_POP(tup) ) )

/* NOTE: PPMPF_TUP_JOIN: Join two ppmpf tuples together.*/
#define PPMPF_TUP_JOIN(z,x) \
    (PPMPF_DREF(z)PPMPF_IFELSE( PPMPF_NOR( PPMPF_TUP_EMPTY(z) \
                                         , PPMPF_TUP_EMPTY(x)) \
                              , PPMPF_COMMA \
                              , PPMPF_EMPTY)()PPMPF_DREF(x))

/* NOTE: PPMPF_TUP_SPLIT: Split a ppmpf tuple into pair of two tuples at a
 * given position n */
#define PPMPF_TUP_SPLIT(n,tup) \
        PPMPF_COMPOSE( ((), PPMPF_DREF(tup)) \
                     , (PPMPF_TUP_SPLIT_)    \
                       (PPMPF_CAT(PPMPF_TUP_A0,PPMPF_DIGIT(0,n))) \
                       (PPMPF_CAT(PPMPF_TUP_A1,PPMPF_PNX(PPMPF_DIGIT(1,n)))) \
                       (PPMPF_CAT(PPMPF_TUP_A2,PPMPF_PNX(PPMPF_DIGIT(2,n)))) \
                       (PPMPF_CAT(PPMPF_TUP_A3,PPMPF_PNX(PPMPF_DIGIT(3,n)))))

/* NOTE: PPMPF_TUP_ATPOS: return ppmpf element at position n */
#define PPMPF_TUP_ATPOS(n,tup) \
        PPMPF_COMPOSE( PPMPF_TUP_SPLIT(PPMPF_PREV(n),tup) \
                     , (PPMPF_DPAR)    \
                       PPMPF_IFELSE( PPMPF_IEQL(n,PPMPF_IMINV()) \
                                   , (PPMPF_DPAR)                \
                                     (PPMPF_TUP_GET)             \
                                   , (PPMPF_TUP_GET)             \
                                     (PPMPF_DPAR)                \
                                     (PPMPF_TUP_POP) )           \
                       (PPMPF_ENCLOSE))

#endif /* _ODREEX_PPMPF_TUPLE_FUNCTIONS_HH_ */
<commit_msg>Added PPMPF_TUP_SPLITL, PPMPF_TUP_SPLITR.<commit_after>/* --
 * Copyright (C) 2013, George Makrydakis <irrequietus@gmail.com>
 *
 * This file is part of odreex.
 *
 * odreex is free software: you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * odreex 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 General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * odreex. If not, see http://www.gnu.org/licenses/.
 *
 */

#ifndef _ODREEX_PPMPF_TUPLE_FUNCTIONS_HH_
#define _ODREEX_PPMPF_TUPLE_FUNCTIONS_HH_

#include <odreex/ppmpf/base.hh>
#include <odreex/ppmpf/core.hh>
#include <odreex/ppmpf/tupseq.hh>
#include <odreex/ppmpf/fold.hh>
#include <odreex/ppmpf/tuple/atpos.hh>

/* NOTE: PPMPF_TUP2SEQ: convert a ppmpf tuple to a ppmpf sequence, preserving
 * the original order of elements. */
#define PPMPF_TUP2SEQ(tup) \
        PPMPF_DREF( \
            PPMPF_TUP_FOLDL( PPMPF_T2S_ \
                           , (PPMPF_TUP_GET(tup)) \
                           , PPMPF_TUP_POP(tup) ) )

/* NOTE: PPMPF_TUP_JOIN: Join two ppmpf tuples together.*/
#define PPMPF_TUP_JOIN(z,x) \
    (PPMPF_DREF(z)PPMPF_IFELSE( PPMPF_NOR( PPMPF_TUP_EMPTY(z) \
                                         , PPMPF_TUP_EMPTY(x)) \
                              , PPMPF_COMMA \
                              , PPMPF_EMPTY)()PPMPF_DREF(x))

/* NOTE: PPMPF_TUP_SPLIT: Split a ppmpf tuple into pair of two tuples at a
 * given position n */
#define PPMPF_TUP_SPLIT(n,tup) \
        PPMPF_COMPOSE( ((), PPMPF_DREF(tup)) \
                     , (PPMPF_TUP_SPLIT_)    \
                       (PPMPF_CAT(PPMPF_TUP_A0,PPMPF_DIGIT(0,n))) \
                       (PPMPF_CAT(PPMPF_TUP_A1,PPMPF_PNX(PPMPF_DIGIT(1,n)))) \
                       (PPMPF_CAT(PPMPF_TUP_A2,PPMPF_PNX(PPMPF_DIGIT(2,n)))) \
                       (PPMPF_CAT(PPMPF_TUP_A3,PPMPF_PNX(PPMPF_DIGIT(3,n)))))

/* NOTE: PPMPF_TUP_SPLITL: Split a ppmpf tuple into pair of two tuples at a
 * given position n and return the first of the two (left) */
#define PPMPF_TUP_SPLITL(n,tup) \
        PPMPF_COMPOSE( PPMPF_TUP_SPLIT(PPMPF_PREV(n),tup) \
                     , (PPMPF_DPAR)    \
                       (PPMPF_DPAR)    \
                       (PPMPF_TUP_GET) \
                       (PPMPF_ENCLOSE) )

/* NOTE: PPMPF_TUP_SPLITR: Split a ppmpf tuple into pair of two tuples at a
 * given position n and return the second of the two (right) */
#define PPMPF_TUP_SPLITR(n,tup) \
        PPMPF_COMPOSE( PPMPF_TUP_SPLIT(PPMPF_PREV(n),tup) \
                     , (PPMPF_DPAR)    \
                       (PPMPF_DPAR)    \
                       (PPMPF_TUP_POP) \
                       (PPMPF_ENCLOSE) )

/* NOTE: PPMPF_TUP_ATPOS: return ppmpf element at position n */
#define PPMPF_TUP_ATPOS(n,tup) \
        PPMPF_COMPOSE( PPMPF_TUP_SPLIT(PPMPF_PREV(n),tup) \
                     , (PPMPF_DPAR)    \
                       PPMPF_IFELSE( PPMPF_IEQL(n,PPMPF_IMINV()) \
                                   , (PPMPF_DPAR)                \
                                     (PPMPF_TUP_GET)             \
                                   , (PPMPF_TUP_GET)             \
                                     (PPMPF_DPAR)                \
                                     (PPMPF_TUP_POP) )           \
                       (PPMPF_ENCLOSE))

#endif /* _ODREEX_PPMPF_TUPLE_FUNCTIONS_HH_ */
<|endoftext|>


<commit_before>#include <Arduino.h>
#include "SoftwareSerial.h"
#include "A6lib.h"

#ifdef DEBUG
#define log(msg) Serial.print(msg)
#define logln(msg) Serial.println(msg)
#else
#define log(msg)
#define logln(msg)
#endif

#define OK 1
#define NOTOK 2
#define TIMEOUT 3

#define A6_CMD_TIMEOUT 2000

/////////////////////////////////////////////
// Public methods.
//

A6::A6(int transmitPin, int receivePin) {
    A6conn = new SoftwareSerial(receivePin, transmitPin, false, 1024);
    A6conn->setTimeout(100);
}

A6::~A6() {
    delete A6conn;
}

// Initialize the software serial connection and change the baud rate from the
// default (autodetected) to the desired speed.
void A6::begin(long baudRate) {
    // Give the module some time to settle.
    logln("Waiting for the module to initialize...");
    delay(20000);
    logln("Done.");

    A6conn->flush();

    setRate(baudRate);

    // Factory reset.
    A6command("AT&F", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);

    // Echo off.
    A6command("ATE0", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);

    // Set caller ID on.
    A6command("AT+CLIP=1", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);

    // Set SMS to text mode.
    A6command("AT+CMGF=1", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);

    // Switch audio to headset.
    enableSpeaker(0);
}

// Reboot the module by setting the specified pin HIGH, then LOW. The pin should
// be connected to a P-MOSFET, not the A6's POWER pin.
void A6::powerCycle(int pin) {
    logln("Power-cycling module...");

    pinMode(pin, OUTPUT);
    digitalWrite(pin, LOW);

    delay(1000);

    digitalWrite(pin, HIGH);

    // Give the module some time to settle.
    logln("Power-cycle done.");

    A6conn->flush();
}

// Dial a number.
void A6::dial(String number) {
    char buffer[50];

    logln("Dialing number...");

    sprintf(buffer, "ATD%s;", number.c_str());
    A6command(buffer, "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}

// Redial the last number.
void A6::redial() {
    logln("Redialing last number...");
    A6command("AT+DLST", "OK", "CONNECT", A6_CMD_TIMEOUT, 2, NULL);
}

// Answer a call.
void A6::answer() {
    A6command("ATA", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}

// Hang up the phone.
void A6::hangUp() {
    A6command("ATH", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}

// Check whether there is an active call.
callInfo A6::checkCallStatus() {
    char number[50];
    String response = "";
    int respStart = 0, matched = 0;
    callInfo cinfo = (const struct callInfo){ 0 };

    // Issue the command and wait for the response.
    A6command("AT+CLCC", "OK", "+CLCC", A6_CMD_TIMEOUT, 2, &response);

    // Parse the response if it contains a valid +CLCC.
    respStart = response.indexOf("+CLCC");
    if (respStart >= 0) {
        matched = sscanf(response.substring(respStart).c_str(), "+CLCC: %d,%d,%d,%d,%d,\"%s\",%d", &cinfo.index, &cinfo.direction, &cinfo.state, &cinfo.mode, &cinfo.multiparty, number, &cinfo.type);
        cinfo.number = String(number);
    }

    return cinfo;
}

// Send an SMS.
byte A6::sendSMS(String number, String text) {
    char ctrlZ[2] = { 0x1a, 0x00 };
    char buffer[100];

    if (text.length() > 159) {
        // We can't send messages longer than 160 characters.
        return NOTOK;
    }

    log("Sending SMS to ");
    log(number);
    logln("...");

    sprintf(buffer, "AT+CMGS=\"%s\"", number.c_str());
    A6command(buffer, ">", "yy", A6_CMD_TIMEOUT, 2, NULL);
    delay(100);
    A6conn->println(text.c_str());
    A6conn->println(ctrlZ);
    A6conn->println();

    return OK;
}

// Set the volume for the speaker. level should be a number between 5 and
// 8 inclusive.
void A6::setVol(byte level) {
    char buffer[30];

    // level should be between 5 and 8.
    level = min(max(level, 5), 8);
    sprintf(buffer, "AT+CLVL=%d", level);
    A6command(buffer, "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}

// Enable the speaker, rather than the headphones. Pass 0 to route audio through
// headphones, 1 through speaker.
void A6::enableSpeaker(byte enable) {
    char buffer[30];

    // enable should be between 0 and 1.
    enable = min(max(enable, 0), 1);
    sprintf(buffer, "AT+SNFS=%d", enable);
    A6command(buffer, "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}

/////////////////////////////////////////////
// Private methods.
//

// Autodetect the connection rate.
int A6::detectRate() {
    int rate = 0;
    int rates[] = {115200, 9600, 1200, 2400, 4800, 19200, 38400, 57600};

    // Try to autodetect the rate.
    logln("Autodetecting connection rate...");
    for (int i = 0; i < 8; i++) {
        rate = rates[i];

        A6conn->begin(rate);
        log("Trying rate ");
        log(rate);
        logln("...");

        delay(100);
        if (A6command("\rAT", "OK", "+CME", 3000, 2, NULL) == OK) {
            return rate;
        }
    }

    // Return a default rate.
    return 9600;
}

// Set the A6 baud rate.
void A6::setRate(long baudRate) {
    int rate = detectRate();

    // The rate is already the desired rate, return.
    if (rate == baudRate) return;

    logln("Setting baud rate on the module...");
    // Change the rate to the requested.
    char buffer[30];
    sprintf(buffer, "AT+IPR=%d", baudRate);
    A6command(buffer, "OK", "+IPR=", A6_CMD_TIMEOUT, 3, NULL);

    logln("Switching to the new rate...");
    // Begin the connection again at the requested rate.
    A6conn->begin(baudRate);
    logln("Rate set.");
}

// Read some data from the A6 in a non-blocking manner.
String A6::read() {
    String reply = "";
    if (A6conn->available()) reply = A6conn->readString();
    return reply;
}

// Issue a command.
byte A6::A6command(const char *command, const char *resp1, const char *resp2, int timeout, int repetitions, String *response) {
    byte returnValue = NOTOK;
    byte count = 0;

    // Get rid of any buffered output.
    A6conn->flush();

    while (count < repetitions && returnValue != OK) {
        log("Issuing command: ");
        logln(command);

        A6conn->print(command);
        A6conn->print("\r");

        if (A6waitFor(resp1, resp2, timeout, response) == OK) {
            returnValue = OK;
        } else {
            returnValue = NOTOK;
        }
        count++;
    }
    return returnValue;
}

// Wait for responses.
byte A6::A6waitFor(const char *resp1, const char *resp2, int timeout, String *response) {
    unsigned long entry = millis();
    int count = 0;
    String reply = "";
    byte retVal = 99;
    do {
        reply += read();
        yield();
    } while ((reply.indexOf(resp1) + reply.indexOf(resp2) == -2) && millis() - entry < timeout);

    if (reply != "") {
        log("Reply in ");
        log((millis() - entry));
        log(" ms: ");
        logln(reply);
    }

    if (response != NULL) *response = reply;

    if ((millis() - entry) >= timeout) {
        retVal = TIMEOUT;
        logln("Timed out.");
    } else {
        if (reply.indexOf(resp1) + reply.indexOf(resp2) > -2) {
            logln("Reply OK.");
            retVal = OK;
        } else {
            logln("Reply NOT OK.");
            retVal = NOTOK;
        }
    }
    return retVal;
}
<commit_msg>Improve rate looping.<commit_after>#include <Arduino.h>
#include "SoftwareSerial.h"
#include "A6lib.h"

#ifdef DEBUG
#define log(msg) Serial.print(msg)
#define logln(msg) Serial.println(msg)
#else
#define log(msg)
#define logln(msg)
#endif

#define countof(a) (sizeof(a) / sizeof(a[0]))

#define OK 1
#define NOTOK 2
#define TIMEOUT 3

#define A6_CMD_TIMEOUT 2000

/////////////////////////////////////////////
// Public methods.
//

A6::A6(int transmitPin, int receivePin) {
    A6conn = new SoftwareSerial(receivePin, transmitPin, false, 1024);
    A6conn->setTimeout(100);
}

A6::~A6() {
    delete A6conn;
}

// Initialize the software serial connection and change the baud rate from the
// default (autodetected) to the desired speed.
void A6::begin(long baudRate) {
    // Give the module some time to settle.
    logln("Waiting for the module to initialize...");
    delay(20000);
    logln("Done.");

    A6conn->flush();

    setRate(baudRate);

    // Factory reset.
    A6command("AT&F", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);

    // Echo off.
    A6command("ATE0", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);

    // Set caller ID on.
    A6command("AT+CLIP=1", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);

    // Set SMS to text mode.
    A6command("AT+CMGF=1", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);

    // Switch audio to headset.
    enableSpeaker(0);
}

// Reboot the module by setting the specified pin HIGH, then LOW. The pin should
// be connected to a P-MOSFET, not the A6's POWER pin.
void A6::powerCycle(int pin) {
    logln("Power-cycling module...");

    pinMode(pin, OUTPUT);
    digitalWrite(pin, LOW);

    delay(1000);

    digitalWrite(pin, HIGH);

    // Give the module some time to settle.
    logln("Power-cycle done.");

    A6conn->flush();
}

// Dial a number.
void A6::dial(String number) {
    char buffer[50];

    logln("Dialing number...");

    sprintf(buffer, "ATD%s;", number.c_str());
    A6command(buffer, "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}

// Redial the last number.
void A6::redial() {
    logln("Redialing last number...");
    A6command("AT+DLST", "OK", "CONNECT", A6_CMD_TIMEOUT, 2, NULL);
}

// Answer a call.
void A6::answer() {
    A6command("ATA", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}

// Hang up the phone.
void A6::hangUp() {
    A6command("ATH", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}

// Check whether there is an active call.
callInfo A6::checkCallStatus() {
    char number[50];
    String response = "";
    int respStart = 0, matched = 0;
    callInfo cinfo = (const struct callInfo){ 0 };

    // Issue the command and wait for the response.
    A6command("AT+CLCC", "OK", "+CLCC", A6_CMD_TIMEOUT, 2, &response);

    // Parse the response if it contains a valid +CLCC.
    respStart = response.indexOf("+CLCC");
    if (respStart >= 0) {
        matched = sscanf(response.substring(respStart).c_str(), "+CLCC: %d,%d,%d,%d,%d,\"%s\",%d", &cinfo.index, &cinfo.direction, &cinfo.state, &cinfo.mode, &cinfo.multiparty, number, &cinfo.type);
        cinfo.number = String(number);
    }

    return cinfo;
}

// Send an SMS.
byte A6::sendSMS(String number, String text) {
    char ctrlZ[2] = { 0x1a, 0x00 };
    char buffer[100];

    if (text.length() > 159) {
        // We can't send messages longer than 160 characters.
        return NOTOK;
    }

    log("Sending SMS to ");
    log(number);
    logln("...");

    sprintf(buffer, "AT+CMGS=\"%s\"", number.c_str());
    A6command(buffer, ">", "yy", A6_CMD_TIMEOUT, 2, NULL);
    delay(100);
    A6conn->println(text.c_str());
    A6conn->println(ctrlZ);
    A6conn->println();

    return OK;
}

// Set the volume for the speaker. level should be a number between 5 and
// 8 inclusive.
void A6::setVol(byte level) {
    char buffer[30];

    // level should be between 5 and 8.
    level = min(max(level, 5), 8);
    sprintf(buffer, "AT+CLVL=%d", level);
    A6command(buffer, "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}

// Enable the speaker, rather than the headphones. Pass 0 to route audio through
// headphones, 1 through speaker.
void A6::enableSpeaker(byte enable) {
    char buffer[30];

    // enable should be between 0 and 1.
    enable = min(max(enable, 0), 1);
    sprintf(buffer, "AT+SNFS=%d", enable);
    A6command(buffer, "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}

/////////////////////////////////////////////
// Private methods.
//

// Autodetect the connection rate.
int A6::detectRate() {
    int rate = 0;
    int rates[] = {115200, 9600, 1200, 2400, 4800, 19200, 38400, 57600};

    // Try to autodetect the rate.
    logln("Autodetecting connection rate...");
    for (int i = 0; i < countof(rates); i++) {
        rate = rates[i];

        A6conn->begin(rate);
        log("Trying rate ");
        log(rate);
        logln("...");

        delay(100);
        if (A6command("\r\r\rAT", "OK", "+CME", 2000, 2, NULL) == OK) {
            return rate;
        }
    }

    // Return a default rate.
    return 9600;
}

// Set the A6 baud rate.
void A6::setRate(long baudRate) {
    int rate = detectRate();

    // The rate is already the desired rate, return.
    if (rate == baudRate) return;

    logln("Setting baud rate on the module...");
    // Change the rate to the requested.
    char buffer[30];
    sprintf(buffer, "AT+IPR=%d", baudRate);
    A6command(buffer, "OK", "+IPR=", A6_CMD_TIMEOUT, 3, NULL);

    logln("Switching to the new rate...");
    // Begin the connection again at the requested rate.
    A6conn->begin(baudRate);
    logln("Rate set.");
}

// Read some data from the A6 in a non-blocking manner.
String A6::read() {
    String reply = "";
    if (A6conn->available()) reply = A6conn->readString();
    return reply;
}

// Issue a command.
byte A6::A6command(const char *command, const char *resp1, const char *resp2, int timeout, int repetitions, String *response) {
    byte returnValue = NOTOK;
    byte count = 0;

    // Get rid of any buffered output.
    A6conn->flush();

    while (count < repetitions && returnValue != OK) {
        log("Issuing command: ");
        logln(command);

        A6conn->print(command);
        A6conn->print("\r");

        if (A6waitFor(resp1, resp2, timeout, response) == OK) {
            returnValue = OK;
        } else {
            returnValue = NOTOK;
        }
        count++;
    }
    return returnValue;
}

// Wait for responses.
byte A6::A6waitFor(const char *resp1, const char *resp2, int timeout, String *response) {
    unsigned long entry = millis();
    int count = 0;
    String reply = "";
    byte retVal = 99;
    do {
        reply += read();
        yield();
    } while ((reply.indexOf(resp1) + reply.indexOf(resp2) == -2) && millis() - entry < timeout);

    if (reply != "") {
        log("Reply in ");
        log((millis() - entry));
        log(" ms: ");
        logln(reply);
    }

    if (response != NULL) *response = reply;

    if ((millis() - entry) >= timeout) {
        retVal = TIMEOUT;
        logln("Timed out.");
    } else {
        if (reply.indexOf(resp1) + reply.indexOf(resp2) > -2) {
            logln("Reply OK.");
            retVal = OK;
        } else {
            logln("Reply NOT OK.");
            retVal = NOTOK;
        }
    }
    return retVal;
}
<|endoftext|>


<commit_before>#include <Common/config.h>
#include <Common/task.h>

#include <util/delay.h>
#include <avr/interrupt.h>

#include "p2k.h"

using namespace P2KConfig;

#define TICK_FREQ       250

#define PIN_OPEN        5

const byte SOLUTION1[5] = { 3, 2, 1, 4, 4 };
const byte SOLUTION2[5] = { 3, 2, 2, 2, 1 };

enum {
  FLAG_SECOND,
  FLAG_BLINK,
  FLAG_OPEN,
  FLAG_CLOSE
};

enum {
  STATE_INIT,
  STATE_OPEN
};

volatile byte gFlags;
volatile byte gState;

P2K panel;
bool gSolved1;
bool gSolved2;
bool gSolvedAll;
bool gCashOpen;

byte gCount;

void taskRestart() {
  gSolvedAll = false;
  gCashOpen = false;
  gCount = 0;
  panel.clear();
}

void taskComplete() {
  gSolvedAll = true;
  gCount++;
  bit_set(gFlags, FLAG_OPEN);
  gCashOpen = true;
}

byte taskIsDone() {
  return gSolvedAll;
}

byte taskCallback(byte cmd, byte nParams, byte *nResults, byte *busParams)
{
  switch (cmd) {
    case CMD_COUNT:
    {
      *nResults = 1;
      busParams[0] = gCount;
    }
  }
  return 0;
}

void setup() {
  gState = STATE_INIT;

  pinMode(PIN_OPEN, OUTPUT);

  // Setup Timer0
  // Set CTC mode, TOP = OCRA, prescaler 1024
  // Overflow 125Hz (8ms)
  TIMER0_SETUP(TIMER0_FAST_PWM, TIMER0_PRESCALER(TICK_FREQ));
  //TCCR0A = (1 << WGM01) | (1 << WGM00);
  //TCCR0B = (1 << CS02) | (1 << CS00) | (1 << WGM02);
  TIMSK0 = (1 << TOIE0);
  //OCR0A = (byte)(F_CPU / (1024UL * TICK_FREQ)) - 1;
  OCR0A = TIMER0_COUNTS(TICK_FREQ) - 1;

  panel.setup();

  taskRestart();
  taskSetup(BUS_ADDRESS);
}

void loop() {
  static byte led = 0;
  static bool phase = true;

  if (bit_check(gFlags, FLAG_BLINK))
  {
    bit_clear(gFlags, FLAG_BLINK);

    bool ok1 = true;
    bool ok2 = true;
    for (byte idx = 0; idx < 5; idx++) {
      byte state = panel.getButtons(idx);
      byte state1 = state & 0x0F;
      byte state2 = state & 0xF0;
      byte mask1 = 1 << (4 - SOLUTION1[idx]);
      byte mask2 = 1 << (8 - SOLUTION2[idx]);
      if (state1 != mask1) {
        ok1 = false;
      }
      if (state2 != mask2) {
        ok2 = false;
      }
      //if (!gTaskDone) {
      //  panel.setLED(idx, (state1 == mask1));
      //  panel.setLED(idx + 5, (state2 == mask2));
      //}
    }

    bool wasDone = taskIsDone();
      if (!gSolved1 && ok1) {
        for (byte idx = 0; idx < 5; idx++) panel.setLED(idx, true);
        gSolved1 = ok1;
      }
      if (!gSolved2 && ok2) {
        for (byte idx = 0; idx < 5; idx++) panel.setLED(idx + 5, true);
        gSolved2 = ok2;
      }
      if (gSolved1 && !ok1) {
        for (byte idx = 0; idx < 5; idx++) panel.setLED(idx, false);
        gSolved1 = ok1;
      }
      if (gSolved2 && !ok2) {
        for (byte idx = 0; idx < 5; idx++) panel.setLED(idx + 5, false);
        gSolved2 = ok2;
      }
      gSolvedAll = gSolved1 && gSolved2;

      if (taskIsDone()) {

        if (!wasDone) {
          led = 0;
          phase = true;
          taskComplete();

        }

        panel.setLED(led, phase);
        if (++led >= 10) {
          led = 0;
          phase = !phase;
        }
      }

  }

  taskLoop();
}

ISR(TIMER0_OVF_vect) {
  static word millis = 0;
  static word millis2 = 0;
  static word millis3 = 0;
  static word millis4 = 0;

  millis += (1000UL / TICK_FREQ);
  millis2 += (1000UL / TICK_FREQ);

  if (millis >= 1000) {
    millis -= 1000;
    bit_set(gFlags, FLAG_SECOND);
  }
  if (millis2 >= 200) {
    millis2 -= 200;
    bit_set(gFlags, FLAG_BLINK);
  }

  panel.update();

  if (bit_check(gFlags, FLAG_OPEN)) {
    millis3 += (1000UL / TICK_FREQ);

    if (millis3 > 500) {
      bit_clear(gFlags, FLAG_OPEN);
      pinWrite(PIN_OPEN, HIGH);
      millis4 = 0;
      bit_set(gFlags, FLAG_CLOSE);
    }
  }
  if (bit_check(gFlags, FLAG_CLOSE)) {
    millis4 += (1000UL / TICK_FREQ);

    if (millis4 > 100) {
      bit_clear(gFlags, FLAG_CLOSE);
      pinWrite(PIN_OPEN, LOW);
      millis3 = 0;
    }
  }
}
<commit_msg>Fix task completion<commit_after>#include <Common/config.h>
#include <Common/task.h>

#include <util/delay.h>
#include <avr/interrupt.h>

#include "p2k.h"

using namespace P2KConfig;

#define TICK_FREQ       250

#define PIN_OPEN        5

const byte SOLUTION1[5] = { 3, 2, 1, 4, 4 };
const byte SOLUTION2[5] = { 3, 2, 2, 2, 1 };

enum {
	FLAG_SECOND, FLAG_BLINK, FLAG_OPEN, FLAG_CLOSE
};

enum {
	STATE_INIT, STATE_OPEN
};

volatile byte gFlags;
volatile byte gState;

P2K panel;
bool gSolved1;
bool gSolved2;
bool gSolvedAll;
bool gCashOpen;

byte gCount;

void taskRestart() {
	gSolvedAll = false;
	gCashOpen = false;
	gCount = 0;
	panel.clear();
}

void taskComplete() {
	gSolvedAll = true;
	gCount++;
	bit_set(gFlags, FLAG_OPEN);
	gCashOpen = true;
}

byte taskIsDone() {
	return gSolvedAll;
}

byte taskCallback(byte cmd, byte nParams, byte *nResults, byte *busParams) {
	switch (cmd) {
	case CMD_COUNT: {
		*nResults = 1;
		busParams[0] = gCount;
	}
	}
	return 0;
}

void setup() {
	gState = STATE_INIT;

	pinMode(PIN_OPEN, OUTPUT);

	// Setup Timer0
	// Set CTC mode, TOP = OCRA, prescaler 1024
	// Overflow 125Hz (8ms)
	TIMER0_SETUP(TIMER0_FAST_PWM, TIMER0_PRESCALER(TICK_FREQ));
	//TCCR0A = (1 << WGM01) | (1 << WGM00);
	//TCCR0B = (1 << CS02) | (1 << CS00) | (1 << WGM02);
	TIMSK0 = (1 << TOIE0);
	//OCR0A = (byte)(F_CPU / (1024UL * TICK_FREQ)) - 1;
	OCR0A = TIMER0_COUNTS(TICK_FREQ) - 1;

	panel.setup();

	taskRestart();
	taskSetup(BUS_ADDRESS);
}

void loop() {
	static byte led = 0;
	static bool phase = true;

	bool ok1 = true;
	bool ok2 = true;
	for (byte idx = 0; idx < 5; idx++) {
		byte state = panel.getButtons(idx);
		byte state1 = state & 0x0F;
		byte state2 = state & 0xF0;
		byte mask1 = 1 << (4 - SOLUTION1[idx]);
		byte mask2 = 1 << (8 - SOLUTION2[idx]);
		if (state1 != mask1) {
			ok1 = false;
		}
		if (state2 != mask2) {
			ok2 = false;
		}
	}

	if (!gSolved1 && ok1) {
		for (byte idx = 0; idx < 5; idx++)
			panel.setLED(idx, true);
	}
	if (!gSolved2 && ok2) {
		for (byte idx = 0; idx < 5; idx++)
			panel.setLED(idx + 5, true);
	}
	if (gSolved1 && !ok1) {
		for (byte idx = 0; idx < 5; idx++)
			panel.setLED(idx, false);
	}
	if (gSolved2 && !ok2) {
		for (byte idx = 0; idx < 5; idx++)
			panel.setLED(idx + 5, false);
	}
	if (ok1 && ok2 && (!gSolved1 || !gSolved2)) {
		led = 0;
		phase = true;
		taskComplete();
	}
	gSolved1 = ok1;
	gSolved2 = ok2;
	gSolvedAll = gSolved1 && gSolved2;

	if (taskIsDone()) {
		panel.setLED(led, phase);
		if (++led >= 10) {
			led = 0;
			phase = !phase;
		}
	}

	taskLoop();
}

ISR(TIMER0_OVF_vect) {
	static word millis = 0;
	static word millis2 = 0;
	static word millis3 = 0;
	static word millis4 = 0;

	millis += (1000UL / TICK_FREQ);
	millis2 += (1000UL / TICK_FREQ);

	if (millis >= 1000) {
		millis -= 1000;
		bit_set(gFlags, FLAG_SECOND);
	}
	if (millis2 >= 200) {
		millis2 -= 200;
		bit_set(gFlags, FLAG_BLINK);
	}

	panel.update();

	if (bit_check(gFlags, FLAG_OPEN)) {
		millis3 += (1000UL / TICK_FREQ);

		if (millis3 > 500) {
			bit_clear(gFlags, FLAG_OPEN);
			pinWrite(PIN_OPEN, HIGH);
			millis4 = 0;
			bit_set(gFlags, FLAG_CLOSE);
		}
	}
	if (bit_check(gFlags, FLAG_CLOSE)) {
		millis4 += (1000UL / TICK_FREQ);

		if (millis4 > 100) {
			bit_clear(gFlags, FLAG_CLOSE);
			pinWrite(PIN_OPEN, LOW);
			millis3 = 0;
		}
	}
}
<|endoftext|>


<commit_before>
#ifndef __PICKABLE_HPP__
#define __PICKABLE_HPP__

#include <vector>

#include "allocore/ui/al_Gnomon.hpp"
#include "allocore/ui/al_BoundingBox.hpp"

namespace al {

struct PickableState {
  bool hover, selected;
  Pose pose;
  Vec3f scale;

  PickableState(){
    pose = Pose();
    scale = Vec3f(1);
    hover = selected = false;
  }
};

struct PickableBase : virtual PickableState {
  PickableBase *parent = 0;
  std::vector<PickableBase *> children;
  bool alwaysTestChildren = true;

  // initial values, and previous values
  Pose pose0, prevPose;
  Vec3f scale0, prevScale;

  /// intersection test must be specified
  virtual double intersect(Rayd &r) = 0;

  /// override these callbacks
  virtual bool onPoint(Rayd &r, double t, bool child){return false;}
  virtual bool onPick(Rayd &r, double t, bool child){return false;}
  virtual bool onDrag(Rayd &r, double t, bool child){return false;}
  virtual bool onUnpick(Rayd &r, double t, bool child){return false;}

  /// do interaction on self and children, call onPoint callbacks
  virtual bool point(Rayd &r){
    bool child = false;
    double t = intersect(r);
    if(t > 0.0 || alwaysTestChildren){
      for(int i=0; i < children.size(); i++){
        Rayd ray = transformRayLocal(r);
        child |= children[i]->point(ray);
      }
    }
    return onPoint(r,t,child);
  }

  /// do interaction on self and children, call onPick callbacks
  virtual bool pick(Rayd &r){
    bool child = false;
    double t = intersect(r);
    if(t > 0.0 || alwaysTestChildren){
      for(int i=0; i < children.size(); i++){
        Rayd ray = transformRayLocal(r);
        child |= children[i]->pick(ray);
      }
    }
    return onPick(r,t,child);
  }

  /// do interaction on self and children, call onDrag callbacks
  virtual bool drag(Rayd &r){
    bool child = false;
    double t = intersect(r);
    if(t > 0.0 || alwaysTestChildren){
      for(int i=0; i < children.size(); i++){
        Rayd ray = transformRayLocal(r);
        child |= children[i]->drag(ray);
      }
    }
    return onDrag(r,t,child);
  }

  /// do interaction on self and children, call onUnpick callbacks
  virtual bool unpick(Rayd &r){
    bool child = false;
    double t = intersect(r);
    if(t > 0.0 || alwaysTestChildren){
      for(int i=0; i < children.size(); i++){
        Rayd ray = transformRayLocal(r);
        child |= children[i]->unpick(ray);
      }
    }
    return onUnpick(r,t,child);
  }

  virtual void draw(Graphics &g){}
  virtual void drawChildren(Graphics &g){
    pushMatrix(g);
    for(int i=0; i < children.size(); i++){
      children[i]->draw(g);
    }
    popMatrix(g);
  }

  bool intersects(Rayd &r){ return intersect(r) > 0.0; }
  bool intersectsChild(Rayd &r){
    bool child = false;
    for(int i=0; i < children.size(); i++){
      Rayd ray = transformRayLocal(r);
      child |= children[i]->intersects(ray);
    }
    return child;
  }

  void addChild(PickableBase &pickable){
    pickable.parent = this;
    children.push_back(&pickable);
  }

  /// apply pickable pose transforms
  inline void pushMatrix(Graphics &g){
    g.pushMatrix();
    g.translate(pose.pos());
    g.rotate(pose.quat());
    g.scale(scale);
  }
  /// pop matrix.
  inline void popMatrix(Graphics &g){
    g.popMatrix();
  }

  /// transform a ray in world space to local space
  Rayd transformRayLocal(const Rayd &ray){
    Matrix4d t,r,s;
    Matrix4d model = t.translate(pose.pos()) * r.fromQuat(pose.quat()) * s.scale(scale);
    Matrix4d invModel = Matrix4d::inverse(model);
    Vec4d o = invModel.transform(Vec4d(ray.o, 1));
    Vec4d d = invModel.transform(Vec4d(ray.d, 0));
    return Rayd(o.sub<3>(0), d.sub<3>(0));
  }

  /// transfrom a vector in local space to world space
  Vec3f transformVecWorld(const Vec3f &v, float w=1){
    Matrix4d t,r,s;
    Matrix4d model = t.translate(pose.pos()) * r.fromQuat(pose.quat()) * s.scale(scale);
    Vec4d o = model.transform(Vec4d(v, w));
    return Vec3f(o.sub<3>(0));
  }
};

/// Bounding Box Pickable
struct Pickable : PickableBase {
  Mesh *mesh; // pointer to mesh that is wrapped
  BoundingBox bb; // original bounding box
  BoundingBox aabb; // axis aligned bounding box (after pose/scale transforms)

  // used for moving pickable naturally
  Vec3f selectOffset;
  float selectDist;

  Pickable(){}
  Pickable(Mesh &m){set(m);}

  /// initialize bounding box;
  void set(Mesh &m){
    mesh = &m;
    bb.set(*mesh);
  }

  /// override base methods
  double intersect(Rayd &r){
    return intersectBB(r);
  }

  bool onPoint(Rayd &r, double t, bool child){
    if(t > 0.0){
      if(child){
        hover = false;
      } else {
        hover = true;
      }
    } else hover = false;
    return hover || child;
  }

  bool onPick(Rayd &r, double t, bool child){
    if(t > 0.0){
      if(child){
        selected = false;
      } else {
        prevPose.set(pose);
        selectDist = t;
        selectOffset = pose.pos() - r(t);
        selected = true;
      }
    } else selected = false;
    return selected || child;
  }

  bool onDrag(Rayd &r, double t, bool child){
    if(t > 0.0){
      if(child){
        return true;
      } else if(selected){
        Vec3f newPos = r(selectDist) + selectOffset;
        pose.pos().set(newPos);
        return true;
      }
    }
    return false;
  }

  bool onUnpick(Rayd &r, double t, bool child){
    if(!hover) selected = false;
    return false;
  }

  // draw
  void draw(Graphics &g){
    pushMatrix(g);
    glPushAttrib(GL_CURRENT_BIT);
    if(mesh) g.draw(*mesh);

    if(selected) g.color(0,1,1);
    else if(hover) g.color(1,1,1);
    g.draw(bb.mesh);
    g.draw(bb.tics);

    // drawLabels(g);
    drawChildren(g);
    glPopAttrib();
    popMatrix(g);
  }

  void drawMesh(Graphics &g){
    if(!mesh) return;
    pushMatrix(g);
    g.draw(*mesh);
    popMatrix(g);
  }
  void drawBB(Graphics &g){
    if(!selected && !hover) return;
    pushMatrix(g);
    glPushAttrib(GL_CURRENT_BIT);
    if(selected) g.color(0,1,1);
    else if(hover) g.color(1,1,1);
    g.draw(bb.mesh);
    g.draw(bb.tics);
    glPopAttrib();
    popMatrix(g);
  }
  void drawGrid(Graphics &g){
    pushMatrix(g);
    if(selected || hover){
      g.lineWidth(2);
      g.draw(bb.gridMesh[1]);
      g.lineWidth(1);
      g.draw(bb.gridMesh[0]);
    } else {}
    popMatrix(g);
  }

  void drawLabels(Graphics &g, Font& font, Pose &cam_pose){
    if(!selected && !hover) return;
    g.pushMatrix();
    bb.drawLabels(g, font, cam_pose, pose, scale.x);
    g.popMatrix();
  }

  void drawOrigin(Graphics &g){
    Gnomon gnomon;
    pushMatrix(g);
    gnomon.draw(g);
    popMatrix(g);
  }

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

  /// set the pickable's center position
  void setCenter(Vec3f& pos){
    updateAABB();
    Vec3f offset = aabb.cen - pose.pos();
    pose.pos().set(pos - offset);
  }

  /// set pickable's orientation maintaining same center position
  void setQuat(Quatf& q){
    updateAABB();
    Vec3f cen;
    cen.set(aabb.cen);
    pose.quat().set(q);
    setCenter(cen);
  }

  /// intersect ray with pickable BoundingBox
  double intersectBB(Rayd &ray){
    Rayd r = transformRayLocal(ray);
    return r.intersectBox(bb.cen, bb.dim);
  }

  /// intersect ray with pickable AxisAlignedBoundingBox
  double intersectAABB(Rayd &ray){
    return ray.intersectBox(aabb.cen, aabb.dim);
  }

  /// intersect ray with bounding sphere
  float intersectBoundingSphere(Rayd &ray){
    return ray.intersectSphere( transformVecWorld(bb.cen), (bb.dim*scale).mag()/2.0);
  }

  /// calculate Axis aligned bounding box from mesh bounding box and current transforms
  void updateAABB(){
    // thanks to http://zeuxcg.org/2010/10/17/aabb-from-obb-with-component-wise-abs/
    Matrix4d t,r,s;
    Matrix4d model = t.translate(pose.pos()) * r.fromQuat(pose.quat()) * s.scale(scale);
    Matrix4d absModel(model);
    for(int i=0; i<16; i++) absModel[i] = abs(absModel[i]);
    Vec4d cen = model.transform(Vec4d(bb.cen, 1));
    Vec4d dim = absModel.transform(Vec4d(bb.dim, 0));
    aabb.setCenterDim(cen.sub<3>(0),dim.sub<3>(0));
  }

};

} // ::al

#endif
<commit_msg>don't need to intersect on drag and selected<commit_after>
#ifndef __PICKABLE_HPP__
#define __PICKABLE_HPP__

#include <vector>

#include "allocore/ui/al_Gnomon.hpp"
#include "allocore/ui/al_BoundingBox.hpp"

namespace al {

struct PickableState {
  bool hover, selected;
  Pose pose;
  Vec3f scale;

  PickableState(){
    pose = Pose();
    scale = Vec3f(1);
    hover = selected = false;
  }
};

struct PickableBase : virtual PickableState {
  PickableBase *parent = 0;
  std::vector<PickableBase *> children;
  bool alwaysTestChildren = true;

  // initial values, and previous values
  Pose pose0, prevPose;
  Vec3f scale0, prevScale;

  /// intersection test must be specified
  virtual double intersect(Rayd &r) = 0;

  /// override these callbacks
  virtual bool onPoint(Rayd &r, double t, bool child){return false;}
  virtual bool onPick(Rayd &r, double t, bool child){return false;}
  virtual bool onDrag(Rayd &r, double t, bool child){return false;}
  virtual bool onUnpick(Rayd &r, double t, bool child){return false;}

  /// do interaction on self and children, call onPoint callbacks
  virtual bool point(Rayd &r){
    bool child = false;
    double t = intersect(r);
    if(t > 0.0 || alwaysTestChildren){
      for(int i=0; i < children.size(); i++){
        Rayd ray = transformRayLocal(r);
        child |= children[i]->point(ray);
      }
    }
    return onPoint(r,t,child);
  }

  /// do interaction on self and children, call onPick callbacks
  virtual bool pick(Rayd &r){
    bool child = false;
    double t = intersect(r);
    if(t > 0.0 || alwaysTestChildren){
      for(int i=0; i < children.size(); i++){
        Rayd ray = transformRayLocal(r);
        child |= children[i]->pick(ray);
      }
    }
    return onPick(r,t,child);
  }

  /// do interaction on self and children, call onDrag callbacks
  virtual bool drag(Rayd &r){
    bool child = false;
    double t = intersect(r);
    if(t > 0.0 || alwaysTestChildren){
      for(int i=0; i < children.size(); i++){
        Rayd ray = transformRayLocal(r);
        child |= children[i]->drag(ray);
      }
    }
    return onDrag(r,t,child);
  }

  /// do interaction on self and children, call onUnpick callbacks
  virtual bool unpick(Rayd &r){
    bool child = false;
    double t = intersect(r);
    if(t > 0.0 || alwaysTestChildren){
      for(int i=0; i < children.size(); i++){
        Rayd ray = transformRayLocal(r);
        child |= children[i]->unpick(ray);
      }
    }
    return onUnpick(r,t,child);
  }

  virtual void draw(Graphics &g){}
  virtual void drawChildren(Graphics &g){
    pushMatrix(g);
    for(int i=0; i < children.size(); i++){
      children[i]->draw(g);
    }
    popMatrix(g);
  }

  bool intersects(Rayd &r){ return intersect(r) > 0.0; }
  bool intersectsChild(Rayd &r){
    bool child = false;
    for(int i=0; i < children.size(); i++){
      Rayd ray = transformRayLocal(r);
      child |= children[i]->intersects(ray);
    }
    return child;
  }

  void addChild(PickableBase &pickable){
    pickable.parent = this;
    children.push_back(&pickable);
  }

  /// apply pickable pose transforms
  inline void pushMatrix(Graphics &g){
    g.pushMatrix();
    g.translate(pose.pos());
    g.rotate(pose.quat());
    g.scale(scale);
  }
  /// pop matrix.
  inline void popMatrix(Graphics &g){
    g.popMatrix();
  }

  /// transform a ray in world space to local space
  Rayd transformRayLocal(const Rayd &ray){
    Matrix4d t,r,s;
    Matrix4d model = t.translate(pose.pos()) * r.fromQuat(pose.quat()) * s.scale(scale);
    Matrix4d invModel = Matrix4d::inverse(model);
    Vec4d o = invModel.transform(Vec4d(ray.o, 1));
    Vec4d d = invModel.transform(Vec4d(ray.d, 0));
    return Rayd(o.sub<3>(0), d.sub<3>(0));
  }

  /// transfrom a vector in local space to world space
  Vec3f transformVecWorld(const Vec3f &v, float w=1){
    Matrix4d t,r,s;
    Matrix4d model = t.translate(pose.pos()) * r.fromQuat(pose.quat()) * s.scale(scale);
    Vec4d o = model.transform(Vec4d(v, w));
    return Vec3f(o.sub<3>(0));
  }
  /// transfrom a vector in world space to local space
  Vec3f transformVecLocal(const Vec3f &v, float w=1){
    Matrix4d t,r,s;
    Matrix4d invModel = t.translate(pose.pos()) * r.fromQuat(pose.quat()) * s.scale(scale);
    Vec4d o = invModel.transform(Vec4d(v, w));
    return Vec3f(o.sub<3>(0));
  }
};

/// Bounding Box Pickable
struct Pickable : PickableBase {
  Mesh *mesh; // pointer to mesh that is wrapped
  BoundingBox bb; // original bounding box
  BoundingBox aabb; // axis aligned bounding box (after pose/scale transforms)

  // used for moving pickable naturally
  Vec3f selectOffset;
  float selectDist;

  Pickable(){}
  Pickable(Mesh &m){set(m);}

  /// initialize bounding box;
  void set(Mesh &m){
    mesh = &m;
    bb.set(*mesh);
  }

  /// override base methods
  double intersect(Rayd &r){
    return intersectBB(r);
  }

  bool onPoint(Rayd &r, double t, bool child){
    if(t > 0.0){
      if(child){
        hover = false;
      } else {
        hover = true;
      }
    } else hover = false;
    return hover || child;
  }

  bool onPick(Rayd &r, double t, bool child){
    if(t > 0.0){
      if(child){
        selected = false;
      } else {
        prevPose.set(pose);
        selectDist = t;
        selectOffset = pose.pos() - r(t);
        selected = true;
      }
    } else selected = false;
    return selected || child;
  }

  bool onDrag(Rayd &r, double t, bool child){
    // if(t > 0.0){
      if(child){
        return true;
      } else if(selected){
        Vec3f newPos = r(selectDist) + selectOffset;
        pose.pos().set(newPos);
        return true;
      }
    // }
    return false;
  }

  bool onUnpick(Rayd &r, double t, bool child){
    if(!hover) selected = false;
    return false;
  }

  // draw
  void draw(Graphics &g){
    pushMatrix(g);
    glPushAttrib(GL_CURRENT_BIT);
    if(mesh) g.draw(*mesh);

    if(selected) g.color(0,1,1);
    else if(hover) g.color(1,1,1);
    g.draw(bb.mesh);
    g.draw(bb.tics);

    // drawLabels(g);
    glPopAttrib();
    popMatrix(g);
    drawChildren(g);
  }

  void drawMesh(Graphics &g){
    if(!mesh) return;
    pushMatrix(g);
    g.draw(*mesh);
    popMatrix(g);
  }
  void drawBB(Graphics &g){
    if(!selected && !hover) return;
    pushMatrix(g);
    glPushAttrib(GL_CURRENT_BIT);
    if(selected) g.color(0,1,1);
    else if(hover) g.color(1,1,1);
    g.draw(bb.mesh);
    g.draw(bb.tics);
    glPopAttrib();
    popMatrix(g);
  }
  void drawGrid(Graphics &g){
    pushMatrix(g);
    if(selected || hover){
      g.lineWidth(2);
      g.draw(bb.gridMesh[1]);
      g.lineWidth(1);
      g.draw(bb.gridMesh[0]);
    } else {}
    popMatrix(g);
  }

  void drawLabels(Graphics &g, Font& font, Pose &cam_pose){
    if(!selected && !hover) return;
    g.pushMatrix();
    bb.drawLabels(g, font, cam_pose, pose, scale.x);
    g.popMatrix();
  }

  void drawOrigin(Graphics &g){
    Gnomon gnomon;
    pushMatrix(g);
    gnomon.draw(g);
    popMatrix(g);
  }

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

  /// set the pickable's center position
  void setCenter(Vec3f& pos){
    updateAABB();
    Vec3f offset = aabb.cen - pose.pos();
    pose.pos().set(pos - offset);
  }

  /// set pickable's orientation maintaining same center position
  void setQuat(Quatf& q){
    updateAABB();
    Vec3f cen;
    cen.set(aabb.cen);
    pose.quat().set(q);
    setCenter(cen);
  }

  /// intersect ray with pickable BoundingBox
  double intersectBB(Rayd &ray){
    Rayd r = transformRayLocal(ray);
    return r.intersectBox(bb.cen, bb.dim);
  }

  /// intersect ray with pickable AxisAlignedBoundingBox
  double intersectAABB(Rayd &ray){
    return ray.intersectBox(aabb.cen, aabb.dim);
  }

  /// intersect ray with bounding sphere
  float intersectBoundingSphere(Rayd &ray){
    return ray.intersectSphere( transformVecWorld(bb.cen), (bb.dim*scale).mag()/2.0);
  }

  /// calculate Axis aligned bounding box from mesh bounding box and current transforms
  void updateAABB(){
    // thanks to http://zeuxcg.org/2010/10/17/aabb-from-obb-with-component-wise-abs/
    Matrix4d t,r,s;
    Matrix4d model = t.translate(pose.pos()) * r.fromQuat(pose.quat()) * s.scale(scale);
    Matrix4d absModel(model);
    for(int i=0; i<16; i++) absModel[i] = abs(absModel[i]);
    Vec4d cen = model.transform(Vec4d(bb.cen, 1));
    Vec4d dim = absModel.transform(Vec4d(bb.dim, 0));
    aabb.setCenterDim(cen.sub<3>(0),dim.sub<3>(0));
  }

};

} // ::al

#endif
<|endoftext|>