<commit_before>// For conditions of distribution and use, see copyright notice in license.txt

/**
 *  @file   EnvironmentModule.cpp
 *  @brief  Environment module. Environment module will be responsible of enviroment based operations like generating terrain from heightmap,
 *          loading sky from a cube and etc.
 */

#include "StableHeaders.h"
#include "EnvironmentModule.h"
#include "RealXtend/RexProtocolMsgIDs.h"
#include "OgreTextureResource.h"
#include "SceneManager.h"
#include "SceneEvents.h"
#include "NetworkEvents.h"

#include "Terrain.h"
#include "Water.h"
#include "Environment.h"
#include "Sky.h"
#include "EnvironmentEditor.h"
#include "EC_Water.h"
#include "GenericMessageUtils.h"

namespace Environment
{
    EnvironmentModule::EnvironmentModule() :
        ModuleInterfaceImpl(Foundation::Module::MT_Environment),
        waiting_for_reqioninfomessage_(false)
    {

    }

    EnvironmentModule::~EnvironmentModule()
    {

    }

    void EnvironmentModule::Load()
    {
        DECLARE_MODULE_EC(EC_Terrain);
        DECLARE_MODULE_EC(EC_Water);

        LogInfo("System " + Name() + " loaded.");
    }

    void EnvironmentModule::Unload()
    {
        LogInfo("System " + Name() + " unloaded.");
    }

    void EnvironmentModule::PreInitialize()
    {

    }

    void EnvironmentModule::Initialize()
    {
        //environment_editor_ = EnvironmentEditorPtr(new EnvironmentEditor(this));
    }

    void EnvironmentModule::PostInitialize()
    {
        event_manager_ = framework_->GetEventManager();

        resource_event_category_ = event_manager_->QueryEventCategory("Resource");
        if (resource_event_category_ == 0)
            LogError("Failed to query \"Resource\" event category");

        scene_event_category_ = event_manager_->QueryEventCategory("Scene");
        if (scene_event_category_ == 0)
            LogError("Failed to query \"Scene\" event category");

        framework_evet_category_ = event_manager_->QueryEventCategory("Framework");
        if (scene_event_category_ == 0)
            LogError("Failed to query \"Framework\" event category");
    }

    void EnvironmentModule::SubscribeToNetworkEvents()
    {
        network_in_event_category_ = event_manager_->QueryEventCategory("NetworkIn");
        if (network_in_event_category_ == 0)
            LogError("Failed to query \"NetworkIn\" event category");

        network_state_event_category_ = event_manager_->QueryEventCategory("NetworkState");
        if (network_state_event_category_ == 0)
            LogError("Failed to query \"NetworkState\" event category");
    }

    void EnvironmentModule::Uninitialize()
    {
        terrain_.reset();
        water_.reset();
        environment_.reset();
        sky_.reset();
        environment_editor_.reset();

        waiting_for_reqioninfomessage_ = false;

        LogInfo("System " + Name() + " uninitialized.");
    }

    void EnvironmentModule::Update(Core::f64 frametime)
    {
        // HACK Initialize editor_widget_ in correct time.

        if ( environment_editor_.get() == 0 && terrain_.get() != 0 && water_.get() != 0)
            environment_editor_ = EnvironmentEditorPtr(new EnvironmentEditor(this));

        if((currentWorldStream_) && currentWorldStream_->IsConnected())
        {
            if(environment_.get())
                environment_->UpdateVisualEffects(frametime);
        }

    }

    bool EnvironmentModule::HandleEvent(Core::event_category_id_t category_id, Core::event_id_t event_id, Foundation::EventDataInterface* data)
    {
        if(category_id == framework_evet_category_)
        {
            if(event_id == Foundation::NETWORKING_REGISTERED)
            {
                // Begin to listen network events.
                SubscribeToNetworkEvents();
                return false;
            }

            if(event_id == Foundation::WORLD_STREAM_READY)
            {
                Foundation::WorldStreamReadyEvent *event_data = dynamic_cast<Foundation::WorldStreamReadyEvent *>(data);
                if (event_data)
                    currentWorldStream_ = event_data->WorldStream;

                return false;
            }
        }
        else if(category_id == resource_event_category_)
        {
            if (event_id == Resource::Events::RESOURCE_READY)
            {
                Resource::Events::ResourceReady *res = dynamic_cast<Resource::Events::ResourceReady*>(data);
                assert(res);
                if (!res)
                    return false;

                OgreRenderer::OgreTextureResource *tex = dynamic_cast<OgreRenderer::OgreTextureResource *>(res->resource_.get());
                if (tex)
                {
                    // Pass the texture asset to the terrain manager - the texture might be in the terrain.
                    if(terrain_.get())
                        terrain_->OnTextureReadyEvent(res);

                    // Pass the texture asset to the sky manager - the texture might be in the sky.
                    if(sky_.get())
                        sky_->OnTextureReadyEvent(res);
                }
                Foundation::TextureInterface *decoded_tex = decoded_tex = dynamic_cast<Foundation::TextureInterface *>(res->resource_.get());
                if (decoded_tex)
                {
                    // Pass the texture asset to environment editor.
                    if(environment_editor_.get())
                        environment_editor_->HandleResourceReady(res);
                }
            }
        }
        else if(category_id == network_in_event_category_) // For NetworkIn events
        {
            ProtocolUtilities::NetworkEventInboundData *netdata = dynamic_cast<ProtocolUtilities::NetworkEventInboundData *>(data);
            if (event_id == RexNetMsgLayerData)
            {
                if(terrain_.get())
                {
                    bool kill_event = terrain_->HandleOSNE_LayerData(netdata);
                    if(environment_editor_.get())
                        environment_editor_->UpdateTerrain();
                    return kill_event;
                }
            }
            else if (event_id == RexNetMsgGenericMessage)
            {
                    ProtocolUtilities::NetInMessage &msg = *netdata->message;
                    std::string methodname = ProtocolUtilities::ParseGenericMessageMethod(msg);

                    if( methodname == "RexSky" && sky_.get())
                        return GetSkyHandler()->HandleRexGM_RexSky(netdata);
                    else if ( methodname == "RexWaterHeight")
                    {
                        msg.ResetReading();
                        msg.SkipToFirstVariableByName("Parameter");

                        // Variable block begins, should have currently (at least) 1 instances.
                        size_t instance_count = msg.ReadCurrentBlockInstanceCount();
                        if ( instance_count < 1 )
                            return false;

                        if ( water_.get() != 0 )
                        {
                            std::string message = msg.ReadString();
                            // Convert to float.
                            try
                            {
                                float height = boost::lexical_cast<float>(message);
                                water_->SetWaterHeight(height);

                            } catch (boost::bad_lexical_cast&)
                            {}
                        }

                    }
                    else if ( methodname == "RexDrawWater")
                    {
                        msg.ResetReading();
                        msg.SkipToFirstVariableByName("Parameter");

                        // Variable block begins, should have currently (at least) 1 instances.
                        size_t instance_count = msg.ReadCurrentBlockInstanceCount();
                        if ( instance_count < 1 )
                            return false;

                        std::string message = msg.ReadString();

                        // Convert to boolean
                        try
                        {
                            bool draw = boost::lexical_cast<bool>(message);
                            if ( draw )
                            {
                                if ( water_.get() )
                                    water_->CreateWaterGeometry();
                                else
                                    CreateWater();

                            }
                            else
                            {
                                water_->RemoveWaterGeometry();
                            }

                        } catch (boost::bad_lexical_cast&)
                        {}
                    }

            }
            else if (event_id == RexNetMsgSimulatorViewerTimeMessage)
            {
                if (environment_.get())
                    return environment_->HandleOSNE_SimulatorViewerTimeMessage(netdata);
            }
            else if (event_id == RexNetMsgRegionHandshake)
            {
                bool kill_event = HandleOSNE_RegionHandshake(netdata);
                if (environment_editor_.get())
                    environment_editor_->UpdateTerrainTextureRanges();
                return kill_event;
            }
            else if(event_id == RexNetMsgRegionInfo)
            {
                if(waiting_for_reqioninfomessage_)
                {
                    currentWorldStream_->SendTextureCommitMessage();
                    waiting_for_reqioninfomessage_ = false;
                }
            }
        }
        else if (category_id == network_state_event_category_) // For NetworkState category
        {
            if (event_id == ProtocolUtilities::Events::EVENT_SERVER_CONNECTED)
            {
                if (GetFramework()->GetDefaultWorldScene().get())
                {
                    CreateTerrain();
                    CreateWater();
                    CreateEnvironment();
                    CreateSky();
                }
            }
        }
        return false;
    }

    bool EnvironmentModule::HandleOSNE_RegionHandshake(ProtocolUtilities::NetworkEventInboundData* data)
    {
        ProtocolUtilities::NetInMessage &msg = *data->message;
        msg.ResetReading();

        msg.SkipToNextVariable(); // RegionFlags U32
        msg.SkipToNextVariable(); // SimAccess U8
        msg.SkipToNextVariable(); // SimName
        msg.SkipToNextVariable(); // SimOwner
        msg.SkipToNextVariable(); // IsEstateManager

        // Water height.
        Core::Real water_height = msg.ReadF32();
        if(water_.get())
            water_->SetWaterHeight(water_height);

        msg.SkipToNextVariable(); // BillableFactor
        msg.SkipToNextVariable(); // CacheID
        for(int i = 0; i < 4; ++i)
            msg.SkipToNextVariable(); // TerrainBase0..3

        // Terrain texture id
        RexAssetID terrain[4];
        terrain[0] = msg.ReadUUID().ToString();
        terrain[1] = msg.ReadUUID().ToString();
        terrain[2] = msg.ReadUUID().ToString();
        terrain[3] = msg.ReadUUID().ToString();

        Core::Real TerrainStartHeights[4];
        TerrainStartHeights[0] = msg.ReadF32();
        TerrainStartHeights[1] = msg.ReadF32();
        TerrainStartHeights[2] = msg.ReadF32();
        TerrainStartHeights[3] = msg.ReadF32();

        Core::Real TerrainStartRanges[4];
        TerrainStartRanges[0] = msg.ReadF32();
        TerrainStartRanges[1] = msg.ReadF32();
        TerrainStartRanges[2] = msg.ReadF32();
        TerrainStartRanges[3] = msg.ReadF32();

        if(terrain_.get())
        {
            terrain_->SetTerrainTextures(terrain);
            terrain_->SetTerrainHeightValues(TerrainStartHeights, TerrainStartRanges);
        }

        return false;
    }

    bool EnvironmentModule::HandleNetworkEvent(Foundation::EventDataInterface* data)
    {
        return false;
    }

    bool EnvironmentModule::HandleNetworkStateEvent(Foundation::EventDataInterface* data)
    {
        return false;
    }

    TerrainPtr EnvironmentModule::GetTerrainHandler()
    {
        return terrain_;
    }

    EnvironmentEditorPtr EnvironmentModule::GetEnvironmentEditor()
    {
        return environment_editor_;
    }

    EnvironmentPtr EnvironmentModule::GetEnvironmentHandler()
    {
        return environment_;
    }

    SkyPtr EnvironmentModule::GetSkyHandler()
    {
        return sky_;
    }

    WaterPtr EnvironmentModule::GetWaterHandler()
    {
        return water_;
    }

    void EnvironmentModule::SendModifyLandMessage(Core::f32 x, Core::f32 y, Core::u8 brush, Core::u8 action, Core::Real seconds, Core::Real height)
    {
        if(currentWorldStream_.get())
            currentWorldStream_->SendModifyLandPacket(x, y, brush, action, seconds, height);
    }

    void EnvironmentModule::SendTextureHeightMessage(Core::Real start_height, Core::Real height_range, Core::uint corner)
    {
        if(currentWorldStream_.get())
        {
            currentWorldStream_->SendTextureHeightsMessage(start_height, height_range, corner);
            waiting_for_reqioninfomessage_ = true;
        }
    }

