<commit_before>/**
 * @file llpluginprocesschild.cpp
 * @brief LLPluginProcessChild handles the child side of the external-process plugin API.
 *
 * @cond
 * $LicenseInfo:firstyear=2008&license=viewergpl$
 *
 * Copyright (c) 2008, Linden Research, Inc.
 *
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlife.com/developers/opensource/gplv2
 *
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at http://secondlife.com/developers/opensource/flossexception
 *
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 *
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 * @endcond
 */

#include "linden_common.h"

#include "llpluginprocesschild.h"
#include "llplugininstance.h"
#include "llpluginmessagepipe.h"
#include "llpluginmessageclasses.h"

static const F32 HEARTBEAT_SECONDS = 1.0f;
static const F32 PLUGIN_IDLE_SECONDS = 1.0f / 100.0f;  // Each call to idle will give the plugin this much time.

LLPluginProcessChild::LLPluginProcessChild()
{
	mInstance = NULL;
	mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);
	mSleepTime = PLUGIN_IDLE_SECONDS;	// default: send idle messages at 100Hz
	mCPUElapsed = 0.0f;
}

LLPluginProcessChild::~LLPluginProcessChild()
{
	if(mInstance != NULL)
	{
		sendMessageToPlugin(LLPluginMessage("base", "cleanup"));

		// IMPORTANT: under some (unknown) circumstances the apr_dso_unload() triggered when mInstance is deleted
		// appears to fail and lock up which means that a given instance of the slplugin process never exits.
		// This is bad, especially when users try to update their version of SL - it fails because the slplugin
		// process as well as a bunch of plugin specific files are locked and cannot be overwritten.
		exit( 0 );
		//delete mInstance;
		//mInstance = NULL;
	}
}

void LLPluginProcessChild::killSockets(void)
{
	killMessagePipe();
	mSocket.reset();
}

void LLPluginProcessChild::init(U32 launcher_port)
{
	mLauncherHost = LLHost("127.0.0.1", launcher_port);
	setState(STATE_INITIALIZED);
}

void LLPluginProcessChild::idle(void)
{
	bool idle_again;
	do
	{
		if(mSocketError != APR_SUCCESS)
		{
			LL_INFOS("Plugin") << "message pipe is in error state, moving to STATE_ERROR"<< LL_ENDL;
			setState(STATE_ERROR);
		}

		if((mState > STATE_INITIALIZED) && (mMessagePipe == NULL))
		{
			// The pipe has been closed -- we're done.
			// TODO: This could be slightly more subtle, but I'm not sure it needs to be.
			LL_INFOS("Plugin") << "message pipe went away, moving to STATE_ERROR"<< LL_ENDL;
			setState(STATE_ERROR);
		}

		// If a state needs to go directly to another state (as a performance enhancement), it can set idle_again to true after calling setState().
		// USE THIS CAREFULLY, since it can starve other code.  Specifically make sure there's no way to get into a closed cycle and never return.
		// When in doubt, don't do it.
		idle_again = false;

		if(mInstance != NULL)
		{
			// Provide some time to the plugin
			mInstance->idle();
		}

		switch(mState)
		{
			case STATE_UNINITIALIZED:
			break;

			case STATE_INITIALIZED:
				if(mSocket->blockingConnect(mLauncherHost))
				{
					// This automatically sets mMessagePipe
					new LLPluginMessagePipe(this, mSocket);

					setState(STATE_CONNECTED);
				}
				else
				{
					// connect failed
					setState(STATE_ERROR);
				}
			break;

			case STATE_CONNECTED:
				sendMessageToParent(LLPluginMessage(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hello"));
				setState(STATE_PLUGIN_LOADING);
			break;

			case STATE_PLUGIN_LOADING:
				if(!mPluginFile.empty())
				{
					mInstance = new LLPluginInstance(this);
					if(mInstance->load(mPluginFile) == 0)
					{
						mHeartbeat.start();
						mHeartbeat.setTimerExpirySec(HEARTBEAT_SECONDS);
						mCPUElapsed = 0.0f;
						setState(STATE_PLUGIN_LOADED);
					}
					else
					{
						setState(STATE_ERROR);
					}
				}
			break;

			case STATE_PLUGIN_LOADED:
				{
					setState(STATE_PLUGIN_INITIALIZING);
					LLPluginMessage message("base", "init");
					message.setValue("user_data_path", mUserDataPath);
					sendMessageToPlugin(message);
				}
			break;

			case STATE_PLUGIN_INITIALIZING:
				// waiting for init_response...
			break;

			case STATE_RUNNING:
				if(mInstance != NULL)
				{
					// Provide some time to the plugin
					LLPluginMessage message("base", "idle");
					message.setValueReal("time", PLUGIN_IDLE_SECONDS);
					sendMessageToPlugin(message);

					mInstance->idle();

					if(mHeartbeat.hasExpired())
					{

						// This just proves that we're not stuck down inside the plugin code.
						LLPluginMessage heartbeat(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "heartbeat");

						// Calculate the approximage CPU usage fraction (floating point value between 0 and 1) used by the plugin this heartbeat cycle.
						// Note that this will not take into account any threads or additional processes the plugin spawns, but it's a first approximation.
						// If we could write OS-specific functions to query the actual CPU usage of this process, that would be a better approximation.
						heartbeat.setValueReal("cpu_usage", mCPUElapsed / mHeartbeat.getElapsedTimeF64());

						sendMessageToParent(heartbeat);

						mHeartbeat.reset();
						mHeartbeat.setTimerExpirySec(HEARTBEAT_SECONDS);
						mCPUElapsed = 0.0f;
					}
				}
				// receivePluginMessage will transition to STATE_UNLOADING
			break;

			case STATE_UNLOADING:
				if(mInstance != NULL)
				{
					sendMessageToPlugin(LLPluginMessage("base", "cleanup"));
					delete mInstance;
					mInstance = NULL;
				}
				setState(STATE_UNLOADED);
			break;

			case STATE_UNLOADED:
				killSockets();
				setState(STATE_DONE);
			break;

			case STATE_ERROR:
				// Close the socket to the launcher
				killSockets();
				// TODO: Where do we go from here?  Just exit()?
				setState(STATE_DONE);
			break;

			case STATE_DONE:
				// just sit here.
			break;
		}

	} while (idle_again);
}

void LLPluginProcessChild::sleep(F64 seconds)
{
	if(mMessagePipe)
	{
		mMessagePipe->pump(seconds);
	}
	else
	{
		ms_sleep((int)(seconds * 1000.0f));
	}
}

void LLPluginProcessChild::pump(void)
{
	if(mMessagePipe)
	{
		mMessagePipe->pump(0.0f);
	}
	else
	{
		// Should we warn here?
	}
}

bool LLPluginProcessChild::isRunning(void)
{
	bool result = false;

	if(mState == STATE_RUNNING)
		result = true;

	return result;
}

bool LLPluginProcessChild::isDone(void)
{
	bool result = false;

	switch(mState)
	{
		case STATE_DONE:
		result = true;
		break;
		default:
		break;
	}

	return result;
}

void LLPluginProcessChild::sendMessageToPlugin(const LLPluginMessage &message)
{
	std::string buffer = message.generate();

	LL_DEBUGS("Plugin") << "Sending to plugin: " << buffer << LL_ENDL;
	LLTimer elapsed;

	mInstance->sendMessage(buffer);

	mCPUElapsed += elapsed.getElapsedTimeF64();
}

void LLPluginProcessChild::sendMessageToParent(const LLPluginMessage &message)
{
	std::string buffer = message.generate();

	LL_DEBUGS("Plugin") << "Sending to parent: " << buffer << LL_ENDL;

	writeMessageRaw(buffer);
}

void LLPluginProcessChild::receiveMessageRaw(const std::string &message)
{
	// Incoming message from the TCP Socket

	LL_DEBUGS("Plugin") << "Received from parent: " << message << LL_ENDL;

	bool passMessage = true;

	// FIXME: how should we handle queueing here?

	{
		// Decode this message
		LLPluginMessage parsed;
		parsed.parse(message);

		std::string message_class = parsed.getClass();
		if(message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL)
		{
			passMessage = false;

			std::string message_name = parsed.getName();
			if(message_name == "load_plugin")
			{
				mPluginFile = parsed.getValue("file");
				mUserDataPath = parsed.getValue("user_data_path");
			}
			else if(message_name == "shm_add")
			{
				std::string name = parsed.getValue("name");
				size_t size = (size_t)parsed.getValueS32("size");

				sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name);
				if(iter != mSharedMemoryRegions.end())
				{
					// Need to remove the old region first
					LL_WARNS("Plugin") << "Adding a duplicate shared memory segment!" << LL_ENDL;
				}
				else
				{
					// This is a new region
					LLPluginSharedMemory *region = new LLPluginSharedMemory;
					if(region->attach(name, size))
					{
						mSharedMemoryRegions.insert(sharedMemoryRegionsType::value_type(name, region));

						std::stringstream addr;
						addr << region->getMappedAddress();

						// Send the add notification to the plugin
						LLPluginMessage message("base", "shm_added");
						message.setValue("name", name);
						message.setValueS32("size", (S32)size);
						message.setValuePointer("address", region->getMappedAddress());
						sendMessageToPlugin(message);

						// and send the response to the parent
						message.setMessage(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_add_response");
						message.setValue("name", name);
						sendMessageToParent(message);
					}
					else
					{
						LL_WARNS("Plugin") << "Couldn't create a shared memory segment!" << LL_ENDL;
					}
				}

			}
			else if(message_name == "shm_remove")
			{
				std::string name = parsed.getValue("name");
				sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name);
				if(iter != mSharedMemoryRegions.end())
				{
					// forward the remove request to the plugin -- its response will trigger us to detach the segment.
					LLPluginMessage message("base", "shm_remove");
					message.setValue("name", name);
					sendMessageToPlugin(message);
				}
				else
				{
					LL_WARNS("Plugin") << "shm_remove for unknown memory segment!" << LL_ENDL;
				}
			}
			else if(message_name == "sleep_time")
			{
				mSleepTime = parsed.getValueReal("time");
			}
			else if(message_name == "crash")
			{
				// Crash the plugin
				LL_ERRS("Plugin") << "Plugin crash requested." << LL_ENDL;
			}
			else if(message_name == "hang")
			{
				// Hang the plugin
				LL_WARNS("Plugin") << "Plugin hang requested." << LL_ENDL;
				while(1)
				{
					// wheeeeeeeee......
				}
			}
			else
			{
				LL_WARNS("Plugin") << "Unknown internal message from parent: " << message_name << LL_ENDL;
			}
		}
	}

	if(passMessage && mInstance != NULL)
	{
		LLTimer elapsed;

		mInstance->sendMessage(message);

		mCPUElapsed += elapsed.getElapsedTimeF64();
	}
}

/* virtual */
void LLPluginProcessChild::receivePluginMessage(const std::string &message)
{
	LL_DEBUGS("Plugin") << "Received from plugin: " << message << LL_ENDL;

	// Incoming message from the plugin instance
	bool passMessage = true;

	// FIXME: how should we handle queueing here?

	// Intercept certain base messages (responses to ones sent by this class)
	{
		// Decode this message
		LLPluginMessage parsed;
		parsed.parse(message);
		std::string message_class = parsed.getClass();
		if(message_class == "base")
		{
			std::string message_name = parsed.getName();
			if(message_name == "init_response")
			{
				// The plugin has finished initializing.
				setState(STATE_RUNNING);

				// Don't pass this message up to the parent
				passMessage = false;

				LLPluginMessage new_message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "load_plugin_response");
				LLSD versions = parsed.getValueLLSD("versions");
				new_message.setValueLLSD("versions", versions);

				if(parsed.hasValue("plugin_version"))
				{
					std::string plugin_version = parsed.getValue("plugin_version");
					new_message.setValueLLSD("plugin_version", plugin_version);
				}

				// Let the parent know it's loaded and initialized.
				sendMessageToParent(new_message);
			}
			else if(message_name == "shm_remove_response")
			{
				// Don't pass this message up to the parent
				passMessage = false;

				std::string name = parsed.getValue("name");
				sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name);
				if(iter != mSharedMemoryRegions.end())
				{
					// detach the shared memory region
					iter->second->detach();

					// and remove it from our map
					mSharedMemoryRegions.erase(iter);

					// Finally, send the response to the parent.
					LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_remove_response");
					message.setValue("name", name);
					sendMessageToParent(message);
				}
				else
				{
					LL_WARNS("Plugin") << "shm_remove_response for unknown memory segment!" << LL_ENDL;
				}
			}
		}
	}

	if(passMessage)
	{
		LL_DEBUGS("Plugin") << "Passing through to parent: " << message << LL_ENDL;
		writeMessageRaw(message);
	}
}

