<commit_before>// This code is based on Sabberstone project.
// Copyright (c) 2017-2019 SabberStone Team, darkfriend77 & rnilva
// RosettaStone is hearthstone simulator using C++ with reinforcement learning.
// Copyright (c) 2019 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

#include <Rosetta/Enchants/Trigger.hpp>
#include <Rosetta/Games/Game.hpp>
#include <Rosetta/Models/Enchantment.hpp>
#include <Rosetta/Tasks/ITask.hpp>

#include <stdexcept>

namespace RosettaStone
{
Trigger::Trigger(TriggerType type) : m_triggerType(type)
{
    switch (type)
    {
        case TriggerType::PLAY_CARD:
            m_sequenceType = SequenceType::PLAY_CARD;
            break;
        case TriggerType::CAST_SPELL:
        case TriggerType::AFTER_CAST:
            m_sequenceType = SequenceType::PLAY_SPELL;
            break;
        case TriggerType::TURN_END:
            fastExecution = true;
            break;
        default:
            m_sequenceType = SequenceType::NONE;
    }
}

Trigger::Trigger(Trigger& prototype, Entity& owner)
    : triggerSource(prototype.triggerSource),
      tasks(prototype.tasks),
      condition(prototype.condition),
      fastExecution(prototype.fastExecution),
      removeAfterTriggered(prototype.removeAfterTriggered),
      m_triggerType(prototype.m_triggerType),
      m_sequenceType(prototype.m_sequenceType),
      m_owner(&owner)
{
    // Do nothing
}

void Trigger::Activate(Entity* source)
{
    auto* instance = new Trigger(*this, *source);
    Game* game = source->owner->GetGame();

    source->activatedTrigger = instance;

    auto triggerFunc = [instance](Player* p, Entity* e) {
        instance->Process(p, e);
    };

    switch (m_triggerType)
    {
        case TriggerType::TURN_START:
            game->triggerManager.startTurnTrigger = std::move(triggerFunc);
            break;
        case TriggerType::TURN_END:
            game->triggerManager.endTurnTrigger = std::move(triggerFunc);
            break;
        case TriggerType::PLAY_CARD:
            game->triggerManager.playCardTrigger = std::move(triggerFunc);
            break;
        case TriggerType::CAST_SPELL:
            game->triggerManager.castSpellTrigger = std::move(triggerFunc);
            break;
        case TriggerType::AFTER_CAST:
            game->triggerManager.afterCastTrigger = std::move(triggerFunc);
            break;
        case TriggerType::HEAL:
            game->triggerManager.healTrigger = std::move(triggerFunc);
            break;
        case TriggerType::ATTACK:
            game->triggerManager.attackTrigger = std::move(triggerFunc);
            break;
        case TriggerType::SUMMON:
            game->triggerManager.summonTrigger = std::move(triggerFunc);
            break;
        case TriggerType::PREDAMAGE:
            switch (triggerSource)
            {
                case TriggerSource::HERO:
                {
                    source->owner->GetHero()->preDamageTrigger =
                        std::move(triggerFunc);
                    break;
                }
                case TriggerSource::SELF:
                {
                    auto minion = dynamic_cast<Minion*>(source);
                    minion->preDamageTrigger = std::move(triggerFunc);
                    break;
                }
                case TriggerSource::ENCHANTMENT_TARGET:
                {
                    const auto enchantment = dynamic_cast<Enchantment*>(source);
                    auto minion =
                        dynamic_cast<Minion*>(enchantment->GetTarget());
                    minion->preDamageTrigger = std::move(triggerFunc);
                    break;
                }
                default:
                    break;
            }
            break;
        case TriggerType::TAKE_DAMAGE:
            game->triggerManager.takeDamageTrigger = std::move(triggerFunc);
            break;
        default:
            throw std::invalid_argument(
                "Trigger::Activate() - Invalid trigger type!");
    }
}

void Trigger::Remove() const
{
    Game* game = m_owner->owner->GetGame();

    switch (m_triggerType)
    {
        case TriggerType::TURN_START:
            game->triggerManager.startTurnTrigger = nullptr;
            break;
        case TriggerType::TURN_END:
            game->triggerManager.endTurnTrigger = nullptr;
            break;
        case TriggerType::PLAY_CARD:
            game->triggerManager.playCardTrigger = nullptr;
            break;
        case TriggerType::CAST_SPELL:
            game->triggerManager.castSpellTrigger = nullptr;
            break;
        case TriggerType::AFTER_CAST:
            game->triggerManager.afterCastTrigger = nullptr;
            break;
        case TriggerType::HEAL:
            game->triggerManager.healTrigger = nullptr;
            break;
        case TriggerType::ATTACK:
            game->triggerManager.attackTrigger = nullptr;
            break;
        case TriggerType::SUMMON:
            game->triggerManager.summonTrigger = nullptr;
            break;
        case TriggerType::PREDAMAGE:
            switch (triggerSource)
            {
                case TriggerSource::HERO:
                {
                    m_owner->owner->GetHero()->preDamageTrigger = nullptr;
                    break;
                }
                case TriggerSource::SELF:
                {
                    auto minion = dynamic_cast<Minion*>(m_owner);
                    minion->preDamageTrigger = nullptr;
                    break;
                }
                case TriggerSource::ENCHANTMENT_TARGET:
                {
                    const auto enchantment =
                        dynamic_cast<Enchantment*>(m_owner);
                    auto minion =
                        dynamic_cast<Minion*>(enchantment->GetTarget());
                    minion->preDamageTrigger = nullptr;
                    break;
                }
                default:
                    break;
            }
        case TriggerType::TAKE_DAMAGE:
            game->triggerManager.takeDamageTrigger = nullptr;
            break;
        default:
            throw std::invalid_argument(
                "Trigger::Remove() - Invalid trigger type!");
    }

    delete m_owner->activatedTrigger;
}

void Trigger::Process(Player* player, Entity* source)
{
    if (m_sequenceType == SequenceType::NONE)
    {
        Validate(player, source);
    }

    if (!m_isValidated)
    {
        return;
    }

    ProcessInternal(source);
}

void Trigger::ProcessInternal(Entity* source)
{
    m_isValidated = false;

    for (auto& task : tasks)
    {
        task->SetPlayer(m_owner->owner);
        task->SetSource(m_owner);

        if (source != nullptr)
        {
            task->SetTarget(source);
        }
        else
        {
            const auto enchantment = dynamic_cast<Enchantment*>(m_owner);
            if (enchantment != nullptr && enchantment->GetTarget() != nullptr)
            {
                task->SetTarget(enchantment->GetTarget());
            }
            else
            {
                task->SetTarget(nullptr);
            }
        }

        if (fastExecution)
        {
            task->Run();
        }
        else
        {
            m_owner->owner->GetGame()->taskQueue.Enqueue(task);
        }

        if (removeAfterTriggered)
        {
            Remove();
        }
    }

    m_isValidated = false;
}

void Trigger::Validate(Player* player, Entity* source)
{
    switch (triggerSource)
    {
        case TriggerSource::NONE:
            break;
        case TriggerSource::SELF:
            if (source != m_owner)
            {
                return;
            }
            break;
        case TriggerSource::HERO:
            if (dynamic_cast<Hero*>(source) == nullptr ||
                source->owner != m_owner->owner)
            {
                return;
            }
            break;
        case TriggerSource::ALL_MINIONS:
            if (dynamic_cast<Minion*>(source) == nullptr)
            {
                return;
            }
            break;
        case TriggerSource::MINIONS_EXCEPT_SELF:
            if (dynamic_cast<Minion*>(source) == nullptr ||
                source->owner != m_owner->owner || source == m_owner)
            {
                return;
            }
            break;
        case TriggerSource::ENCHANTMENT_TARGET:
        {
            const auto enchantment = dynamic_cast<Enchantment*>(m_owner);
            if (enchantment == nullptr ||
                enchantment->GetTarget()->id != source->id)
            {
                return;
            }
            break;
        }
        case TriggerSource::FRIENDLY:
        {
            if (source->owner != m_owner->owner)
            {
                return;
            }
            break;
        }
        default:
            throw std::invalid_argument(
                "Trigger::Validate() - Invalid source trigger!");
    }

    switch (m_triggerType)
    {
        case TriggerType::TURN_START:
        case TriggerType::TURN_END:
            if (player != m_owner->owner)
            {
                return;
            }
            break;
        case TriggerType::PLAY_CARD:
        case TriggerType::SUMMON:
            if (source == m_owner)
            {
                return;
            }
            break;
        case TriggerType::CAST_SPELL:
        case TriggerType::AFTER_CAST:
        case TriggerType::HEAL:
        case TriggerType::ATTACK:
        case TriggerType::PREDAMAGE:
        case TriggerType::TAKE_DAMAGE:
            break;
        default:
            throw std::invalid_argument(
                "Trigger::Validate() - Invalid trigger type!");
    }

    if (condition != nullptr)
    {
        const bool res = (source != nullptr) ? condition->Evaluate(source)
                                             : condition->Evaluate(m_owner);

        if (!res)
        {
            return;
        }
    }

    m_isValidated = true;
}
}  // namespace RosettaStone
<commit_msg>feat(card-impl): Add code to process trigger that has sequence type<commit_after>// This code is based on Sabberstone project.
// Copyright (c) 2017-2019 SabberStone Team, darkfriend77 & rnilva
// RosettaStone is hearthstone simulator using C++ with reinforcement learning.
// Copyright (c) 2019 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

#include <Rosetta/Commons/Utils.hpp>
#include <Rosetta/Enchants/Trigger.hpp>
#include <Rosetta/Games/Game.hpp>
#include <Rosetta/Models/Enchantment.hpp>
#include <Rosetta/Tasks/ITask.hpp>

#include <stdexcept>