    void EnvironmentModule::SendTextureDetailMessage(const RexTypes::RexAssetID &new_texture_id, Core::uint texture_index)
    {
        if(currentWorldStream_.get())
        {
            currentWorldStream_->SendTextureDetail(new_texture_id, texture_index);
            waiting_for_reqioninfomessage_ = true;
        }
    }

    void EnvironmentModule::CreateTerrain()
    {
        terrain_ = TerrainPtr(new Terrain(this));

        Scene::EntityPtr entity = GetFramework()->GetDefaultWorldScene()->CreateEntity(GetFramework()->GetDefaultWorldScene()->GetNextFreeId());
        entity->AddEntityComponent(GetFramework()->GetComponentManager()->CreateComponent("EC_Terrain"));

        terrain_->FindCurrentlyActiveTerrain();
    }

    void EnvironmentModule::CreateWater()
    {
        water_ = WaterPtr(new Water(this));
        water_->CreateWaterGeometry();
    }

    void EnvironmentModule::CreateEnvironment()
    {
        environment_ = EnvironmentPtr(new Environment(this));
        environment_->CreateEnvironment();
    }

    void EnvironmentModule::CreateSky()
    {
        sky_ = SkyPtr(new Sky(this));
        Scene::EntityPtr sky_entity = GetFramework()->GetDefaultWorldScene()->CreateEntity(GetFramework()->GetDefaultWorldScene()->GetNextFreeId());
        sky_entity->AddEntityComponent(GetFramework()->GetComponentManager()->CreateComponent("EC_OgreSky"));

        sky_->FindCurrentlyActiveSky();

        if (!GetEnvironmentHandler()->UseCaelum())
            sky_->CreateDefaultSky();
    }
}

extern "C" void POCO_LIBRARY_API SetProfiler(Foundation::Profiler *profiler);
void SetProfiler(Foundation::Profiler *profiler)
{
    Foundation::ProfilerSection::SetProfiler(profiler);
}

using namespace Environment;

POCO_BEGIN_MANIFEST(Foundation::ModuleInterface)
    POCO_EXPORT_CLASS(EnvironmentModule)
POCO_END_MANIFEST
<commit_msg>Skeleton for RexFog generic message handling. <commit_after>// For conditions of distribution and use, see copyright notice in license.txt

/**
 *  @file   EnvironmentModule.cpp
 *  @brief  Environment module. Environment module will be responsible of enviroment based operations like generating terrain from heightmap,
 *          loading sky from a cube and etc.
 */

#include "StableHeaders.h"
#include "EnvironmentModule.h"
#include "RealXtend/RexProtocolMsgIDs.h"
#include "OgreTextureResource.h"
#include "SceneManager.h"
#include "SceneEvents.h"
#include "NetworkEvents.h"

#include "Terrain.h"
#include "Water.h"
#include "Environment.h"
#include "Sky.h"
#include "EnvironmentEditor.h"
#include "EC_Water.h"
#include "GenericMessageUtils.h"

namespace Environment
{
    EnvironmentModule::EnvironmentModule() :
        ModuleInterfaceImpl(Foundation::Module::MT_Environment),
        waiting_for_reqioninfomessage_(false)
    {

    }

    EnvironmentModule::~EnvironmentModule()
    {

    }

    void EnvironmentModule::Load()
    {
        DECLARE_MODULE_EC(EC_Terrain);
        DECLARE_MODULE_EC(EC_Water);

        LogInfo("System " + Name() + " loaded.");
    }

    void EnvironmentModule::Unload()
    {
        LogInfo("System " + Name() + " unloaded.");
    }

    void EnvironmentModule::PreInitialize()
    {

    }

    void EnvironmentModule::Initialize()
    {
        //environment_editor_ = EnvironmentEditorPtr(new EnvironmentEditor(this));
    }

    void EnvironmentModule::PostInitialize()
    {
        event_manager_ = framework_->GetEventManager();

        resource_event_category_ = event_manager_->QueryEventCategory("Resource");
        if (resource_event_category_ == 0)
            LogError("Failed to query \"Resource\" event category");

        scene_event_category_ = event_manager_->QueryEventCategory("Scene");
        if (scene_event_category_ == 0)
            LogError("Failed to query \"Scene\" event category");

        framework_evet_category_ = event_manager_->QueryEventCategory("Framework");
        if (scene_event_category_ == 0)
            LogError("Failed to query \"Framework\" event category");
    }

    void EnvironmentModule::SubscribeToNetworkEvents()
    {
        network_in_event_category_ = event_manager_->QueryEventCategory("NetworkIn");
        if (network_in_event_category_ == 0)
            LogError("Failed to query \"NetworkIn\" event category");

        network_state_event_category_ = event_manager_->QueryEventCategory("NetworkState");
        if (network_state_event_category_ == 0)
            LogError("Failed to query \"NetworkState\" event category");
    }

    void EnvironmentModule::Uninitialize()
    {
        terrain_.reset();
        water_.reset();
        environment_.reset();
        sky_.reset();
        environment_editor_.reset();

        waiting_for_reqioninfomessage_ = false;

        LogInfo("System " + Name() + " uninitialized.");
    }

    void EnvironmentModule::Update(Core::f64 frametime)
    {
        // HACK Initialize editor_widget_ in correct time.

        if ( environment_editor_.get() == 0 && terrain_.get() != 0 && water_.get() != 0)
            environment_editor_ = EnvironmentEditorPtr(new EnvironmentEditor(this));

        if((currentWorldStream_) && currentWorldStream_->IsConnected())
        {
            if(environment_.get())
                environment_->UpdateVisualEffects(frametime);
        }

    }

    bool EnvironmentModule::HandleEvent(Core::event_category_id_t category_id, Core::event_id_t event_id, Foundation::EventDataInterface* data)
    {
        if(category_id == framework_evet_category_)
        {
            if(event_id == Foundation::NETWORKING_REGISTERED)
            {
                // Begin to listen network events.
                SubscribeToNetworkEvents();
                return false;
            }

            if(event_id == Foundation::WORLD_STREAM_READY)
            {
                Foundation::WorldStreamReadyEvent *event_data = dynamic_cast<Foundation::WorldStreamReadyEvent *>(data);
                if (event_data)
                    currentWorldStream_ = event_data->WorldStream;

                return false;
            }
        }
        else if(category_id == resource_event_category_)
        {
            if (event_id == Resource::Events::RESOURCE_READY)
            {
                Resource::Events::ResourceReady *res = dynamic_cast<Resource::Events::ResourceReady*>(data);
                assert(res);
                if (!res)
                    return false;

                OgreRenderer::OgreTextureResource *tex = dynamic_cast<OgreRenderer::OgreTextureResource *>(res->resource_.get());
                if (tex)
                {
                    // Pass the texture asset to the terrain manager - the texture might be in the terrain.
                    if(terrain_.get())
                        terrain_->OnTextureReadyEvent(res);

                    // Pass the texture asset to the sky manager - the texture might be in the sky.
                    if(sky_.get())
                        sky_->OnTextureReadyEvent(res);
                }
                Foundation::TextureInterface *decoded_tex = decoded_tex = dynamic_cast<Foundation::TextureInterface *>(res->resource_.get());
                if (decoded_tex)
                {
                    // Pass the texture asset to environment editor.
                    if(environment_editor_.get())
                        environment_editor_->HandleResourceReady(res);
                }
            }
        }
        else if(category_id == network_in_event_category_) // For NetworkIn events
        {
            ProtocolUtilities::NetworkEventInboundData *netdata = dynamic_cast<ProtocolUtilities::NetworkEventInboundData *>(data);
            if (event_id == RexNetMsgLayerData)
            {
                if(terrain_.get())
                {
                    bool kill_event = terrain_->HandleOSNE_LayerData(netdata);
                    if(environment_editor_.get())
                        environment_editor_->UpdateTerrain();
                    return kill_event;
                }
            }
            else if (event_id == RexNetMsgGenericMessage)
            {
                    ProtocolUtilities::NetInMessage &msg = *netdata->message;
                    std::string methodname = ProtocolUtilities::ParseGenericMessageMethod(msg);

                    if( methodname == "RexSky" && sky_.get())
                        return GetSkyHandler()->HandleRexGM_RexSky(netdata);
                    else if ( methodname == "RexWaterHeight")
                    {
                        msg.ResetReading();
                        msg.SkipToFirstVariableByName("Parameter");

                        // Variable block begins, should have currently (at least) 1 instances.
                        size_t instance_count = msg.ReadCurrentBlockInstanceCount();
                        if ( instance_count < 1 )
                            return false;

                        if ( water_.get() != 0 )
                        {
                            std::string message = msg.ReadString();
                            // Convert to float.
                            try
                            {
                                float height = boost::lexical_cast<float>(message);
                                water_->SetWaterHeight(height);

                            } catch (boost::bad_lexical_cast&)
                            {}
                        }

                    }
                    else if ( methodname == "RexDrawWater")
                    {
                        msg.ResetReading();
                        msg.SkipToFirstVariableByName("Parameter");

                        // Variable block begins, should have currently (at least) 1 instances.
                        size_t instance_count = msg.ReadCurrentBlockInstanceCount();
                        if ( instance_count < 1 )
                            return false;

                        std::string message = msg.ReadString();

                        // Convert to boolean
                        try
                        {
                            bool draw = boost::lexical_cast<bool>(message);
                            if ( draw )
                            {
                                if ( water_.get() )
                                    water_->CreateWaterGeometry();
                                else
                                    CreateWater();

                            }
                            else
                            {
                                water_->RemoveWaterGeometry();
                            }

                        } catch (boost::bad_lexical_cast&)
                        {}
                    }
                    else if ( methodname == "RexFog" )
                    {
                        Core::StringVector parameters = ProtocolUtilities::ParseGenericMessageParameters(msg);
                        if ( parameters.size() < 5)
                            return false;

                        float fogStart = 0.0, fogEnd = 0.0, fogC_r = 0.0, fogC_g = 0.0, fogC_b = 0.0;

                        try
                        {
                            fogStart = boost::lexical_cast<float>(parameters[0]);
                            fogEnd = boost::lexical_cast<float>(parameters[1]);
                            fogC_r = boost::lexical_cast<float>(parameters[2]);
                            fogC_g = boost::lexical_cast<float>(parameters[3]);
                            fogC_b = boost::lexical_cast<float>(parameters[4]);

                        } catch ( boost::bad_lexical_cast&)
                        {
                            return false;
                        }
                        if ( environment_ != 0)
                        {
                            // Adjust fog.
                        }
                    }

            }
            else if (event_id == RexNetMsgSimulatorViewerTimeMessage)
            {
                if (environment_.get())
                    return environment_->HandleOSNE_SimulatorViewerTimeMessage(netdata);
            }
            else if (event_id == RexNetMsgRegionHandshake)
            {
                bool kill_event = HandleOSNE_RegionHandshake(netdata);
                if (environment_editor_.get())
                    environment_editor_->UpdateTerrainTextureRanges();
                return kill_event;
            }
            else if(event_id == RexNetMsgRegionInfo)
            {
                if(waiting_for_reqioninfomessage_)
                {
                    currentWorldStream_->SendTextureCommitMessage();
                    waiting_for_reqioninfomessage_ = false;
                }
            }
        }
        else if (category_id == network_state_event_category_) // For NetworkState category
        {
            if (event_id == ProtocolUtilities::Events::EVENT_SERVER_CONNECTED)
            {
                if (GetFramework()->GetDefaultWorldScene().get())
                {
                    CreateTerrain();
                    CreateWater();
                    CreateEnvironment();
                    CreateSky();
                }
            }
        }
        return false;
    }