void LLPluginProcessChild::setState(EState state)
{
	LL_DEBUGS("Plugin") << "setting state to " << state << LL_ENDL;
	mState = state;
};
<commit_msg>CID-184<commit_after>/**
 * @file llpluginprocesschild.cpp
 * @brief LLPluginProcessChild handles the child side of the external-process plugin API.
 *
 * @cond
 * $LicenseInfo:firstyear=2008&license=viewergpl$
 *
 * Copyright (c) 2008, Linden Research, Inc.
 *
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlife.com/developers/opensource/gplv2
 *
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at http://secondlife.com/developers/opensource/flossexception
 *
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 *
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 * @endcond
 */

#include "linden_common.h"

#include "llpluginprocesschild.h"
#include "llplugininstance.h"
#include "llpluginmessagepipe.h"
#include "llpluginmessageclasses.h"

static const F32 HEARTBEAT_SECONDS = 1.0f;
static const F32 PLUGIN_IDLE_SECONDS = 1.0f / 100.0f;  // Each call to idle will give the plugin this much time.

LLPluginProcessChild::LLPluginProcessChild()
{
	mInstance = NULL;
	mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);
	mSleepTime = PLUGIN_IDLE_SECONDS;	// default: send idle messages at 100Hz
	mCPUElapsed = 0.0f;
}

LLPluginProcessChild::~LLPluginProcessChild()
{
	if(mInstance != NULL)
	{
		sendMessageToPlugin(LLPluginMessage("base", "cleanup"));

		// IMPORTANT: under some (unknown) circumstances the apr_dso_unload() triggered when mInstance is deleted
		// appears to fail and lock up which means that a given instance of the slplugin process never exits.
		// This is bad, especially when users try to update their version of SL - it fails because the slplugin
		// process as well as a bunch of plugin specific files are locked and cannot be overwritten.
		exit( 0 );
		//delete mInstance;
		//mInstance = NULL;
	}
}

void LLPluginProcessChild::killSockets(void)
{
	killMessagePipe();
	mSocket.reset();
}

void LLPluginProcessChild::init(U32 launcher_port)
{
	mLauncherHost = LLHost("127.0.0.1", launcher_port);
	setState(STATE_INITIALIZED);
}

void LLPluginProcessChild::idle(void)
{
	bool idle_again;
	do
	{
		if(mSocketError != APR_SUCCESS)
		{
			LL_INFOS("Plugin") << "message pipe is in error state, moving to STATE_ERROR"<< LL_ENDL;
			setState(STATE_ERROR);
		}

		if((mState > STATE_INITIALIZED) && (mMessagePipe == NULL))
		{
			// The pipe has been closed -- we're done.
			// TODO: This could be slightly more subtle, but I'm not sure it needs to be.
			LL_INFOS("Plugin") << "message pipe went away, moving to STATE_ERROR"<< LL_ENDL;
			setState(STATE_ERROR);
		}

		// If a state needs to go directly to another state (as a performance enhancement), it can set idle_again to true after calling setState().
		// USE THIS CAREFULLY, since it can starve other code.  Specifically make sure there's no way to get into a closed cycle and never return.
		// When in doubt, don't do it.
		idle_again = false;

		if(mInstance != NULL)
		{
			// Provide some time to the plugin
			mInstance->idle();
		}

		switch(mState)
		{
			case STATE_UNINITIALIZED:
			break;

			case STATE_INITIALIZED:
				if(mSocket->blockingConnect(mLauncherHost))
				{
					// This automatically sets mMessagePipe
					new LLPluginMessagePipe(this, mSocket);

					setState(STATE_CONNECTED);
				}
				else
				{
					// connect failed
					setState(STATE_ERROR);
				}
			break;

			case STATE_CONNECTED:
				sendMessageToParent(LLPluginMessage(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hello"));
				setState(STATE_PLUGIN_LOADING);
			break;

			case STATE_PLUGIN_LOADING:
				if(!mPluginFile.empty())
				{
					mInstance = new LLPluginInstance(this);
					if(mInstance->load(mPluginFile) == 0)
					{
						mHeartbeat.start();
						mHeartbeat.setTimerExpirySec(HEARTBEAT_SECONDS);
						mCPUElapsed = 0.0f;
						setState(STATE_PLUGIN_LOADED);
					}
					else
					{
						setState(STATE_ERROR);
					}
				}
			break;

			case STATE_PLUGIN_LOADED:
				{
					setState(STATE_PLUGIN_INITIALIZING);
					LLPluginMessage message("base", "init");
					message.setValue("user_data_path", mUserDataPath);
					sendMessageToPlugin(message);
				}
			break;

			case STATE_PLUGIN_INITIALIZING:
				// waiting for init_response...
			break;

			case STATE_RUNNING:
				if(mInstance != NULL)
				{
					// Provide some time to the plugin
					LLPluginMessage message("base", "idle");
					message.setValueReal("time", PLUGIN_IDLE_SECONDS);
					sendMessageToPlugin(message);

					mInstance->idle();

					if(mHeartbeat.hasExpired())
					{

						// This just proves that we're not stuck down inside the plugin code.
						LLPluginMessage heartbeat(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "heartbeat");

						// Calculate the approximage CPU usage fraction (floating point value between 0 and 1) used by the plugin this heartbeat cycle.
						// Note that this will not take into account any threads or additional processes the plugin spawns, but it's a first approximation.
						// If we could write OS-specific functions to query the actual CPU usage of this process, that would be a better approximation.
						heartbeat.setValueReal("cpu_usage", mCPUElapsed / mHeartbeat.getElapsedTimeF64());

						sendMessageToParent(heartbeat);

						mHeartbeat.reset();
						mHeartbeat.setTimerExpirySec(HEARTBEAT_SECONDS);
						mCPUElapsed = 0.0f;
					}
				}
				// receivePluginMessage will transition to STATE_UNLOADING
			break;

			case STATE_UNLOADING:
				if(mInstance != NULL)
				{
					sendMessageToPlugin(LLPluginMessage("base", "cleanup"));
					delete mInstance;
					mInstance = NULL;
				}
				setState(STATE_UNLOADED);
			break;

			case STATE_UNLOADED:
				killSockets();
				setState(STATE_DONE);
			break;

			case STATE_ERROR:
				// Close the socket to the launcher
				killSockets();
				// TODO: Where do we go from here?  Just exit()?
				setState(STATE_DONE);
			break;

			case STATE_DONE:
				// just sit here.
			break;
		}

	} while (idle_again);
}

void LLPluginProcessChild::sleep(F64 seconds)
{
	if(mMessagePipe)
	{
		mMessagePipe->pump(seconds);
	}
	else
	{
		ms_sleep((int)(seconds * 1000.0f));
	}
}

void LLPluginProcessChild::pump(void)
{
	if(mMessagePipe)
	{
		mMessagePipe->pump(0.0f);
	}
	else
	{
		// Should we warn here?
	}
}

bool LLPluginProcessChild::isRunning(void)
{
	bool result = false;

	if(mState == STATE_RUNNING)
		result = true;

	return result;
}

bool LLPluginProcessChild::isDone(void)
{
	bool result = false;

	switch(mState)
	{
		case STATE_DONE:
		result = true;
		break;
		default:
		break;
	}

	return result;
}

void LLPluginProcessChild::sendMessageToPlugin(const LLPluginMessage &message)
{
	std::string buffer = message.generate();

	LL_DEBUGS("Plugin") << "Sending to plugin: " << buffer << LL_ENDL;
	LLTimer elapsed;

	mInstance->sendMessage(buffer);

	mCPUElapsed += elapsed.getElapsedTimeF64();
}

void LLPluginProcessChild::sendMessageToParent(const LLPluginMessage &message)
{
	std::string buffer = message.generate();

	LL_DEBUGS("Plugin") << "Sending to parent: " << buffer << LL_ENDL;

	writeMessageRaw(buffer);
}

void LLPluginProcessChild::receiveMessageRaw(const std::string &message)
{
	// Incoming message from the TCP Socket

	LL_DEBUGS("Plugin") << "Received from parent: " << message << LL_ENDL;

	bool passMessage = true;

	// FIXME: how should we handle queueing here?

	{
		// Decode this message
		LLPluginMessage parsed;
		parsed.parse(message);

		std::string message_class = parsed.getClass();
		if(message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL)
		{
			passMessage = false;

			std::string message_name = parsed.getName();
			if(message_name == "load_plugin")
			{
				mPluginFile = parsed.getValue("file");
				mUserDataPath = parsed.getValue("user_data_path");
			}
			else if(message_name == "shm_add")
			{
				std::string name = parsed.getValue("name");
				size_t size = (size_t)parsed.getValueS32("size");

				sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name);
				if(iter != mSharedMemoryRegions.end())
				{
					// Need to remove the old region first
					LL_WARNS("Plugin") << "Adding a duplicate shared memory segment!" << LL_ENDL;
				}
				else
				{
					// This is a new region
					LLPluginSharedMemory *region = new LLPluginSharedMemory;
					if(region->attach(name, size))
					{
						mSharedMemoryRegions.insert(sharedMemoryRegionsType::value_type(name, region));

						std::stringstream addr;
						addr << region->getMappedAddress();

						// Send the add notification to the plugin
						LLPluginMessage message("base", "shm_added");
						message.setValue("name", name);
						message.setValueS32("size", (S32)size);
						message.setValuePointer("address", region->getMappedAddress());
						sendMessageToPlugin(message);

						// and send the response to the parent
						message.setMessage(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_add_response");
						message.setValue("name", name);
						sendMessageToParent(message);
					}
					else
					{
						LL_WARNS("Plugin") << "Couldn't create a shared memory segment!" << LL_ENDL;
						delete region;
					}
				}

			}
			else if(message_name == "shm_remove")
			{
				std::string name = parsed.getValue("name");
				sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name);
				if(iter != mSharedMemoryRegions.end())
				{
					// forward the remove request to the plugin -- its response will trigger us to detach the segment.
					LLPluginMessage message("base", "shm_remove");
					message.setValue("name", name);
					sendMessageToPlugin(message);
				}
				else
				{
					LL_WARNS("Plugin") << "shm_remove for unknown memory segment!" << LL_ENDL;
				}
			}
			else if(message_name == "sleep_time")
			{
				mSleepTime = parsed.getValueReal("time");
			}
			else if(message_name == "crash")
			{
				// Crash the plugin
				LL_ERRS("Plugin") << "Plugin crash requested." << LL_ENDL;
			}
			else if(message_name == "hang")
			{
				// Hang the plugin
				LL_WARNS("Plugin") << "Plugin hang requested." << LL_ENDL;
				while(1)
				{
					// wheeeeeeeee......
				}
			}
			else
			{
				LL_WARNS("Plugin") << "Unknown internal message from parent: " << message_name << LL_ENDL;
			}
		}
	}

	if(passMessage && mInstance != NULL)
	{
		LLTimer elapsed;

		mInstance->sendMessage(message);

		mCPUElapsed += elapsed.getElapsedTimeF64();
	}
}

/* virtual */
void LLPluginProcessChild::receivePluginMessage(const std::string &message)
{
	LL_DEBUGS("Plugin") << "Received from plugin: " << message << LL_ENDL;

	// Incoming message from the plugin instance
	bool passMessage = true;

	// FIXME: how should we handle queueing here?

	// Intercept certain base messages (responses to ones sent by this class)
	{
		// Decode this message
		LLPluginMessage parsed;
		parsed.parse(message);
		std::string message_class = parsed.getClass();
		if(message_class == "base")
		{
			std::string message_name = parsed.getName();
			if(message_name == "init_response")
			{
				// The plugin has finished initializing.
				setState(STATE_RUNNING);

				// Don't pass this message up to the parent
				passMessage = false;

				LLPluginMessage new_message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "load_plugin_response");
				LLSD versions = parsed.getValueLLSD("versions");
				new_message.setValueLLSD("versions", versions);

				if(parsed.hasValue("plugin_version"))
				{
					std::string plugin_version = parsed.getValue("plugin_version");
					new_message.setValueLLSD("plugin_version", plugin_version);
				}

				// Let the parent know it's loaded and initialized.
				sendMessageToParent(new_message);
			}
			else if(message_name == "shm_remove_response")
			{
				// Don't pass this message up to the parent
				passMessage = false;

				std::string name = parsed.getValue("name");
				sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name);
				if(iter != mSharedMemoryRegions.end())
				{
					// detach the shared memory region
					iter->second->detach();

					// and remove it from our map
					mSharedMemoryRegions.erase(iter);

					// Finally, send the response to the parent.
					LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_remove_response");
					message.setValue("name", name);
					sendMessageToParent(message);
				}
				else
				{
					LL_WARNS("Plugin") << "shm_remove_response for unknown memory segment!" << LL_ENDL;
				}
			}
		}
	}

	if(passMessage)
	{
		LL_DEBUGS("Plugin") << "Passing through to parent: " << message << LL_ENDL;
		writeMessageRaw(message);
	}
}