namespace RosettaStone
{
Trigger::Trigger(TriggerType type) : m_triggerType(type)
{
    switch (type)
    {
        case TriggerType::PLAY_CARD:
            m_sequenceType = SequenceType::PLAY_CARD;
            break;
        case TriggerType::CAST_SPELL:
        case TriggerType::AFTER_CAST:
            m_sequenceType = SequenceType::PLAY_SPELL;
            break;
        case TriggerType::TURN_END:
            fastExecution = true;
            break;
        default:
            m_sequenceType = SequenceType::NONE;
    }
}

Trigger::Trigger(Trigger& prototype, Entity& owner)
    : triggerSource(prototype.triggerSource),
      tasks(prototype.tasks),
      condition(prototype.condition),
      fastExecution(prototype.fastExecution),
      removeAfterTriggered(prototype.removeAfterTriggered),
      m_triggerType(prototype.m_triggerType),
      m_sequenceType(prototype.m_sequenceType),
      m_owner(&owner)
{
    // Do nothing
}

void Trigger::Activate(Entity* source)
{
    auto* instance = new Trigger(*this, *source);
    Game* game = source->owner->GetGame();

    source->activatedTrigger = instance;

    auto triggerFunc = [instance](Player* p, Entity* e) {
        instance->Process(p, e);
    };

    if (m_sequenceType != SequenceType::NONE)
    {
        source->owner->GetGame()->triggers.emplace_back(instance);
    }

    switch (m_triggerType)
    {
        case TriggerType::TURN_START:
            game->triggerManager.startTurnTrigger = std::move(triggerFunc);
            break;
        case TriggerType::TURN_END:
            game->triggerManager.endTurnTrigger = std::move(triggerFunc);
            break;
        case TriggerType::PLAY_CARD:
            game->triggerManager.playCardTrigger = std::move(triggerFunc);
            break;
        case TriggerType::CAST_SPELL:
            game->triggerManager.castSpellTrigger = std::move(triggerFunc);
            break;
        case TriggerType::AFTER_CAST:
            game->triggerManager.afterCastTrigger = std::move(triggerFunc);
            break;
        case TriggerType::HEAL:
            game->triggerManager.healTrigger = std::move(triggerFunc);
            break;
        case TriggerType::ATTACK:
            game->triggerManager.attackTrigger = std::move(triggerFunc);
            break;
        case TriggerType::SUMMON:
            game->triggerManager.summonTrigger = std::move(triggerFunc);
            break;
        case TriggerType::PREDAMAGE:
            switch (triggerSource)
            {
                case TriggerSource::HERO:
                {
                    source->owner->GetHero()->preDamageTrigger =
                        std::move(triggerFunc);
                    break;
                }
                case TriggerSource::SELF:
                {
                    auto minion = dynamic_cast<Minion*>(source);
                    minion->preDamageTrigger = std::move(triggerFunc);
                    break;
                }
                case TriggerSource::ENCHANTMENT_TARGET:
                {
                    const auto enchantment = dynamic_cast<Enchantment*>(source);
                    auto minion =
                        dynamic_cast<Minion*>(enchantment->GetTarget());
                    minion->preDamageTrigger = std::move(triggerFunc);
                    break;
                }
                default:
                    break;
            }
            break;
        case TriggerType::TAKE_DAMAGE:
            game->triggerManager.takeDamageTrigger = std::move(triggerFunc);
            break;
        default:
            throw std::invalid_argument(
                "Trigger::Activate() - Invalid trigger type!");
    }
}

void Trigger::Remove() const
{
    Game* game = m_owner->owner->GetGame();

    switch (m_triggerType)
    {
        case TriggerType::TURN_START:
            game->triggerManager.startTurnTrigger = nullptr;
            break;
        case TriggerType::TURN_END:
            game->triggerManager.endTurnTrigger = nullptr;
            break;
        case TriggerType::PLAY_CARD:
            game->triggerManager.playCardTrigger = nullptr;
            break;
        case TriggerType::CAST_SPELL:
            game->triggerManager.castSpellTrigger = nullptr;
            break;
        case TriggerType::AFTER_CAST:
            game->triggerManager.afterCastTrigger = nullptr;
            break;
        case TriggerType::HEAL:
            game->triggerManager.healTrigger = nullptr;
            break;
        case TriggerType::ATTACK:
            game->triggerManager.attackTrigger = nullptr;
            break;
        case TriggerType::SUMMON:
            game->triggerManager.summonTrigger = nullptr;
            break;
        case TriggerType::PREDAMAGE:
            switch (triggerSource)
            {
                case TriggerSource::HERO:
                {
                    m_owner->owner->GetHero()->preDamageTrigger = nullptr;
                    break;
                }
                case TriggerSource::SELF:
                {
                    auto minion = dynamic_cast<Minion*>(m_owner);
                    minion->preDamageTrigger = nullptr;
                    break;
                }
                case TriggerSource::ENCHANTMENT_TARGET:
                {
                    const auto enchantment =
                        dynamic_cast<Enchantment*>(m_owner);
                    auto minion =
                        dynamic_cast<Minion*>(enchantment->GetTarget());
                    minion->preDamageTrigger = nullptr;
                    break;
                }
                default:
                    break;
            }
        case TriggerType::TAKE_DAMAGE:
            game->triggerManager.takeDamageTrigger = nullptr;
            break;
        default:
            throw std::invalid_argument(
                "Trigger::Remove() - Invalid trigger type!");
    }

    if (m_sequenceType != SequenceType::NONE)
    {
        EraseIf(game->triggers,
                [this](Trigger* trigger) { return trigger == this; });
    }

    delete m_owner->activatedTrigger;
}

void Trigger::Process(Player* player, Entity* source)
{
    if (m_sequenceType == SequenceType::NONE)
    {
        Validate(player, source);
    }

    if (!m_isValidated)
    {
        return;
    }

    ProcessInternal(source);
}

void Trigger::ProcessInternal(Entity* source)
{
    m_isValidated = false;

    for (auto& task : tasks)
    {
        task->SetPlayer(m_owner->owner);
        task->SetSource(m_owner);

        if (source != nullptr)
        {
            task->SetTarget(source);
        }
        else
        {
            const auto enchantment = dynamic_cast<Enchantment*>(m_owner);
            if (enchantment != nullptr && enchantment->GetTarget() != nullptr)
            {
                task->SetTarget(enchantment->GetTarget());
            }
            else
            {
                task->SetTarget(nullptr);
            }
        }

        if (fastExecution)
        {
            task->Run();
        }
        else
        {
            m_owner->owner->GetGame()->taskQueue.Enqueue(task);
        }

        if (removeAfterTriggered)
        {
            Remove();
        }
    }

    m_isValidated = false;
}

void Trigger::Validate(Player* player, Entity* source)
{
    switch (triggerSource)
    {
        case TriggerSource::NONE:
            break;
        case TriggerSource::SELF:
            if (source != m_owner)
            {
                return;
            }
            break;
        case TriggerSource::HERO:
            if (dynamic_cast<Hero*>(source) == nullptr ||
                source->owner != m_owner->owner)
            {
                return;
            }
            break;
        case TriggerSource::ALL_MINIONS:
            if (dynamic_cast<Minion*>(source) == nullptr)
            {
                return;
            }
            break;
        case TriggerSource::MINIONS_EXCEPT_SELF:
            if (dynamic_cast<Minion*>(source) == nullptr ||
                source->owner != m_owner->owner || source == m_owner)
            {
                return;
            }
            break;
        case TriggerSource::ENCHANTMENT_TARGET:
        {
            const auto enchantment = dynamic_cast<Enchantment*>(m_owner);
            if (enchantment == nullptr ||
                enchantment->GetTarget()->id != source->id)
            {
                return;
            }
            break;
        }
        case TriggerSource::FRIENDLY:
        {
            if (source->owner != m_owner->owner)
            {
                return;
            }
            break;
        }
        default:
            throw std::invalid_argument(
                "Trigger::Validate() - Invalid source trigger!");
    }

    switch (m_triggerType)
    {
        case TriggerType::TURN_START:
        case TriggerType::TURN_END:
            if (player != m_owner->owner)
            {
                return;
            }
            break;
        case TriggerType::PLAY_CARD:
        case TriggerType::SUMMON:
            if (source == m_owner)
            {
                return;
            }
            break;
        case TriggerType::CAST_SPELL:
        case TriggerType::AFTER_CAST:
        case TriggerType::HEAL:
        case TriggerType::ATTACK:
        case TriggerType::PREDAMAGE:
        case TriggerType::TAKE_DAMAGE:
            break;
        default:
            throw std::invalid_argument(
                "Trigger::Validate() - Invalid trigger type!");
    }

    if (condition != nullptr)
    {
        const bool res = (source != nullptr) ? condition->Evaluate(source)
                                             : condition->Evaluate(m_owner);

        if (!res)
        {
            return;
        }
    }

    m_isValidated = true;
}
}  // namespace RosettaStone
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/no_windows2000_unittest.h"
#include "base/win_util.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/url_request/url_request_unittest.h"

// This test does not work on win2k. See http://b/1070036
class InspectorControllerTest : public NoWindows2000Test<UITest> {
 protected:
  TabProxy* GetActiveTabProxy() {
    scoped_ptr<BrowserProxy> window_proxy(automation()->GetBrowserWindow(0));
    EXPECT_TRUE(window_proxy.get());

    int active_tab_index = 0;
    EXPECT_TRUE(window_proxy->GetActiveTabIndex(&active_tab_index));
    return window_proxy->GetTab(active_tab_index);
  }

  void NavigateTab(TabProxy* tab_proxy, const GURL& url) {
    ASSERT_TRUE(tab_proxy->NavigateToURL(url));
  }
};

// This test also does not work in single process. See http://b/1214920
TEST_F(InspectorControllerTest, InspectElement) {
  if (IsTestCaseDisabled())
    return;

  if (CommandLine().HasSwitch(switches::kSingleProcess))
    return;

  TestServer server(L"chrome/test/data");
  ::scoped_ptr<TabProxy> tab(GetActiveTabProxy());
  // We don't track resources until we've opened the inspector.
  NavigateTab(tab.get(), server.TestServerPageW(L"files/inspector/test1.html"));
  tab->InspectElement(0, 0);
  NavigateTab(tab.get(), server.TestServerPageW(L"files/inspector/test1.html"));
  EXPECT_EQ(1, tab->InspectElement(0, 0));
  NavigateTab(tab.get(), server.TestServerPageW(L"files/inspector/test2.html"));
  EXPECT_EQ(2, tab->InspectElement(0, 0));
}
<commit_msg>Reverting 7206.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/no_windows2000_unittest.h"
#include "base/win_util.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/url_request/url_request_unittest.h"

// This test does not work on win2k. See http://b/1070036
class InspectorControllerTest : public NoWindows2000Test<UITest> {
 protected:
  TabProxy* GetActiveTabProxy() {
    scoped_ptr<BrowserProxy> window_proxy(automation()->GetBrowserWindow(0));
    EXPECT_TRUE(window_proxy.get());

    int active_tab_index = 0;
    EXPECT_TRUE(window_proxy->GetActiveTabIndex(&active_tab_index));
    return window_proxy->GetTab(active_tab_index);
  }

  void NavigateTab(TabProxy* tab_proxy, const GURL& url) {
    ASSERT_TRUE(tab_proxy->NavigateToURL(url));
  }
};

// This test also does not work in single process. See http://b/1214920
// Disabled, see http://crbug.com/4655
TEST_F(InspectorControllerTest, DISABLED_InspectElement) {
  if (IsTestCaseDisabled())
    return;

  if (CommandLine().HasSwitch(switches::kSingleProcess))
    return;

  TestServer server(L"chrome/test/data");
  ::scoped_ptr<TabProxy> tab(GetActiveTabProxy());
  // We don't track resources until we've opened the inspector.
  NavigateTab(tab.get(), server.TestServerPageW(L"files/inspector/test1.html"));
  tab->InspectElement(0, 0);
  NavigateTab(tab.get(), server.TestServerPageW(L"files/inspector/test1.html"));
  EXPECT_EQ(1, tab->InspectElement(0, 0));
  NavigateTab(tab.get(), server.TestServerPageW(L"files/inspector/test2.html"));
  EXPECT_EQ(2, tab->InspectElement(0, 0));
}

<|endoftext|>