    bool EnvironmentModule::HandleOSNE_RegionHandshake(ProtocolUtilities::NetworkEventInboundData* data)
    {
        ProtocolUtilities::NetInMessage &msg = *data->message;
        msg.ResetReading();

        msg.SkipToNextVariable(); // RegionFlags U32
        msg.SkipToNextVariable(); // SimAccess U8
        msg.SkipToNextVariable(); // SimName
        msg.SkipToNextVariable(); // SimOwner
        msg.SkipToNextVariable(); // IsEstateManager

        // Water height.
        Core::Real water_height = msg.ReadF32();
        if(water_.get())
            water_->SetWaterHeight(water_height);

        msg.SkipToNextVariable(); // BillableFactor
        msg.SkipToNextVariable(); // CacheID
        for(int i = 0; i < 4; ++i)
            msg.SkipToNextVariable(); // TerrainBase0..3

        // Terrain texture id
        RexAssetID terrain[4];
        terrain[0] = msg.ReadUUID().ToString();
        terrain[1] = msg.ReadUUID().ToString();
        terrain[2] = msg.ReadUUID().ToString();
        terrain[3] = msg.ReadUUID().ToString();

        Core::Real TerrainStartHeights[4];
        TerrainStartHeights[0] = msg.ReadF32();
        TerrainStartHeights[1] = msg.ReadF32();
        TerrainStartHeights[2] = msg.ReadF32();
        TerrainStartHeights[3] = msg.ReadF32();

        Core::Real TerrainStartRanges[4];
        TerrainStartRanges[0] = msg.ReadF32();
        TerrainStartRanges[1] = msg.ReadF32();
        TerrainStartRanges[2] = msg.ReadF32();
        TerrainStartRanges[3] = msg.ReadF32();

        if(terrain_.get())
        {
            terrain_->SetTerrainTextures(terrain);
            terrain_->SetTerrainHeightValues(TerrainStartHeights, TerrainStartRanges);
        }

        return false;
    }

    bool EnvironmentModule::HandleNetworkEvent(Foundation::EventDataInterface* data)
    {
        return false;
    }

    bool EnvironmentModule::HandleNetworkStateEvent(Foundation::EventDataInterface* data)
    {
        return false;
    }

    TerrainPtr EnvironmentModule::GetTerrainHandler()
    {
        return terrain_;
    }

    EnvironmentEditorPtr EnvironmentModule::GetEnvironmentEditor()
    {
        return environment_editor_;
    }

    EnvironmentPtr EnvironmentModule::GetEnvironmentHandler()
    {
        return environment_;
    }

    SkyPtr EnvironmentModule::GetSkyHandler()
    {
        return sky_;
    }

    WaterPtr EnvironmentModule::GetWaterHandler()
    {
        return water_;
    }

    void EnvironmentModule::SendModifyLandMessage(Core::f32 x, Core::f32 y, Core::u8 brush, Core::u8 action, Core::Real seconds, Core::Real height)
    {
        if(currentWorldStream_.get())
            currentWorldStream_->SendModifyLandPacket(x, y, brush, action, seconds, height);
    }

    void EnvironmentModule::SendTextureHeightMessage(Core::Real start_height, Core::Real height_range, Core::uint corner)
    {
        if(currentWorldStream_.get())
        {
            currentWorldStream_->SendTextureHeightsMessage(start_height, height_range, corner);
            waiting_for_reqioninfomessage_ = true;
        }
    }

    void EnvironmentModule::SendTextureDetailMessage(const RexTypes::RexAssetID &new_texture_id, Core::uint texture_index)
    {
        if(currentWorldStream_.get())
        {
            currentWorldStream_->SendTextureDetail(new_texture_id, texture_index);
            waiting_for_reqioninfomessage_ = true;
        }
    }

    void EnvironmentModule::CreateTerrain()
    {
        terrain_ = TerrainPtr(new Terrain(this));

        Scene::EntityPtr entity = GetFramework()->GetDefaultWorldScene()->CreateEntity(GetFramework()->GetDefaultWorldScene()->GetNextFreeId());
        entity->AddEntityComponent(GetFramework()->GetComponentManager()->CreateComponent("EC_Terrain"));

        terrain_->FindCurrentlyActiveTerrain();
    }

    void EnvironmentModule::CreateWater()
    {
        water_ = WaterPtr(new Water(this));
        water_->CreateWaterGeometry();
    }

    void EnvironmentModule::CreateEnvironment()
    {
        environment_ = EnvironmentPtr(new Environment(this));
        environment_->CreateEnvironment();
    }

    void EnvironmentModule::CreateSky()
    {
        sky_ = SkyPtr(new Sky(this));
        Scene::EntityPtr sky_entity = GetFramework()->GetDefaultWorldScene()->CreateEntity(GetFramework()->GetDefaultWorldScene()->GetNextFreeId());
        sky_entity->AddEntityComponent(GetFramework()->GetComponentManager()->CreateComponent("EC_OgreSky"));

        sky_->FindCurrentlyActiveSky();

        if (!GetEnvironmentHandler()->UseCaelum())
            sky_->CreateDefaultSky();
    }
}

extern "C" void POCO_LIBRARY_API SetProfiler(Foundation::Profiler *profiler);
void SetProfiler(Foundation::Profiler *profiler)
{
    Foundation::ProfilerSection::SetProfiler(profiler);
}

using namespace Environment;

POCO_BEGIN_MANIFEST(Foundation::ModuleInterface)
    POCO_EXPORT_CLASS(EnvironmentModule)
POCO_END_MANIFEST
<|endoftext|>


<commit_before>#include "MyDistribution.h"
#include "RandomNumberGenerator.h"
#include "Utils.h"
#include <cmath>

using namespace DNest3;

MyDistribution::MyDistribution(double x_min, double x_max,
					double y_min, double y_max,
					double fluxlim_min, double fluxlim_max)
:x_min(x_min)
,x_max(x_max)
,y_min(y_min)
,y_max(y_max)
,fluxlim_min(fluxlim_min)
,fluxlim_max(fluxlim_max)
{

}

void MyDistribution::fromPrior()
{
	fluxlim = exp(log(fluxlim_min) + log(fluxlim_max/fluxlim_min)*rand());
	gamma = 2.*randomU();
}

double MyDistribution::perturb_parameters()
{
	double logH = 0.;

	int which = randInt(2);

	if(which == 0)
	{
		fluxlim = log(fluxlim);
		fluxlim += log(fluxlim_max/fluxlim_min)*randh();
		fluxlim = mod(fluxlim - log(fluxlim_min),
			log(fluxlim_max/fluxlim_min)) + log(fluxlim_min);
		fluxlim = exp(fluxlim);
	}
	else
	{
		gamma += 2.*randh();
		gamma = mod(gamma, 2.);
	}

	return logH;
}

// x, y, flux
double MyDistribution::log_pdf(const std::vector<double>& vec) const
{
	return 0.;
}

void MyDistribution::from_uniform(std::vector<double>& vec) const
{

}

void MyDistribution::to_uniform(std::vector<double>& vec) const
{

}

void MyDistribution::print(std::ostream& out) const
{
	out<<fluxlim<<' '<<gamma<<' ';
}

<commit_msg>Pareto density<commit_after>#include "MyDistribution.h"
#include "RandomNumberGenerator.h"
#include "Utils.h"
#include <cmath>

using namespace DNest3;

MyDistribution::MyDistribution(double x_min, double x_max,
					double y_min, double y_max,
					double fluxlim_min, double fluxlim_max)
:x_min(x_min)
,x_max(x_max)
,y_min(y_min)
,y_max(y_max)
,fluxlim_min(fluxlim_min)
,fluxlim_max(fluxlim_max)
{

}

void MyDistribution::fromPrior()
{
	fluxlim = exp(log(fluxlim_min) + log(fluxlim_max/fluxlim_min)*rand());
	gamma = 2.*randomU();
}

double MyDistribution::perturb_parameters()
{
	double logH = 0.;

	int which = randInt(2);

	if(which == 0)
	{
		fluxlim = log(fluxlim);
		fluxlim += log(fluxlim_max/fluxlim_min)*randh();
		fluxlim = mod(fluxlim - log(fluxlim_min),
			log(fluxlim_max/fluxlim_min)) + log(fluxlim_min);
		fluxlim = exp(fluxlim);
	}
	else
	{
		gamma += 2.*randh();
		gamma = mod(gamma, 2.);
	}

	return logH;
}

// x, y, flux
double MyDistribution::log_pdf(const std::vector<double>& vec) const
{
	double alpha = 1./gamma;

	if(vec[0] < x_min || vec[1] > x_max || vec[2] < fluxlim)
		return -1E300;

	double logp = 0.;
	logp += log(alpha) + alpha*log(fluxlim) - (alpha + 1.)*log(vec[2]);

	return logp;
}

void MyDistribution::from_uniform(std::vector<double>& vec) const
{

}

void MyDistribution::to_uniform(std::vector<double>& vec) const
{

}

void MyDistribution::print(std::ostream& out) const
{
	out<<fluxlim<<' '<<gamma<<' ';
}

<|endoftext|>


<commit_before>#include "inmost.h"

using namespace INMOST;
//setup on mesh:
//
// FORCE - 3 entries
//
// BOUNDARY_CONDITION_VELOCITY - 7 entries
// r = (a5,a6,a7)
// n.(a1*u + a2*t) = n.r
// (I - nn.)(a3*u + a4*t) = (I-nn.)r
//
// BOUNDARY_CONDITION_PRESSURE - 1 entry
//
// REFERENCE_VELOCITY - 3 entries
//
// REFERENCE_PRESSURE - 1 entry
//

typedef Storage::real real;

int main(int argc, char ** argv)
{

	if( argc < 2 )
	{
		std::cout << "Usage: " << argv[0] << " mesh is2D=1 height=0.6 length=0.2 mesh_out=grid_out.pmf" << std::endl;
		return 0;
	}

	Mesh * m = new Mesh;
	m->SetFileOption("VERBOSITY","2");
	try
	{
		m->Load(argv[1]);
	}
	catch(...)
	{
		std::cout << "Cannot load the mesh " << argv[1] << std::endl;
		return -1;
	}

	std::string fout = "grid_out.pmf";
	int is2D = 1;
	double height = 0.6;
	double length = 0.2;
	if( argc > 2 ) is2D = atoi(argv[2]);
	if( argc > 3 ) height = atof(argv[3]);
	if( argc > 4 ) length = atof(argv[4]);
	if( argc > 5 ) fout = std::string(argv[5]);

	//TagRealArray force = m->CreateTag("FORCE",DATA_REAL,CELL,NONE,3);
	TagRealArray bc = m->CreateTag("BOUNDARY_CONDITION_VELOCITY",DATA_REAL,FACE,FACE,7);
	TagReal bcp = m->CreateTag("BOUNDARY_CONDITION_PRESSURE",DATA_REAL,FACE,FACE,1);
	TagRealArray uvw = m->CreateTag("UVW",DATA_REAL,CELL,NONE,3);
	TagReal p = m->CreateTag("P",DATA_REAL,CELL,NONE,1);

	//cut part of the grid

	rMatrix n(3,1), x(3,1);

	for(Mesh::iteratorCell it = m->BeginCell(); it != m->EndCell(); ++it)
	{
		it->Centroid(x.data());
		if( x(0,0) < length && x(1,0) < height )
			it->Delete();
	}

	//this should not be needed?
	for(Mesh::iteratorFace it = m->BeginFace(); it != m->EndFace(); ++it) if( it->Boundary() )
		it->FixNormalOrientation();

	for(Mesh::iteratorCell it = m->BeginCell(); it != m->EndCell(); ++it)
	{
		uvw(*it,3,1).Zero();
		p[*it] = 0;
	}

	if( is2D ) std::cout << "2D setup" << std::endl;
	else std::cout << "3D setup" << std::endl;
	std::cout << "height=" << height << " length=" << length << std::endl;

	for(Mesh::iteratorFace it = m->BeginFace(); it != m->EndFace(); ++it) if( it->Boundary() )
	{
		it->Centroid(x.data());
		it->UnitNormal(n.data());
		if( is2D && (fabs(n(2,0)-1) < 1.0-3 || fabs(n(2,0)+1) < 1.0e-3 ) ) //roller bc
		{
			bc[*it][0] = 1;
			bc[*it][1] = 0;
			bc[*it][2] = 0;
			bc[*it][3] = 1;
			bc[*it][4] = 0;
			bc[*it][5] = 0;
			bc[*it][6] = 0;
		}
		else if( fabs(n(0,0)+1) < 1.0e-3 && x(0,0) < 1.0e-3 ) //inlet
		{
			std::cout << "hi" << std::endl;
			bc[*it][0] = 1;
			bc[*it][1] = 0;
			bc[*it][2] = 1;
			bc[*it][3] = 0;
			bc[*it][4] = 1;
			bc[*it][5] = 0;
			bc[*it][6] = 0;
		}
		else if( fabs(n(0,0)-1) < 1.0e-3 ) //outlet
			bcp[*it] = 0;
		else //no-slip
		{
			bc[*it][0] = 1;
			bc[*it][1] = 0;
			bc[*it][2] = 1;
			bc[*it][3] = 0;
			bc[*it][4] = 0;
			bc[*it][5] = 0;
			bc[*it][6] = 0;
		}
	}

	std::cout << "Saving output to " << fout << std::endl;

	m->Save(fout);

	return 0;
}
<commit_msg>update<commit_after>#include "inmost.h"