void LLPluginProcessChild::setState(EState state)
{
	LL_DEBUGS("Plugin") << "setting state to " << state << LL_ENDL;
	mState = state;
};
<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2018 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <inviwo/qt/editor/toolsmenu.h>
#include <inviwo/qt/editor/inviwomainwindow.h>
#include <inviwo/core/common/inviwoapplication.h>
#include <inviwo/core/common/inviwomodule.h>
#include <inviwo/core/common/inviwomodulefactoryobject.h>
#include <inviwo/core/util/stdextensions.h>
#include <inviwo/core/util/filesystem.h>
#include <inviwo/core/util/utilities.h>
#include <inviwo/core/ports/inport.h>
#include <inviwo/core/ports/outport.h>
#include <inviwo/core/properties/property.h>
#include <inviwo/core/processors/processor.h>
#include <inviwo/core/processors/processorfactory.h>
#include <inviwo/core/network/processornetwork.h>

#include <modules/qtwidgets/inviwoqtutils.h>

#ifdef IVW_INVIWO_META
#include <inviwo/qt/editor/toolsmetamenu.h>
#endif

#include <warn/push>
#include <warn/ignore/all>
#include <QMenu>
#include <QMenuBar>
#include <QAction>
#include <QInputDialog>
#include <QClipboard>
#include <QFile>
#include <QApplication>

#include <iostream>
#include <algorithm>
#include <warn/pop>

namespace inviwo {

namespace {

void createProcessorDocMenu(InviwoApplication *app, QMenu *docsMenu) {
    auto factory = app->getProcessorFactory();

    for (auto &m : app->getModules()) {
        auto &processors = m->getProcessors();
        if (processors.empty()) continue;

        auto modMenu = docsMenu->addMenu(utilqt::toQString(m->getIdentifier()));
        for (auto &pfo : processors) {
            auto action = modMenu->addAction(utilqt::toQString(pfo->getDisplayName()));
            docsMenu->connect(action, &QAction::triggered, [pfo, factory]() {
                const auto processor = factory->create(pfo->getClassIdentifier());
                const auto &inports = processor->getInports();
                const auto &outports = processor->getOutports();
                const auto &properties = processor->getProperties();
                const auto classID = processor->getClassIdentifier();
                const auto &dispName = processor->getDisplayName();

                std::ostringstream oss;
                oss << "/** \\docpage{" << classID << ", " << dispName << "}" << std::endl;
                oss << "* ![](" << classID << ".png?classIdentifier=" << classID << ")"
                    << std::endl;
                oss << "* " << std::endl;
                oss << "* Description of the processor" << std::endl;
                oss << "* " << std::endl;
                oss << "* " << std::endl;
                if (!inports.empty()) {
                    oss << "* ### Inports" << std::endl;
                    for (const auto &port : inports) {
                        oss << "*   * __" << port->getIdentifier() << "__ Describe port.\n";
                    }
                    oss << "* \n";
                }

                if (!outports.empty()) {
                    oss << "* ### Outports" << std::endl;
                    for (const auto &port : outports) {
                        oss << "*   * __" << port->getIdentifier() << "__ Describe port.\n";
                    }
                    oss << "* \n";
                }

                if (!properties.empty()) {
                    oss << "* ### Properties" << std::endl;
                    for (const auto &prop : properties) {
                        oss << "*   * __" << prop->getDisplayName() << "__ Describe property.\n";
                    }
                    oss << "* \n";
                }
                oss << "*/\n";

                QApplication::clipboard()->setText(utilqt::toQString(oss.str()));
                LogInfoCustom("ToolMenu", "DOXYGEN Template code for processor "
                                              << dispName << " copied to clipboard");
                LogInfoCustom("ToolMenu", oss.str());
            });
        }
    }
}

void createRegressionActions(QWidget *parent, InviwoApplication *app, QMenu *menu) {
    for (const auto &module : app->getModules()) {
        auto action = menu->addAction(utilqt::toQString(module->getIdentifier()));

        QObject::connect(
            action, &QAction::triggered, [modulename = module->getIdentifier(), parent, app]() {
                bool ok;
                const auto name = QInputDialog::getText(
                    parent, "Create Regression Test", "Regression test name", QLineEdit::Normal, "",
                    &ok, Qt::WindowFlags() | Qt::MSWindowsFixedSizeDialogHint);
                if (ok) {
                    const auto lname = toLower(utilqt::fromQString(name));

                    LogInfoCustom("ToolMenu", "Creating regression test " << lname);
                    if (auto module = app->getModuleByIdentifier(modulename)) {
                        const auto regressiondir = module->getPath(ModulePath::RegressionTests);
                        const auto testdir = regressiondir + "/" + lname;
                        if (filesystem::directoryExists(testdir)) {
                            LogErrorCustom(
                                "ToolMenu",
                                "Dir: \"" << testdir << "\" already exits. use a different name");
                            return;
                        }
                        filesystem::createDirectoryRecursively(testdir);

                        const auto workspacename = testdir + "/" + lname + ".inv";
                        LogInfoCustom("ToolMenu",
                                      "Saving regression workspace to: " << workspacename);
                        util::saveNetwork(app->getProcessorNetwork(), workspacename);
                        util::saveAllCanvases(app->getProcessorNetwork(), testdir);
                    }
                }
            });
    }
}

}  // namespace

ToolsMenu::ToolsMenu(InviwoMainWindow *win) : QMenu(tr("&Tools"), win) {
    auto docsMenu = addMenu("Create &Processors Docs");
    connect(docsMenu, &QMenu::aboutToShow, [docsMenu, win]() {
        docsMenu->clear();
        createProcessorDocMenu(win->getInviwoApplication(), docsMenu);
    });

    auto regressionMenu = addMenu("Create &Regression Test");
    connect(regressionMenu, &QMenu::aboutToShow, [regressionMenu, win]() {
        regressionMenu->clear();
        createRegressionActions(win, win->getInviwoApplication(), regressionMenu);
    });

#ifdef IVW_INVIWO_META
    auto sourceMenu = addMenu("Create &Sources");
    addInviwoMetaAction(sourceMenu);
#endif
}

}  // namespace inviwo
<commit_msg>Qt: doc generation fix (tools menu) * now lists all processor properties (instead of only first level)<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2018 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <inviwo/qt/editor/toolsmenu.h>
#include <inviwo/qt/editor/inviwomainwindow.h>
#include <inviwo/core/common/inviwoapplication.h>
#include <inviwo/core/common/inviwomodule.h>
#include <inviwo/core/common/inviwomodulefactoryobject.h>
#include <inviwo/core/util/stdextensions.h>
#include <inviwo/core/util/filesystem.h>
#include <inviwo/core/util/utilities.h>
#include <inviwo/core/ports/inport.h>
#include <inviwo/core/ports/outport.h>
#include <inviwo/core/properties/property.h>
#include <inviwo/core/processors/processor.h>
#include <inviwo/core/processors/processorfactory.h>
#include <inviwo/core/network/processornetwork.h>

#include <modules/qtwidgets/inviwoqtutils.h>

#ifdef IVW_INVIWO_META
#include <inviwo/qt/editor/toolsmetamenu.h>
#endif

#include <warn/push>
#include <warn/ignore/all>
#include <QMenu>
#include <QMenuBar>
#include <QAction>
#include <QInputDialog>
#include <QClipboard>
#include <QFile>
#include <QApplication>

#include <iostream>
#include <algorithm>
#include <warn/pop>