<commit_before>/**
 * Toward a resource manager.
 *
 * First of all, I believe that resources should be stored/managed by type. I
 * am not sure this is the right way to do so, but I have the impression I
 * should start like that.
 * => one manager by resource type
 *
 * Also, I do not feel I will need to store managers in a container. Thus, there
 * is no reason to make all resources or managers inherit from a common base. We
 * can then use template.
 * => use templates
 *
 * Should we use UID (unique identifiers), handles or pointers to refer to resources?
 * - UID
 *   × by using string hashes, we can have something like get( "Building_04" )
 *   × a hash value will be used instead of the string to search into the resource database
 *   × to avoid hashing the string every time, we could do get( hash( "Building_04" ) ).
 *     this way, the hash will be computed at compile time (check it!). The issue is for
 *     scripts, where the hash should be computed once and then cached.
 *   × collisions should be handled. I have seen a method to do so [1,2], but it may
 *     a little too complex for now. Instead, I propose to build a dictionary, built
 *     when the hash() function is called, and throw an exception when two words are
 *     given the same hash value. It may be brutal, but it works. When a user have
 *     an exception, he/she knows what words are in conflict and can change one of
 *     them.
 * - handles
 *   × nice way to manage resources in a tight buffer
 *   × how to get an handle for a resource? At resource creation, the handle can
 *     then be deployed to where the resource is used. We must then know where the
 *     resource is needed. An alternative, is to have a dictionary to go from a
 *     name to a handle, and add an entry a resource creation with the couple
 *     (name,handle). Still, the resource should be created before the handle is
 *     recovered from the dictionary. A simple fix could be to return a null handle
 *     if a resource with this name is not known. Then, we have a null handle, we
 *     can ask again to the dictionary if it knows the handle of a name. Thus, at
 *     every use of a handle, we should check if it is null. Note that this should
 *     not be done in the tight buffer, since what to return in case of a null
 *     handle? Instead, we can return an empty resource object, that will be filled
 *     when a resource with that name is loaded.
 *   × when a resource is reloaded, it should use the same memory place, to have
 *     the same handle.
 * - pointers
 *   × we could say that with basic pointers, a resource cannot be reloaded. If
 *     the raw memory is encapsulated inside a wrapper, I do not see why not.
 *   × we could say that resources will not be in contiguous memory. Still, if
 *     we wanted to contiguous memory, we would use an array, so I do not see
 *     the issue here.
 *   × How to get the pointers? We would go by name or by handles. Thus, this
 *     case is just an implementation detail of UID and handles.
 *
 * I have seen examples with UID, handles and pointers on the web, but I do not
 * make a clear separation between the three cases. I cannot see why we cannot use
 * the three. So, the main questions are:
 * - how to store the resources, both on client side and inside the manager?
 * - how to handle the destruction of a resource? e.g. when client still has a copy
 *
 * When a resource is destroyed, it is not clear to me that this resource should
 * continue to exist if it is still referred to by other parts of the code. For
 * example, if I destroy a particular mesh, I do not expect to still see it on
 * the screen: instances using that resource should now use an empty mesh. On the
 * other hand, an instance of empty mesh will still exist after the deletion of the
 * resource. Even if the memory consumption is expected to be lower, we still use
 * a mesh resource. Also, a segmentation fault occurring when accessing to a
 * destroyed resource will provide better debugging information.
 *
 * For now, I will simply store the resources inside the map. Clients will have
 * access to those resources thanks to references, meaning they should not keep such
 * references after resource deletion.
 *
 *
 * [1] http://cowboyprogramming.com/2007/01/04/practical-hash-ids/
 *
 * [2] http://www.randygaul.net/2015/12/11/preprocessed-strings-for-asset-ids/
 */

# include "../graphics-origin/graphics_origin.h"
# include "../graphics-origin/tools/log.h"
# include <unordered_map>
namespace graphics_origin {

  uint32_t hash_name( const std::string& lower_case_ascii_name )
  {
    return std::hash<std::string>()( lower_case_ascii_name );
  }

  template< typename resource_type >
  class resource_manager {
  public:

    class resource :
        public resource_type {
    public:
      static resource null;

      bool is_null() const noexcept
      {
        return this == &null;
      }

      uint32_t get_uid() const noexcept
      {
        return uid;
      }

      uint32_t get_scope() const noexcept
      {
        return scope;
      }

      resource( uint32_t id ) :
        uid{id}, scope{0}
      {
        LOG(debug, "a resource [0x" << std::hex <<  uid << "] is created " << this );
      }

      resource() :
        uid{0}, scope{0}
      {
        LOG(debug, "default resource is created " << this );
      }

      resource& operator=( resource&& other )
      {
        scope = other.scope;
        uid = other.uid;
        resource_type::operator=(std::move(other));
        return *this;
      }

    private:
      resource( const resource& other );

      friend resource_manager;
      uint32_t uid;
      uint32_t scope;
    };

    resource_manager()
    {}

    void load(
        const std::string& filename,
        const std::string& lower_case_ascii_name )
    {
      // what should we do if a resource with that name already exist?
      uint32_t id = hash_name( lower_case_ascii_name );
      auto res = resources.emplace( id, id );
      if( !res.second )
        {
          try
            {
              res.first->second.~resource();
              new((void*)&res.first->second) resource( id/*constructor parameters here*/);
              LOG( debug, "resource [0x" << std::hex << id << " re")
            }
          catch(...)
            {
              LOG( warning, "something went wrong in the construction of resource " << filename << ". Using default resource." );
              new((void*)&res.first->second) resource( id );
            }
        }
      //return id?
    }

    resource& get( uint32_t uid )
    {
      auto search = resources.find( uid );
      if( search != resources.end() )
        return search->second;
      return resource::null;
    }

  private:
    std::unordered_map< uint32_t, resource > resources;
  };

  template< typename resource_type >
  typename resource_manager<resource_type>::resource
  resource_manager<resource_type>::resource::null = resource_manager<resource_type>::resource{};

  struct test_data {
    test_data() :
      dummy{ 0 }
    {}
    int dummy;
  };

  static int execute( int argc, char* argv[] )
  {
    (void)argc;
    (void)argv;

    typedef resource_manager< test_data > test_data_manager;
    typedef test_data_manager::resource resource;

    test_data_manager manager;
    manager.load( "dummy_file.thing", "dummy" );
    uint32_t dummy_id = hash_name( "dummy" );
    resource& res  = manager.get( dummy_id );
    resource& null = resource::null;

    res.dummy = 1;

    LOG( debug, "res  is null: " << res.is_null() );
    LOG( debug, "null is null: " << null.is_null() );
    LOG( debug, "")
    LOG( debug, "res  dummy: " << res.dummy );
    LOG( debug, "null dummy: " << null.dummy );

    return 0;
  }
}

int main( int argc, char* argv[] )
{
  return graphics_origin::execute( argc, argv );
}
<commit_msg>experiments with CRC32<commit_after>/**
 * Toward a resource manager.
 *
 * First of all, I believe that resources should be stored/managed by type. I
 * am not sure this is the right way to do so, but I have the impression I
 * should start like that.
 * => one manager by resource type
 *
 * Also, I do not feel I will need to store managers in a container. Thus, there
 * is no reason to make all resources or managers inherit from a common base. We
 * can then use template.
 * => use templates
 *
 * Should we use UID (unique identifiers), handles or pointers to refer to resources?
 * - UID
 *   × by using string hashes, we can have something like get( "building_04" )
 *   × a hash value will be used instead of the string to search into the resource database
 *   × to avoid hashing the string every time, we could do:
 *   constexpr uint32_t building_04_id = hash( "building_04" );
 *   ...
 *   get( building_04_id );
 *     this way, the hash will be computed at compile time. The issue is for
 *     scripts, where the hash should be computed once and then cached.
 *   × collisions should be handled. I have seen a method to do so [1,2], but it may
 *     a little too complex for now. Instead, I propose to build a dictionary, built
 *     when the hash() function is called, and throw an exception when two words are
 *     given the same hash value. It may be brutal, but it works. When a user have
 *     an exception, he/she knows what words are in conflict and can change one of
 *     them.
 * - handles
 *   × nice way to manage resources in a tight buffer
 *   × how to get an handle for a resource? At resource creation, the handle can
 *     then be deployed to where the resource is used. We must then know where the
 *     resource is needed. An alternative, is to have a dictionary to go from a
 *     name to a handle, and add an entry a resource creation with the couple
 *     (name,handle). Still, the resource should be created before the handle is
 *     recovered from the dictionary. A simple fix could be to return a null handle
 *     if a resource with this name is not known. Then, we have a null handle, we
 *     can ask again to the dictionary if it knows the handle of a name. Thus, at
 *     every use of a handle, we should check if it is null. Note that this should
 *     not be done in the tight buffer, since what to return in case of a null
 *     handle? Instead, we can return an empty resource object, that will be filled
 *     when a resource with that name is loaded.
 *   × when a resource is reloaded, it should use the same memory place, to have
 *     the same handle.
 * - pointers
 *   × we could say that with basic pointers, a resource cannot be reloaded. If
 *     the raw memory is encapsulated inside a wrapper, I do not see why not.
 *   × we could say that resources will not be in contiguous memory. Still, if
 *     we wanted to contiguous memory, we would use an array, so I do not see
 *     the issue here.
 *   × How to get the pointers? We would go by name or by handles. Thus, this
 *     case is just an implementation detail of UID and handles.
 *
 * I have seen examples with UID, handles and pointers on the web, but I do not
 * make a clear separation between the three cases. I cannot see why we cannot use
 * the three. So, the main questions are:
 * - how to store the resources, both on client side and inside the manager?
 * - how to handle the destruction of a resource? e.g. when client still has a copy
 *
 * When a resource is destroyed, it is not clear to me that this resource should
 * continue to exist if it is still referred to by other parts of the code. For
 * example, if I destroy a particular mesh, I do not expect to still see it on
 * the screen: instances using that resource should now use an empty mesh. On the
 * other hand, an instance of empty mesh will still exist after the deletion of the
 * resource. Even if the memory consumption is expected to be lower, we still use
 * a mesh resource. Also, a segmentation fault occurring when accessing to a
 * destroyed resource will provide better debugging information.
 *
 * For now, I will simply store the resources inside the map. Clients will have
 * access to those resources thanks to references, meaning they should not keep such
 * references after resource deletion.
 *
 *
 * [1] http://cowboyprogramming.com/2007/01/04/practical-hash-ids/
 *
 * [2] http://www.randygaul.net/2015/12/11/preprocessed-strings-for-asset-ids/
 */

# include "../graphics-origin/graphics_origin.h"
# include "../graphics-origin/tools/log.h"
# include <unordered_map>
namespace graphics_origin {

  uint32_t hash_name( const std::string& lower_case_ascii_name )
  {
    return std::hash<std::string>()( lower_case_ascii_name );
  }

  template< typename resource_type >
  class resource_manager {
  public:

    class resource :
        public resource_type {
    public:
      static resource null;

      bool is_null() const noexcept
      {
        return this == &null;
      }

      uint32_t get_uid() const noexcept
      {
        return uid;
      }

      uint32_t get_scope() const noexcept
      {
        return scope;
      }

      resource( uint32_t id ) :
        uid{id}, scope{0}
      {
        LOG(debug, "a resource [0x" << std::hex <<  uid << "] is created " << this );
      }

      resource() :
        uid{0}, scope{0}
      {
        LOG(debug, "default resource is created " << this );
      }

      resource& operator=( resource&& other )
      {
        scope = other.scope;
        uid = other.uid;
        resource_type::operator=(std::move(other));
        return *this;
      }

    private:
      resource( const resource& other );

      friend resource_manager;
      uint32_t uid;
      uint32_t scope;
    };

    resource_manager()
    {}

    void load(
        const std::string& filename,
        const std::string& lower_case_ascii_name )
    {
      // what should we do if a resource with that name already exist?
      uint32_t id = hash_name( lower_case_ascii_name );
      auto res = resources.emplace( id, id );
      if( !res.second )
        {
          try
            {
              res.first->second.~resource();
              new((void*)&res.first->second) resource( id/*constructor parameters here*/);
              LOG( debug, "resource [0x" << std::hex << id << " re")
            }
          catch(...)
            {
              LOG( warning, "something went wrong in the construction of resource " << filename << ". Using default resource." );
              new((void*)&res.first->second) resource( id );
            }
        }
      //return id?
    }

    resource& get( uint32_t uid )
    {
      auto search = resources.find( uid );
      if( search != resources.end() )
        return search->second;
      return resource::null;
    }

  private:
    std::unordered_map< uint32_t, resource > resources;
  };

  template< typename resource_type >
  typename resource_manager<resource_type>::resource
  resource_manager<resource_type>::resource::null = resource_manager<resource_type>::resource{};

  struct test_data {
    test_data() :
      dummy{ 0 }
    {}
    int dummy;
  };

  namespace cexp
  {

      // Small implementation of std::array, needed until constexpr
      // is added to the function 'reference operator[](size_type)'
      template <typename T, std::size_t N>
      struct array {
          T m_data[N];