using namespace INMOST;
//setup on mesh:
//
// FORCE - 3 entries
//
// BOUNDARY_CONDITION_VELOCITY - 7 entries
// r = (a5,a6,a7)
// n.(a1*u + a2*t) = n.r
// (I - nn.)(a3*u + a4*t) = (I-nn.)r
//
// BOUNDARY_CONDITION_PRESSURE - 1 entry
//
// REFERENCE_VELOCITY - 3 entries
//
// REFERENCE_PRESSURE - 1 entry
//

typedef Storage::real real;

int main(int argc, char ** argv)
{

	if( argc < 2 )
	{
		std::cout << "Usage: " << argv[0] << " mesh is2D=1 height=0.6 length=0.2 mesh_out=grid_out.pmf" << std::endl;
		return 0;
	}

	Mesh * m = new Mesh;
	m->SetFileOption("VERBOSITY","2");
	try
	{
		m->Load(argv[1]);
	}
	catch(...)
	{
		std::cout << "Cannot load the mesh " << argv[1] << std::endl;
		return -1;
	}

	std::string fout = "grid_out.pmf";
	int is2D = 1;
	double height = 0.7;
	double length = 0.2;
	if( argc > 2 ) is2D = atoi(argv[2]);
	if( argc > 3 ) height = atof(argv[3]);
	if( argc > 4 ) length = atof(argv[4]);
	if( argc > 5 ) fout = std::string(argv[5]);

	//TagRealArray force = m->CreateTag("FORCE",DATA_REAL,CELL,NONE,3);
	TagRealArray bc = m->CreateTag("BOUNDARY_CONDITION_VELOCITY",DATA_REAL,FACE,FACE,7);
	TagReal bcp = m->CreateTag("BOUNDARY_CONDITION_PRESSURE",DATA_REAL,FACE,FACE,1);
	TagRealArray uvw = m->CreateTag("UVW",DATA_REAL,CELL,NONE,3);
	TagReal p = m->CreateTag("P",DATA_REAL,CELL,NONE,1);

	//cut part of the grid

	rMatrix n(3,1), x(3,1);

	for(Mesh::iteratorCell it = m->BeginCell(); it != m->EndCell(); ++it)
	{
		it->Centroid(x.data());
		if( x(0,0) < length && x(1,0) < height )
			it->Delete();
	}

	//this should not be needed?
	for(Mesh::iteratorFace it = m->BeginFace(); it != m->EndFace(); ++it) if( it->Boundary() )
		it->FixNormalOrientation();

	for(Mesh::iteratorCell it = m->BeginCell(); it != m->EndCell(); ++it)
	{
		uvw(*it,3,1).Zero();
		p[*it] = 0;
	}

	if( is2D ) std::cout << "2D setup" << std::endl;
	else std::cout << "3D setup" << std::endl;
	std::cout << "height=" << height << " length=" << length << std::endl;

	for(Mesh::iteratorFace it = m->BeginFace(); it != m->EndFace(); ++it) if( it->Boundary() )
	{
		it->Centroid(x.data());
		it->UnitNormal(n.data());
		if( is2D && (fabs(n(2,0)-1) < 1.0-3 || fabs(n(2,0)+1) < 1.0e-3 ) ) //roller bc
		{
			bc[*it][0] = 1;
			bc[*it][1] = 0;
			bc[*it][2] = 0;
			bc[*it][3] = 1;
			bc[*it][4] = 0;
			bc[*it][5] = 0;
			bc[*it][6] = 0;
		}
		else if( fabs(n(0,0)+1) < 1.0e-3 && x(0,0) < 1.0e-3 ) //inlet
		{
			bc[*it][0] = 1;
			bc[*it][1] = 0;
			bc[*it][2] = 1;
			bc[*it][3] = 0;
			bc[*it][4] = 1;
			bc[*it][5] = 0;
			bc[*it][6] = 0;
		}
		else if( fabs(n(0,0)-1) < 1.0e-3 ) //outlet
			bcp[*it] = 0;
		else //no-slip
		{
			bc[*it][0] = 1;
			bc[*it][1] = 0;
			bc[*it][2] = 1;
			bc[*it][3] = 0;
			bc[*it][4] = 0;
			bc[*it][5] = 0;
			bc[*it][6] = 0;
		}
	}

	std::cout << "Saving output to " << fout << std::endl;

	m->Save(fout);

	return 0;
}
<|endoftext|>


<commit_before>/** \copyright
 * Copyright (c) 2016, Balazs Racz
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * 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 HOLDER 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 BootloaderHal.cxx
 *
 * ESP8266-specific implementation of the HAL (Hardware Abstraction Layer) used
 * by the OpenLCB bootloader.
 *
 * @author Balazs Racz
 * @date 19 Jun 2016
 */

#include <string.h>
#include <stdint.h>

#include <c_types.h>
#include "freertos/bootloader_hal.h"

extern "C" {
#include "eboot_command.h"
#include "flash.h"
}

#include "freertos_drivers/esp8266/Esp8266Gpio.hxx"
#include "utils/ESPWifiClient.hxx"
#include "utils/Crc.hxx"
#include "utils/GpioInitializer.hxx"
#include "utils/blinker.h"
#include "nmranet_config.h"
#include "nmranet/Defs.hxx"
#include "nmranet/If.hxx"
#include "nmranet/BootloaderPort.hxx"

extern "C" {

void reboot_now();

struct HW
{
    /* original / standard definitions.
        GPIO_PIN(MOT_A_HI, GpioOutputSafeLow, 4);
        GPIO_PIN(MOT_A_LO, GpioOutputSafeLow, 5);

        GPIO_PIN(MOT_B_HI, GpioOutputSafeLow, 14);
        GPIO_PIN(MOT_B_LO, GpioOutputSafeLow, 12);

        // forward: A=HI B=LO

        GPIO_PIN(LIGHT_FRONT, GpioOutputSafeLow, 13);
        GPIO_PIN(LIGHT_BACK, GpioOutputSafeLow, 15);

        GPIO_PIN(F1, GpioOutputSafeLow, 2);

        //typedef DummyPin F1_Pin;

    */

    GPIO_PIN(MOT_A_HI, GpioOutputSafeLow, 4);
    GPIO_PIN(MOT_A_LO, GpioOutputSafeLow, 5);

    GPIO_PIN(MOT_B_HI, GpioOutputSafeLow, 14);
    GPIO_PIN(MOT_B_LO, GpioOutputSafeLow, 12);

    static constexpr bool invertLow = false;

    // forward: A=HI B=LO

    // typedef BLINKER_Pin LIGHT_FRONT_Pin;
    GPIO_PIN(LIGHT_FRONT, GpioOutputSafeLow, 13);
    GPIO_PIN(LIGHT_BACK, GpioOutputSafeLow, 15);

    GPIO_PIN(F1, GpioOutputSafeHigh, 2);
    // typedef DummyPin F1_Pin;

    typedef GpioInitializer<        //
        MOT_A_HI_Pin, MOT_A_LO_Pin, //
        MOT_B_HI_Pin, MOT_B_LO_Pin, //
        LIGHT_FRONT_Pin, LIGHT_BACK_Pin, F1_Pin> GpioInit;
};

void bootloader_hw_set_to_safe(void)
{
    HW::GpioInit::hw_set_to_safe();
}

void bootloader_hw_init()
{
}

void bootloader_led(enum BootloaderLed id, bool value)
{
    switch (id)
    {
        case LED_ACTIVE:
            HW::F1_Pin::set(value);
            return;
        case LED_WRITING:
            resetblink(value ? 1 : 0);
            return;
        case LED_CSUM_ERROR:
            printf("Checksum: %s\n", value ? "error" : "ok");
            return;
        case LED_REQUEST:
            printf("Manual request: %s\n", value ? "yes" : "no");
            return;
        default:
            ; /* ignore */
    }
}

bool request_bootloader()
{
    extern uint32_t __bootloader_magic_ptr;
    if (__bootloader_magic_ptr == REQUEST_BOOTLOADER)
    {
        __bootloader_magic_ptr = 0;
        return true;
    }
    // there is no way to request bootloader mode by pressing a button for now.
    return false;
}

/// Pointer in the memory where the SPI flash is mapped.
#define FLASH_MAP_ADDRESS (0x40200000)
/// Offset in the SPI flash where the user code block is located. This has to
/// be larger than the size of the bootloader binary.
#define USER_CODE_OFFSET (3 * 128 * 1024)
/// Size of the memory mapped region of flash.
#define USER_CODE_END (1024 * 1024)
/// Offset inside the user code block where the application starts. Used to
/// calculate where to load the application from when booting.
#define HEADER_LEN (4096)

void get_flash_boundaries(const void **flash_min, const void **flash_max,
    const struct app_header **app_header)
{
    *flash_min = (void *)(FLASH_MAP_ADDRESS + USER_CODE_OFFSET);
    *flash_max = (void *)(FLASH_MAP_ADDRESS + USER_CODE_END);
    *app_header = (struct app_header *)(FLASH_MAP_ADDRESS + USER_CODE_OFFSET);
}

void checksum_data(const void *data, uint32_t size, uint32_t *checksum)
{
    memset(checksum, 0, 16);
    crc3_crc16_ibm(data, size, (uint16_t*) checksum);
}

extern const uint16_t DEFAULT_ALIAS;

uint16_t nmranet_alias()
{
    /// TODO(balazs.racz):  fix this
    return DEFAULT_ALIAS;
}

extern const nmranet::NodeID NODE_ID;

uint64_t nmranet_nodeid()
{
    /// TODO(balazs.racz):  read some form of EEPROM instead.
    return NODE_ID;
}

Executor<1> g_executor{NO_THREAD()};
Service g_service(&g_executor);
CanHubFlow g_can_hub(&g_service);
nmranet::BootloaderPort g_bootloader_port(&g_service);
bool bootloader_reset_request = false;

bool read_can_frame(struct can_frame *frame)
{
    return g_bootloader_port.read_can_frame(frame);
}

bool try_send_can_frame(const struct can_frame &frame)
{
    auto *b = g_can_hub.alloc();
    *b->data()->mutable_frame() = frame;
    b->data()->skipMember_ = &g_bootloader_port;
    g_can_hub.send(b);
    return true;
}

void bootloader_reboot(void)
{
    bootloader_reset_request = true;
}

void application_entry(void)
{
    printf("Starting application.\n");
    struct eboot_command cmd;
    memset(&cmd, 0, sizeof(cmd));
    cmd.action = ACTION_LOAD_APP;
    cmd.args[0] = USER_CODE_OFFSET + HEADER_LEN - APP_START_OFFSET;
    eboot_command_write(&cmd);
    reboot_now();
}

void erase_flash_page(const void *address)
{
    bootloader_led(LED_ACTIVE, 0);
    bootloader_led(LED_WRITING, 1);
    uint32_t a = (uint32_t) address;
    a -= FLASH_MAP_ADDRESS;
    SPIEraseSector(a/FLASH_SECTOR_SIZE);
    bootloader_led(LED_WRITING, 0);
    bootloader_led(LED_ACTIVE, 1);
}

void write_flash(const void *address, const void *data, uint32_t size_bytes)
{
    bootloader_led(LED_ACTIVE, 0);
    bootloader_led(LED_WRITING, 1);

    uint32_t a = (uint32_t) address;
    a -= FLASH_MAP_ADDRESS;
    SPIWrite(a, (void*)data, size_bytes);

    bootloader_led(LED_WRITING, 0);
    bootloader_led(LED_ACTIVE, 1);
}

void get_flash_page_info(
    const void *address, const void **page_start, uint32_t *page_length_bytes)
{
    uint32_t value = (uint32_t)address;
    value &= (FLASH_SECTOR_SIZE - 1);
    *page_start = (const void *)value;
    *page_length_bytes = FLASH_SECTOR_SIZE;
}

extern char WIFI_SSID[];
extern char WIFI_PASS[];
extern char WIFI_HUB_HOSTNAME[];
extern int WIFI_HUB_PORT;

bool bootloader_init();
bool bootloader_loop();

} // extern "C"