namespace inviwo {

namespace {

void createProcessorDocMenu(InviwoApplication *app, QMenu *docsMenu) {
    auto factory = app->getProcessorFactory();

    for (auto &m : app->getModules()) {
        auto &processors = m->getProcessors();
        if (processors.empty()) continue;

        auto modMenu = docsMenu->addMenu(utilqt::toQString(m->getIdentifier()));
        for (auto &pfo : processors) {
            auto action = modMenu->addAction(utilqt::toQString(pfo->getDisplayName()));
            docsMenu->connect(action, &QAction::triggered, [pfo, factory]() {
                const auto processor = factory->create(pfo->getClassIdentifier());
                const auto &inports = processor->getInports();
                const auto &outports = processor->getOutports();
                const auto &properties = processor->getPropertiesRecursive();
                const auto classID = processor->getClassIdentifier();
                const auto &dispName = processor->getDisplayName();

                std::ostringstream oss;
                oss << "/** \\docpage{" << classID << ", " << dispName << "}" << std::endl;
                oss << "* ![](" << classID << ".png?classIdentifier=" << classID << ")"
                    << std::endl;
                oss << "* " << std::endl;
                oss << "* Description of the processor" << std::endl;
                oss << "* " << std::endl;
                oss << "* " << std::endl;
                if (!inports.empty()) {
                    oss << "* ### Inports" << std::endl;
                    for (const auto &port : inports) {
                        oss << "*   * __" << port->getIdentifier() << "__ Describe port.\n";
                    }
                    oss << "* \n";
                }

                if (!outports.empty()) {
                    oss << "* ### Outports" << std::endl;
                    for (const auto &port : outports) {
                        oss << "*   * __" << port->getIdentifier() << "__ Describe port.\n";
                    }
                    oss << "* \n";
                }

                if (!properties.empty()) {
                    oss << "* ### Properties" << std::endl;
                    for (const auto &prop : properties) {
                        oss << "*   * __" << prop->getDisplayName() << "__ Describe property.\n";
                    }
                    oss << "* \n";
                }
                oss << "*/\n";

                QApplication::clipboard()->setText(utilqt::toQString(oss.str()));
                LogInfoCustom("ToolMenu", "DOXYGEN Template code for processor "
                                              << dispName << " copied to clipboard");
                LogInfoCustom("ToolMenu", oss.str());
            });
        }
    }
}

void createRegressionActions(QWidget *parent, InviwoApplication *app, QMenu *menu) {
    for (const auto &module : app->getModules()) {
        auto action = menu->addAction(utilqt::toQString(module->getIdentifier()));

        QObject::connect(
            action, &QAction::triggered, [modulename = module->getIdentifier(), parent, app]() {
                bool ok;
                const auto name = QInputDialog::getText(
                    parent, "Create Regression Test", "Regression test name", QLineEdit::Normal, "",
                    &ok, Qt::WindowFlags() | Qt::MSWindowsFixedSizeDialogHint);
                if (ok) {
                    const auto lname = toLower(utilqt::fromQString(name));

                    LogInfoCustom("ToolMenu", "Creating regression test " << lname);
                    if (auto module = app->getModuleByIdentifier(modulename)) {
                        const auto regressiondir = module->getPath(ModulePath::RegressionTests);
                        const auto testdir = regressiondir + "/" + lname;
                        if (filesystem::directoryExists(testdir)) {
                            LogErrorCustom(
                                "ToolMenu",
                                "Dir: \"" << testdir << "\" already exits. use a different name");
                            return;
                        }
                        filesystem::createDirectoryRecursively(testdir);

                        const auto workspacename = testdir + "/" + lname + ".inv";
                        LogInfoCustom("ToolMenu",
                                      "Saving regression workspace to: " << workspacename);
                        util::saveNetwork(app->getProcessorNetwork(), workspacename);
                        util::saveAllCanvases(app->getProcessorNetwork(), testdir);
                    }
                }
            });
    }
}

}  // namespace

ToolsMenu::ToolsMenu(InviwoMainWindow *win) : QMenu(tr("&Tools"), win) {
    auto docsMenu = addMenu("Create &Processors Docs");
    connect(docsMenu, &QMenu::aboutToShow, [docsMenu, win]() {
        docsMenu->clear();
        createProcessorDocMenu(win->getInviwoApplication(), docsMenu);
    });

    auto regressionMenu = addMenu("Create &Regression Test");
    connect(regressionMenu, &QMenu::aboutToShow, [regressionMenu, win]() {
        regressionMenu->clear();
        createRegressionActions(win, win->getInviwoApplication(), regressionMenu);
    });

#ifdef IVW_INVIWO_META
    auto sourceMenu = addMenu("Create &Sources");
    addInviwoMetaAction(sourceMenu);
#endif
}

}  // namespace inviwo
<|endoftext|>


<commit_before>#include "Engine.h"

#include "properties/SEScalarTime.h"
#include "properties/SEScalarForce.h"
#include "properties/SEScalarPressure.h"
#include "patient/actions/SEChestCompressionForce.h"
#include "system/physiology/SECardiovascularSystem.h"
#include "system/physiology/SEBloodChemistrySystem.h"
#include "system/physiology/SERespiratorySystem.h"
#include "patient/actions/SEAirwayObstruction.h"
#include "properties/SEScalarFraction.h"
#include "properties/SEScalarFrequency.h"
#include "properties/SEScalarMassPerVolume.h"
#include "properties/SEScalarPressure.h"
#include "properties/SEScalarTemperature.h"
#include "properties/SEScalarTime.h"
#include "properties/SEScalarVolume.h"
#include "properties/SEScalarVolumePerTime.h"
#include "properties/SEFunctionTimeVsVolume.h"
#include "engine/PhysiologyEngineTrack.h"
#include "scenario/SEPhysiologySystemDataRequest.h"
#include <chrono>
#include <thread>
#include <cstring>
#include "substance/SESubstanceManager.h"
#include "patient/actions/SESubstanceBolus.h"
#include "system/equipment/Anesthesia/SEAnesthesiaMachine.h"
#include "system/equipment/Anesthesia/SEAnesthesiaMachineOxygenBottle.h"
#include "system/equipment/Anesthesia/actions/SEAnesthesiaMachineConfiguration.h"

Engine::Engine(Driver * pDriver)
{
    m_pDriver = pDriver;
}
void Engine::Initialize()
{
    m_engine = CreateBioGearsEngine("CPR.log");
    if (!m_engine->InitializeEngine("Standard.xml"))
    {
        std::cerr << "Unable to initialize engine\n";
    }

    m_dt = m_engine->GetTimeStep(SEScalarTime::s) * 1000.0;
    m_pAnesthesiaMachineConfig = new SEAnesthesiaMachineConfiguration(m_engine->GetSubstanceManager());

    SEAnesthesiaMachine& config = m_pAnesthesiaMachineConfig->GetConfiguration();
    config.SetState(CDM::enumOnOff::Off); //changed it to Off at the beginning
    config.GetInletFlow().SetValue(2.0, SEScalarVolumePerTime::L_Per_min);
    config.GetInspiratoryExpiratoryRatio().SetValue(.5);
    config.GetOxygenFraction().SetValue(0.21); //0.21 in the air
    config.SetOxygenSource(CDM::enumAnesthesiaMachineOxygenSource::Wall);
    config.GetPositiveEndExpiredPressure().SetValue(0.0, SEScalarPressure::cmH2O);
    config.SetPrimaryGas(CDM::enumAnesthesiaMachinePrimaryGas::Nitrogen);
    config.GetReliefValvePressure().SetValue(20.0, SEScalarPressure::cmH2O);
    config.GetRespiratoryRate().SetValue(12, SEScalarFrequency::Per_min);
    config.GetVentilatorPressure().SetValue(0.0, SEScalarPressure::cmH2O);
    config.SetVentilatorMask(CDM::enumOnOff::On);
    config.GetOxygenBottleOne().GetVolume().SetValue(660.0, SEScalarVolume::L);
    config.GetOxygenBottleTwo().GetVolume().SetValue(660.0, SEScalarVolume::L);
}

crow::json::wvalue Engine::GetPatientStatus() {
    crow::json::wvalue status;
    /* heartrate      |66.03         |double value round to two decimal places
     * resprate       |75.48         |double value round to two decimal places
     * systolicbp     |37.99         |double value round to two decimal places
     * diastolicbp    |120.91        |double value round to two decimal places
     * oxygen         |93.60         |double value round to two decimal places
     */
    status["heart_rate"] = m_engine->GetCardiovascularSystem()->GetHeartRate(SEScalarFrequency::Per_min);
    status["oxygen_saturation"] = m_engine->GetBloodChemistrySystem()->GetOxygenSaturation();
    status["systolic_arterial_pressure"] = m_engine->GetCardiovascularSystem()->GetSystolicArterialPressure(SEScalarPressure::mmHg);
    status["diastolic_arterialPressure"] = m_engine->GetCardiovascularSystem()->GetDiastolicArterialPressure(SEScalarPressure::mmHg);
    status["respiration_rate"] = m_engine->GetRespiratorySystem()->GetRespirationRate(SEScalarFrequency::Per_min);
    status["hash"] = "abcdefg";

    return status;
}

void Engine::operator()()
{
    using Clock = std::chrono::high_resolution_clock;

    curl_global_init(CURL_GLOBAL_ALL);

    double timeElapsed = 0.0;
    int failureCount = 0; //if it fails to connect for five times, the program is terminated.
    while (Running())
    {
        Clock::time_point start = Clock::now();
        {

            std::lock_guard<std::mutex> lock(m_pressureMutex);

        }
        if (timeElapsed > 500.0) {
            timeElapsed = 0;
            /* Now specify the POST data */
            crow::json::wvalue status;
            status["heart_rate"] = m_engine->GetCardiovascularSystem()->GetHeartRate(SEScalarFrequency::Per_min);
            status["oxygen_saturation"] = m_engine->GetBloodChemistrySystem()->GetOxygenSaturation();
            status["systolic_arterial_pressure"] = m_engine->GetCardiovascularSystem()->GetSystolicArterialPressure(SEScalarPressure::mmHg);
            status["diastolic_arterialPressure"] = m_engine->GetCardiovascularSystem()->GetDiastolicArterialPressure(SEScalarPressure::mmHg);
            status["respiration_rate"] = m_engine->GetRespiratorySystem()->GetRespirationRate(SEScalarFrequency::Per_min);
            status["hash"] = "abcdefg";
            /* get a curl handle */
            CURL * curl = curl_easy_init();

            if (curl) {
                curl_easy_setopt(curl, CURLOPT_URL, "http://localhost:6666/update");
                char* result=strdup(crow::json::dump(status).c_str());
                curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(result));
                curl_easy_setopt(curl, CURLOPT_POSTFIELDS, result);
                CURLcode res = curl_easy_perform(curl);
                if(res != CURLE_OK) {
                    fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
                    failureCount++;
                    if (failureCount > 4) exit(1);
                } else {
                    failureCount = 0;
                }

                curl_easy_cleanup(curl);
                free(result);
            }
        }

        m_engine->AdvanceModelTime();

        Clock::time_point stop = Clock::now();

        double executionTime = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start).count();
        if (executionTime < m_dt)
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<long int>(m_dt - executionTime)));
        }
        timeElapsed += m_dt;
    }
}
void Engine::BolusDrug(std::string drugName, double concentration, double dose)
{

    // std::lock_guard<std::mutex> lock(m_pressureMutex);
    const SESubstance* succs = m_engine->GetSubstanceManager().GetSubstance(drugName);

    // Create a substance bolus action to administer the substance
    SESubstanceBolus bolus(*succs);
    bolus.GetConcentration().SetValue(concentration,SEScalarMassPerVolume::ug_Per_mL);
    bolus.GetDose().SetValue(dose,SEScalarVolume::mL);
    bolus.SetAdminRoute(CDM::enumSubstanceAdministration::Intravenous);
    m_engine->ProcessAction(bolus);
    std::cout << "Giving the patient .\n\n" << drugName << " with "
    << dose << " dosage and " << concentration << " concentration" <<endl;
}