          using value_type = T;
          using reference = value_type &;
          using const_reference = const value_type &;
          using size_type = std::size_t;

          // This is NOT constexpr in std::array until C++17
          constexpr reference operator[](size_type i) noexcept {
              return m_data[i];
          }

          constexpr const_reference operator[](size_type i) const noexcept {
              return m_data[i];
          }

          constexpr size_type size() const noexcept {
              return N;
          }
      };

  }

  // Generates CRC-32 table, algorithm based from this link:
  // http://www.hackersdelight.org/hdcodetxt/crc.c.txt
  constexpr auto gen_crc32_table() {
      constexpr auto num_bytes = 256;
      constexpr auto num_iterations = 8;
      constexpr auto polynomial = 0xEDB88320;

      auto crc32_table = cexp::array<uint32_t, num_bytes>{};

      for (auto byte = 0u; byte < num_bytes; ++byte) {
          auto crc = byte;

          for (auto i = 0; i < num_iterations; ++i) {
              auto mask = -(crc & 1);
              crc = (crc >> 1) ^ (polynomial & mask);
          }

          crc32_table[byte] = crc;
      }

      return crc32_table;
  }

  // Stores CRC-32 table and softly validates it.
  static constexpr auto crc32_table = gen_crc32_table();

  // Generates CRC-32 code from null-terminated, c-string,
  // algorithm based from this link:
  // http://www.hackersdelight.org/hdcodetxt/crc.c.txt
  constexpr auto crc32(const char *in) {
      auto crc = 0xFFFFFFFFu;

      for (auto i = 0u; auto c = in[i]; ++i) {
          crc = crc32_table[(crc ^ c) & 0xFF] ^ (crc >> 8);
      }

      return ~crc;
  }

  void dummy( uint32_t i )
  {
    uint32_t b = i;
    LOG( debug, b );
  }

  static int execute( int argc, char* argv[] )
  {
    (void)argc;
    (void)argv;

    typedef resource_manager< test_data > test_data_manager;
    typedef test_data_manager::resource resource;

    test_data_manager manager;
    manager.load( "dummy_file.thing", "dummy" );
    uint32_t dummy_id = hash_name( "dummy" );
    resource& res  = manager.get( dummy_id );
    resource& null = resource::null;

    res.dummy = 1;

    LOG( debug, "res  is null: " << res.is_null() );
    LOG( debug, "null is null: " << null.is_null() );
    LOG( debug, "")
    LOG( debug, "res  dummy: " << res.dummy );
    LOG( debug, "null dummy: " << null.dummy );

    dummy( crc32("test_me/man.conf") );

    return 0;
  }
}

int main( int argc, char* argv[] )
{
  return graphics_origin::execute( argc, argv );
}
<|endoftext|>


<commit_before>#include "openmc/finalize.h"

#include "openmc/bank.h"
#include "openmc/capi.h"
#include "openmc/cmfd_solver.h"
#include "openmc/constants.h"
#include "openmc/cross_sections.h"
#include "openmc/dagmc.h"
#include "openmc/eigenvalue.h"
#include "openmc/geometry.h"
#include "openmc/geometry_aux.h"
#include "openmc/material.h"
#include "openmc/mesh.h"
#include "openmc/message_passing.h"
#include "openmc/nuclide.h"
#include "openmc/photon.h"
#include "openmc/random_lcg.h"
#include "openmc/settings.h"
#include "openmc/simulation.h"
#include "openmc/source.h"
#include "openmc/surface.h"
#include "openmc/thermal.h"
#include "openmc/timer.h"
#include "openmc/tallies/tally.h"
#include "openmc/volume_calc.h"

#include "xtensor/xview.hpp"

namespace openmc {

void free_memory()
{
  free_memory_geometry();
  free_memory_surfaces();
  free_memory_material();
  free_memory_volume();
  free_memory_simulation();
  free_memory_photon();
  free_memory_settings();
  free_memory_thermal();
  library_clear();
  nuclides_clear();
  free_memory_source();
  free_memory_mesh();
  free_memory_tally();
  free_memory_bank();
  free_memory_cmfd();
#ifdef DAGMC
  free_memory_dagmc();
#endif
}

}

using namespace openmc;

int openmc_finalize()
{
  // Clear results
  openmc_reset();

  // Reset timers
  reset_timers();

  // Reset global variables
  settings::assume_separate = false;
  settings::check_overlaps = false;
  settings::confidence_intervals = false;
  settings::create_fission_neutrons = true;
  settings::electron_treatment = ELECTRON_LED;
  settings::energy_cutoff = {0.0, 1000.0, 0.0, 0.0};
  settings::entropy_on = false;
  settings::gen_per_batch = 1;
  settings::legendre_to_tabular = true;
  settings::legendre_to_tabular_points = -1;
  settings::n_particles = -1;
  settings::output_summary = true;
  settings::output_tallies = true;
  settings::particle_restart_run = false;
  settings::photon_transport = false;
  settings::reduce_tallies = true;
  settings::res_scat_on = false;
  settings::res_scat_method = ResScatMethod::rvs;
  settings::res_scat_energy_min = 0.01;
  settings::res_scat_energy_max = 1000.0;
  settings::restart_run = false;
  settings::run_CE = true;
  settings::run_mode = -1;
  settings::dagmc = false;
  settings::source_latest = false;
  settings::source_separate = false;
  settings::source_write = true;
  settings::survival_biasing = false;
  settings::temperature_default = 293.6;
  settings::temperature_method = TEMPERATURE_NEAREST;
  settings::temperature_multipole = false;
  settings::temperature_range = {0.0, 0.0};
  settings::temperature_tolerance = 10.0;
  settings::trigger_on = false;
  settings::trigger_predict = false;
  settings::trigger_batch_interval = 1;
  settings::ufs_on = false;
  settings::urr_ptables_on = true;
  settings::verbosity = 7;
  settings::weight_cutoff = 0.25;
  settings::weight_survive = 1.0;
  settings::write_all_tracks = false;
  settings::write_initial_source = false;

  simulation::keff = 1.0;
  simulation::n_lost_particles = 0;
  simulation::satisfy_triggers = false;
  simulation::total_gen = 0;

  simulation::entropy_mesh = nullptr;
  simulation::ufs_mesh = nullptr;

  data::energy_max = {INFTY, INFTY};
  data::energy_min = {0.0, 0.0};
  model::root_universe = -1;
  openmc::openmc_set_seed(DEFAULT_SEED);

  // Deallocate arrays
  free_memory();

  // Free all MPI types
#ifdef OPENMC_MPI
  MPI_Type_free(&mpi::bank);
#endif

  return 0;
}

int openmc_reset()
{
  for (auto& t : model::tallies) {
    t->reset();
  }

  // Reset global tallies
  simulation::n_realizations = 0;
  xt::view(simulation::global_tallies, xt::all()) = 0.0;

  simulation::k_col_abs = 0.0;
  simulation::k_col_tra = 0.0;
  simulation::k_abs_tra = 0.0;
  simulation::k_sum = {0.0, 0.0};

  return 0;
}

int openmc_hard_reset()
{
  // Reset all tallies and timers
  openmc_reset();
  reset_timers();

  // Reset total generations and keff guess
  simulation::keff = 1.0;
  simulation::total_gen = 0;

  // Reset the random number generator state
  openmc::openmc_set_seed(DEFAULT_SEED);
  return 0;
}
<commit_msg>Free CMFD memory on master process<commit_after>#include "openmc/finalize.h"

#include "openmc/bank.h"
#include "openmc/capi.h"
#include "openmc/cmfd_solver.h"
#include "openmc/constants.h"
#include "openmc/cross_sections.h"
#include "openmc/dagmc.h"
#include "openmc/eigenvalue.h"
#include "openmc/geometry.h"
#include "openmc/geometry_aux.h"
#include "openmc/material.h"
#include "openmc/mesh.h"
#include "openmc/message_passing.h"
#include "openmc/nuclide.h"
#include "openmc/photon.h"
#include "openmc/random_lcg.h"
#include "openmc/settings.h"
#include "openmc/simulation.h"
#include "openmc/source.h"
#include "openmc/surface.h"
#include "openmc/thermal.h"
#include "openmc/timer.h"
#include "openmc/tallies/tally.h"
#include "openmc/volume_calc.h"

#include "xtensor/xview.hpp"

namespace openmc {

void free_memory()
{
  free_memory_geometry();
  free_memory_surfaces();
  free_memory_material();
  free_memory_volume();
  free_memory_simulation();
  free_memory_photon();
  free_memory_settings();
  free_memory_thermal();
  library_clear();
  nuclides_clear();
  free_memory_source();
  free_memory_mesh();
  free_memory_tally();
  free_memory_bank();
  if (mpi::master) {
    free_memory_cmfd();
  }
#ifdef DAGMC
  free_memory_dagmc();
#endif
}

}

using namespace openmc;

int openmc_finalize()
{
  // Clear results
  openmc_reset();

  // Reset timers
  reset_timers();

  // Reset global variables
  settings::assume_separate = false;
  settings::check_overlaps = false;
  settings::confidence_intervals = false;
  settings::create_fission_neutrons = true;
  settings::electron_treatment = ELECTRON_LED;
  settings::energy_cutoff = {0.0, 1000.0, 0.0, 0.0};
  settings::entropy_on = false;
  settings::gen_per_batch = 1;
  settings::legendre_to_tabular = true;
  settings::legendre_to_tabular_points = -1;
  settings::n_particles = -1;
  settings::output_summary = true;
  settings::output_tallies = true;
  settings::particle_restart_run = false;
  settings::photon_transport = false;
  settings::reduce_tallies = true;
  settings::res_scat_on = false;
  settings::res_scat_method = ResScatMethod::rvs;
  settings::res_scat_energy_min = 0.01;
  settings::res_scat_energy_max = 1000.0;
  settings::restart_run = false;
  settings::run_CE = true;
  settings::run_mode = -1;
  settings::dagmc = false;
  settings::source_latest = false;
  settings::source_separate = false;
  settings::source_write = true;
  settings::survival_biasing = false;
  settings::temperature_default = 293.6;
  settings::temperature_method = TEMPERATURE_NEAREST;
  settings::temperature_multipole = false;
  settings::temperature_range = {0.0, 0.0};
  settings::temperature_tolerance = 10.0;
  settings::trigger_on = false;
  settings::trigger_predict = false;
  settings::trigger_batch_interval = 1;
  settings::ufs_on = false;
  settings::urr_ptables_on = true;
  settings::verbosity = 7;
  settings::weight_cutoff = 0.25;
  settings::weight_survive = 1.0;
  settings::write_all_tracks = false;
  settings::write_initial_source = false;

  simulation::keff = 1.0;
  simulation::n_lost_particles = 0;
  simulation::satisfy_triggers = false;
  simulation::total_gen = 0;

  simulation::entropy_mesh = nullptr;
  simulation::ufs_mesh = nullptr;

  data::energy_max = {INFTY, INFTY};
  data::energy_min = {0.0, 0.0};
  model::root_universe = -1;
  openmc::openmc_set_seed(DEFAULT_SEED);

  // Deallocate arrays
  free_memory();

  // Free all MPI types
#ifdef OPENMC_MPI
  MPI_Type_free(&mpi::bank);
#endif

  return 0;
}

int openmc_reset()
{
  for (auto& t : model::tallies) {
    t->reset();
  }

  // Reset global tallies
  simulation::n_realizations = 0;
  xt::view(simulation::global_tallies, xt::all()) = 0.0;

  simulation::k_col_abs = 0.0;
  simulation::k_col_tra = 0.0;
  simulation::k_abs_tra = 0.0;
  simulation::k_sum = {0.0, 0.0};

  return 0;
}