class BootloaderFlow : public StateFlowBase {
public:
    BootloaderFlow() : StateFlowBase(&g_service) {}

    void start() {
        start_flow(STATE(loop));
    }

private:
    Action loop() {
        bootloader_loop();
        if (bootloader_reset_request) {
            return sleep_and_call(&timer_, MSEC_TO_NSEC(500), STATE(reset));
        }
        return yield_and_call(STATE(loop));
    }

    Action reset() {
        printf("Rebooting bootloader.\n");
        eboot_command_clear();
        reboot_now();
        return exit();
    }

    StateFlowTimer timer_{this};
};

int appl_main(int argc, char**argv) {
    bootloader_hw_set_to_safe();
    bootloader_hw_init();
    bootloader_init();
    printf("bootloader init done.\n");
    g_can_hub.register_port(&g_bootloader_port);
    resetblink(1);
    new ESPWifiClient(WIFI_SSID, WIFI_PASS, &g_can_hub, WIFI_HUB_HOSTNAME,
                      WIFI_HUB_PORT, 1200, []()
        {
            resetblink(0);
            // This will actually return due to the event-driven OS
            // implementation of the stack.
            g_executor.thread_body();
            (new BootloaderFlow())->start();
        });
    return 0;
}

<commit_msg>Esp8266 bootloader updates: - adds manual force pin. - adds a few magic bytes to the checksummer - makes erasing flash by blocks and not sectors. This is faster.<commit_after>/** \copyright
 * Copyright (c) 2016, Balazs Racz
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * 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 HOLDER 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 BootloaderHal.cxx
 *
 * ESP8266-specific implementation of the HAL (Hardware Abstraction Layer) used
 * by the OpenLCB bootloader.
 *
 * @author Balazs Racz
 * @date 19 Jun 2016
 */

#include <string.h>
#include <stdint.h>

#include <c_types.h>
#include "freertos/bootloader_hal.h"

extern "C" {
#include "eboot_command.h"
#include "flash.h"
}

#include "freertos_drivers/esp8266/Esp8266Gpio.hxx"
#include "utils/ESPWifiClient.hxx"
#include "utils/Crc.hxx"
#include "utils/GpioInitializer.hxx"
#include "utils/blinker.h"
#include "nmranet_config.h"
#include "nmranet/Defs.hxx"
#include "nmranet/If.hxx"
#include "nmranet/BootloaderPort.hxx"

extern "C" {

void reboot_now();

struct HW
{
    /* original / standard definitions.
        GPIO_PIN(MOT_A_HI, GpioOutputSafeLow, 4);
        GPIO_PIN(MOT_A_LO, GpioOutputSafeLow, 5);

        GPIO_PIN(MOT_B_HI, GpioOutputSafeLow, 14);
        GPIO_PIN(MOT_B_LO, GpioOutputSafeLow, 12);

        // forward: A=HI B=LO

        GPIO_PIN(LIGHT_FRONT, GpioOutputSafeLow, 13);
        GPIO_PIN(LIGHT_BACK, GpioOutputSafeLow, 15);

        GPIO_PIN(F1, GpioOutputSafeLow, 2);

        //typedef DummyPin F1_Pin;

    */

    GPIO_PIN(MOT_A_HI, GpioOutputSafeLow, 4);
    GPIO_PIN(MOT_A_LO, GpioOutputSafeLow, 5);

    GPIO_PIN(MOT_B_HI, GpioOutputSafeLow, 14);
    GPIO_PIN(MOT_B_LO, GpioOutputSafeLow, 12);

    static constexpr bool invertLow = false;

    // forward: A=HI B=LO

    // typedef BLINKER_Pin LIGHT_FRONT_Pin;
    GPIO_PIN(LIGHT_FRONT, GpioOutputSafeLow, 13);
    GPIO_PIN(LIGHT_BACK, GpioOutputSafeLow, 15);

    // Doubles as manual request pin.
    GPIO_PIN(REQ_BLOAD, GpioInputPU, 13);

    GPIO_PIN(F1, GpioOutputSafeHigh, 2);
    // typedef DummyPin F1_Pin;

    typedef GpioInitializer<        //
        MOT_A_HI_Pin, MOT_A_LO_Pin, //
        MOT_B_HI_Pin, MOT_B_LO_Pin, //
//        LIGHT_FRONT_Pin, LIGHT_BACK_Pin,
        F1_Pin> GpioInit;
};

void bootloader_hw_set_to_safe(void)
{
    HW::GpioInit::hw_set_to_safe();
    HW::GpioInit::hw_init();
    HW::REQ_BLOAD_Pin::hw_init();
}

void bootloader_hw_init()
{
}

void bootloader_led(enum BootloaderLed id, bool value)
{
    switch (id)
    {
        case LED_ACTIVE:
            HW::F1_Pin::set(value);
            return;
        case LED_WRITING:
            resetblink(value ? 1 : 0);
            return;
        case LED_CSUM_ERROR:
            printf("Checksum: %s\n", value ? "error" : "ok");
            return;
        case LED_REQUEST:
            printf("Manual request: %s\n", value ? "yes" : "no");
            return;
        default:
            ; /* ignore */
    }
}

bool request_bootloader()
{
    HW::REQ_BLOAD_Pin::hw_init();
    extern uint32_t __bootloader_magic_ptr;
    if (__bootloader_magic_ptr == REQUEST_BOOTLOADER)
    {
        __bootloader_magic_ptr = 0;
        return true;
    }
    return !HW::REQ_BLOAD_Pin::get();

    // there is no way to request bootloader mode by pressing a button for now.
    //return false;
}

/// Pointer in the memory where the SPI flash is mapped.
#define FLASH_MAP_ADDRESS (0x40200000)
/// Offset in the SPI flash where the user code block is located. This has to
/// be larger than the size of the bootloader binary.
#define USER_CODE_OFFSET (3 * 128 * 1024)
/// Size of the memory mapped region of flash.
#define USER_CODE_END (1024 * 1024)
/// Offset inside the user code block where the application starts. Used to
/// calculate where to load the application from when booting.
#define HEADER_LEN (4096)

void get_flash_boundaries(const void **flash_min, const void **flash_max,
    const struct app_header **app_header)
{
    *flash_min = (void *)(FLASH_MAP_ADDRESS + USER_CODE_OFFSET);
    *flash_max = (void *)(FLASH_MAP_ADDRESS + USER_CODE_END);
    *app_header = (struct app_header *)(FLASH_MAP_ADDRESS + USER_CODE_OFFSET);
}

void checksum_data(const void *data, uint32_t size, uint32_t *checksum)
{
    memset(checksum, 0, 16);
    crc3_crc16_ibm(data, size, (uint16_t*) checksum);
    // We put some magic into the checksum as well.
    checksum[2] = 0x73a92bd1;
    checksum[3] = 0x5a5a55aa;
}

extern const uint16_t DEFAULT_ALIAS;

uint16_t nmranet_alias()
{
    /// TODO(balazs.racz):  fix this
    return DEFAULT_ALIAS;
}

extern const nmranet::NodeID NODE_ID;

uint64_t nmranet_nodeid()
{
    /// TODO(balazs.racz):  read some form of EEPROM instead.
    return NODE_ID;
}

Executor<1> g_executor{NO_THREAD()};
Service g_service(&g_executor);
CanHubFlow g_can_hub(&g_service);
nmranet::BootloaderPort g_bootloader_port(&g_service);
bool bootloader_reset_request = false;

bool read_can_frame(struct can_frame *frame)
{
    return g_bootloader_port.read_can_frame(frame);
}

bool try_send_can_frame(const struct can_frame &frame)
{
    auto *b = g_can_hub.alloc();
    *b->data()->mutable_frame() = frame;
    b->data()->skipMember_ = &g_bootloader_port;
    g_can_hub.send(b);
    return true;
}

void bootloader_reboot(void)
{
    bootloader_reset_request = true;
}

void application_entry(void)
{
    printf("Starting application.\n");
    struct eboot_command cmd;
    memset(&cmd, 0, sizeof(cmd));
    cmd.action = ACTION_LOAD_APP;
    cmd.args[0] = USER_CODE_OFFSET + HEADER_LEN - APP_START_OFFSET;
    eboot_command_write(&cmd);
    reboot_now();
}

void erase_flash_page(const void *address)
{
    bootloader_led(LED_ACTIVE, 0);
    bootloader_led(LED_WRITING, 1);
    uint32_t a = (uint32_t) address;
    a -= FLASH_MAP_ADDRESS;
    unsigned page = a/FLASH_BLOCK_SIZE;
    SPIEraseBlock(page);
    printf("erase page %u\n", page);
    bootloader_led(LED_WRITING, 0);
    bootloader_led(LED_ACTIVE, 1);
}

void write_flash(const void *address, const void *data, uint32_t size_bytes)
{
    bootloader_led(LED_ACTIVE, 0);
    bootloader_led(LED_WRITING, 1);

    uint32_t a = (uint32_t) address;
    a -= FLASH_MAP_ADDRESS;
    SPIWrite(a, (void*)data, size_bytes);
    printf("write addr %06x len %u\n", a, size_bytes);

    bootloader_led(LED_WRITING, 0);
    bootloader_led(LED_ACTIVE, 1);
}

void get_flash_page_info(
    const void *address, const void **page_start, uint32_t *page_length_bytes)
{
    uint32_t value = (uint32_t)address;
    value &= ~(FLASH_BLOCK_SIZE - 1);
    *page_start = (const void *)value;
    *page_length_bytes = FLASH_BLOCK_SIZE;
}

extern char WIFI_SSID[];
extern char WIFI_PASS[];
extern char WIFI_HUB_HOSTNAME[];
extern int WIFI_HUB_PORT;

bool bootloader_init();
bool bootloader_loop();

} // extern "C"

class BootloaderFlow : public StateFlowBase {
public:
    BootloaderFlow() : StateFlowBase(&g_service) {}