void Engine::AnesthesiaMachine(double oxygenFraction, bool status){
    // You can set configuration by modifing the configuration class directly
    // Or you can point to an XML with configuration data.
    // Modifying the class will keep any old settings that are not provided in the config
    // Using a xml will set the anesthesia machine to only the property states specified in the file
    SEAnesthesiaMachine& config = m_pAnesthesiaMachineConfig->GetConfiguration();

    if (status == true) {
        config.GetOxygenFraction().SetValue(oxygenFraction);
        config.SetState(CDM::enumOnOff::On);
        std::cout << "Turning on the Anesthesia Machine and placing mask on patient for spontaneous breathing with machine connection.\n\n";
    } else {
        config.SetState(CDM::enumOnOff::Off);
        std::cout << "Turning off the Anesthesia Machine and removing the mask.\n\n";
    }

    m_engine->ProcessAction(*m_pAnesthesiaMachineConfig);

}
void Engine::SetPressure(double pressure)
{
    std::lock_guard<std::mutex> lock(m_pressureMutex);

    m_pressure = pressure;
    std::cout<<"set the pressure"<<std::endl;
    m_newPressure = true;
}
<commit_msg>change update url<commit_after>#include "Engine.h"

#include "properties/SEScalarTime.h"
#include "properties/SEScalarForce.h"
#include "properties/SEScalarPressure.h"
#include "patient/actions/SEChestCompressionForce.h"
#include "system/physiology/SECardiovascularSystem.h"
#include "system/physiology/SEBloodChemistrySystem.h"
#include "system/physiology/SERespiratorySystem.h"
#include "patient/actions/SEAirwayObstruction.h"
#include "properties/SEScalarFraction.h"
#include "properties/SEScalarFrequency.h"
#include "properties/SEScalarMassPerVolume.h"
#include "properties/SEScalarPressure.h"
#include "properties/SEScalarTemperature.h"
#include "properties/SEScalarTime.h"
#include "properties/SEScalarVolume.h"
#include "properties/SEScalarVolumePerTime.h"
#include "properties/SEFunctionTimeVsVolume.h"
#include "engine/PhysiologyEngineTrack.h"
#include "scenario/SEPhysiologySystemDataRequest.h"
#include <chrono>
#include <thread>
#include <cstring>
#include "substance/SESubstanceManager.h"
#include "patient/actions/SESubstanceBolus.h"
#include "system/equipment/Anesthesia/SEAnesthesiaMachine.h"
#include "system/equipment/Anesthesia/SEAnesthesiaMachineOxygenBottle.h"
#include "system/equipment/Anesthesia/actions/SEAnesthesiaMachineConfiguration.h"

Engine::Engine(Driver * pDriver)
{
    m_pDriver = pDriver;
}
void Engine::Initialize()
{
    m_engine = CreateBioGearsEngine("CPR.log");
    if (!m_engine->InitializeEngine("Standard.xml"))
    {
        std::cerr << "Unable to initialize engine\n";
    }

    m_dt = m_engine->GetTimeStep(SEScalarTime::s) * 1000.0;
    m_pAnesthesiaMachineConfig = new SEAnesthesiaMachineConfiguration(m_engine->GetSubstanceManager());

    SEAnesthesiaMachine& config = m_pAnesthesiaMachineConfig->GetConfiguration();
    config.SetState(CDM::enumOnOff::Off); //changed it to Off at the beginning
    config.GetInletFlow().SetValue(2.0, SEScalarVolumePerTime::L_Per_min);
    config.GetInspiratoryExpiratoryRatio().SetValue(.5);
    config.GetOxygenFraction().SetValue(0.21); //0.21 in the air
    config.SetOxygenSource(CDM::enumAnesthesiaMachineOxygenSource::Wall);
    config.GetPositiveEndExpiredPressure().SetValue(0.0, SEScalarPressure::cmH2O);
    config.SetPrimaryGas(CDM::enumAnesthesiaMachinePrimaryGas::Nitrogen);
    config.GetReliefValvePressure().SetValue(20.0, SEScalarPressure::cmH2O);
    config.GetRespiratoryRate().SetValue(12, SEScalarFrequency::Per_min);
    config.GetVentilatorPressure().SetValue(0.0, SEScalarPressure::cmH2O);
    config.SetVentilatorMask(CDM::enumOnOff::On);
    config.GetOxygenBottleOne().GetVolume().SetValue(660.0, SEScalarVolume::L);
    config.GetOxygenBottleTwo().GetVolume().SetValue(660.0, SEScalarVolume::L);
}

crow::json::wvalue Engine::GetPatientStatus() {
    crow::json::wvalue status;
    /* heartrate      |66.03         |double value round to two decimal places
     * resprate       |75.48         |double value round to two decimal places
     * systolicbp     |37.99         |double value round to two decimal places
     * diastolicbp    |120.91        |double value round to two decimal places
     * oxygen         |93.60         |double value round to two decimal places
     */
    status["heart_rate"] = m_engine->GetCardiovascularSystem()->GetHeartRate(SEScalarFrequency::Per_min);
    status["oxygen_saturation"] = m_engine->GetBloodChemistrySystem()->GetOxygenSaturation();
    status["systolic_arterial_pressure"] = m_engine->GetCardiovascularSystem()->GetSystolicArterialPressure(SEScalarPressure::mmHg);
    status["diastolic_arterialPressure"] = m_engine->GetCardiovascularSystem()->GetDiastolicArterialPressure(SEScalarPressure::mmHg);
    status["respiration_rate"] = m_engine->GetRespiratorySystem()->GetRespirationRate(SEScalarFrequency::Per_min);
    status["hash"] = "abcdefg";

    return status;
}

void Engine::operator()()
{
    using Clock = std::chrono::high_resolution_clock;

    curl_global_init(CURL_GLOBAL_ALL);

    double timeElapsed = 0.0;
    int failureCount = 0; //if it fails to connect for five times, the program is terminated.
    while (Running())
    {
        Clock::time_point start = Clock::now();
        {

            std::lock_guard<std::mutex> lock(m_pressureMutex);

        }
        if (timeElapsed > 500.0) {
            timeElapsed = 0;
            /* Now specify the POST data */
            crow::json::wvalue status;
            status["heart_rate"] = m_engine->GetCardiovascularSystem()->GetHeartRate(SEScalarFrequency::Per_min);
            status["oxygen_saturation"] = m_engine->GetBloodChemistrySystem()->GetOxygenSaturation();
            status["systolic_arterial_pressure"] = m_engine->GetCardiovascularSystem()->GetSystolicArterialPressure(SEScalarPressure::mmHg);
            status["diastolic_arterialPressure"] = m_engine->GetCardiovascularSystem()->GetDiastolicArterialPressure(SEScalarPressure::mmHg);
            status["respiration_rate"] = m_engine->GetRespiratorySystem()->GetRespirationRate(SEScalarFrequency::Per_min);
            status["hash"] = "abcdefg";
            /* get a curl handle */
            CURL * curl = curl_easy_init();

            if (curl) {
                curl_easy_setopt(curl, CURLOPT_URL, "http://localhost:6666/biogears/update");
                char* result=strdup(crow::json::dump(status).c_str());
                curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(result));
                curl_easy_setopt(curl, CURLOPT_POSTFIELDS, result);
                CURLcode res = curl_easy_perform(curl);
                if(res != CURLE_OK) {
                    fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
                    failureCount++;
                    if (failureCount > 4) exit(1);
                } else {
                    failureCount = 0;
                }

                curl_easy_cleanup(curl);
                free(result);
            }
        }

        m_engine->AdvanceModelTime();

        Clock::time_point stop = Clock::now();

        double executionTime = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start).count();
        if (executionTime < m_dt)
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<long int>(m_dt - executionTime)));
        }
        timeElapsed += m_dt;
    }
}
void Engine::BolusDrug(std::string drugName, double concentration, double dose)
{

    // std::lock_guard<std::mutex> lock(m_pressureMutex);
    const SESubstance* succs = m_engine->GetSubstanceManager().GetSubstance(drugName);

    // Create a substance bolus action to administer the substance
    SESubstanceBolus bolus(*succs);
    bolus.GetConcentration().SetValue(concentration,SEScalarMassPerVolume::ug_Per_mL);
    bolus.GetDose().SetValue(dose,SEScalarVolume::mL);
    bolus.SetAdminRoute(CDM::enumSubstanceAdministration::Intravenous);
    m_engine->ProcessAction(bolus);
    std::cout << "Giving the patient .\n\n" << drugName << " with "
    << dose << " dosage and " << concentration << " concentration" <<endl;
}

void Engine::AnesthesiaMachine(double oxygenFraction, bool status){
    // You can set configuration by modifing the configuration class directly
    // Or you can point to an XML with configuration data.
    // Modifying the class will keep any old settings that are not provided in the config
    // Using a xml will set the anesthesia machine to only the property states specified in the file
    SEAnesthesiaMachine& config = m_pAnesthesiaMachineConfig->GetConfiguration();

    if (status == true) {
        config.GetOxygenFraction().SetValue(oxygenFraction);
        config.SetState(CDM::enumOnOff::On);
        std::cout << "Turning on the Anesthesia Machine and placing mask on patient for spontaneous breathing with machine connection.\n\n";
    } else {
        config.SetState(CDM::enumOnOff::Off);
        std::cout << "Turning off the Anesthesia Machine and removing the mask.\n\n";
    }

    m_engine->ProcessAction(*m_pAnesthesiaMachineConfig);

}
void Engine::SetPressure(double pressure)
{
    std::lock_guard<std::mutex> lock(m_pressureMutex);

    m_pressure = pressure;
    std::cout<<"set the pressure"<<std::endl;
    m_newPressure = true;
}

<|endoftext|>


<commit_before>#pragma once
/**
	@file
	@brief format string

	Copyright (C) 2011 Cybozu Labs, Inc., all rights reserved.
*/
#include <string>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <cybozu/exception.hpp>

#if defined(__clang__) || (defined(__GNUC_PREREQ) && __GNUC_PREREQ(4, 4))
#define CYBOZU_FORMAT_DISABLE_WARNING
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#endif