int openmc_hard_reset()
{
  // Reset all tallies and timers
  openmc_reset();
  reset_timers();

  // Reset total generations and keff guess
  simulation::keff = 1.0;
  simulation::total_gen = 0;

  // Reset the random number generator state
  openmc::openmc_set_seed(DEFAULT_SEED);
  return 0;
}
<|endoftext|>


<commit_before>
/*
	This file is part of cpp-ethereum.

	cpp-ethereum 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.

	cpp-ethereum 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 cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2014
 * Unit tests for the solidity expression compiler, testing the behaviour of the code.
 */

#include <string>
#include <boost/test/unit_test.hpp>
#include <libethereum/State.h>
#include <libethereum/Executive.h>
#include <libsolidity/CompilerStack.h>

using namespace std;

namespace dev
{
namespace solidity
{
namespace test
{

class ExecutionFramework
{
public:
	ExecutionFramework() { g_logVerbosity = 0; }

	bytes compileAndRun(std::string const& _sourceCode)
	{
		bytes code = dev::solidity::CompilerStack::compile(_sourceCode);
		sendMessage(code, true);
		return m_output;
	}

	bytes callFunction(byte _index, bytes const& _data)
	{
		sendMessage(bytes(1, _index) + _data, false);
		return m_output;
	}

	bytes callFunction(byte _index, u256 const& _argument1)
	{
		callFunction(_index, toBigEndian(_argument1));
		return m_output;
	}

private:
	void sendMessage(bytes const& _data, bool _isCreation)
	{
		eth::Executive executive(m_state);
		eth::Transaction t = _isCreation ? eth::Transaction(0, m_gasPrice, m_gas, _data)
										 : eth::Transaction(0, m_gasPrice, m_gas, m_contractAddress, _data);
		bytes transactionRLP = t.rlp();
		try
		{
			// this will throw since the transaction is invalid, but it should nevertheless store the transaction
			executive.setup(&transactionRLP);
		}
		catch (...) {}
		if (_isCreation)
		{
			BOOST_REQUIRE(!executive.create(Address(), 0, m_gasPrice, m_gas, &_data, Address()));
			m_contractAddress = executive.newAddress();
			BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress));
		}
		else
			BOOST_REQUIRE(!executive.call(m_contractAddress, Address(), 0, m_gasPrice, &_data, m_gas, Address()));
		BOOST_REQUIRE(executive.go());
		executive.finalize();
		m_output = executive.out().toBytes();
	}

	Address m_contractAddress;
	eth::State m_state;
	u256 const m_gasPrice = 100 * eth::szabo;
	u256 const m_gas = 1000000;
	bytes m_output;
};

BOOST_AUTO_TEST_SUITE(SolidityCompilerEndToEndTest)

BOOST_AUTO_TEST_CASE(smoke_test)
{
	char const* sourceCode = "contract test {\n"
							 "  function f(uint a) returns(uint d) { return a * 7; }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	u256 a = 0x200030004;
	bytes result = framework.callFunction(0, a);
	BOOST_CHECK(result == toBigEndian(a * 7));
}

BOOST_AUTO_TEST_CASE(empty_contract)
{
	char const* sourceCode = "contract test {\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(0, bytes()).empty());
}

BOOST_AUTO_TEST_CASE(recursive_calls)
{
	char const* sourceCode = "contract test {\n"
							 "  function f(uint n) returns(uint nfac) {\n"
							 "    if (n <= 1) return 1;\n"
							 "    else return n * f(n - 1);\n"
							 "  }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(1)));
	BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(1)));
	BOOST_CHECK(framework.callFunction(0, u256(2)) == toBigEndian(u256(2)));
	BOOST_CHECK(framework.callFunction(0, u256(3)) == toBigEndian(u256(6)));
	BOOST_CHECK(framework.callFunction(0, u256(4)) == toBigEndian(u256(24)));
}

BOOST_AUTO_TEST_CASE(while_loop)
{
	char const* sourceCode = "contract test {\n"
							 "  function f(uint n) returns(uint nfac) {\n"
							 "    nfac = 1;\n"
							 "    var i = 2;\n"
							 "    while (i <= n) nfac *= i++;\n"
							 "  }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(1)));
	BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(1)));
	BOOST_CHECK(framework.callFunction(0, u256(2)) == toBigEndian(u256(2)));
	BOOST_CHECK(framework.callFunction(0, u256(3)) == toBigEndian(u256(6)));
	BOOST_CHECK(framework.callFunction(0, u256(4)) == toBigEndian(u256(24)));
}

BOOST_AUTO_TEST_CASE(calling_other_functions)
{
	// note that the index of a function is its index in the sorted sequence of functions
	char const* sourceCode = "contract collatz {\n"
							 "  function run(uint x) returns(uint y) {\n"
							 "    while ((y = x) > 1) {\n"
							 "      if (x % 2 == 0) x = evenStep(x);\n"
							 "      else x = oddStep(x);\n"
							 "    }\n"
							 "  }\n"
							 "  function evenStep(uint x) returns(uint y) {\n"
							 "    return x / 2;\n"
							 "  }\n"
							 "  function oddStep(uint x) returns(uint y) {\n"
							 "    return 3 * x + 1;\n"
							 "  }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(2, u256(0)) == toBigEndian(u256(0)));
	BOOST_CHECK(framework.callFunction(2, u256(1)) == toBigEndian(u256(1)));
	BOOST_CHECK(framework.callFunction(2, u256(2)) == toBigEndian(u256(1)));
	BOOST_CHECK(framework.callFunction(2, u256(8)) == toBigEndian(u256(1)));
	BOOST_CHECK(framework.callFunction(2, u256(127)) == toBigEndian(u256(1)));
}

BOOST_AUTO_TEST_CASE(many_local_variables)
{
	char const* sourceCode = "contract test {\n"
							 "  function run(uint x1, uint x2, uint x3) returns(uint y) {\n"
							 "    var a = 0x1; var b = 0x10; var c = 0x100;\n"
							 "    y = a + b + c + x1 + x2 + x3;\n"
							 "    y += b + x2;\n"
							 "  }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(0, toBigEndian(u256(0x1000)) + toBigEndian(u256(0x10000)) + toBigEndian(u256(0x100000)))
				== toBigEndian(u256(0x121121)));
}

BOOST_AUTO_TEST_CASE(multiple_return_values)
{
	char const* sourceCode = "contract test {\n"
							 "  function run(bool x1, uint x2) returns(uint y1, bool y2, uint y3) {\n"
							 "    y1 = x2; y2 = x1;\n"
							 "  }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(0, bytes(1, 1) + toBigEndian(u256(0xcd)))
				== toBigEndian(u256(0xcd)) + bytes(1, 1) + toBigEndian(u256(0)));
}

BOOST_AUTO_TEST_CASE(short_circuiting)
{
	char const* sourceCode = "contract test {\n"
							 "  function run(uint x) returns(uint y) {\n"
							 "    x == 0 || ((x = 8) > 0);\n"
							 "    return x;"
							 "  }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(0)));
	BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(8)));
}

//@todo test smaller types

BOOST_AUTO_TEST_SUITE_END()

}
}
} // end namespaces

<commit_msg>Tests for break and continue in nested loops.<commit_after>
/*
	This file is part of cpp-ethereum.

	cpp-ethereum 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.

	cpp-ethereum 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 cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2014
 * Unit tests for the solidity expression compiler, testing the behaviour of the code.
 */

#include <string>
#include <boost/test/unit_test.hpp>
#include <libethereum/State.h>
#include <libethereum/Executive.h>
#include <libsolidity/CompilerStack.h>

using namespace std;

namespace dev
{
namespace solidity
{
namespace test
{

class ExecutionFramework
{
public:
	ExecutionFramework() { g_logVerbosity = 0; }

	bytes compileAndRun(std::string const& _sourceCode)
	{
		bytes code = dev::solidity::CompilerStack::compile(_sourceCode);
		sendMessage(code, true);
		return m_output;
	}

	bytes callFunction(byte _index, bytes const& _data)
	{
		sendMessage(bytes(1, _index) + _data, false);
		return m_output;
	}

	bytes callFunction(byte _index, u256 const& _argument1)
	{
		callFunction(_index, toBigEndian(_argument1));
		return m_output;
	}

private:
	void sendMessage(bytes const& _data, bool _isCreation)
	{
		eth::Executive executive(m_state);
		eth::Transaction t = _isCreation ? eth::Transaction(0, m_gasPrice, m_gas, _data)
										 : eth::Transaction(0, m_gasPrice, m_gas, m_contractAddress, _data);
		bytes transactionRLP = t.rlp();
		try
		{
			// this will throw since the transaction is invalid, but it should nevertheless store the transaction
			executive.setup(&transactionRLP);
		}
		catch (...) {}
		if (_isCreation)
		{
			BOOST_REQUIRE(!executive.create(Address(), 0, m_gasPrice, m_gas, &_data, Address()));
			m_contractAddress = executive.newAddress();
			BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress));
		}
		else
			BOOST_REQUIRE(!executive.call(m_contractAddress, Address(), 0, m_gasPrice, &_data, m_gas, Address()));
		BOOST_REQUIRE(executive.go());
		executive.finalize();
		m_output = executive.out().toBytes();
	}

	Address m_contractAddress;
	eth::State m_state;
	u256 const m_gasPrice = 100 * eth::szabo;
	u256 const m_gas = 1000000;
	bytes m_output;
};

BOOST_AUTO_TEST_SUITE(SolidityCompilerEndToEndTest)

BOOST_AUTO_TEST_CASE(smoke_test)
{
	char const* sourceCode = "contract test {\n"
							 "  function f(uint a) returns(uint d) { return a * 7; }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	u256 a = 0x200030004;
	bytes result = framework.callFunction(0, a);
	BOOST_CHECK(result == toBigEndian(a * 7));
}

BOOST_AUTO_TEST_CASE(empty_contract)
{
	char const* sourceCode = "contract test {\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(0, bytes()).empty());
}

BOOST_AUTO_TEST_CASE(recursive_calls)
{
	char const* sourceCode = "contract test {\n"
							 "  function f(uint n) returns(uint nfac) {\n"
							 "    if (n <= 1) return 1;\n"
							 "    else return n * f(n - 1);\n"
							 "  }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(1)));
	BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(1)));
	BOOST_CHECK(framework.callFunction(0, u256(2)) == toBigEndian(u256(2)));
	BOOST_CHECK(framework.callFunction(0, u256(3)) == toBigEndian(u256(6)));
	BOOST_CHECK(framework.callFunction(0, u256(4)) == toBigEndian(u256(24)));
}

BOOST_AUTO_TEST_CASE(while_loop)
{
	char const* sourceCode = "contract test {\n"
							 "  function f(uint n) returns(uint nfac) {\n"
							 "    nfac = 1;\n"
							 "    var i = 2;\n"
							 "    while (i <= n) nfac *= i++;\n"
							 "  }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(1)));
	BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(1)));
	BOOST_CHECK(framework.callFunction(0, u256(2)) == toBigEndian(u256(2)));
	BOOST_CHECK(framework.callFunction(0, u256(3)) == toBigEndian(u256(6)));
	BOOST_CHECK(framework.callFunction(0, u256(4)) == toBigEndian(u256(24)));
}