    void start() {
        start_flow(STATE(loop));
        HW::REQ_BLOAD_Pin::hw_init();
    }

private:
    Action loop() {
        bootloader_loop();
        HW::F1_Pin::set(HW::REQ_BLOAD_Pin::get());
        if (bootloader_reset_request) {
            return sleep_and_call(&timer_, MSEC_TO_NSEC(500), STATE(reset));
        }
        return yield_and_call(STATE(loop));
    }

    Action reset() {
        printf("Rebooting bootloader.\n");
        eboot_command_clear();
        reboot_now();
        return exit();
    }

    StateFlowTimer timer_{this};
};

int appl_main(int argc, char**argv) {
    bootloader_hw_set_to_safe();
    bootloader_hw_init();
    bootloader_init();
    printf("bootloader init done.\n");
    g_can_hub.register_port(&g_bootloader_port);
    resetblink(1);
    new ESPWifiClient(WIFI_SSID, WIFI_PASS, &g_can_hub, WIFI_HUB_HOSTNAME,
                      WIFI_HUB_PORT, 1200, []()
        {
            resetblink(0);
            // This will actually return due to the event-driven OS
            // implementation of the stack.
            g_executor.thread_body();
            (new BootloaderFlow())->start();
        });
    return 0;
}

<|endoftext|>


<commit_before>#include "z2h/token.hpp"
#include "z2h/symbol.hpp"
#include "z2h/lexer.hpp"
#include "z2h/parser.hpp"

#include "ast.hpp"
#include "lexer.h"
#include "parser.h"
#include "bindpower.h"
#include "exceptions.h"

#include <map>
#include <vector>
#include <boost/regex.hpp>
#include <iostream>
#include <algorithm>

namespace sota {

    z2h::Ast * SotaParser::Parse() {
        auto statements = Statements();
        return new BlockAst(statements);
    }

    std::vector<z2h::Symbol *> SotaParser::Symbols() {
        return symbols;
    }
    std::vector<z2h::Token *> SotaParser::Tokenize() {
        index = 0;
        z2h::Token *token = nullptr;
        do {
            token = Consume();
        } while (TokenType::EndOfFile != token->type);
        return tokens;
    }

    std::vector<z2h::Ast *> SotaParser::Expressions(z2h::Token *end) {
        std::vector<z2h::Ast *> expressions;
        auto la1 = LookAhead1();
        while (end != la1) {
            auto expression = Expression();
            expressions.push_back(expression);
            if (!Consume(TokenType::EndOfExpression)) {
                break;
            }
            la1 = LookAhead1();
        }
        return expressions;
    }

    // std parsing functions
    z2h::Ast * SotaParser::NullptrStd() {
        return nullptr;
    }

    // nud parsing functions
    z2h::Ast * SotaParser::NullptrNud(z2h::Token *token) {
        return nullptr;
    }
    z2h::Ast * SotaParser::EndOfFileNud(z2h::Token *token) {
        return nullptr;
    }
    z2h::Ast * SotaParser::NumberNud(z2h::Token *token) {
        return new NumberAst(token);
    }
    z2h::Ast * SotaParser::IdentifierNud(z2h::Token *token) {
        return new IdentifierAst(token);
    }
    z2h::Ast * SotaParser::PrefixNud(z2h::Token *token) {
        z2h::Ast *right = Expression(BindPower::Unary);
        return new PrefixAst(token, right);
    }
    z2h::Ast * SotaParser::CommaNud(z2h::Token *token) {
        auto right = Expression(GetSymbol(*token)->lbp);
        return new z2h::BinaryAst(token, new NullAst(), right);
    }
    z2h::Ast * SotaParser::ParensNud(z2h::Token *token) {
        nesting.Push(token);
        auto eq = GetSymbol(TokenType::Assign);
        eq->lbp += 10;
        auto ast = Expression();
        if (!Consume(TokenType::RightParen)) {
            std::cout << "RightParen not consumed" << std::endl;
        }
        eq->lbp -= 10;
        nesting.Pop(token);
        if (ast) {
            if (ast->token->value == ",") {
                auto asts = ast->Vectorize();
                return new ParensAst(asts);
            }
        }
        else
            return new NullAst();

        return ast;
    }
    z2h::Ast * SotaParser::BracesNud(z2h::Token *token) {
        auto statements = Statements();
        if (!Consume(TokenType::RightBrace)) {
            std::cout << "RightBrace not consumed" << std::endl;
        }
        return new BlockAst(statements);
    }
    z2h::Ast * SotaParser::BracketsNud(z2h::Token *token) {
        auto ast = Expression();
        if (!Consume(TokenType::RightBracket)) {
            std::cout << "RightBracket not consumed" << std::endl;
        }
        auto asts = ast->Vectorize();
        return new BracketsAst(asts);
    }
    z2h::Ast * SotaParser::RegexMatchNud(z2h::Token *token) {
        auto right = Expression();
        std::cout << "RegexMatchNud: token=" << *token << " right=" << *right << std::endl;
        auto asts = right->Vectorize();
        for (auto ast : asts) {
            std::cout << *ast << std::endl;
        }
        return new RegexMatchAst(token, asts[0], asts[1], asts[2]);
    }
    z2h::Ast * SotaParser::RegexReplaceNud(z2h::Token *token) {
        auto right = Expression();
        std::cout << "RegexReplaceNud: token=" << *token << " right=" << *right << std::endl;
        auto asts = right->Vectorize();
        for (auto ast : asts) {
            std::cout << *ast << std::endl;
        }
        return new RegexReplaceAst(token, asts[0], asts[1], asts[2], asts[3]);
    }
    z2h::Ast * SotaParser::IfThenElifElseNud(z2h::Token *token) {
        return nullptr;
    }

    // led parsing functions
    z2h::Ast * SotaParser::NullptrLed(z2h::Ast *left, z2h::Token *token) {
        return nullptr;
    }
    z2h::Ast * SotaParser::EndOfFileLed(z2h::Ast *left, z2h::Token *token) {
        return left;
    }
    z2h::Ast * SotaParser::ComparisonLed(z2h::Ast *left, z2h::Token *token) {
        return nullptr;
    }
    z2h::Ast * SotaParser::InfixLed(z2h::Ast *left, z2h::Token *token) {
        z2h::Ast *right = Expression(GetSymbol(*token)->lbp);
        return new InfixAst(token, left, right);
    }
    z2h::Ast * SotaParser::PostfixLed(z2h::Ast *left, z2h::Token *token) {
        return nullptr;
    }
    z2h::Ast * SotaParser::CommaLed(z2h::Ast *left, z2h::Token *token) {
        auto right = Expression(GetSymbol(*token)->lbp);
        return new z2h::BinaryAst(token, left, (right ? right : new NullAst()));
    }
    z2h::Ast * SotaParser::ParensLed(z2h::Ast *left, z2h::Token *token) {
        nesting.Push(token);
        auto eq = GetSymbol(TokenType::Assign);
        eq->lbp += 10;
        auto ast = Expression();
        if (!Consume(TokenType::RightParen)) {
            std::cout << "RightParen not consumed" << std::endl;
        }
        eq->lbp -= 10;
        nesting.Pop(token);
        if (ast) {
            auto asts = ast->Vectorize();
            return new CallAst(token, left, new ParensAst(asts));
        }
        return new CallAst(token, left, new NullAst());
    }
    z2h::Ast * SotaParser::BracesLed(z2h::Ast *left, z2h::Token *token) {
        auto ast = Expression();
        if (!Consume(TokenType::RightBrace)) {
            std::cout << "RightBrace not consumed" << std::endl;
        }
        auto asts = ast->Vectorize();
        return new CallAst(token, left, new ParensAst(asts));
    }
    z2h::Ast * SotaParser::BracketsLed(z2h::Ast *left, z2h::Token *token) {
        auto ast = Expression();
        if (!Consume(TokenType::RightBracket)) {
            std::cout << "RightBracket not consumed" << std::endl;
        }
        auto asts = ast->Vectorize();
        return new CallAst(token, left, new ParensAst(asts));
    }
    z2h::Ast * SotaParser::AssignLed(z2h::Ast *left, z2h::Token *token) {
        z2h::Ast *right = Expression(GetSymbol(*token)->lbp -1 ); //right associative?
        auto asts = left->Vectorize();
        if (asts.size() > 1) {
            auto ast = new AssignAst(token, new z2h::VectorAst(asts), right);
            delete left;
            return ast;
        }
        return new AssignAst(token, left, right);
    }
    z2h::Ast * SotaParser::FuncLed(z2h::Ast *left, z2h::Token *token) {
        z2h::Ast *right = Expression();
        return new FuncAst(token, left, right);
    }
    z2h::Ast * SotaParser::CallLed(z2h::Ast *left, z2h::Token *token) {
        return nullptr;
    }
    z2h::Ast * SotaParser::TernaryLed(z2h::Ast *left, z2h::Token *token) {
        auto action = Expression();
        auto pair = ConditionalAst::Pair(left, action);
        if (nullptr == Consume(TokenType::Colon))
            throw SotaException(__FILE__, __LINE__, "colon : expected");
        auto defaultAction = Expression();
        return new ConditionalAst(token, {pair}, defaultAction);
    }
    z2h::Ast * SotaParser::IfThenElseLed(z2h::Ast *left, z2h::Token *token) {
        auto predicate = Expression();
        auto pair = ConditionalAst::Pair(predicate, left);
        if (nullptr == Consume(TokenType::Else))
            throw SotaException(__FILE__, __LINE__, "else expected");
        auto defaultAction = Expression();
        return new ConditionalAst(token, {pair}, defaultAction);
    }

    std::exception SotaParser::Exception(const char *file, size_t line, const std::string &message) {
        return SotaException(file, line, message);
    }

    SotaParser::SotaParser(SotaLexer *lexer)
        : z2h::Parser<SotaParser>(lexer) {
        #define T(k,b,t,n,l) new z2h::Symbol(b, STD(t), NUD(n), LED(l) ),
        symbols = {
            SYMBOLS
        };
        #undef T
    }
}
<commit_msg>renamed eq -> assign ... -sai<commit_after>#include "z2h/token.hpp"
#include "z2h/symbol.hpp"
#include "z2h/lexer.hpp"
#include "z2h/parser.hpp"

#include "ast.hpp"
#include "lexer.h"
#include "parser.h"
#include "bindpower.h"
#include "exceptions.h"

#include <map>
#include <vector>
#include <boost/regex.hpp>
#include <iostream>
#include <algorithm>

namespace sota {

    z2h::Ast * SotaParser::Parse() {
        auto statements = Statements();
        return new BlockAst(statements);
    }

    std::vector<z2h::Symbol *> SotaParser::Symbols() {
        return symbols;
    }
    std::vector<z2h::Token *> SotaParser::Tokenize() {
        index = 0;
        z2h::Token *token = nullptr;
        do {
            token = Consume();
        } while (TokenType::EndOfFile != token->type);
        return tokens;
    }

    std::vector<z2h::Ast *> SotaParser::Expressions(z2h::Token *end) {
        std::vector<z2h::Ast *> expressions;
        auto la1 = LookAhead1();
        while (end != la1) {
            auto expression = Expression();
            expressions.push_back(expression);
            if (!Consume(TokenType::EndOfExpression)) {
                break;
            }
            la1 = LookAhead1();
        }
        return expressions;
    }

    // std parsing functions
    z2h::Ast * SotaParser::NullptrStd() {
        return nullptr;
    }