namespace cybozu {

inline void vformat(std::string& str, const char *format, va_list args)
{
#ifdef _MSC_VER
	_locale_t curLoc = _get_current_locale();
	int size = _vscprintf_l(format, curLoc, args);
	if (size < 0 || size >= INT_MAX) throw cybozu::Exception("vformat:_vscprintf_l");

	str.resize(size + 1);

	int ret = _vsprintf_s_l(&str[0], size + 1, format, curLoc, args);
	if (ret < 0) throw cybozu::Exception("vformat:_vsprintf_s_l");
	str.resize(size);
#else
#if 1
	char *p;
	int ret = vasprintf(&p, format, args);
	if (ret < 0) throw cybozu::Exception("vformat:vasnprintf");
	try {
		str.assign(p, ret);
		free(p);
	} catch (...) {
		free(p);
		throw std::bad_alloc();
	}
#else
	// slow
	va_list keep;
	va_copy(keep, args);
	int len = vsnprintf(0, 0, format, args); // len excludes the null byte
	if (len < 0) throw cybozu::Exception("vformat:vasnprintf err1");
	str.resize(len + 1);
	len = vsnprintf(&str[0], str.size(), format, keep); // len incluedes the null byte
	if (len < 0) throw cybozu::Exception("vformat:vasnprintf err2");
	str.resize(len);
#endif
#endif
}

#ifdef _MSC_VER
	#define CYBOZU_FORMAT_PRINTF _Printf_format_string_
#else
	#define CYBOZU_FORMAT_PRINTF
#endif

#ifdef __GNUC__
__attribute__((format(printf, 2, 3)))
#endif
inline void format(std::string& str, CYBOZU_FORMAT_PRINTF const char *format, ...)
{
	va_list args;
	va_start(args, format);
	cybozu::vformat(str, format, args);
	va_end(args);
}

#ifdef __GNUC__
__attribute__((format(printf, 1, 2)))
#endif
inline std::string format(CYBOZU_FORMAT_PRINTF const char *format, ...)
{
	std::string str;
	va_list args;
	va_start(args, format);
	cybozu::vformat(str, format, args);
	va_end(args);
	return str;
}

} // cybozu

#ifdef CYBOZU_FORMAT_DISABLE_WARNING
#pragma GCC diagnostic push
#endif
<commit_msg>fix macro error if __GNUC_PREREQ is not defined<commit_after>#pragma once
/**
	@file
	@brief format string

	Copyright (C) 2011 Cybozu Labs, Inc., all rights reserved.
*/
#include <string>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <cybozu/exception.hpp>

#if defined(__clang__) || (defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 4)
#define CYBOZU_FORMAT_DISABLE_WARNING
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#endif

namespace cybozu {

inline void vformat(std::string& str, const char *format, va_list args)
{
#ifdef _MSC_VER
	_locale_t curLoc = _get_current_locale();
	int size = _vscprintf_l(format, curLoc, args);
	if (size < 0 || size >= INT_MAX) throw cybozu::Exception("vformat:_vscprintf_l");

	str.resize(size + 1);

	int ret = _vsprintf_s_l(&str[0], size + 1, format, curLoc, args);
	if (ret < 0) throw cybozu::Exception("vformat:_vsprintf_s_l");
	str.resize(size);
#else
#if 1
	char *p;
	int ret = vasprintf(&p, format, args);
	if (ret < 0) throw cybozu::Exception("vformat:vasnprintf");
	try {
		str.assign(p, ret);
		free(p);
	} catch (...) {
		free(p);
		throw std::bad_alloc();
	}
#else
	// slow
	va_list keep;
	va_copy(keep, args);
	int len = vsnprintf(0, 0, format, args); // len excludes the null byte
	if (len < 0) throw cybozu::Exception("vformat:vasnprintf err1");
	str.resize(len + 1);
	len = vsnprintf(&str[0], str.size(), format, keep); // len incluedes the null byte
	if (len < 0) throw cybozu::Exception("vformat:vasnprintf err2");
	str.resize(len);
#endif
#endif
}

#ifdef _MSC_VER
	#define CYBOZU_FORMAT_PRINTF _Printf_format_string_
#else
	#define CYBOZU_FORMAT_PRINTF
#endif

#ifdef __GNUC__
__attribute__((format(printf, 2, 3)))
#endif
inline void format(std::string& str, CYBOZU_FORMAT_PRINTF const char *format, ...)
{
	va_list args;
	va_start(args, format);
	cybozu::vformat(str, format, args);
	va_end(args);
}

#ifdef __GNUC__
__attribute__((format(printf, 1, 2)))
#endif
inline std::string format(CYBOZU_FORMAT_PRINTF const char *format, ...)
{
	std::string str;
	va_list args;
	va_start(args, format);
	cybozu::vformat(str, format, args);
	va_end(args);
	return str;
}

} // cybozu

#ifdef CYBOZU_FORMAT_DISABLE_WARNING
#pragma GCC diagnostic push
#endif
<|endoftext|>


<commit_before>void MakeTPCRecoParam(AliRecoParam::EventSpecie_t default=AliRecoParam::kLowMult) {
//========================================================================
//
// Steering macro for TPC reconstruction parameters
//
// Author: M.Ivanov
// Contact: marian.ivanov@cern.ch
//
//========================================================================

  const char* macroname = "MakeTPCRecoParam.C";

  // Activate CDB storage and load geometry from CDB
  AliCDBManager* cdb = AliCDBManager::Instance();
  if(!cdb->IsDefaultStorageSet()) cdb->SetDefaultStorage("local://OCDB");
  //
  //
  TObjArray *recoParamArray = new TObjArray();
  {
    AliTPCRecoParam * tpcRecoParam = AliTPCRecoParam::GetLowFluxParam();
    tpcRecoParam->SetEventSpecie(AliRecoParam::kLowMult);
    recoParamArray->AddLast(tpcRecoParam);
  }
  {
    AliTPCRecoParam * tpcRecoParam = AliTPCRecoParam::GetHighFluxParam();
    tpcRecoParam->SetEventSpecie(AliRecoParam::kHighMult);
    recoParamArray->AddLast(tpcRecoParam);
  }

  {
    AliTPCRecoParam * tpcRecoParam = AliTPCRecoParam::GetLaserTestParam(kFALSE);
    tpcRecoParam->SetEventSpecie(AliRecoParam::kCalib);
    recoParamArray->AddLast(tpcRecoParam);
  }

  {
    AliTPCRecoParam * tpcRecoParam = AliTPCRecoParam::GetCosmicTestParam(kFALSE);
    tpcRecoParam->SetEventSpecie(AliRecoParam::kCosmic);
    recoParamArray->AddLast(tpcRecoParam);
  }

  // Set the default
  Bool_t defaultIsSet = kFALSE;
  for(Int_t i =0; i < recoParamArray->GetEntriesFast(); i++) {
    AliDetectorRecoParam *param = (AliDetectorRecoParam *)recoParamArray->UncheckedAt(i);
    if (!param) continue;
    if (default & param->GetEventSpecie()) {
      param->SetAsDefault();
      defaultIsSet = kTRUE;
    }
  }

  if (!defaultIsSet) {
    Error(macroname,"The default reconstruction parameters are not set! Exiting...");
    return;
  }

  // save in CDB storage
  AliCDBMetaData *md= new AliCDBMetaData();
  md->SetResponsible("Marian Ivanov");
  md->SetComment("Reconstruction parameters TPC");
  md->SetAliRootVersion(gSystem->Getenv("ARVERSION"));
  md->SetBeamPeriod(0);
  AliCDBId id("TPC/Calib/RecoParam",0,AliCDBRunRange::Infinity());
  cdb->GetDefaultStorage()->Put(recoParamArray,id, md);
  return;
}

<commit_msg>1. Adding very small systematic error     Double_t sysError[5]={0.01,0.02, 0.01/150., 0.02/150.,0.01/(150*150.)};<commit_after>void MakeTPCRecoParam(AliRecoParam::EventSpecie_t default=AliRecoParam::kLowMult) {
//========================================================================
//
// Steering macro for TPC reconstruction parameters
//
// Author: M.Ivanov
// Contact: marian.ivanov@cern.ch
//
//========================================================================

  const char* macroname = "MakeTPCRecoParam.C";

  // Activate CDB storage and load geometry from CDB
  AliCDBManager* cdb = AliCDBManager::Instance();
  if(!cdb->IsDefaultStorageSet()) cdb->SetDefaultStorage("local://OCDB");
  //
  //
  TObjArray *recoParamArray = new TObjArray();
  {
    AliTPCRecoParam * tpcRecoParam = AliTPCRecoParam::GetLowFluxParam();
    Double_t sysError[5]={0.01,0.02, 0.01/150., 0.02/150.,0.01/(150*150.)};
    tpcRecoParam->SetSystematicError(sysError);
    tpcRecoParam->SetEventSpecie(AliRecoParam::kLowMult);
    tpcRecoParam->SetMinMaxCutAbs(2.5);
    tpcRecoParam->SetMinLeftRightCutAbs(5.);
    tpcRecoParam->SetMinUpDownCutAbs(5.);
    //
    tpcRecoParam->SetMinMaxCutSigma(2.5);
    tpcRecoParam->SetMinLeftRightCutSigma(5.);
    tpcRecoParam->SetMinUpDownCutSigma(5.);

    recoParamArray->AddLast(tpcRecoParam);
  }
  {
    AliTPCRecoParam * tpcRecoParam = AliTPCRecoParam::GetHighFluxParam();
    tpcRecoParam->SetEventSpecie(AliRecoParam::kHighMult);
    Double_t sysError[5]={0.01,0.02, 0.01/150., 0.02/150.,0.01/(150*150.)};
    tpcRecoParam->SetSystematicError(sysError);
    recoParamArray->AddLast(tpcRecoParam);
  }

  {
    AliTPCRecoParam * tpcRecoParam = AliTPCRecoParam::GetLaserTestParam(kFALSE);
    tpcRecoParam->SetEventSpecie(AliRecoParam::kCalib);
    recoParamArray->AddLast(tpcRecoParam);
  }

  {
    AliTPCRecoParam * tpcRecoParam = AliTPCRecoParam::GetCosmicTestParam(kFALSE);
    tpcRecoParam->SetEventSpecie(AliRecoParam::kCosmic);
    tpcRecoParam->SetTimeInterval(60,940);
    Double_t sysError[5]={0.3,1, 0.3/150., 1./150.,0.3/(150*150.)};
    tpcRecoParam->SetSystematicError(sysError);
    //
    tpcRecoParam->SetMinMaxCutAbs(2.5);
    tpcRecoParam->SetMinLeftRightCutAbs(5.);
    tpcRecoParam->SetMinUpDownCutAbs(5.);
    //
    tpcRecoParam->SetMinMaxCutSigma(2.5);
    tpcRecoParam->SetMinLeftRightCutSigma(5.);
    tpcRecoParam->SetMinUpDownCutSigma(5.);
    recoParamArray->AddLast(tpcRecoParam);
  }

  // Set the default
  Bool_t defaultIsSet = kFALSE;
  for(Int_t i =0; i < recoParamArray->GetEntriesFast(); i++) {
    AliDetectorRecoParam *param = (AliDetectorRecoParam *)recoParamArray->UncheckedAt(i);
    if (!param) continue;
    if (default & param->GetEventSpecie()) {
      param->SetAsDefault();
      defaultIsSet = kTRUE;
    }
  }

  if (!defaultIsSet) {
    Error(macroname,"The default reconstruction parameters are not set! Exiting...");
    return;
  }

  // save in CDB storage
  AliCDBMetaData *md= new AliCDBMetaData();
  md->SetResponsible("Marian Ivanov");
  md->SetComment("Reconstruction parameters TPC");
  md->SetAliRootVersion(gSystem->Getenv("ARVERSION"));
  md->SetBeamPeriod(0);
  AliCDBId id("TPC/Calib/RecoParam",0,AliCDBRunRange::Infinity());
  cdb->GetDefaultStorage()->Put(recoParamArray,id, md);
  return;
}