BOOST_AUTO_TEST_CASE(nested_loops)
{
	// tests that break and continue statements in nested loops jump to the correct place
	char const* sourceCode = "contract test {\n"
							 "  function f(uint x) returns(uint y) {\n"
							 "    while (x > 1) {\n"
							 "      if (x == 10) break;\n"
							 "      while (x > 5) {\n"
							 "        if (x == 8) break;\n"
							 "        x--;\n"
							 "        if (x == 6) continue;\n"
							 "        return x;\n"
							 "      }\n"
							 "      x--;\n"
							 "      if (x == 3) continue;\n"
							 "      break;\n"
							 "    }\n"
							 "    return x;\n"
							 "  }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(0)));
	BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(1)));
	BOOST_CHECK(framework.callFunction(0, u256(2)) == toBigEndian(u256(1)));
	BOOST_CHECK(framework.callFunction(0, u256(3)) == toBigEndian(u256(2)));
	BOOST_CHECK(framework.callFunction(0, u256(4)) == toBigEndian(u256(2)));
	BOOST_CHECK(framework.callFunction(0, u256(5)) == toBigEndian(u256(4)));
	BOOST_CHECK(framework.callFunction(0, u256(6)) == toBigEndian(u256(5)));
	BOOST_CHECK(framework.callFunction(0, u256(7)) == toBigEndian(u256(5)));
	BOOST_CHECK(framework.callFunction(0, u256(8)) == toBigEndian(u256(7)));
	BOOST_CHECK(framework.callFunction(0, u256(9)) == toBigEndian(u256(8)));
	BOOST_CHECK(framework.callFunction(0, u256(10)) == toBigEndian(u256(10)));
	BOOST_CHECK(framework.callFunction(0, u256(11)) == toBigEndian(u256(10)));
}

BOOST_AUTO_TEST_CASE(calling_other_functions)
{
	// note that the index of a function is its index in the sorted sequence of functions
	char const* sourceCode = "contract collatz {\n"
							 "  function run(uint x) returns(uint y) {\n"
							 "    while ((y = x) > 1) {\n"
							 "      if (x % 2 == 0) x = evenStep(x);\n"
							 "      else x = oddStep(x);\n"
							 "    }\n"
							 "  }\n"
							 "  function evenStep(uint x) returns(uint y) {\n"
							 "    return x / 2;\n"
							 "  }\n"
							 "  function oddStep(uint x) returns(uint y) {\n"
							 "    return 3 * x + 1;\n"
							 "  }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(2, u256(0)) == toBigEndian(u256(0)));
	BOOST_CHECK(framework.callFunction(2, u256(1)) == toBigEndian(u256(1)));
	BOOST_CHECK(framework.callFunction(2, u256(2)) == toBigEndian(u256(1)));
	BOOST_CHECK(framework.callFunction(2, u256(8)) == toBigEndian(u256(1)));
	BOOST_CHECK(framework.callFunction(2, u256(127)) == toBigEndian(u256(1)));
}

BOOST_AUTO_TEST_CASE(many_local_variables)
{
	char const* sourceCode = "contract test {\n"
							 "  function run(uint x1, uint x2, uint x3) returns(uint y) {\n"
							 "    var a = 0x1; var b = 0x10; var c = 0x100;\n"
							 "    y = a + b + c + x1 + x2 + x3;\n"
							 "    y += b + x2;\n"
							 "  }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(0, toBigEndian(u256(0x1000)) + toBigEndian(u256(0x10000)) + toBigEndian(u256(0x100000)))
				== toBigEndian(u256(0x121121)));
}

BOOST_AUTO_TEST_CASE(multiple_return_values)
{
	char const* sourceCode = "contract test {\n"
							 "  function run(bool x1, uint x2) returns(uint y1, bool y2, uint y3) {\n"
							 "    y1 = x2; y2 = x1;\n"
							 "  }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(0, bytes(1, 1) + toBigEndian(u256(0xcd)))
				== toBigEndian(u256(0xcd)) + bytes(1, 1) + toBigEndian(u256(0)));
}

BOOST_AUTO_TEST_CASE(short_circuiting)
{
	char const* sourceCode = "contract test {\n"
							 "  function run(uint x) returns(uint y) {\n"
							 "    x == 0 || ((x = 8) > 0);\n"
							 "    return x;"
							 "  }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(0)));
	BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(8)));
}

//@todo test smaller types

BOOST_AUTO_TEST_SUITE_END()

}
}
} // end namespaces

<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2013 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 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.
 *
 ****************************************************************************/

/**
 * @file ms5611_spi.cpp
 *
 * SPI interface for MS5611
 */

/* XXX trim includes */
#include <px4_config.h>

#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>

#include <arch/board/board.h>

#include <drivers/device/spi.h>

#include "ms5611.h"
#include "board_config.h"

/* SPI protocol address bits */
#define DIR_READ			(1<<7)
#define DIR_WRITE			(0<<7)
#define ADDR_INCREMENT			(1<<6)

#if defined(PX4_SPIDEV_BARO) || defined(PX4_SPIDEV_EXT_BARO)

device::Device *MS5611_spi_interface(ms5611::prom_u &prom_buf, bool external_bus);

class MS5611_SPI : public device::SPI
{
public:
	MS5611_SPI(uint8_t bus, spi_dev_e device, ms5611::prom_u &prom_buf);
	virtual ~MS5611_SPI();

	virtual int	init();
	virtual int	read(unsigned offset, void *data, unsigned count);
	virtual int	ioctl(unsigned operation, unsigned &arg);

private:
	ms5611::prom_u	&_prom;

	/**
	 * Send a reset command to the MS5611.
	 *
	 * This is required after any bus reset.
	 */
	int		_reset();

	/**
	 * Send a measure command to the MS5611.
	 *
	 * @param addr		Which address to use for the measure operation.
	 */
	int		_measure(unsigned addr);

	/**
	 * Read the MS5611 PROM
	 *
	 * @return		OK if the PROM reads successfully.
	 */
	int		_read_prom();

	/**
	 * Read a 16-bit register value.
	 *
	 * @param reg		The register to read.
	 */
	uint16_t	_reg16(unsigned reg);

	/**
	 * Wrapper around transfer() that prevents interrupt-context transfers
	 * from pre-empting us. The sensor may (does) share a bus with sensors
	 * that are polled from interrupt context (or we may be pre-empted)
	 * so we need to guarantee that transfers complete without interruption.
	 */
	int		_transfer(uint8_t *send, uint8_t *recv, unsigned len);
};

device::Device *
MS5611_spi_interface(ms5611::prom_u &prom_buf, uint8_t busnum)
{
#ifdef PX4_SPI_BUS_EXT

	if (busnum == PX4_SPI_BUS_EXT) {
#ifdef PX4_SPIDEV_EXT_BARO
		return new MS5611_SPI(busnum, (spi_dev_e)PX4_SPIDEV_EXT_BARO, prom_buf);
#else
		return nullptr;
#endif
	}

#endif
	return new MS5611_SPI(busnum, (spi_dev_e)PX4_SPIDEV_BARO, prom_buf);
}

MS5611_SPI::MS5611_SPI(uint8_t bus, spi_dev_e device, ms5611::prom_u &prom_buf) :
	SPI("MS5611_SPI", nullptr, bus, device, SPIDEV_MODE3, 11 * 1000 * 1000 /* will be rounded to 10.4 MHz */),
	_prom(prom_buf)
{
}

MS5611_SPI::~MS5611_SPI()
{
}

int
MS5611_SPI::init()
{
	// Sharing a bus with NuttX drivers
#if defined (CONFIG_ARCH_BOARD_PX4FMU_V4)
	//set_lockmode(SPI::LOCK_THREADS);
#endif

	int ret;

	ret = SPI::init();

	if (ret != OK) {
		DEVICE_DEBUG("SPI init failed");
		goto out;
	}

	/* send reset command */
	ret = _reset();

	if (ret != OK) {
		DEVICE_DEBUG("reset failed");
		goto out;
	}

	/* read PROM */
	ret = _read_prom();

	if (ret != OK) {
		DEVICE_DEBUG("prom readout failed");
		goto out;
	}

out:
	return ret;
}

int
MS5611_SPI::read(unsigned offset, void *data, unsigned count)
{
	union _cvt {
		uint8_t	b[4];
		uint32_t w;
	} *cvt = (_cvt *)data;
	uint8_t buf[4] = { 0 | DIR_WRITE, 0, 0, 0 };

	/* read the most recent measurement */
	int ret = _transfer(&buf[0], &buf[0], sizeof(buf));

	if (ret == OK) {
		/* fetch the raw value */
		cvt->b[0] = buf[3];
		cvt->b[1] = buf[2];
		cvt->b[2] = buf[1];
		cvt->b[3] = 0;

		ret = count;
	}

	return ret;
}

int
MS5611_SPI::ioctl(unsigned operation, unsigned &arg)
{
	int ret;

	switch (operation) {
	case IOCTL_RESET:
		ret = _reset();
		break;

	case IOCTL_MEASURE:
		ret = _measure(arg);
		break;

	default:
		ret = EINVAL;
	}

	if (ret != OK) {
		errno = ret;
		return -1;
	}

	return 0;
}

int
MS5611_SPI::_reset()
{
	uint8_t cmd = ADDR_RESET_CMD | DIR_WRITE;

	return  _transfer(&cmd, nullptr, 1);
}

int
MS5611_SPI::_measure(unsigned addr)
{
	uint8_t cmd = addr | DIR_WRITE;

	return _transfer(&cmd, nullptr, 1);
}

int
MS5611_SPI::_read_prom()
{
	/*
	 * Wait for PROM contents to be in the device (2.8 ms) in the case we are
	 * called immediately after reset.
	 */
	usleep(3000);

	/* read and convert PROM words */
	bool all_zero = true;

	for (int i = 0; i < 8; i++) {
		uint8_t cmd = (ADDR_PROM_SETUP + (i * 2));
		_prom.c[i] = _reg16(cmd);

		if (_prom.c[i] != 0) {
			all_zero = false;
		}

		//DEVICE_DEBUG("prom[%u]=0x%x", (unsigned)i, (unsigned)_prom.c[i]);
	}

	/* calculate CRC and return success/failure accordingly */
	int ret = ms5611::crc4(&_prom.c[0]) ? OK : -EIO;

	if (ret != OK) {
		DEVICE_DEBUG("crc failed");
	}

	if (all_zero) {
		DEVICE_DEBUG("prom all zero");
		ret = -EIO;
	}

	return ret;
}

uint16_t
MS5611_SPI::_reg16(unsigned reg)
{
	uint8_t cmd[3] = { (uint8_t)(reg | DIR_READ), 0, 0 };

	_transfer(cmd, cmd, sizeof(cmd));

	return (uint16_t)(cmd[1] << 8) | cmd[2];
}

int
MS5611_SPI::_transfer(uint8_t *send, uint8_t *recv, unsigned len)
{
	return transfer(send, recv, len);
}

#endif /* PX4_SPIDEV_BARO || PX4_SPIDEV_EXT_BARO */
<commit_msg>MS5611: Ensure to set the lockmode at the right location<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2013 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 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.
 *
 ****************************************************************************/

/**
 * @file ms5611_spi.cpp
 *
 * SPI interface for MS5611
 */

/* XXX trim includes */
#include <px4_config.h>

#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>

#include <arch/board/board.h>

#include <drivers/device/spi.h>

#include "ms5611.h"
#include "board_config.h"

/* SPI protocol address bits */
#define DIR_READ			(1<<7)
#define DIR_WRITE			(0<<7)
#define ADDR_INCREMENT			(1<<6)

#if defined(PX4_SPIDEV_BARO) || defined(PX4_SPIDEV_EXT_BARO)

device::Device *MS5611_spi_interface(ms5611::prom_u &prom_buf, bool external_bus);

class MS5611_SPI : public device::SPI
{
public:
	MS5611_SPI(uint8_t bus, spi_dev_e device, ms5611::prom_u &prom_buf);
	virtual ~MS5611_SPI();

	virtual int	init();
	virtual int	read(unsigned offset, void *data, unsigned count);
	virtual int	ioctl(unsigned operation, unsigned &arg);

private:
	ms5611::prom_u	&_prom;

	/**
	 * Send a reset command to the MS5611.
	 *
	 * This is required after any bus reset.
	 */
	int		_reset();