    // nud parsing functions
    z2h::Ast * SotaParser::NullptrNud(z2h::Token *token) {
        return nullptr;
    }
    z2h::Ast * SotaParser::EndOfFileNud(z2h::Token *token) {
        return nullptr;
    }
    z2h::Ast * SotaParser::NumberNud(z2h::Token *token) {
        return new NumberAst(token);
    }
    z2h::Ast * SotaParser::IdentifierNud(z2h::Token *token) {
        return new IdentifierAst(token);
    }
    z2h::Ast * SotaParser::PrefixNud(z2h::Token *token) {
        z2h::Ast *right = Expression(BindPower::Unary);
        return new PrefixAst(token, right);
    }
    z2h::Ast * SotaParser::CommaNud(z2h::Token *token) {
        auto right = Expression(GetSymbol(*token)->lbp);
        return new z2h::BinaryAst(token, new NullAst(), right);
    }
    z2h::Ast * SotaParser::ParensNud(z2h::Token *token) {
        nesting.Push(token);
        auto assign = GetSymbol(TokenType::Assign);
        assign->lbp += 10;
        auto ast = Expression();
        if (!Consume(TokenType::RightParen)) {
            std::cout << "RightParen not consumed" << std::endl;
        }
        assign->lbp -= 10;
        nesting.Pop(token);
        if (ast) {
            if (ast->token->value == ",") {
                auto asts = ast->Vectorize();
                return new ParensAst(asts);
            }
        }
        else
            return new NullAst();

        return ast;
    }
    z2h::Ast * SotaParser::BracesNud(z2h::Token *token) {
        auto statements = Statements();
        if (!Consume(TokenType::RightBrace)) {
            std::cout << "RightBrace not consumed" << std::endl;
        }
        return new BlockAst(statements);
    }
    z2h::Ast * SotaParser::BracketsNud(z2h::Token *token) {
        auto ast = Expression();
        if (!Consume(TokenType::RightBracket)) {
            std::cout << "RightBracket not consumed" << std::endl;
        }
        auto asts = ast->Vectorize();
        return new BracketsAst(asts);
    }
    z2h::Ast * SotaParser::RegexMatchNud(z2h::Token *token) {
        auto right = Expression();
        std::cout << "RegexMatchNud: token=" << *token << " right=" << *right << std::endl;
        auto asts = right->Vectorize();
        for (auto ast : asts) {
            std::cout << *ast << std::endl;
        }
        return new RegexMatchAst(token, asts[0], asts[1], asts[2]);
    }
    z2h::Ast * SotaParser::RegexReplaceNud(z2h::Token *token) {
        auto right = Expression();
        std::cout << "RegexReplaceNud: token=" << *token << " right=" << *right << std::endl;
        auto asts = right->Vectorize();
        for (auto ast : asts) {
            std::cout << *ast << std::endl;
        }
        return new RegexReplaceAst(token, asts[0], asts[1], asts[2], asts[3]);
    }
    z2h::Ast * SotaParser::IfThenElifElseNud(z2h::Token *token) {
        return nullptr;
    }

    // led parsing functions
    z2h::Ast * SotaParser::NullptrLed(z2h::Ast *left, z2h::Token *token) {
        return nullptr;
    }
    z2h::Ast * SotaParser::EndOfFileLed(z2h::Ast *left, z2h::Token *token) {
        return left;
    }
    z2h::Ast * SotaParser::ComparisonLed(z2h::Ast *left, z2h::Token *token) {
        return nullptr;
    }
    z2h::Ast * SotaParser::InfixLed(z2h::Ast *left, z2h::Token *token) {
        z2h::Ast *right = Expression(GetSymbol(*token)->lbp);
        return new InfixAst(token, left, right);
    }
    z2h::Ast * SotaParser::PostfixLed(z2h::Ast *left, z2h::Token *token) {
        return nullptr;
    }
    z2h::Ast * SotaParser::CommaLed(z2h::Ast *left, z2h::Token *token) {
        auto right = Expression(GetSymbol(*token)->lbp);
        return new z2h::BinaryAst(token, left, (right ? right : new NullAst()));
    }
    z2h::Ast * SotaParser::ParensLed(z2h::Ast *left, z2h::Token *token) {
        nesting.Push(token);
        auto assign = GetSymbol(TokenType::Assign);
        assign->lbp += 10;
        auto ast = Expression();
        if (!Consume(TokenType::RightParen)) {
            std::cout << "RightParen not consumed" << std::endl;
        }
        assign->lbp -= 10;
        nesting.Pop(token);
        if (ast) {
            auto asts = ast->Vectorize();
            return new CallAst(token, left, new ParensAst(asts));
        }
        return new CallAst(token, left, new NullAst());
    }
    z2h::Ast * SotaParser::BracesLed(z2h::Ast *left, z2h::Token *token) {
        auto ast = Expression();
        if (!Consume(TokenType::RightBrace)) {
            std::cout << "RightBrace not consumed" << std::endl;
        }
        auto asts = ast->Vectorize();
        return new CallAst(token, left, new ParensAst(asts));
    }
    z2h::Ast * SotaParser::BracketsLed(z2h::Ast *left, z2h::Token *token) {
        auto ast = Expression();
        if (!Consume(TokenType::RightBracket)) {
            std::cout << "RightBracket not consumed" << std::endl;
        }
        auto asts = ast->Vectorize();
        return new CallAst(token, left, new ParensAst(asts));
    }
    z2h::Ast * SotaParser::AssignLed(z2h::Ast *left, z2h::Token *token) {
        z2h::Ast *right = Expression(GetSymbol(*token)->lbp -1 ); //right associative?
        auto asts = left->Vectorize();
        if (asts.size() > 1) {
            auto ast = new AssignAst(token, new z2h::VectorAst(asts), right);
            delete left;
            return ast;
        }
        return new AssignAst(token, left, right);
    }
    z2h::Ast * SotaParser::FuncLed(z2h::Ast *left, z2h::Token *token) {
        z2h::Ast *right = Expression();
        return new FuncAst(token, left, right);
    }
    z2h::Ast * SotaParser::CallLed(z2h::Ast *left, z2h::Token *token) {
        return nullptr;
    }
    z2h::Ast * SotaParser::TernaryLed(z2h::Ast *left, z2h::Token *token) {
        auto action = Expression();
        auto pair = ConditionalAst::Pair(left, action);
        if (nullptr == Consume(TokenType::Colon))
            throw SotaException(__FILE__, __LINE__, "colon : expected");
        auto defaultAction = Expression();
        return new ConditionalAst(token, {pair}, defaultAction);
    }
    z2h::Ast * SotaParser::IfThenElseLed(z2h::Ast *left, z2h::Token *token) {
        auto predicate = Expression();
        auto pair = ConditionalAst::Pair(predicate, left);
        if (nullptr == Consume(TokenType::Else))
            throw SotaException(__FILE__, __LINE__, "else expected");
        auto defaultAction = Expression();
        return new ConditionalAst(token, {pair}, defaultAction);
    }

    std::exception SotaParser::Exception(const char *file, size_t line, const std::string &message) {
        return SotaException(file, line, message);
    }

    SotaParser::SotaParser(SotaLexer *lexer)
        : z2h::Parser<SotaParser>(lexer) {
        #define T(k,b,t,n,l) new z2h::Symbol(b, STD(t), NUD(n), LED(l) ),
        symbols = {
            SYMBOLS
        };
        #undef T
    }
}
<|endoftext|>


<commit_before>
#include <Rcpp.h>
#include <string>
#include <list>
#include <cstdio>
using namespace Rcpp;
using namespace std;

struct SubString {
  const char *begin, *end;
  string get() {
    return string(begin, end);
  }
};

struct Markup {
  Markup() {
    null = true;
  }

  Markup(const char* str_end) {
    format_spec_needs_expanding = false;
    literal_text.begin = literal_text.end = str_end;
    field_name.begin = field_name.end = str_end;
    conversion = '\0';
    format_spec.begin = format_spec.end = str_end;
    null = false;
    has_markup = false;
  }

  List toList() {
    if (has_markup)
      return List::create(
        Named("literal_text") = literal_text.get(),
        Named("field_name") = field_name.get(),
        Named("conversion") = conversion,
        Named("format_spec") = format_spec.get(),
        Named("format_spec_needs_expanding") = format_spec_needs_expanding
      );
    else
      return List::create(
        Named("literal_text") = literal_text.get(),
        Named("field_name") = R_NilValue,
        Named("conversion") = R_NilValue,
        Named("format_spec") = R_NilValue,
        Named("format_spec_needs_expanding") = format_spec_needs_expanding
      );
  }

  SubString literal_text;
  SubString field_name;
  bool has_markup;
  char conversion;
  SubString format_spec;
  bool format_spec_needs_expanding;
  bool null;
};

const Markup NULL_MARKUP = Markup();

class Parser {
  const char *it, *str_end;

  // this function is a rewriting of cpython's parse_field()
  // located on /Objects/stringlib/unicode_format.h
  void parse_field(Markup& field) {
    int bracket_count = 0;
    char ch;

    // matches the field name
    field.field_name.begin = it;
    while (it != str_end) {
      ch = *it;
      it++;

      if (ch == '{')
        stop("Unexpected '{' in field name");

      if (ch == '[' || ch == '(') bracket_count++;
      if (ch == ']' || ch == ')') bracket_count--;

      if (bracket_count == 0 && (ch == '}' || ch == ':' || ch == '!'))
        break;
    }
    field.field_name.end = it-1;

    if (ch == '!' || ch == ':') {
      if (ch == '!') {
        if (it == str_end)
          stop("End of string while looking for conversion specifier");

        field.conversion = *it;
        it++;

        if (it != str_end) {
          ch = *it;
          it++;

          if (ch == '}')
            return;
          if (ch != ':')
            stop("Expected ':' after conversion specifier");
        }
      }

      field.format_spec.begin = it;
      int braces_count = 1;

      while (it != str_end) {
        ch = *it;
        it++;

        if (ch == '{') {
          field.format_spec_needs_expanding = true;
          braces_count++;
        } else if (ch == '}') {
          braces_count--;

          if (braces_count == 0) {
            field.format_spec.end = it-1;
            return;
          }
        }
      }

      stop("Unmatched '{' in format spec");
    } else if (ch != '}') {
      stop("Expected '}' before end of string");
    }
  }

  // this function is a rewriting of cpython's MarkupIterator_next()
  // located on /Objects/stringlib/unicode_format.h
  Markup next() {
    Markup markup(str_end);
    char ch;

    if (it == str_end)
      return NULL_MARKUP;

    markup.literal_text.begin = it;

    while (it != str_end) {
      ch = *it;
      it++;

      if (ch == '{' || ch == '}') {
        markup.has_markup = true;
        break;
      }
    }

    markup.literal_text.end = it;

    if ((ch == '}') && (it == str_end || ch != *it))
      stop("Single '}' encountered in format string");

    if (it == str_end && ch == '{')
      stop("Single '{' encountered in format string");

    if (it != str_end) {
      if (ch == *it) {
        it++;
        markup.has_markup = false;
      } else
        markup.literal_text.end--;
    }

    if (markup.has_markup)
      parse_field(markup);

    return markup;
  }

public:
  List parse(StringVector& v) {
    it = v[0].begin();
    str_end = v[0].end();

    List result;

    Markup m;
    while (!(m = next()).null) {
      result.push_back(m.toList());
    }

    result.attr("class") = "pformat_compiled";
    return result;
  }

};

//' Preparses a format string
//'
//' @description  Parses a format string into an internal representation
//' compatible with \code{pformat()}.
//'
//' @param format_string the format string
//'
//' @return an object of class \code{pformat.compiled} containing an internal
//' representation of the format string.
//' @export
//'
//' @details This function actually only parses a "layer" of the format string
//' markup. Recursive format strings depend on data, and thus can't be
//' completely parsed yet. In these cases, \code{pformat_parse()} will still be
//' called by \code{pformat()} with format specifications needing expanding.
//'
//' @examples
//' pformat_parse("{} {}")
//' pformat_parse("{1} {2}")
//' @export
// [[Rcpp::export]]
List pformat_parse(StringVector format_string) {
  Parser p;
  return p.parse(format_string);
}