<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef ETL_FAST_EXPR_HPP
#define ETL_FAST_EXPR_HPP

#include "fast_op.hpp"
#include "tmp.hpp"

namespace etl {

template<typename LE, typename RE, typename Enable = void>
struct get_etl_size ;

template<typename LE, typename RE>
struct get_etl_size<LE, RE, enable_if_t<is_etl_expr<LE>::value>>
    : std::integral_constant<std::size_t, std::remove_reference<LE>::type::etl_size> {} ;

template<typename LE, typename RE>
struct get_etl_size<LE, RE, enable_if_t<and_u<is_etl_expr<RE>::value, not_u<is_etl_expr<LE>::value>::value>::value>>
    : std::integral_constant<std::size_t, std::remove_reference<RE>::type::etl_size> {};

template <typename T, typename LeftExpr, typename BinaryOp, typename RightExpr>
class binary_expr {
private:
    static_assert(or_u<is_etl_expr<LeftExpr>::value, is_etl_expr<RightExpr>::value>::value, "At least one of the binary expressions arguments must be an ETL expr");

    LeftExpr _lhs;
    RightExpr _rhs;

    typedef binary_expr<T, LeftExpr, BinaryOp, RightExpr> this_type;

public:
    static constexpr const bool etl_marker = true;
    static constexpr const bool etl_fast = true;
    static constexpr const std::size_t etl_size = get_etl_size<LeftExpr, RightExpr>::value;

    using value_type = T;

    //Cannot be constructed with no args
    binary_expr() = delete;

    //Construct a new expression
    binary_expr(LeftExpr l, RightExpr r) :
            _lhs(std::forward<LeftExpr>(l)), _rhs(std::forward<RightExpr>(r)){
        //Nothing else to init
    }

    //No copying
    binary_expr(const binary_expr&) = delete;
    binary_expr& operator=(const binary_expr&) = delete;

    //No moving
    binary_expr(binary_expr&&) = delete;
    binary_expr& operator=(binary_expr&&) = delete;

    //Accessors

    //TODO size() can be constexpr if Expr is fast_X

    template<typename LE = LeftExpr, enable_if_u<is_etl_expr<LE>::value> = detail::dummy>
    std::size_t size() const {
        return _lhs.size();
    }

    template<typename LE = LeftExpr, disable_if_u<is_etl_expr<LE>::value> = detail::dummy>
    std::size_t size() const {
        return _rhs.size();
    }

    typename std::add_lvalue_reference<LeftExpr>::type lhs(){
        return _lhs;
    }

    typename std::add_lvalue_reference<typename std::add_const<LeftExpr>::type>::type lhs() const {
        return _lhs;
    }

    typename std::add_lvalue_reference<RightExpr>::type rhs(){
        return _rhs;
    }

    typename std::add_lvalue_reference<typename std::add_const<RightExpr>::type>::type rhs() const {
        return _rhs;
    }

    //Apply the expression

    decltype(auto) operator[](std::size_t i) const {
        return BinaryOp::apply(lhs()[i], rhs()[i]);
    }
};

template <typename T, typename Expr, typename UnaryOp>
class unary_expr {
private:
    static_assert(is_etl_expr<Expr>::value, "Only ETL expressions can be used in unary_expr");

    Expr _value;

    typedef unary_expr<T, Expr, UnaryOp> this_type;

public:
    static constexpr const bool etl_marker = true;
    static constexpr const bool etl_fast = true;
    static constexpr const std::size_t etl_size = std::remove_reference<Expr>::type::etl_size;

    using value_type = T;

    //Cannot be constructed with no args
    unary_expr() = delete;

    //Construct a new expression
    unary_expr(Expr l) : _value(std::forward<Expr>(l)){
        //Nothing else to init
    }

    //No copying
    unary_expr(const unary_expr&) = delete;
    unary_expr& operator=(const unary_expr&) = delete;

    //No moving
    unary_expr(unary_expr&&) = delete;
    unary_expr& operator=(unary_expr&&) = delete;

    //Accessors

    template<typename E = Expr, enable_if_u<std::remove_reference<E>::type::etl_fast> = detail::dummy>
    constexpr std::size_t size() const {
        return _value.size();
    }

    template<typename E = Expr, disable_if_u<std::remove_reference<E>::type::etl_fast> = detail::dummy>
    std::size_t size() const {
        return _value.size();
    }

    typename std::add_lvalue_reference<Expr>::type value(){
        return _value;
    }

    typename std::add_lvalue_reference<typename std::add_const<Expr>::type>::type value() const {
        return _value;
    }

    //Apply the expression

    decltype(auto) operator[](std::size_t i) const {
        return UnaryOp::apply(value()[i]);
    }
};

//{{{ Build binary expressions from two ETL expressions (vector,matrix,binary,unary)

template<typename LE, typename RE, enable_if_u<and_u<is_etl_expr<LE>::value, is_etl_expr<RE>::value>::value> = detail::dummy>
auto operator-(const LE& lhs, const RE& rhs) -> binary_expr<typename LE::value_type, const LE&, minus_binary_op<typename LE::value_type>, const RE&> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<is_etl_expr<LE>::value, is_etl_expr<RE>::value>::value> = detail::dummy>
auto operator+(const LE& lhs, const RE& rhs) -> binary_expr<typename LE::value_type, const LE&, plus_binary_op<typename LE::value_type>, const RE&> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<is_etl_expr<LE>::value, is_etl_expr<RE>::value>::value> = detail::dummy>
auto operator*(const LE& lhs, const RE& rhs) -> binary_expr<typename LE::value_type, const LE&, mul_binary_op<typename LE::value_type>, const RE&> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<is_etl_expr<LE>::value, is_etl_expr<RE>::value>::value> = detail::dummy>
auto operator/(const LE& lhs, const RE& rhs) -> binary_expr<typename LE::value_type, const LE&, div_binary_op<typename LE::value_type>, const RE&> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<is_etl_expr<LE>::value, is_etl_expr<RE>::value>::value> = detail::dummy>
auto operator%(const LE& lhs, const RE& rhs) -> binary_expr<typename LE::value_type, const LE&, mod_binary_op<typename LE::value_type>, const RE&> {
    return {lhs, rhs};
}

//}}}

//{{{ Mix scalars and ETL expressions (vector,matrix,binary,unary)

template<typename LE, typename RE, enable_if_u<and_u<std::is_convertible<RE, typename LE::value_type>::value, is_etl_expr<LE>::value>::value> = detail::dummy>
auto operator-(const LE& lhs, RE rhs) -> binary_expr<typename LE::value_type, const LE&, minus_binary_op<typename LE::value_type>, scalar<typename LE::value_type>> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<std::is_convertible<LE, typename RE::value_type>::value, is_etl_expr<RE>::value>::value> = detail::dummy>
auto operator-(LE lhs, const RE& rhs) -> binary_expr<typename RE::value_type, scalar<typename RE::value_type>, minus_binary_op<typename RE::value_type>, const RE&> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<std::is_convertible<RE, typename LE::value_type>::value, is_etl_expr<LE>::value>::value> = detail::dummy>
auto operator+(const LE& lhs, RE rhs) -> binary_expr<typename LE::value_type, const LE&, plus_binary_op<typename LE::value_type>, scalar<typename LE::value_type>> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<std::is_convertible<LE, typename RE::value_type>::value, is_etl_expr<RE>::value>::value> = detail::dummy>
auto operator+(LE lhs, const RE& rhs) -> binary_expr<typename RE::value_type, scalar<typename RE::value_type>, plus_binary_op<typename RE::value_type>, const RE&> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<std::is_convertible<RE, typename LE::value_type>::value, is_etl_expr<LE>::value>::value> = detail::dummy>
auto operator*(const LE& lhs, RE rhs) -> binary_expr<typename LE::value_type, const LE&, mul_binary_op<typename LE::value_type>, scalar<typename LE::value_type>> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<std::is_convertible<LE, typename RE::value_type>::value, is_etl_expr<RE>::value>::value> = detail::dummy>
auto operator*(LE lhs, const RE& rhs) -> binary_expr<typename RE::value_type, scalar<typename RE::value_type>, mul_binary_op<typename RE::value_type>, const RE&> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<std::is_convertible<RE, typename LE::value_type>::value, is_etl_expr<LE>::value>::value> = detail::dummy>
auto operator/(const LE& lhs, RE rhs) -> binary_expr<typename LE::value_type, const LE&, div_binary_op<typename LE::value_type>, scalar<typename LE::value_type>> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<std::is_convertible<LE, typename RE::value_type>::value, is_etl_expr<RE>::value>::value> = detail::dummy>
auto operator/(LE lhs, const RE& rhs) -> binary_expr<typename RE::value_type, scalar<typename RE::value_type>, div_binary_op<typename RE::value_type>, const RE&> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<std::is_convertible<RE, typename LE::value_type>::value, is_etl_expr<LE>::value>::value> = detail::dummy>
auto operator%(const LE& lhs, RE rhs) -> binary_expr<typename LE::value_type, const LE&, mod_binary_op<typename LE::value_type>, scalar<typename LE::value_type>> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<std::is_convertible<LE, typename RE::value_type>::value, is_etl_expr<RE>::value>::value> = detail::dummy>
auto operator%(LE lhs, const RE& rhs) -> binary_expr<typename RE::value_type, scalar<typename RE::value_type>, mod_binary_op<typename RE::value_type>, const RE&> {
    return {lhs, rhs};
}

//}}}

//{{{ Apply an unary expression on an ETL expression (vector,matrix,binary,unary)

template<typename E, enable_if_u<is_etl_expr<E>::value> = detail::dummy>
auto abs(const E& value) -> unary_expr<typename E::value_type, const E&, abs_unary_op<typename E::value_type>> {
    return {value};
}

template<typename E, enable_if_u<is_etl_expr<E>::value> = detail::dummy>
auto log(const E& value) -> unary_expr<typename E::value_type, const E&, log_unary_op<typename E::value_type>> {
    return {value};
}

template<typename E, enable_if_u<is_etl_expr<E>::value> = detail::dummy>
auto sign(const E& value) -> unary_expr<typename E::value_type, const E&, sign_unary_op<typename E::value_type>> {
    return {value};
}

//}}}

//{{{ Apply a reduction on an ETL expression (vector,matrix,binary,unary)

template<typename E, enable_if_u<is_etl_expr<E>::value> = detail::dummy>
typename E::value_type sum(const E& values){
    auto acc = static_cast<typename E::value_type>(0);

    for(std::size_t i = 0; i < values.size(); ++i){
        acc += values[i];
    }

    return acc;
}

template<typename E, enable_if_u<is_etl_expr<E>::value> = detail::dummy>
typename E::value_type mean(const E& values){
    return sum(values) / values.size();
}

//}}}

} //end of namespace etl