	/**
	 * Send a measure command to the MS5611.
	 *
	 * @param addr		Which address to use for the measure operation.
	 */
	int		_measure(unsigned addr);

	/**
	 * Read the MS5611 PROM
	 *
	 * @return		OK if the PROM reads successfully.
	 */
	int		_read_prom();

	/**
	 * Read a 16-bit register value.
	 *
	 * @param reg		The register to read.
	 */
	uint16_t	_reg16(unsigned reg);

	/**
	 * Wrapper around transfer() that prevents interrupt-context transfers
	 * from pre-empting us. The sensor may (does) share a bus with sensors
	 * that are polled from interrupt context (or we may be pre-empted)
	 * so we need to guarantee that transfers complete without interruption.
	 */
	int		_transfer(uint8_t *send, uint8_t *recv, unsigned len);
};

device::Device *
MS5611_spi_interface(ms5611::prom_u &prom_buf, uint8_t busnum)
{
#ifdef PX4_SPI_BUS_EXT

	if (busnum == PX4_SPI_BUS_EXT) {
#ifdef PX4_SPIDEV_EXT_BARO
		return new MS5611_SPI(busnum, (spi_dev_e)PX4_SPIDEV_EXT_BARO, prom_buf);
#else
		return nullptr;
#endif
	}

#endif
	return new MS5611_SPI(busnum, (spi_dev_e)PX4_SPIDEV_BARO, prom_buf);
}

MS5611_SPI::MS5611_SPI(uint8_t bus, spi_dev_e device, ms5611::prom_u &prom_buf) :
	SPI("MS5611_SPI", nullptr, bus, device, SPIDEV_MODE3, 11 * 1000 * 1000 /* will be rounded to 10.4 MHz */),
	_prom(prom_buf)
{
}

MS5611_SPI::~MS5611_SPI()
{
}

int
MS5611_SPI::init()
{
	int ret;

	ret = SPI::init();

	if (ret != OK) {
		DEVICE_DEBUG("SPI init failed");
		goto out;
	}

	/* sharing a bus with NuttX drivers */
#if defined (CONFIG_ARCH_BOARD_PX4FMU_V4)
	//set_lockmode(SPI::LOCK_THREADS);
#endif

	/* send reset command */
	ret = _reset();

	if (ret != OK) {
		DEVICE_DEBUG("reset failed");
		goto out;
	}

	/* read PROM */
	ret = _read_prom();

	if (ret != OK) {
		DEVICE_DEBUG("prom readout failed");
		goto out;
	}

out:
	return ret;
}

int
MS5611_SPI::read(unsigned offset, void *data, unsigned count)
{
	union _cvt {
		uint8_t	b[4];
		uint32_t w;
	} *cvt = (_cvt *)data;
	uint8_t buf[4] = { 0 | DIR_WRITE, 0, 0, 0 };

	/* read the most recent measurement */
	int ret = _transfer(&buf[0], &buf[0], sizeof(buf));

	if (ret == OK) {
		/* fetch the raw value */
		cvt->b[0] = buf[3];
		cvt->b[1] = buf[2];
		cvt->b[2] = buf[1];
		cvt->b[3] = 0;

		ret = count;
	}

	return ret;
}

int
MS5611_SPI::ioctl(unsigned operation, unsigned &arg)
{
	int ret;

	switch (operation) {
	case IOCTL_RESET:
		ret = _reset();
		break;

	case IOCTL_MEASURE:
		ret = _measure(arg);
		break;

	default:
		ret = EINVAL;
	}

	if (ret != OK) {
		errno = ret;
		return -1;
	}

	return 0;
}

int
MS5611_SPI::_reset()
{
	uint8_t cmd = ADDR_RESET_CMD | DIR_WRITE;

	return  _transfer(&cmd, nullptr, 1);
}

int
MS5611_SPI::_measure(unsigned addr)
{
	uint8_t cmd = addr | DIR_WRITE;

	return _transfer(&cmd, nullptr, 1);
}

int
MS5611_SPI::_read_prom()
{
	/*
	 * Wait for PROM contents to be in the device (2.8 ms) in the case we are
	 * called immediately after reset.
	 */
	usleep(3000);

	/* read and convert PROM words */
	bool all_zero = true;

	for (int i = 0; i < 8; i++) {
		uint8_t cmd = (ADDR_PROM_SETUP + (i * 2));
		_prom.c[i] = _reg16(cmd);

		if (_prom.c[i] != 0) {
			all_zero = false;
		}

		//DEVICE_DEBUG("prom[%u]=0x%x", (unsigned)i, (unsigned)_prom.c[i]);
	}

	/* calculate CRC and return success/failure accordingly */
	int ret = ms5611::crc4(&_prom.c[0]) ? OK : -EIO;

	if (ret != OK) {
		DEVICE_DEBUG("crc failed");
	}

	if (all_zero) {
		DEVICE_DEBUG("prom all zero");
		ret = -EIO;
	}

	return ret;
}

uint16_t
MS5611_SPI::_reg16(unsigned reg)
{
	uint8_t cmd[3] = { (uint8_t)(reg | DIR_READ), 0, 0 };

	_transfer(cmd, cmd, sizeof(cmd));

	return (uint16_t)(cmd[1] << 8) | cmd[2];
}

int
MS5611_SPI::_transfer(uint8_t *send, uint8_t *recv, unsigned len)
{
	return transfer(send, recv, len);
}

#endif /* PX4_SPIDEV_BARO || PX4_SPIDEV_EXT_BARO */
<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2013 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 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.
 *
 ****************************************************************************/

/**
 * @file ms5611_spi.cpp
 *
 * SPI interface for MS5611
 */

/* XXX trim includes */
#include <px4_config.h>

#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>

#include <arch/board/board.h>

#include <drivers/device/spi.h>

#include "ms5611.h"
#include "board_config.h"

/* SPI protocol address bits */
#define DIR_READ			(1<<7)
#define DIR_WRITE			(0<<7)
#define ADDR_INCREMENT			(1<<6)

#if defined(PX4_SPIDEV_BARO) || defined(PX4_SPIDEV_EXT_BARO)

device::Device *MS5611_spi_interface(ms5611::prom_u &prom_buf, bool external_bus);

class MS5611_SPI : public device::SPI
{
public:
	MS5611_SPI(uint8_t bus, spi_dev_e device, ms5611::prom_u &prom_buf);
	virtual ~MS5611_SPI();

	virtual int	init();
	virtual int	read(unsigned offset, void *data, unsigned count);
	virtual int	ioctl(unsigned operation, unsigned &arg);

private:
	ms5611::prom_u	&_prom;

	/**
	 * Send a reset command to the MS5611.
	 *
	 * This is required after any bus reset.
	 */
	int		_reset();

	/**
	 * Send a measure command to the MS5611.
	 *
	 * @param addr		Which address to use for the measure operation.
	 */
	int		_measure(unsigned addr);

	/**
	 * Read the MS5611 PROM
	 *
	 * @return		OK if the PROM reads successfully.
	 */
	int		_read_prom();

	/**
	 * Read a 16-bit register value.
	 *
	 * @param reg		The register to read.
	 */
	uint16_t	_reg16(unsigned reg);

	/**
	 * Wrapper around transfer() that prevents interrupt-context transfers
	 * from pre-empting us. The sensor may (does) share a bus with sensors
	 * that are polled from interrupt context (or we may be pre-empted)
	 * so we need to guarantee that transfers complete without interruption.
	 */
	int		_transfer(uint8_t *send, uint8_t *recv, unsigned len);
};

device::Device *
MS5611_spi_interface(ms5611::prom_u &prom_buf, uint8_t busnum)
{
#ifdef PX4_SPI_BUS_EXT

	if (busnum == PX4_SPI_BUS_EXT) {
#ifdef PX4_SPIDEV_EXT_BARO
		return new MS5611_SPI(busnum, (spi_dev_e)PX4_SPIDEV_EXT_BARO, prom_buf);
#else
		return nullptr;
#endif
	}

#endif
	return new MS5611_SPI(busnum, (spi_dev_e)PX4_SPIDEV_BARO, prom_buf);
}

MS5611_SPI::MS5611_SPI(uint8_t bus, spi_dev_e device, ms5611::prom_u &prom_buf) :
	SPI("MS5611_SPI", nullptr, bus, device, SPIDEV_MODE3, 11 * 1000 * 1000 /* will be rounded to 10.4 MHz */),
	_prom(prom_buf)
{
}

MS5611_SPI::~MS5611_SPI()
{
}

int
MS5611_SPI::init()
{
	// Sharing a bus with NuttX drivers
#if defined (CONFIG_ARCH_BOARD_PX4FMU_V4)
	set_lockmode(SPI::LOCK_THREADS);
#endif

	int ret;

	ret = SPI::init();

	if (ret != OK) {
		DEVICE_DEBUG("SPI init failed");
		goto out;
	}

	/* send reset command */
	ret = _reset();

	if (ret != OK) {
		DEVICE_DEBUG("reset failed");
		goto out;
	}

	/* read PROM */
	ret = _read_prom();

	if (ret != OK) {
		DEVICE_DEBUG("prom readout failed");
		goto out;
	}

out:
	return ret;
}

int
MS5611_SPI::read(unsigned offset, void *data, unsigned count)
{
	union _cvt {
		uint8_t	b[4];
		uint32_t w;
	} *cvt = (_cvt *)data;
	uint8_t buf[4] = { 0 | DIR_WRITE, 0, 0, 0 };

	/* read the most recent measurement */
	int ret = _transfer(&buf[0], &buf[0], sizeof(buf));

	if (ret == OK) {
		/* fetch the raw value */
		cvt->b[0] = buf[3];
		cvt->b[1] = buf[2];
		cvt->b[2] = buf[1];
		cvt->b[3] = 0;

		ret = count;
	}

	return ret;
}

int
MS5611_SPI::ioctl(unsigned operation, unsigned &arg)
{
	int ret;

	switch (operation) {
	case IOCTL_RESET:
		ret = _reset();
		break;

	case IOCTL_MEASURE:
		ret = _measure(arg);
		break;

	default:
		ret = EINVAL;
	}

	if (ret != OK) {
		errno = ret;
		return -1;
	}

	return 0;
}

int
MS5611_SPI::_reset()
{
	uint8_t cmd = ADDR_RESET_CMD | DIR_WRITE;

	return  _transfer(&cmd, nullptr, 1);
}

int
MS5611_SPI::_measure(unsigned addr)
{
	uint8_t cmd = addr | DIR_WRITE;

	return _transfer(&cmd, nullptr, 1);
}

int
MS5611_SPI::_read_prom()
{
	/*
	 * Wait for PROM contents to be in the device (2.8 ms) in the case we are
	 * called immediately after reset.
	 */
	usleep(3000);

	/* read and convert PROM words */
	bool all_zero = true;

	for (int i = 0; i < 8; i++) {
		uint8_t cmd = (ADDR_PROM_SETUP + (i * 2));
		_prom.c[i] = _reg16(cmd);

		if (_prom.c[i] != 0) {
			all_zero = false;
		}

		//DEVICE_DEBUG("prom[%u]=0x%x", (unsigned)i, (unsigned)_prom.c[i]);
	}

	/* calculate CRC and return success/failure accordingly */
	int ret = ms5611::crc4(&_prom.c[0]) ? OK : -EIO;

	if (ret != OK) {
		DEVICE_DEBUG("crc failed");
	}

	if (all_zero) {
		DEVICE_DEBUG("prom all zero");
		ret = -EIO;
	}

	return ret;
}

uint16_t
MS5611_SPI::_reg16(unsigned reg)
{
	uint8_t cmd[3] = { (uint8_t)(reg | DIR_READ), 0, 0 };

	_transfer(cmd, cmd, sizeof(cmd));

	return (uint16_t)(cmd[1] << 8) | cmd[2];
}