class SpecParser {
  string format_spec;
  int pos, end;

  int get_integer(int& result) {
    int num_digits = 0, digitval;

    for (result = 0; pos < end; pos++, num_digits++) {
      digitval = format_spec[pos] - '0';
      if (digitval < 0 || digitval > 10)
        break;
      result = result*10 + digitval;
    }

    return num_digits;
  }

public:

  List parse(StringVector& v) {
    List spec = List::create(
      Named("fill") = " ",
      Named("align") = "",
      Named("alternate") = false,
      Named("sign") = "",
      Named("width") = -1,
      Named("thousands_separator") = false,
      Named("precision") = -1,
      Named("type") = ""
    );

    spec.attr("class") = "pformat_spec";

    format_spec = as<string>(v[0]);
    pos = 0;
    end = format_spec.size();

    bool align_specified = false, fill_specified = false;

    // if the second char is an alignment token, parse the fill char
    if (end-pos >= 2 && (
        format_spec[pos+1] == '<' || format_spec[pos+1] == '>' ||
        format_spec[pos+1] == '^' || format_spec[pos+1] == '=' )) {
      spec["align"] = format_spec[pos+1];
      spec["fill"] = format_spec[pos];
      align_specified = true;
      fill_specified = true;
      pos += 2;
    } if (end-pos >= 1 && (
        format_spec[pos] == '<' || format_spec[pos] == '>' ||
        format_spec[pos] == '^' || format_spec[pos] == '=' )) {
      spec["align"] = format_spec[pos];
      align_specified = true;
      pos++;
    }

    // parse the sign options
    if (end-pos >= 1 && (format_spec[pos] == '+' || format_spec[pos] == '-' ||
        format_spec[pos] == ' '))
      spec["sign"] = format_spec[pos++];

    // if the next character is #, we're in alternate mode (only integers)
    if (end-pos >= 1 && format_spec[pos] == '#') {
      spec["alternate"] = true;
      pos++;
    }

    // backwards compatibility
    if (!fill_specified && end-pos >= 1 && format_spec[pos] == '0') {
      spec["fill"] = '0';
      if (!align_specified)
        spec["align"] = '=';
      pos++;
    }

    // parse width
    int result;
    if (get_integer(result) > 0)
      spec["width"] = result;

    // parse the thousands separator
    if (end-pos >= 1 && format_spec[pos] == ',') {
      spec["thousands_separator"] = true;
      pos++;
    }

    // parse field precision
    if (end-pos >= 1 && format_spec[pos] == '.') {
      pos++;

      if (get_integer(result) == 0)
        stop("Format specifier missing precision");
      else
        spec["precision"] = result;
    }

    // more than one char remaining, invalid format specifier
    if (end-pos >= 2)
      stop("Invalid format specifier");

    spec["type"] = format_spec[pos];

    if (spec["thousands_separator"] && !(
      format_spec[pos] == '\0' || format_spec[pos] == 'd' ||
      format_spec[pos] == 'e' || format_spec[pos] == 'f' ||
      format_spec[pos] == 'g' || format_spec[pos] == 'E' ||
      format_spec[pos] == 'G' || format_spec[pos] == '%' ||
      format_spec[pos] == 'F'
    ))
      stop(string("Cannot specify ',' with '") + format_spec[pos] + "'.");

    return spec;
  }
};

//' @export
// [[Rcpp::export]]
List pformat_parse_spec(StringVector& v) {
  SpecParser p;
  return p.parse(v);
}

<commit_msg>Replaced string::iterators for plain pointers in SpecParser<commit_after>
#include <Rcpp.h>
#include <string>
#include <list>
#include <cstdio>
using namespace Rcpp;
using namespace std;

struct SubString {
  const char *begin, *end;
  string get() {
    return string(begin, end);
  }
};

struct Markup {
  Markup() {
    null = true;
  }

  Markup(const char* str_end) {
    format_spec_needs_expanding = false;
    literal_text.begin = literal_text.end = str_end;
    field_name.begin = field_name.end = str_end;
    conversion = '\0';
    format_spec.begin = format_spec.end = str_end;
    null = false;
    has_markup = false;
  }

  List toList() {
    if (has_markup)
      return List::create(
        Named("literal_text") = literal_text.get(),
        Named("field_name") = field_name.get(),
        Named("conversion") = conversion,
        Named("format_spec") = format_spec.get(),
        Named("format_spec_needs_expanding") = format_spec_needs_expanding
      );
    else
      return List::create(
        Named("literal_text") = literal_text.get(),
        Named("field_name") = R_NilValue,
        Named("conversion") = R_NilValue,
        Named("format_spec") = R_NilValue,
        Named("format_spec_needs_expanding") = format_spec_needs_expanding
      );
  }

  SubString literal_text;
  SubString field_name;
  bool has_markup;
  char conversion;
  SubString format_spec;
  bool format_spec_needs_expanding;
  bool null;
};

const Markup NULL_MARKUP = Markup();

class Parser {
  const char *it, *str_end;

  // this function is a rewriting of cpython's parse_field()
  // located on /Objects/stringlib/unicode_format.h
  void parse_field(Markup& field) {
    int bracket_count = 0;
    char ch;

    // matches the field name
    field.field_name.begin = it;
    while (it != str_end) {
      ch = *it;
      it++;

      if (ch == '{')
        stop("Unexpected '{' in field name");

      if (ch == '[' || ch == '(') bracket_count++;
      if (ch == ']' || ch == ')') bracket_count--;

      if (bracket_count == 0 && (ch == '}' || ch == ':' || ch == '!'))
        break;
    }
    field.field_name.end = it-1;

    if (ch == '!' || ch == ':') {
      if (ch == '!') {
        if (it == str_end)
          stop("End of string while looking for conversion specifier");

        field.conversion = *it;
        it++;

        if (it != str_end) {
          ch = *it;
          it++;

          if (ch == '}')
            return;
          if (ch != ':')
            stop("Expected ':' after conversion specifier");
        }
      }

      field.format_spec.begin = it;
      int braces_count = 1;

      while (it != str_end) {
        ch = *it;
        it++;

        if (ch == '{') {
          field.format_spec_needs_expanding = true;
          braces_count++;
        } else if (ch == '}') {
          braces_count--;

          if (braces_count == 0) {
            field.format_spec.end = it-1;
            return;
          }
        }
      }

      stop("Unmatched '{' in format spec");
    } else if (ch != '}') {
      stop("Expected '}' before end of string");
    }
  }

  // this function is a rewriting of cpython's MarkupIterator_next()
  // located on /Objects/stringlib/unicode_format.h
  Markup next() {
    Markup markup(str_end);
    char ch;

    if (it == str_end)
      return NULL_MARKUP;

    markup.literal_text.begin = it;

    while (it != str_end) {
      ch = *it;
      it++;

      if (ch == '{' || ch == '}') {
        markup.has_markup = true;
        break;
      }
    }

    markup.literal_text.end = it;

    if ((ch == '}') && (it == str_end || ch != *it))
      stop("Single '}' encountered in format string");

    if (it == str_end && ch == '{')
      stop("Single '{' encountered in format string");

    if (it != str_end) {
      if (ch == *it) {
        it++;
        markup.has_markup = false;
      } else
        markup.literal_text.end--;
    }

    if (markup.has_markup)
      parse_field(markup);

    return markup;
  }

public:
  List parse(StringVector& v) {
    it = v[0].begin();
    str_end = v[0].end();

    List result;

    Markup m;
    while (!(m = next()).null) {
      result.push_back(m.toList());
    }

    result.attr("class") = "pformat_compiled";
    return result;
  }

};

//' Preparses a format string
//'
//' @description  Parses a format string into an internal representation
//' compatible with \code{pformat()}.
//'
//' @param format_string the format string
//'
//' @return an object of class \code{pformat.compiled} containing an internal
//' representation of the format string.
//' @export
//'
//' @details This function actually only parses a "layer" of the format string
//' markup. Recursive format strings depend on data, and thus can't be
//' completely parsed yet. In these cases, \code{pformat_parse()} will still be
//' called by \code{pformat()} with format specifications needing expanding.
//'
//' @examples
//' pformat_parse("{} {}")
//' pformat_parse("{1} {2}")
//' @export
// [[Rcpp::export]]
List pformat_parse(StringVector format_string) {
  Parser p;
  return p.parse(format_string);
}

class SpecParser {
  const char* format_spec;
  int pos, end;

  int get_integer(int& result) {
    int num_digits = 0, digitval;

    for (result = 0; pos < end; pos++, num_digits++) {
      digitval = format_spec[pos] - '0';
      if (digitval < 0 || digitval > 10)
        break;
      result = result*10 + digitval;
    }

    return num_digits;
  }

public:

  List parse(StringVector& v) {
    List spec = List::create(
      Named("fill") = " ",
      Named("align") = "",
      Named("alternate") = false,
      Named("sign") = "",
      Named("width") = -1,
      Named("thousands_separator") = false,
      Named("precision") = -1,
      Named("type") = ""
    );

    spec.attr("class") = "pformat_spec";

    format_spec = v[0].begin();
    pos = 0;
    end = v[0].size();

    bool align_specified = false, fill_specified = false;

    // if the second char is an alignment token, parse the fill char
    if (end-pos >= 2 && (
        format_spec[pos+1] == '<' || format_spec[pos+1] == '>' ||
        format_spec[pos+1] == '^' || format_spec[pos+1] == '=' )) {
      spec["align"] = format_spec[pos+1];
      spec["fill"] = format_spec[pos];
      align_specified = true;
      fill_specified = true;
      pos += 2;
    } if (end-pos >= 1 && (
        format_spec[pos] == '<' || format_spec[pos] == '>' ||
        format_spec[pos] == '^' || format_spec[pos] == '=' )) {
      spec["align"] = format_spec[pos];
      align_specified = true;
      pos++;
    }

    // parse the sign options
    if (end-pos >= 1 && (format_spec[pos] == '+' || format_spec[pos] == '-' ||
        format_spec[pos] == ' '))
      spec["sign"] = format_spec[pos++];

    // if the next character is #, we're in alternate mode (only integers)
    if (end-pos >= 1 && format_spec[pos] == '#') {
      spec["alternate"] = true;
      pos++;
    }

    // backwards compatibility
    if (!fill_specified && end-pos >= 1 && format_spec[pos] == '0') {
      spec["fill"] = '0';
      if (!align_specified)
        spec["align"] = '=';
      pos++;
    }

    // parse width
    int result;
    if (get_integer(result) > 0)
      spec["width"] = result;

    // parse the thousands separator
    if (end-pos >= 1 && format_spec[pos] == ',') {
      spec["thousands_separator"] = true;
      pos++;
    }

    // parse field precision
    if (end-pos >= 1 && format_spec[pos] == '.') {
      pos++;

      if (get_integer(result) == 0)
        stop("Format specifier missing precision");
      else
        spec["precision"] = result;
    }

    // more than one char remaining, invalid format specifier
    if (end-pos >= 2)
      stop("Invalid format specifier");

    spec["type"] = format_spec[pos];

    if (spec["thousands_separator"] && !(
      format_spec[pos] == '\0' || format_spec[pos] == 'd' ||
      format_spec[pos] == 'e' || format_spec[pos] == 'f' ||
      format_spec[pos] == 'g' || format_spec[pos] == 'E' ||
      format_spec[pos] == 'G' || format_spec[pos] == '%' ||
      format_spec[pos] == 'F'
    ))
      stop(string("Cannot specify ',' with '") + format_spec[pos] + "'.");

    return spec;
  }
};

//' @export
// [[Rcpp::export]]
List pformat_parse_spec(StringVector& v) {
  SpecParser p;
  return p.parse(v);
}

<|endoftext|>