#endif
<commit_msg>Clean<commit_after>//=======================================================================
// Copyright (c) 2014 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef ETL_FAST_EXPR_HPP
#define ETL_FAST_EXPR_HPP

#include "fast_op.hpp"
#include "tmp.hpp"

namespace etl {

template<typename LE, typename RE, typename Enable = void>
struct get_etl_size ;

template<typename LE, typename RE>
struct get_etl_size<LE, RE, enable_if_t<is_etl_expr<LE>::value>>
    : std::integral_constant<std::size_t, std::remove_reference<LE>::type::etl_size> {} ;

template<typename LE, typename RE>
struct get_etl_size<LE, RE, enable_if_t<and_u<is_etl_expr<RE>::value, not_u<is_etl_expr<LE>::value>::value>::value>>
    : std::integral_constant<std::size_t, std::remove_reference<RE>::type::etl_size> {};

template <typename T, typename LeftExpr, typename BinaryOp, typename RightExpr>
class binary_expr {
private:
    static_assert(or_u<is_etl_expr<LeftExpr>::value, is_etl_expr<RightExpr>::value>::value, "At least one of the binary expressions arguments must be an ETL expr");

    LeftExpr _lhs;
    RightExpr _rhs;

public:
    static constexpr const bool etl_marker = true;
    static constexpr const bool etl_fast = true;
    static constexpr const std::size_t etl_size = get_etl_size<LeftExpr, RightExpr>::value;

    using value_type = T;

    //Cannot be constructed with no args
    binary_expr() = delete;

    //Construct a new expression
    binary_expr(LeftExpr l, RightExpr r) :
            _lhs(std::forward<LeftExpr>(l)), _rhs(std::forward<RightExpr>(r)){
        //Nothing else to init
    }

    //No copying
    binary_expr(const binary_expr&) = delete;
    binary_expr& operator=(const binary_expr&) = delete;

    //No moving
    binary_expr(binary_expr&&) = delete;
    binary_expr& operator=(binary_expr&&) = delete;

    //Accessors

    //TODO size() can be constexpr if Expr is fast_X

    template<typename LE = LeftExpr, enable_if_u<is_etl_expr<LE>::value> = detail::dummy>
    std::size_t size() const {
        return _lhs.size();
    }

    template<typename LE = LeftExpr, disable_if_u<is_etl_expr<LE>::value> = detail::dummy>
    std::size_t size() const {
        return _rhs.size();
    }

    typename std::add_lvalue_reference<LeftExpr>::type lhs(){
        return _lhs;
    }

    typename std::add_lvalue_reference<typename std::add_const<LeftExpr>::type>::type lhs() const {
        return _lhs;
    }

    typename std::add_lvalue_reference<RightExpr>::type rhs(){
        return _rhs;
    }

    typename std::add_lvalue_reference<typename std::add_const<RightExpr>::type>::type rhs() const {
        return _rhs;
    }

    //Apply the expression

    decltype(auto) operator[](std::size_t i) const {
        return BinaryOp::apply(lhs()[i], rhs()[i]);
    }
};

template <typename T, typename Expr, typename UnaryOp>
class unary_expr {
private:
    static_assert(is_etl_expr<Expr>::value, "Only ETL expressions can be used in unary_expr");

    Expr _value;

public:
    static constexpr const bool etl_marker = true;
    static constexpr const bool etl_fast = true;
    static constexpr const std::size_t etl_size = std::remove_reference<Expr>::type::etl_size;

    using value_type = T;

    //Cannot be constructed with no args
    unary_expr() = delete;

    //Construct a new expression
    unary_expr(Expr l) : _value(std::forward<Expr>(l)){
        //Nothing else to init
    }

    //No copying
    unary_expr(const unary_expr&) = delete;
    unary_expr& operator=(const unary_expr&) = delete;

    //No moving
    unary_expr(unary_expr&&) = delete;
    unary_expr& operator=(unary_expr&&) = delete;

    //Accessors

    template<typename E = Expr, enable_if_u<std::remove_reference<E>::type::etl_fast> = detail::dummy>
    constexpr std::size_t size() const {
        return _value.size();
    }

    template<typename E = Expr, disable_if_u<std::remove_reference<E>::type::etl_fast> = detail::dummy>
    std::size_t size() const {
        return _value.size();
    }

    typename std::add_lvalue_reference<Expr>::type value(){
        return _value;
    }

    typename std::add_lvalue_reference<typename std::add_const<Expr>::type>::type value() const {
        return _value;
    }

    //Apply the expression

    decltype(auto) operator[](std::size_t i) const {
        return UnaryOp::apply(value()[i]);
    }
};

//{{{ Build binary expressions from two ETL expressions (vector,matrix,binary,unary)

template<typename LE, typename RE, enable_if_u<and_u<is_etl_expr<LE>::value, is_etl_expr<RE>::value>::value> = detail::dummy>
auto operator-(const LE& lhs, const RE& rhs) -> binary_expr<typename LE::value_type, const LE&, minus_binary_op<typename LE::value_type>, const RE&> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<is_etl_expr<LE>::value, is_etl_expr<RE>::value>::value> = detail::dummy>
auto operator+(const LE& lhs, const RE& rhs) -> binary_expr<typename LE::value_type, const LE&, plus_binary_op<typename LE::value_type>, const RE&> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<is_etl_expr<LE>::value, is_etl_expr<RE>::value>::value> = detail::dummy>
auto operator*(const LE& lhs, const RE& rhs) -> binary_expr<typename LE::value_type, const LE&, mul_binary_op<typename LE::value_type>, const RE&> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<is_etl_expr<LE>::value, is_etl_expr<RE>::value>::value> = detail::dummy>
auto operator/(const LE& lhs, const RE& rhs) -> binary_expr<typename LE::value_type, const LE&, div_binary_op<typename LE::value_type>, const RE&> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<is_etl_expr<LE>::value, is_etl_expr<RE>::value>::value> = detail::dummy>
auto operator%(const LE& lhs, const RE& rhs) -> binary_expr<typename LE::value_type, const LE&, mod_binary_op<typename LE::value_type>, const RE&> {
    return {lhs, rhs};
}

//}}}

//{{{ Mix scalars and ETL expressions (vector,matrix,binary,unary)

template<typename LE, typename RE, enable_if_u<and_u<std::is_convertible<RE, typename LE::value_type>::value, is_etl_expr<LE>::value>::value> = detail::dummy>
auto operator-(const LE& lhs, RE rhs) -> binary_expr<typename LE::value_type, const LE&, minus_binary_op<typename LE::value_type>, scalar<typename LE::value_type>> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<std::is_convertible<LE, typename RE::value_type>::value, is_etl_expr<RE>::value>::value> = detail::dummy>
auto operator-(LE lhs, const RE& rhs) -> binary_expr<typename RE::value_type, scalar<typename RE::value_type>, minus_binary_op<typename RE::value_type>, const RE&> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<std::is_convertible<RE, typename LE::value_type>::value, is_etl_expr<LE>::value>::value> = detail::dummy>
auto operator+(const LE& lhs, RE rhs) -> binary_expr<typename LE::value_type, const LE&, plus_binary_op<typename LE::value_type>, scalar<typename LE::value_type>> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<std::is_convertible<LE, typename RE::value_type>::value, is_etl_expr<RE>::value>::value> = detail::dummy>
auto operator+(LE lhs, const RE& rhs) -> binary_expr<typename RE::value_type, scalar<typename RE::value_type>, plus_binary_op<typename RE::value_type>, const RE&> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<std::is_convertible<RE, typename LE::value_type>::value, is_etl_expr<LE>::value>::value> = detail::dummy>
auto operator*(const LE& lhs, RE rhs) -> binary_expr<typename LE::value_type, const LE&, mul_binary_op<typename LE::value_type>, scalar<typename LE::value_type>> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<std::is_convertible<LE, typename RE::value_type>::value, is_etl_expr<RE>::value>::value> = detail::dummy>
auto operator*(LE lhs, const RE& rhs) -> binary_expr<typename RE::value_type, scalar<typename RE::value_type>, mul_binary_op<typename RE::value_type>, const RE&> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<std::is_convertible<RE, typename LE::value_type>::value, is_etl_expr<LE>::value>::value> = detail::dummy>
auto operator/(const LE& lhs, RE rhs) -> binary_expr<typename LE::value_type, const LE&, div_binary_op<typename LE::value_type>, scalar<typename LE::value_type>> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<std::is_convertible<LE, typename RE::value_type>::value, is_etl_expr<RE>::value>::value> = detail::dummy>
auto operator/(LE lhs, const RE& rhs) -> binary_expr<typename RE::value_type, scalar<typename RE::value_type>, div_binary_op<typename RE::value_type>, const RE&> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<std::is_convertible<RE, typename LE::value_type>::value, is_etl_expr<LE>::value>::value> = detail::dummy>
auto operator%(const LE& lhs, RE rhs) -> binary_expr<typename LE::value_type, const LE&, mod_binary_op<typename LE::value_type>, scalar<typename LE::value_type>> {
    return {lhs, rhs};
}

template<typename LE, typename RE, enable_if_u<and_u<std::is_convertible<LE, typename RE::value_type>::value, is_etl_expr<RE>::value>::value> = detail::dummy>
auto operator%(LE lhs, const RE& rhs) -> binary_expr<typename RE::value_type, scalar<typename RE::value_type>, mod_binary_op<typename RE::value_type>, const RE&> {
    return {lhs, rhs};
}

//}}}

//{{{ Apply an unary expression on an ETL expression (vector,matrix,binary,unary)

template<typename E, enable_if_u<is_etl_expr<E>::value> = detail::dummy>
auto abs(const E& value) -> unary_expr<typename E::value_type, const E&, abs_unary_op<typename E::value_type>> {
    return {value};
}

template<typename E, enable_if_u<is_etl_expr<E>::value> = detail::dummy>
auto log(const E& value) -> unary_expr<typename E::value_type, const E&, log_unary_op<typename E::value_type>> {
    return {value};
}

template<typename E, enable_if_u<is_etl_expr<E>::value> = detail::dummy>
auto sign(const E& value) -> unary_expr<typename E::value_type, const E&, sign_unary_op<typename E::value_type>> {
    return {value};
}

//}}}

//{{{ Apply a reduction on an ETL expression (vector,matrix,binary,unary)

template<typename E, enable_if_u<is_etl_expr<E>::value> = detail::dummy>
typename E::value_type sum(const E& values){
    auto acc = static_cast<typename E::value_type>(0);

    for(std::size_t i = 0; i < values.size(); ++i){
        acc += values[i];
    }

    return acc;
}

template<typename E, enable_if_u<is_etl_expr<E>::value> = detail::dummy>
typename E::value_type mean(const E& values){
    return sum(values) / values.size();
}

//}}}

} //end of namespace etl

#endif
<|endoftext|>