int
MS5611_SPI::_transfer(uint8_t *send, uint8_t *recv, unsigned len)
{
	return transfer(send, recv, len);
}

#endif /* PX4_SPIDEV_BARO || PX4_SPIDEV_EXT_BARO */
<commit_msg>Do not enable new bus sync yet<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2013 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 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.
 *
 ****************************************************************************/

/**
 * @file ms5611_spi.cpp
 *
 * SPI interface for MS5611
 */

/* XXX trim includes */
#include <px4_config.h>

#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>

#include <arch/board/board.h>

#include <drivers/device/spi.h>

#include "ms5611.h"
#include "board_config.h"

/* SPI protocol address bits */
#define DIR_READ			(1<<7)
#define DIR_WRITE			(0<<7)
#define ADDR_INCREMENT			(1<<6)

#if defined(PX4_SPIDEV_BARO) || defined(PX4_SPIDEV_EXT_BARO)

device::Device *MS5611_spi_interface(ms5611::prom_u &prom_buf, bool external_bus);

class MS5611_SPI : public device::SPI
{
public:
	MS5611_SPI(uint8_t bus, spi_dev_e device, ms5611::prom_u &prom_buf);
	virtual ~MS5611_SPI();

	virtual int	init();
	virtual int	read(unsigned offset, void *data, unsigned count);
	virtual int	ioctl(unsigned operation, unsigned &arg);

private:
	ms5611::prom_u	&_prom;

	/**
	 * Send a reset command to the MS5611.
	 *
	 * This is required after any bus reset.
	 */
	int		_reset();

	/**
	 * Send a measure command to the MS5611.
	 *
	 * @param addr		Which address to use for the measure operation.
	 */
	int		_measure(unsigned addr);

	/**
	 * Read the MS5611 PROM
	 *
	 * @return		OK if the PROM reads successfully.
	 */
	int		_read_prom();

	/**
	 * Read a 16-bit register value.
	 *
	 * @param reg		The register to read.
	 */
	uint16_t	_reg16(unsigned reg);

	/**
	 * Wrapper around transfer() that prevents interrupt-context transfers
	 * from pre-empting us. The sensor may (does) share a bus with sensors
	 * that are polled from interrupt context (or we may be pre-empted)
	 * so we need to guarantee that transfers complete without interruption.
	 */
	int		_transfer(uint8_t *send, uint8_t *recv, unsigned len);
};

device::Device *
MS5611_spi_interface(ms5611::prom_u &prom_buf, uint8_t busnum)
{
#ifdef PX4_SPI_BUS_EXT

	if (busnum == PX4_SPI_BUS_EXT) {
#ifdef PX4_SPIDEV_EXT_BARO
		return new MS5611_SPI(busnum, (spi_dev_e)PX4_SPIDEV_EXT_BARO, prom_buf);
#else
		return nullptr;
#endif
	}

#endif
	return new MS5611_SPI(busnum, (spi_dev_e)PX4_SPIDEV_BARO, prom_buf);
}

MS5611_SPI::MS5611_SPI(uint8_t bus, spi_dev_e device, ms5611::prom_u &prom_buf) :
	SPI("MS5611_SPI", nullptr, bus, device, SPIDEV_MODE3, 11 * 1000 * 1000 /* will be rounded to 10.4 MHz */),
	_prom(prom_buf)
{
}

MS5611_SPI::~MS5611_SPI()
{
}

int
MS5611_SPI::init()
{
	// Sharing a bus with NuttX drivers
#if defined (CONFIG_ARCH_BOARD_PX4FMU_V4)
	//set_lockmode(SPI::LOCK_THREADS);
#endif

	int ret;

	ret = SPI::init();

	if (ret != OK) {
		DEVICE_DEBUG("SPI init failed");
		goto out;
	}

	/* send reset command */
	ret = _reset();

	if (ret != OK) {
		DEVICE_DEBUG("reset failed");
		goto out;
	}

	/* read PROM */
	ret = _read_prom();

	if (ret != OK) {
		DEVICE_DEBUG("prom readout failed");
		goto out;
	}

out:
	return ret;
}

int
MS5611_SPI::read(unsigned offset, void *data, unsigned count)
{
	union _cvt {
		uint8_t	b[4];
		uint32_t w;
	} *cvt = (_cvt *)data;
	uint8_t buf[4] = { 0 | DIR_WRITE, 0, 0, 0 };

	/* read the most recent measurement */
	int ret = _transfer(&buf[0], &buf[0], sizeof(buf));

	if (ret == OK) {
		/* fetch the raw value */
		cvt->b[0] = buf[3];
		cvt->b[1] = buf[2];
		cvt->b[2] = buf[1];
		cvt->b[3] = 0;

		ret = count;
	}

	return ret;
}

int
MS5611_SPI::ioctl(unsigned operation, unsigned &arg)
{
	int ret;

	switch (operation) {
	case IOCTL_RESET:
		ret = _reset();
		break;

	case IOCTL_MEASURE:
		ret = _measure(arg);
		break;

	default:
		ret = EINVAL;
	}

	if (ret != OK) {
		errno = ret;
		return -1;
	}

	return 0;
}

int
MS5611_SPI::_reset()
{
	uint8_t cmd = ADDR_RESET_CMD | DIR_WRITE;

	return  _transfer(&cmd, nullptr, 1);
}

int
MS5611_SPI::_measure(unsigned addr)
{
	uint8_t cmd = addr | DIR_WRITE;

	return _transfer(&cmd, nullptr, 1);
}

int
MS5611_SPI::_read_prom()
{
	/*
	 * Wait for PROM contents to be in the device (2.8 ms) in the case we are
	 * called immediately after reset.
	 */
	usleep(3000);

	/* read and convert PROM words */
	bool all_zero = true;

	for (int i = 0; i < 8; i++) {
		uint8_t cmd = (ADDR_PROM_SETUP + (i * 2));
		_prom.c[i] = _reg16(cmd);

		if (_prom.c[i] != 0) {
			all_zero = false;
		}

		//DEVICE_DEBUG("prom[%u]=0x%x", (unsigned)i, (unsigned)_prom.c[i]);
	}

	/* calculate CRC and return success/failure accordingly */
	int ret = ms5611::crc4(&_prom.c[0]) ? OK : -EIO;

	if (ret != OK) {
		DEVICE_DEBUG("crc failed");
	}

	if (all_zero) {
		DEVICE_DEBUG("prom all zero");
		ret = -EIO;
	}

	return ret;
}

uint16_t
MS5611_SPI::_reg16(unsigned reg)
{
	uint8_t cmd[3] = { (uint8_t)(reg | DIR_READ), 0, 0 };

	_transfer(cmd, cmd, sizeof(cmd));

	return (uint16_t)(cmd[1] << 8) | cmd[2];
}

int
MS5611_SPI::_transfer(uint8_t *send, uint8_t *recv, unsigned len)
{
	return transfer(send, recv, len);
}

#endif /* PX4_SPIDEV_BARO || PX4_SPIDEV_EXT_BARO */
<|endoftext|>


<commit_before>#include "Mesh_io.h"

namespace P_RVD
{
	bool mesh_load(const std::string _filepath, Mesh& _M, bool _meshpoints, FileType _filetype)
	{
		bool hasVt = false, hasVn = false;

		FILE* file = fopen(_filepath.c_str(), "r");
		if (file == NULL)
		{
			fprintf(stderr, "Impossible to open the file!");
			return false;
		}

		while (true)
		{
			char lineHeader[128];	//we suppose that the length of each line is below 128
			int res = fscanf(file, "%s", lineHeader);
			if (res == EOF)
				break;	//end of the file

			if (strcmp(lineHeader, "v") == 0)
			{
				Vector3d vertex;
				fscanf(file, "%lf %lf %lf", &vertex.x, &vertex.y, &vertex.z);
				_M.meshVertices.addPoint(vertex);
			}

			if (strcmp(lineHeader, "vt") == 0 && hasVt != true)
				hasVt = true;

			if (strcmp(lineHeader, "vn") == 0 && hasVn != true)
				hasVn = true;

			if (strcmp(lineHeader, "f") == 0 && _meshpoints)
			{
				Vector3i t_vIndex, t_vtIndex, t_vnIndex;
				if (hasVn && hasVt)
				{
					int matched = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d", &t_vIndex.x, &t_vtIndex.x, &t_vnIndex.x,
						&t_vIndex.y, &t_vtIndex.y, &t_vnIndex.y, &t_vIndex.z, &t_vtIndex.z, &t_vnIndex.z);
					if (matched != 9)
					{
						printf("File can not be read by the parser");
						return false;
					}
				}
				else if (hasVn || hasVt)
				{
					int matched = fscanf(file, "%d/%d %d/%d %d/%d", &t_vIndex.x, &t_vtIndex.x, &t_vIndex.y, &t_vtIndex.y,
						&t_vIndex.z, &t_vtIndex.z);
					if (matched != 6)
					{
						printf("File can not be read by the parser");
						return false;
					}
				}
				else
				{
					int matched = fscanf(file, "%d %d %d", &t_vIndex.x, &t_vIndex.y, &t_vIndex.z);
				}
				_M.meshFacets.addFacet((t_index)t_vIndex.x, (t_index)t_vIndex.y, (t_index)t_vIndex.z);
			}
		}

		return true;
	}

}<commit_msg>update t_index<commit_after>#include "Mesh_io.h"

namespace P_RVD
{
	bool mesh_load(const std::string _filepath, Mesh& _M, bool _meshpoints, FileType _filetype)
	{
		bool hasVt = false, hasVn = false;

		FILE* file = fopen(_filepath.c_str(), "r");
		if (file == NULL)
		{
			fprintf(stderr, "Impossible to open the file!");
			return false;
		}

		while (true)
		{
			char lineHeader[128];	//we suppose that the length of each line is below 128
			int res = fscanf(file, "%s", lineHeader);
			if (res == EOF)
				break;	//end of the file

			if (strcmp(lineHeader, "v") == 0)
			{
				Vector3d vertex;
				fscanf(file, "%lf %lf %lf", &vertex.x, &vertex.y, &vertex.z);
				_M.meshVertices.addPoint(vertex);
			}

			if (strcmp(lineHeader, "vt") == 0 && hasVt != true)
				hasVt = true;

			if (strcmp(lineHeader, "vn") == 0 && hasVn != true)
				hasVn = true;

			if (strcmp(lineHeader, "f") == 0 && _meshpoints)
			{
				Vector3i t_vIndex, t_vtIndex, t_vnIndex;
				if (hasVn && hasVt)
				{
					int matched = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d", &t_vIndex.x, &t_vtIndex.x, &t_vnIndex.x,
						&t_vIndex.y, &t_vtIndex.y, &t_vnIndex.y, &t_vIndex.z, &t_vtIndex.z, &t_vnIndex.z);
					if (matched != 9)
					{
						printf("File can not be read by the parser");
						return false;
					}
				}
				else if (hasVn || hasVt)
				{
					int matched = fscanf(file, "%d/%d %d/%d %d/%d", &t_vIndex.x, &t_vtIndex.x, &t_vIndex.y, &t_vtIndex.y,
						&t_vIndex.z, &t_vtIndex.z);
					if (matched != 6)
					{
						printf("File can not be read by the parser");
						return false;
					}
				}
				else
				{
					int matched = fscanf(file, "%d %d %d", &t_vIndex.x, &t_vIndex.y, &t_vIndex.z);
				}
				_M.meshFacets.addFacet((t_index)t_vIndex.x - 1, (t_index)t_vIndex.y - 1, (t_index)t_vIndex.z - 1);
			}
		}

		return true;
	}

}<|endoftext|>