<commit_before>#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>

#include <mtp/ptp/Device.h>

#include <map>
#include <string>

namespace
{
	class FuseWrapper
	{
		struct FileInfo
		{
			std::vector<mtp::u32> Files;
		};

		std::mutex		_mutex;
		mtp::DevicePtr	_device;
		mtp::SessionPtr	_session;

		typedef std::map<std::string, mtp::u32> Files;
		Files			_files;

		typedef std::map<std::string, mtp::u32> Storages;
		Storages		_storages;

	public:
		FuseWrapper(mtp::DevicePtr device): _device(device), _session(device->OpenSession(1))
		{
			mtp::msg::StorageIDs ids = _session->GetStorageIDs();
			for(size_t i = 0; i < ids.StorageIDs.size(); ++i)
			{
				mtp::u32 id = ids.StorageIDs[i];
				mtp::msg::StorageInfo si = _session->GetStorageInfo(id);
				std::string path = "/" + (!si.VolumeLabel.empty()? si.VolumeLabel: si.StorageDescription);
				if (!path.empty())
					_storages[path] = id;
			}
		}

		int GetAttr(const char *path_, struct stat *stbuf)
		{
			std::string path(path_);
			if (path == "/")
			{
				stbuf->st_mode = S_IFDIR | 0755;
				stbuf->st_nlink = 2;
				return 0;
			}

			mtp::scoped_mutex_lock l(_mutex);
			Storages::const_iterator i = _storages.find(path);
			if (i != _storages.end())
			{
				stbuf->st_mode = S_IFDIR | 0755;
				stbuf->st_nlink = 2;
				return 0;
			}

			mtp::u32 id = Resolve(path);
			if (id)
			{
				stbuf->st_mode = 0644;

				mtp::ObjectFormat format((mtp::ObjectFormat)_session->GetObjectIntegerProperty(id, mtp::ObjectProperty::ObjectFormat));
				if (format == mtp::ObjectFormat::Association)
					stbuf->st_mode |= S_IFDIR | 0111;
				else
					stbuf->st_mode |= S_IFREG;

				stbuf->st_nlink = 1;
				stbuf->st_size = _session->GetObjectIntegerProperty(id, mtp::ObjectProperty::ObjectSize);
				return 0;
			}
			return -ENOENT;
		}

		void Append(const std::string &path, const mtp::msg::ObjectHandles &handles, void * buf, fuse_fill_dir_t filler)
		{
			for(auto & id : handles.ObjectHandles)
			{
				try
				{
					std::string name = _session->GetObjectStringProperty(id, mtp::ObjectProperty::ObjectFilename);
					_files[path + "/" + name] = id;
					if (filler)
						filler(buf, name.c_str(), NULL, 0);
				} catch(const std::exception &ex)
				{ }
			}
		}

		mtp::u32 Resolve(const std::string &path)
		{
			Files::const_iterator file = _files.find(path);
			if (file != _files.end())
				return file->second;

			// /STORAGE/dir1/dir2/file

			size_t idx = 0;
			while(idx < path.size())
			{
				size_t next = path.find('/', idx + 1);
				std::string subpath(path.substr(0, next));

				Storages::const_iterator storage = _storages.find(subpath);
				if (storage != _storages.end())
				{
					mtp::msg::ObjectHandles list = _session->GetObjectHandles(storage->second, mtp::Session::AllFormats, mtp::Session::Root);
					Append(subpath, list, 0, 0);
				}
				else
				{
					Files::const_iterator file = _files.find(subpath);
					if (file != _files.end())
					{
						mtp::msg::ObjectHandles list = _session->GetObjectHandles(mtp::Session::AllStorages, mtp::Session::AllFormats, file->second);
						Append(subpath, list, 0, 0);
					}
					else
						return 0;
				}
				if (next == path.npos)
					break;
				else
					idx = next;
			}

			file = _files.find(path);
			if (file != _files.end())
				return file->second;

			return 0;
		}

		int ReadDir(const char *path_, void *buf, fuse_fill_dir_t filler,
					 off_t offset, struct fuse_file_info *fi)
		{
			std::string path(path_);
			mtp::scoped_mutex_lock l(_mutex);
			if (path == "/")
			{
				filler(buf, ".", NULL, 0);
				filler(buf, "..", NULL, 0);

				for(auto & r : _storages)
				{
					filler(buf, r.first.c_str() + 1, NULL, 0);
				}
				return 0;
			}

			Storages::const_iterator storage = _storages.find(path);
			if (storage != _storages.end())
			{
				filler(buf, ".", NULL, 0);
				filler(buf, "..", NULL, 0);

				mtp::msg::ObjectHandles list = _session->GetObjectHandles(storage->second, mtp::Session::AllFormats, mtp::Session::Root);
				Append(path, list, buf, filler);
				return 0;
			}

			mtp::u32 id = Resolve(path);

			if (id)
			{
				filler(buf, ".", NULL, 0);
				filler(buf, "..", NULL, 0);

				mtp::msg::ObjectHandles list = _session->GetObjectHandles(mtp::Session::AllStorages, mtp::Session::AllFormats, id);
				Append(path, list, buf, filler);
				return 0;
			}

			return -ENOENT;
		}

		int Unlink (const char *path_)
		{
			std::string path(path_);
			mtp::scoped_mutex_lock l(_mutex);
			mtp::u32 id = Resolve(path);
			if (!id)
				return -ENOENT;
			_session->DeleteObject(id);
			_files.erase(path);
			return 0;
		}

		int ResolveParent(const std::string &path, std::string &filename, mtp::u32 &storageId, mtp::u32 &parentId)
		{
			size_t parentPos = path.rfind('/');
			if (parentPos == path.npos)
				return -ENOENT;
			if (parentPos == 0)
				return -EACCES;

			size_t storagePos = path.find('/', 1);
			if (storagePos == path.npos)
				return -EACCES;

			std::string storage = path.substr(0, storagePos);
			Storages::const_iterator i = _storages.find(storage);
			if (i != _storages.end())
			{
				storageId = i->second;
			}
			else
				return -ENOENT;

			std::string parent = path.substr(0, parentPos);
			parentId = parent != storage? Resolve(parent): mtp::Session::Root;
			//printf("resolve parent %s -> %s %s %u %u\n", path.c_str(), storage.c_str(), parent.c_str(), storageId, parentId);

			if (storageId == 0 || parentId == 0)
				return -ENOENT;

			filename = path.substr(parentPos + 1);
			return 0;
		}

		int MakeDir (const char *path_, mode_t mode)
		{
			std::string path(path_);

			mtp::scoped_mutex_lock l(_mutex);
			mtp::u32 storageId, parentId;
			std::string filename;
			int r = ResolveParent(path, filename, storageId, parentId);
			if (r)
				return r;

			mtp::msg::ObjectInfo oi;
			oi.Filename = filename;
			oi.ObjectFormat = mtp::ObjectFormat::Association;
			oi.AssociationType = 1;
			_session->SendObjectInfo(oi, storageId, parentId);
			return 0;
		}

		int RemoveDir (const char *path)
		{ return Unlink(path); }

		int Create(const char *path_, mode_t mode, struct fuse_file_info *fi)
		{
			std::string path(path_);
			mtp::scoped_mutex_lock l(_mutex);
			mtp::u32 storageId, parentId;
			std::string filename;
			int r = ResolveParent(path, filename, storageId, parentId);
			if (r)
				return r;

			mtp::msg::ObjectInfo oi;
			oi.Filename = filename;
			oi.ObjectFormat = mtp::ObjectFormatFromFilename(filename);
			_session->SendObjectInfo(oi, storageId, parentId);
			return 0;
		}

		int Open(const char *path, struct fuse_file_info *fi)
		{
			mtp::scoped_mutex_lock l(_mutex);
			return Resolve(path)? 0: -ENOENT;
		}

		int Read(const char *path, char *buf, size_t size, off_t offset,
					  struct fuse_file_info *fi)
		{
			mtp::scoped_mutex_lock l(_mutex);
			mtp::u32 id = Resolve(path);
			if (!id)
				return -ENOENT;

			mtp::ByteArray data = _session->GetPartialObject(id, offset, size);
			if (data.size() > size)
				throw std::runtime_error("too much data");
			std::copy(data.begin(), data.end(), buf);
			return data.size();
		}

		int Flush(const char *path, struct fuse_file_info *fi)
		{ return -EIO; }

		int Write(const char *path, const char *buf, size_t size, off_t offset,
					  struct fuse_file_info *fi)
		{ return -EIO; }

		int Truncate(const char *path, off_t offset)
		{
			return -EIO;
		}

		int StatFS (const char *path, struct statvfs *stat)
		{
			stat->f_namemax = 254;
			return 0;
		}
	};

	mtp::DevicePtr					g_device;
	std::unique_ptr<FuseWrapper>	g_wrapper;

#define WRAP_EX(...) do { \
		try { return __VA_ARGS__ ; } \
		catch (const std::exception &ex) \
		{ fprintf(stderr, #__VA_ARGS__ " failed: %s", ex.what()); return -EIO; } \
	} while(false)

	int GetAttr(const char *path, struct stat *stbuf)
	{ WRAP_EX(g_wrapper->GetAttr(path, stbuf)); }

	int ReadDir(const char *path, void *buf, fuse_fill_dir_t filler,
				 off_t offset, struct fuse_file_info *fi)
	{ WRAP_EX(g_wrapper->ReadDir(path, buf, filler, offset, fi)); }

	int Open(const char *path, struct fuse_file_info *fi)
	{ WRAP_EX(g_wrapper->Open(path, fi)); }

	int Create(const char *path, mode_t mode, struct fuse_file_info *fi)
	{ WRAP_EX(g_wrapper->Create(path, mode, fi)); }

	int Read(const char *path, char *buf, size_t size, off_t offset,
				  struct fuse_file_info *fi)
	{ WRAP_EX(g_wrapper->Read(path, buf, size, offset, fi)); }

	int Write(const char *path, const char *buf, size_t size, off_t offset,
				  struct fuse_file_info *fi)
	{ WRAP_EX(g_wrapper->Write(path, buf, size, offset, fi)); }

	int Flush (const char *path, struct fuse_file_info *fi)
	{ WRAP_EX(g_wrapper->Flush(path, fi)); }

	int Unlink (const char *path)
	{ WRAP_EX(g_wrapper->Unlink(path)); }

	int MakeDir (const char *path, mode_t mode)
	{ WRAP_EX(g_wrapper->MakeDir(path, mode)); }

	int RemoveDir (const char *path)
	{ WRAP_EX(g_wrapper->RemoveDir(path)); }

	int Truncate(const char *path, off_t offset)
	{ WRAP_EX(g_wrapper->Truncate(path, offset)); }

	int StatFS (const char *path, struct statvfs *stat)
	{ WRAP_EX(g_wrapper->StatFS(path, stat)); }
}

int main(int argc, char **argv)
{
	try
	{
		g_device = mtp::Device::Find();
		if (!g_device)
			throw std::runtime_error("no MTP device found");
		g_wrapper.reset(new FuseWrapper(g_device));
	} catch(const std::exception &ex)
	{ printf("%s\n", ex.what()); return 1; }

	struct fuse_operations ops = {};

	ops.getattr		= &GetAttr;
	ops.readdir		= &ReadDir;
	ops.open		= &Open;
	ops.create		= &Create;
	ops.read		= &Read;
	ops.write		= &Write;
	ops.flush		= &Flush;
	ops.mkdir		= &MakeDir;
	ops.rmdir		= &RemoveDir;
	ops.unlink		= &Unlink;
	ops.truncate	= &Truncate;
	ops.statfs		= &StatFS;

	return fuse_main(argc, argv, &ops, NULL);
}
<commit_msg>implemented write/truncate<commit_after>#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>

#include <mtp/ptp/Device.h>

#include <map>
#include <string>

namespace
{
	class FuseWrapper
	{
		struct FileInfo
		{
			std::vector<mtp::u32> Files;
		};

		std::mutex		_mutex;
		mtp::DevicePtr	_device;
		mtp::SessionPtr	_session;

		typedef std::map<std::string, mtp::u32> Files;
		Files			_files;

		typedef mtp::Session::ObjectEditSessionPtr ObjectEditSessionPtr;
		typedef std::map<mtp::u32, ObjectEditSessionPtr> OpenedFiles;
		OpenedFiles		_openedFiles;

		typedef std::map<std::string, mtp::u32> Storages;
		Storages		_storages;

	public:
		FuseWrapper(mtp::DevicePtr device): _device(device), _session(device->OpenSession(1))
		{
			mtp::msg::StorageIDs ids = _session->GetStorageIDs();
			for(size_t i = 0; i < ids.StorageIDs.size(); ++i)
			{
				mtp::u32 id = ids.StorageIDs[i];
				mtp::msg::StorageInfo si = _session->GetStorageInfo(id);
				std::string path = "/" + (!si.VolumeLabel.empty()? si.VolumeLabel: si.StorageDescription);
				if (!path.empty())
					_storages[path] = id;
			}
		}

		int GetAttr(const char *path_, struct stat *stbuf)
		{
			std::string path(path_);
			if (path == "/")
			{
				stbuf->st_mode = S_IFDIR | 0755;
				stbuf->st_nlink = 2;
				return 0;
			}

			mtp::scoped_mutex_lock l(_mutex);
			Storages::const_iterator i = _storages.find(path);
			if (i != _storages.end())
			{
				stbuf->st_mode = S_IFDIR | 0755;
				stbuf->st_nlink = 2;
				return 0;
			}

			mtp::u32 id = Resolve(path);
			if (id)
			{
				stbuf->st_mode = 0644;

				mtp::ObjectFormat format((mtp::ObjectFormat)_session->GetObjectIntegerProperty(id, mtp::ObjectProperty::ObjectFormat));
				if (format == mtp::ObjectFormat::Association)
					stbuf->st_mode |= S_IFDIR | 0111;
				else
					stbuf->st_mode |= S_IFREG;

				stbuf->st_nlink = 1;
				stbuf->st_size = _session->GetObjectIntegerProperty(id, mtp::ObjectProperty::ObjectSize);
				return 0;
			}
			return -ENOENT;
		}

		void Append(const std::string &path, const mtp::msg::ObjectHandles &handles, void * buf, fuse_fill_dir_t filler)
		{
			for(auto & id : handles.ObjectHandles)
			{
				try
				{
					std::string name = _session->GetObjectStringProperty(id, mtp::ObjectProperty::ObjectFilename);
					_files[path + "/" + name] = id;
					if (filler)
						filler(buf, name.c_str(), NULL, 0);
				} catch(const std::exception &ex)
				{ }
			}
		}

		mtp::u32 Resolve(const std::string &path)
		{
			Files::const_iterator file = _files.find(path);
			if (file != _files.end())
				return file->second;

			// /STORAGE/dir1/dir2/file

			size_t idx = 0;
			while(idx < path.size())
			{
				size_t next = path.find('/', idx + 1);
				std::string subpath(path.substr(0, next));

				Storages::const_iterator storage = _storages.find(subpath);
				if (storage != _storages.end())
				{
					mtp::msg::ObjectHandles list = _session->GetObjectHandles(storage->second, mtp::Session::AllFormats, mtp::Session::Root);
					Append(subpath, list, 0, 0);
				}
				else
				{
					Files::const_iterator file = _files.find(subpath);
					if (file != _files.end())
					{
						mtp::msg::ObjectHandles list = _session->GetObjectHandles(mtp::Session::AllStorages, mtp::Session::AllFormats, file->second);
						Append(subpath, list, 0, 0);
					}
					else
						return 0;
				}
				if (next == path.npos)
					break;
				else
					idx = next;
			}

			file = _files.find(path);
			if (file != _files.end())
				return file->second;

			return 0;
		}

		int ReadDir(const char *path_, void *buf, fuse_fill_dir_t filler,
					 off_t offset, struct fuse_file_info *fi)
		{
			std::string path(path_);
			mtp::scoped_mutex_lock l(_mutex);
			if (path == "/")
			{
				filler(buf, ".", NULL, 0);
				filler(buf, "..", NULL, 0);

				for(auto & r : _storages)
				{
					filler(buf, r.first.c_str() + 1, NULL, 0);
				}
				return 0;
			}

			Storages::const_iterator storage = _storages.find(path);
			if (storage != _storages.end())
			{
				filler(buf, ".", NULL, 0);
				filler(buf, "..", NULL, 0);

				mtp::msg::ObjectHandles list = _session->GetObjectHandles(storage->second, mtp::Session::AllFormats, mtp::Session::Root);
				Append(path, list, buf, filler);
				return 0;
			}

			mtp::u32 id = Resolve(path);

			if (id)
			{
				filler(buf, ".", NULL, 0);
				filler(buf, "..", NULL, 0);

				mtp::msg::ObjectHandles list = _session->GetObjectHandles(mtp::Session::AllStorages, mtp::Session::AllFormats, id);
				Append(path, list, buf, filler);
				return 0;
			}

			return -ENOENT;
		}

		int Unlink (const char *path_)
		{
			std::string path(path_);
			mtp::scoped_mutex_lock l(_mutex);
			mtp::u32 id = Resolve(path);
			if (!id)
				return -ENOENT;
			_session->DeleteObject(id);
			_files.erase(path);
			return 0;
		}

		int ResolveParent(const std::string &path, std::string &filename, mtp::u32 &storageId, mtp::u32 &parentId)
		{
			size_t parentPos = path.rfind('/');
			if (parentPos == path.npos)
				return -ENOENT;
			if (parentPos == 0)
				return -EACCES;

			size_t storagePos = path.find('/', 1);
			if (storagePos == path.npos)
				return -EACCES;

			std::string storage = path.substr(0, storagePos);
			Storages::const_iterator i = _storages.find(storage);
			if (i != _storages.end())
			{
				storageId = i->second;
			}
			else
				return -ENOENT;

			std::string parent = path.substr(0, parentPos);
			parentId = parent != storage? Resolve(parent): mtp::Session::Root;
			//printf("resolve parent %s -> %s %s %u %u\n", path.c_str(), storage.c_str(), parent.c_str(), storageId, parentId);

			if (storageId == 0 || parentId == 0)
				return -ENOENT;

			filename = path.substr(parentPos + 1);
			return 0;
		}

		int MakeDir (const char *path_, mode_t mode)
		{
			std::string path(path_);

			mtp::scoped_mutex_lock l(_mutex);
			mtp::u32 storageId, parentId;
			std::string filename;
			int r = ResolveParent(path, filename, storageId, parentId);
			if (r)
				return r;

			mtp::msg::ObjectInfo oi;
			oi.Filename = filename;
			oi.ObjectFormat = mtp::ObjectFormat::Association;
			oi.AssociationType = 1;
			_session->SendObjectInfo(oi, storageId, parentId);
			return 0;
		}

		int RemoveDir (const char *path)
		{ return Unlink(path); }

		int Create(const char *path_, mode_t mode, struct fuse_file_info *fi)
		{
			std::string path(path_);
			mtp::scoped_mutex_lock l(_mutex);
			mtp::u32 storageId, parentId;
			std::string filename;
			int r = ResolveParent(path, filename, storageId, parentId);
			if (r)
				return r;

			mtp::msg::ObjectInfo oi;
			oi.Filename = filename;
			oi.ObjectFormat = mtp::ObjectFormatFromFilename(filename);
			_session->SendObjectInfo(oi, storageId, parentId);
			return 0;
		}

		int Open(const char *path, struct fuse_file_info *fi)
		{
			mtp::scoped_mutex_lock l(_mutex);
			return Resolve(path)? 0: -ENOENT;
		}

		int Read(const char *path, char *buf, size_t size, off_t offset,
					  struct fuse_file_info *fi)
		{
			mtp::scoped_mutex_lock l(_mutex);
			mtp::u32 id = Resolve(path);
			if (!id)
				return -ENOENT;

			mtp::ByteArray data = _session->GetPartialObject(id, offset, size);
			if (data.size() > size)
				throw std::runtime_error("too much data");
			std::copy(data.begin(), data.end(), buf);
			return data.size();
		}

		ObjectEditSessionPtr GetSession(mtp::u32 id)
		{
			mtp::scoped_mutex_lock l(_mutex);
			OpenedFiles::const_iterator i = _openedFiles.find(id);
			if (i != _openedFiles.end())
				return i->second;
			else
				return _openedFiles[id] = mtp::Session::EditObject(_session, id);
		}

		int Flush(const char *path, struct fuse_file_info *fi)
		{
			mtp::scoped_mutex_lock l(_mutex);
			mtp::u32 id = Resolve(path);
			if (!id)
				return -ENOENT;
			_openedFiles.erase(id);
			return 0;
		}

		int Write(const char *path, const char *buf, size_t size, off_t offset,
					  struct fuse_file_info *fi)
		{
			mtp::u32 id;
			{
				mtp::scoped_mutex_lock l(_mutex);
				id = Resolve(path);
				if (!id)
					return -ENOENT;
			}

			ObjectEditSessionPtr edit = GetSession(id);
			edit->Send(offset, mtp::ByteArray(buf, buf + size));
			return size;
		}

		int Truncate(const char *path, off_t offset)
		{
			mtp::u32 id;
			{
				mtp::scoped_mutex_lock l(_mutex);
				id = Resolve(path);
				if (!id)
					return -ENOENT;
			}

			ObjectEditSessionPtr edit = GetSession(id);
			edit->Truncate(offset);
			return 0;
		}

		int StatFS (const char *path, struct statvfs *stat)
		{
			stat->f_namemax = 254;
			return 0;
		}
	};

	mtp::DevicePtr					g_device;
	std::unique_ptr<FuseWrapper>	g_wrapper;

#define WRAP_EX(...) do { \
		try { return __VA_ARGS__ ; } \
		catch (const std::exception &ex) \
		{ fprintf(stderr, #__VA_ARGS__ " failed: %s", ex.what()); return -EIO; } \
	} while(false)

	int GetAttr(const char *path, struct stat *stbuf)
	{ WRAP_EX(g_wrapper->GetAttr(path, stbuf)); }

	int ReadDir(const char *path, void *buf, fuse_fill_dir_t filler,
				 off_t offset, struct fuse_file_info *fi)
	{ WRAP_EX(g_wrapper->ReadDir(path, buf, filler, offset, fi)); }

	int Open(const char *path, struct fuse_file_info *fi)
	{ WRAP_EX(g_wrapper->Open(path, fi)); }

	int Create(const char *path, mode_t mode, struct fuse_file_info *fi)
	{ WRAP_EX(g_wrapper->Create(path, mode, fi)); }

	int Read(const char *path, char *buf, size_t size, off_t offset,
				  struct fuse_file_info *fi)
	{ WRAP_EX(g_wrapper->Read(path, buf, size, offset, fi)); }

	int Write(const char *path, const char *buf, size_t size, off_t offset,
				  struct fuse_file_info *fi)
	{ WRAP_EX(g_wrapper->Write(path, buf, size, offset, fi)); }

	int Flush (const char *path, struct fuse_file_info *fi)
	{ WRAP_EX(g_wrapper->Flush(path, fi)); }

	int Unlink (const char *path)
	{ WRAP_EX(g_wrapper->Unlink(path)); }

	int MakeDir (const char *path, mode_t mode)
	{ WRAP_EX(g_wrapper->MakeDir(path, mode)); }

	int RemoveDir (const char *path)
	{ WRAP_EX(g_wrapper->RemoveDir(path)); }

	int Truncate(const char *path, off_t offset)
	{ WRAP_EX(g_wrapper->Truncate(path, offset)); }

	int StatFS (const char *path, struct statvfs *stat)
	{ WRAP_EX(g_wrapper->StatFS(path, stat)); }
}

int main(int argc, char **argv)
{
	try
	{
		g_device = mtp::Device::Find();
		if (!g_device)
			throw std::runtime_error("no MTP device found");
		g_wrapper.reset(new FuseWrapper(g_device));
	} catch(const std::exception &ex)
	{ printf("%s\n", ex.what()); return 1; }

	struct fuse_operations ops = {};

	ops.getattr		= &GetAttr;
	ops.readdir		= &ReadDir;
	ops.open		= &Open;
	ops.create		= &Create;
	ops.read		= &Read;
	ops.write		= &Write;
	ops.flush		= &Flush;
	ops.mkdir		= &MakeDir;
	ops.rmdir		= &RemoveDir;
	ops.unlink		= &Unlink;
	ops.truncate	= &Truncate;
	ops.statfs		= &StatFS;

	return fuse_main(argc, argv, &ops, NULL);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2005, Peter Sommerlad and IFS Institute for Software at HSR Rapperswil, Switzerland
 * All rights reserved.
 *
 * This library/application is free software; you can redistribute and/or modify it under the terms of
 * the license that is included with this library/application in the file license.txt.
 */

//--- interface include --------------------------------------------------------
#include "ITOStorage.h"

//--- standard modules used ----------------------------------------------------
#include "SysLog.h"
#include "MemHeader.h"

//--- c-library modules used ---------------------------------------------------
#include <stdlib.h>
#include <string.h>

#ifdef __370__
extern "C" void finalize();
#endif

#ifdef MEM_DEBUG
#include <stdio.h>

MemChecker::MemChecker(const char *scope, Allocator *a)
	: fAllocator(a)
	, fSizeAllocated(fAllocator->CurrentlyAllocated())
	, fScope(scope)
{
}

MemChecker::~MemChecker()
{
	TraceDelta("MemChecker.~MemChecker: ");
}

void MemChecker::TraceDelta(const char *message)
{
	l_long delta = CheckDelta();
	// CAUTION: DO NOT PROGRAM AS FOLLOWS !!!
	// IT IS ONLY NECESSARY HERE, BECAUSE THIS CODE MIGHT BE EXECUTED DURING
	// atexit() WHEN PART OF THE C++ ENVIRONMENT IS ALREADY GONE (like cerr and cerr)
	// THIS CODE WILL ONLY BE INCLUDED IN DEBUG VERSIONS SO NO SAFETY CONCERN
	// FOR PRODUCTION CODE. Peter.
	char msgbuf[1024] = {'\0'};
	if (message) {
		SysLog::WriteToStderr( message, strlen(message));
	}
	int bufsz = sprintf(msgbuf, "\nMem Usage change by %.0f bytes in %s\n", (double)delta, fScope);
	SysLog::WriteToStderr( msgbuf, bufsz );
}

l_long MemChecker::CheckDelta()
{
	return fAllocator->CurrentlyAllocated() - fSizeAllocated;
}

//------------- Utilities for Memory Tracking --------------
MemTracker::MemTracker(const char *name)
	: fAllocated(0)
	, fMaxAllocated(0)
	, fNumAllocs(0)
	, fSizeAllocated(0)
	, fNumFrees(0)
	, fSizeFreed(0)
	, fId(-1)
	, fpName(name)
{}

void MemTracker::Init(MemTracker *t)
{
	fAllocated = t->fAllocated;
	fNumAllocs = t->fNumAllocs;
	fSizeAllocated = t->fSizeAllocated;
	fNumFrees = t->fNumFrees;
	fSizeFreed = t->fSizeFreed;
	fId = t->fId;
	fMaxAllocated = t->fMaxAllocated;
}

MemTracker::~MemTracker() {}

void MemTracker::SetId(long id)
{
	fId = id;
}

void MemTracker::TrackAlloc(u_long allocSz)
{
	fAllocated += allocSz;
	fNumAllocs++;
	fSizeAllocated += allocSz;
	fMaxAllocated = itoMAX(fMaxAllocated, fAllocated);
}

void MemTracker::TrackFree(u_long allocSz)
{
	fAllocated -= allocSz;
	fNumFrees++;
	fSizeFreed += allocSz;
}

#if !defined(__SUNPRO_CC) || __SUNPRO_CC < 0x500
extern "C" int write(int, const void *, unsigned);
#endif
void MemTracker::PrintStatistic()
{
	// CAUTION: DO NOT PROGRAM AS FOLLOWS !!!
	// IT IS ONLY NECESSARY HERE, BECAUSE THIS CODE MIGHT BE EXECUTED DURING
	// atexit() WHEN PART OF THE C++ ENVIRONMENT IS ALREADY GONE (like cerr and cerr)
	// THIS CODE WILL ONLY BE INCLUDED IN DEBUG VERSIONS SO NO SAFETY CONCERN
	// FOR PRODUCTION CODE. Peter.
	char buf[2048] ; // safety margin for bytes
	::snprintf(buf, sizeof(buf), "\nAllocator [%02ld] [%s]\n"
			   "Peek Allocated  %20lld bytes\n"
			   "Total Allocated %20lld bytes in %15lld runs (%ld/run)\n"
			   "Total Freed     %20lld bytes in %15lld runs (%ld/run)\n"
			   "------------------------------------------\n"
			   "Difference      %20lld bytes\n",
			   fId, fpName, fMaxAllocated,
			   fSizeAllocated , fNumAllocs, (long)(fSizeAllocated / ((fNumAllocs) ? fNumAllocs : 1)),
			   fSizeFreed, fNumFrees, (long)(fSizeFreed / ((fNumFrees) ? fNumFrees : 1)),
			   fAllocated
			  );
	SysLog::WriteToStderr(buf, strlen(buf));
}

MemTracker *Storage::DoMakeMemTracker(const char *name)
{
	return new MemTracker(name);
}

MemTracker *Storage::MakeMemTracker(const char *name)
{
	if  (fgHooks && !fgForceGlobal) {
		return fgHooks->MakeMemTracker(name);
	}
	return Storage::DoMakeMemTracker(name);
}
#endif

#if (defined(__GNUG__)  && __GNUC__ < 3)|| defined (__370__)
#include <new.h>
#elif (defined(__GNUG__)  && __GNUC__ >=3) || (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x500) || (defined(WIN32) && defined(ONLY_STD_IOSTREAM))
#include <new>
#else
void *operator new(size_t size, void *vp)
{
	Assert(size > 0);
	if (vp == 0) {
		return ::calloc(size, sizeof(char));
	}
	return vp;
}
#endif

#if defined(WIN32) && (_MSC_VER >= 1200) && !defined(ONLY_STD_IOSTREAM)// VC6 or greater
void operator delete(void *ptr, void *vp)
{
	if (ptr) {
		::free(ptr);
	}
}
#endif

#if !defined (WIN32)
void operator delete(void *ptr)
{
	if (ptr) {
		::free(ptr);
	}
}
#endif

//---- Storage ------------------------------------------
Allocator *Storage::fgGlobalPool = 0;
StorageHooks *Storage::fgHooks = 0; // exchange this object when MT_Storage is used
bool Storage::fgForceGlobal = false;

Allocator *Storage::Current()
{
	if (fgHooks && !fgForceGlobal) {
		return fgHooks->Current();
	}
	return Storage::DoGlobal();
}
Allocator *Storage::Global()
{
	if (fgHooks && !fgForceGlobal) {
		return fgHooks->Global();
	}
	return Storage::DoGlobal();
}

void Storage::Initialize()
{
	if (fgHooks && !fgForceGlobal) {
		fgHooks->Initialize();
	}
	Allocator *ga = Storage::DoGlobal(); // init here, because of potential race condition
	Storage::DoInitialize();
	// dummy for using ga...
	ga->Free(0);
}

void Storage::Finalize()
{
	if (fgHooks && !fgForceGlobal) {
		fgHooks->Finalize();
	}
	Storage::DoFinalize();
}

void Storage::DoInitialize()
{
#ifdef MEM_DEBUG
	static bool once = true;
	if (once) {
		Storage::DoGloba < l()->PrintStatistic();
		once = false;
	}
#endif
}

void Storage::DoFinalize()
{
#ifdef MEM_DEBUG
	// terminate global allocator
	Storage::DoGlobal()->PrintStatistic();
#endif
}

#ifdef MEM_DEBUG
void Storage::PrintStatistic()
{
	DoGlobal()->PrintStatistic();
}
#endif

Allocator *Storage::DoGlobal()
{
	if (!Storage::fgGlobalPool) {
		Storage::fgGlobalPool = new GlobalAllocator();
	}
	return Storage::fgGlobalPool;
}
//--- Allocator -------------------------------------------------
Allocator::Allocator(long allocatorid) : fAllocatorId(allocatorid), fRefCnt(0) { }
Allocator::~Allocator()
{
	Assert(0 == fRefCnt);
}

void *Allocator::Calloc(int n, size_t size)
{
	void *ret = Alloc(AllocSize(n, size));
	if (ret && n * size > 0) {
		memset(ret, 0, n * size);
	}
	return ret;
}

void *Allocator::Malloc(size_t size)
{
	return Alloc(AllocSize(size, 1));
}

void Allocator::Refresh()
{
	// give the allocator opportunity to reorganize
}

u_long Allocator::AllocSize(u_long n, size_t size)
{
	return (n * size) + MemoryHeader::AlignedSize();
}

void *Allocator::ExtMemStart(void *vp)
{
	if (vp) {
		Assert(((MemoryHeader *)vp)->fMagic == MemoryHeader::gcMagic);
		void *s = (((char *)(vp)) + MemoryHeader::AlignedSize()); // fSize does *not* include header
		// superfluous, Calloc takes care: memset(s, '\0', mh->fSize);
		return s;
	}
	return 0;
}

MemoryHeader *Allocator::RealMemStart(void *vp)
{
	if ( vp ) {
		MemoryHeader *mh = (MemoryHeader *) (((char *)(vp)) - MemoryHeader::AlignedSize());
		if (mh->fMagic == MemoryHeader::gcMagic) {
			return mh;
		}
	}
	return 0;
}

//---- GlobalAllocator ------------------------------------------
GlobalAllocator::GlobalAllocator() : Allocator(13L)
{
#ifdef MEM_DEBUG
	fTracker = Storage::MakeMemTracker("GlobalAllocator");
	fTracker->SetId(fAllocatorId);
#endif
}

GlobalAllocator::~GlobalAllocator()
{
#ifdef MEM_DEBUG
	if (fTracker) {
		delete fTracker;
	}
#endif
}

#ifdef MEM_DEBUG
void GlobalAllocator::ReplaceMemTracker(MemTracker *t)
{
	if (fTracker) {
		t->Init(fTracker);
		delete fTracker;
		fTracker = t;
	}
}

void GlobalAllocator::PrintStatistic()
{
	MemTrackStat((*fTracker));
}

l_long GlobalAllocator::CurrentlyAllocated()
{
	return fTracker->CurrentlyAllocated();
}
#endif

void *GlobalAllocator::Alloc(u_long allocSize)
{
	void *vp = ::malloc(allocSize);
	if (vp) {
		MemoryHeader *mh = new(vp) MemoryHeader(allocSize - MemoryHeader::AlignedSize(),
												MemoryHeader::eUsedNotPooled);

		MemTrackAlloc((*fTracker), mh->fSize);
		return ExtMemStart(mh);
	} else {
		static const char crashmsg[] = "FATAL: GlobalAllocator::Alloc malloc failed. I will crash :-(\n";
		SysLog::WriteToStderr(crashmsg, sizeof(crashmsg));
	}
	return NULL;
}

void  GlobalAllocator::Free(void *vp)
{
	if ( vp ) {
		MemoryHeader *header = RealMemStart(vp);
		if (header && header->fMagic == MemoryHeader::gcMagic) {
			Assert(header->fMagic == MemoryHeader::gcMagic); // should combine magic with state
			Assert(header->fState & MemoryHeader::eUsed);
			MemTrackFree((*fTracker), header->fSize);
			vp = header;
		}
		::free(vp);
	}
}

#ifdef __370__
// need a C-function as the linker cannot resolve C++ here
void finalize()
{
	Storage::Finalize();
}
#endif

bool TestStorageHooks::fgInitialized = false;
void TestStorageHooks::Finalize()
{
}

Allocator *TestStorageHooks::Global()
{
	return 	Storage::DoGlobal();
}

Allocator *TestStorageHooks::Current()
{
	if (fAllocator) {
		return fAllocator;
	}

	return Storage::DoGlobal();
}

void TestStorageHooks::Initialize()
{
	if ( !fgInitialized ) { // need mutex??? not yet, we do not run MT
		fgInitialized = true;
		Storage::DoInitialize();
	}
}

TestStorageHooks::TestStorageHooks(Allocator *wdallocator)
	: fAllocator(wdallocator)
{
}

#ifdef MEM_DEBUG
MemTracker *TestStorageHooks::MakeMemTracker(const char *name)
{
	return new MemTracker(name);
}
#endif
<commit_msg>corrected typo<commit_after>/*
 * Copyright (c) 2005, Peter Sommerlad and IFS Institute for Software at HSR Rapperswil, Switzerland
 * All rights reserved.
 *
 * This library/application is free software; you can redistribute and/or modify it under the terms of
 * the license that is included with this library/application in the file license.txt.
 */

//--- interface include --------------------------------------------------------
#include "ITOStorage.h"

//--- standard modules used ----------------------------------------------------
#include "SysLog.h"
#include "MemHeader.h"

//--- c-library modules used ---------------------------------------------------
#include <stdlib.h>
#include <string.h>

#ifdef __370__
extern "C" void finalize();
#endif

#ifdef MEM_DEBUG
#include <stdio.h>

MemChecker::MemChecker(const char *scope, Allocator *a)
	: fAllocator(a)
	, fSizeAllocated(fAllocator->CurrentlyAllocated())
	, fScope(scope)
{
}

MemChecker::~MemChecker()
{
	TraceDelta("MemChecker.~MemChecker: ");
}

void MemChecker::TraceDelta(const char *message)
{
	l_long delta = CheckDelta();
	// CAUTION: DO NOT PROGRAM AS FOLLOWS !!!
	// IT IS ONLY NECESSARY HERE, BECAUSE THIS CODE MIGHT BE EXECUTED DURING
	// atexit() WHEN PART OF THE C++ ENVIRONMENT IS ALREADY GONE (like cerr and cerr)
	// THIS CODE WILL ONLY BE INCLUDED IN DEBUG VERSIONS SO NO SAFETY CONCERN
	// FOR PRODUCTION CODE. Peter.
	char msgbuf[1024] = {'\0'};
	if (message) {
		SysLog::WriteToStderr( message, strlen(message));
	}
	int bufsz = sprintf(msgbuf, "\nMem Usage change by %.0f bytes in %s\n", (double)delta, fScope);
	SysLog::WriteToStderr( msgbuf, bufsz );
}

l_long MemChecker::CheckDelta()
{
	return fAllocator->CurrentlyAllocated() - fSizeAllocated;
}

//------------- Utilities for Memory Tracking --------------
MemTracker::MemTracker(const char *name)
	: fAllocated(0)
	, fMaxAllocated(0)
	, fNumAllocs(0)
	, fSizeAllocated(0)
	, fNumFrees(0)
	, fSizeFreed(0)
	, fId(-1)
	, fpName(name)
{}

void MemTracker::Init(MemTracker *t)
{
	fAllocated = t->fAllocated;
	fNumAllocs = t->fNumAllocs;
	fSizeAllocated = t->fSizeAllocated;
	fNumFrees = t->fNumFrees;
	fSizeFreed = t->fSizeFreed;
	fId = t->fId;
	fMaxAllocated = t->fMaxAllocated;
}

MemTracker::~MemTracker() {}

void MemTracker::SetId(long id)
{
	fId = id;
}

void MemTracker::TrackAlloc(u_long allocSz)
{
	fAllocated += allocSz;
	fNumAllocs++;
	fSizeAllocated += allocSz;
	fMaxAllocated = itoMAX(fMaxAllocated, fAllocated);
}

void MemTracker::TrackFree(u_long allocSz)
{
	fAllocated -= allocSz;
	fNumFrees++;
	fSizeFreed += allocSz;
}

#if !defined(__SUNPRO_CC) || __SUNPRO_CC < 0x500
extern "C" int write(int, const void *, unsigned);
#endif
void MemTracker::PrintStatistic()
{
	// CAUTION: DO NOT PROGRAM AS FOLLOWS !!!
	// IT IS ONLY NECESSARY HERE, BECAUSE THIS CODE MIGHT BE EXECUTED DURING
	// atexit() WHEN PART OF THE C++ ENVIRONMENT IS ALREADY GONE (like cerr and cerr)
	// THIS CODE WILL ONLY BE INCLUDED IN DEBUG VERSIONS SO NO SAFETY CONCERN
	// FOR PRODUCTION CODE. Peter.
	char buf[2048] ; // safety margin for bytes
	::snprintf(buf, sizeof(buf), "\nAllocator [%02ld] [%s]\n"
			   "Peek Allocated  %20lld bytes\n"
			   "Total Allocated %20lld bytes in %15lld runs (%ld/run)\n"
			   "Total Freed     %20lld bytes in %15lld runs (%ld/run)\n"
			   "------------------------------------------\n"
			   "Difference      %20lld bytes\n",
			   fId, fpName, fMaxAllocated,
			   fSizeAllocated , fNumAllocs, (long)(fSizeAllocated / ((fNumAllocs) ? fNumAllocs : 1)),
			   fSizeFreed, fNumFrees, (long)(fSizeFreed / ((fNumFrees) ? fNumFrees : 1)),
			   fAllocated
			  );
	SysLog::WriteToStderr(buf, strlen(buf));
}

MemTracker *Storage::DoMakeMemTracker(const char *name)
{
	return new MemTracker(name);
}

MemTracker *Storage::MakeMemTracker(const char *name)
{
	if  (fgHooks && !fgForceGlobal) {
		return fgHooks->MakeMemTracker(name);
	}
	return Storage::DoMakeMemTracker(name);
}
#endif

#if (defined(__GNUG__)  && __GNUC__ < 3)|| defined (__370__)
#include <new.h>
#elif (defined(__GNUG__)  && __GNUC__ >=3) || (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x500) || (defined(WIN32) && defined(ONLY_STD_IOSTREAM))
#include <new>
#else
void *operator new(size_t size, void *vp)
{
	Assert(size > 0);
	if (vp == 0) {
		return ::calloc(size, sizeof(char));
	}
	return vp;
}
#endif

#if defined(WIN32) && (_MSC_VER >= 1200) && !defined(ONLY_STD_IOSTREAM)// VC6 or greater
void operator delete(void *ptr, void *vp)
{
	if (ptr) {
		::free(ptr);
	}
}
#endif

#if !defined (WIN32)
void operator delete(void *ptr)
{
	if (ptr) {
		::free(ptr);
	}
}
#endif

//---- Storage ------------------------------------------
Allocator *Storage::fgGlobalPool = 0;
StorageHooks *Storage::fgHooks = 0; // exchange this object when MT_Storage is used
bool Storage::fgForceGlobal = false;

Allocator *Storage::Current()
{
	if (fgHooks && !fgForceGlobal) {
		return fgHooks->Current();
	}
	return Storage::DoGlobal();
}
Allocator *Storage::Global()
{
	if (fgHooks && !fgForceGlobal) {
		return fgHooks->Global();
	}
	return Storage::DoGlobal();
}

void Storage::Initialize()
{
	if (fgHooks && !fgForceGlobal) {
		fgHooks->Initialize();
	}
	Allocator *ga = Storage::DoGlobal(); // init here, because of potential race condition
	Storage::DoInitialize();
	// dummy for using ga...
	ga->Free(0);
}

void Storage::Finalize()
{
	if (fgHooks && !fgForceGlobal) {
		fgHooks->Finalize();
	}
	Storage::DoFinalize();
}

void Storage::DoInitialize()
{
#ifdef MEM_DEBUG
	static bool once = true;
	if (once) {
		Storage::DoGlobal()->PrintStatistic();
		once = false;
	}
#endif
}

void Storage::DoFinalize()
{
#ifdef MEM_DEBUG
	// terminate global allocator
	Storage::DoGlobal()->PrintStatistic();
#endif
}

#ifdef MEM_DEBUG
void Storage::PrintStatistic()
{
	DoGlobal()->PrintStatistic();
}
#endif

Allocator *Storage::DoGlobal()
{
	if (!Storage::fgGlobalPool) {
		Storage::fgGlobalPool = new GlobalAllocator();
	}
	return Storage::fgGlobalPool;
}
//--- Allocator -------------------------------------------------
Allocator::Allocator(long allocatorid) : fAllocatorId(allocatorid), fRefCnt(0) { }
Allocator::~Allocator()
{
	Assert(0 == fRefCnt);
}

void *Allocator::Calloc(int n, size_t size)
{
	void *ret = Alloc(AllocSize(n, size));
	if (ret && n * size > 0) {
		memset(ret, 0, n * size);
	}
	return ret;
}

void *Allocator::Malloc(size_t size)
{
	return Alloc(AllocSize(size, 1));
}

void Allocator::Refresh()
{
	// give the allocator opportunity to reorganize
}

u_long Allocator::AllocSize(u_long n, size_t size)
{
	return (n * size) + MemoryHeader::AlignedSize();
}

void *Allocator::ExtMemStart(void *vp)
{
	if (vp) {
		Assert(((MemoryHeader *)vp)->fMagic == MemoryHeader::gcMagic);
		void *s = (((char *)(vp)) + MemoryHeader::AlignedSize()); // fSize does *not* include header
		// superfluous, Calloc takes care: memset(s, '\0', mh->fSize);
		return s;
	}
	return 0;
}

MemoryHeader *Allocator::RealMemStart(void *vp)
{
	if ( vp ) {
		MemoryHeader *mh = (MemoryHeader *) (((char *)(vp)) - MemoryHeader::AlignedSize());
		if (mh->fMagic == MemoryHeader::gcMagic) {
			return mh;
		}
	}
	return 0;
}

//---- GlobalAllocator ------------------------------------------
GlobalAllocator::GlobalAllocator() : Allocator(13L)
{
#ifdef MEM_DEBUG
	fTracker = Storage::MakeMemTracker("GlobalAllocator");
	fTracker->SetId(fAllocatorId);
#endif
}

GlobalAllocator::~GlobalAllocator()
{
#ifdef MEM_DEBUG
	if (fTracker) {
		delete fTracker;
	}
#endif
}

#ifdef MEM_DEBUG
void GlobalAllocator::ReplaceMemTracker(MemTracker *t)
{
	if (fTracker) {
		t->Init(fTracker);
		delete fTracker;
		fTracker = t;
	}
}

void GlobalAllocator::PrintStatistic()
{
	MemTrackStat((*fTracker));
}

l_long GlobalAllocator::CurrentlyAllocated()
{
	return fTracker->CurrentlyAllocated();
}
#endif

void *GlobalAllocator::Alloc(u_long allocSize)
{
	void *vp = ::malloc(allocSize);
	if (vp) {
		MemoryHeader *mh = new(vp) MemoryHeader(allocSize - MemoryHeader::AlignedSize(),
												MemoryHeader::eUsedNotPooled);

		MemTrackAlloc((*fTracker), mh->fSize);
		return ExtMemStart(mh);
	} else {
		static const char crashmsg[] = "FATAL: GlobalAllocator::Alloc malloc failed. I will crash :-(\n";
		SysLog::WriteToStderr(crashmsg, sizeof(crashmsg));
	}
	return NULL;
}

void  GlobalAllocator::Free(void *vp)
{
	if ( vp ) {
		MemoryHeader *header = RealMemStart(vp);
		if (header && header->fMagic == MemoryHeader::gcMagic) {
			Assert(header->fMagic == MemoryHeader::gcMagic); // should combine magic with state
			Assert(header->fState & MemoryHeader::eUsed);
			MemTrackFree((*fTracker), header->fSize);
			vp = header;
		}
		::free(vp);
	}
}

#ifdef __370__
// need a C-function as the linker cannot resolve C++ here
void finalize()
{
	Storage::Finalize();
}
#endif

bool TestStorageHooks::fgInitialized = false;
void TestStorageHooks::Finalize()
{
}

Allocator *TestStorageHooks::Global()
{
	return 	Storage::DoGlobal();
}

Allocator *TestStorageHooks::Current()
{
	if (fAllocator) {
		return fAllocator;
	}

	return Storage::DoGlobal();
}

void TestStorageHooks::Initialize()
{
	if ( !fgInitialized ) { // need mutex??? not yet, we do not run MT
		fgInitialized = true;
		Storage::DoInitialize();
	}
}

TestStorageHooks::TestStorageHooks(Allocator *wdallocator)
	: fAllocator(wdallocator)
{
}

#ifdef MEM_DEBUG
MemTracker *TestStorageHooks::MakeMemTracker(const char *name)
{
	return new MemTracker(name);
}
#endif
<|endoftext|>


<commit_before>/*
 -----------------------------------------------------------------------------
 This source file is part of OGRE
 (Object-oriented Graphics Rendering Engine)
 For the latest info, see http://www.ogre3d.org/

 Copyright (c) 2000-2009 Torus Knot Software Ltd

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 -----------------------------------------------------------------------------
 */
#include "OgrePlatform.h"
#if OGRE_PLATFORM == OGRE_PLATFORM_SYMBIAN
#include <coecntrl.h>
#endif

#include "SampleBrowser.h"

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#elif OGRE_PLATFORM == OGRE_PLATFORM_IPHONE
#import <UIKit/UIKit.h>
#endif

#if OGRE_PLATFORM != OGRE_PLATFORM_SYMBIAN

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
INT WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, INT)
#else
int main(int argc, char *argv[])
#endif
{
#if OGRE_PLATFORM == OGRE_PLATFORM_IPHONE
	NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
	int retVal = UIApplicationMain(argc, argv, @"UIApplication", @"AppDelegate");
	[pool release];
	return retVal;
#else

	try
	{
		OgreBites::SampleBrowser sb;
		sb.go();
	}
	catch (Ogre::Exception& e)
	{
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
		MessageBoxA(NULL, e.getFullDescription().c_str(), "An exception has occurred!", MB_ICONERROR | MB_TASKMODAL);
#else
		std::cerr << "An exception has occurred: " << e.getFullDescription().c_str() << std::endl;
#endif
	}

#endif
	return 0;
}

#endif // OGRE_PLATFORM != OGRE_PLATFORM_SYMBIAN

#if OGRE_PLATFORM == OGRE_PLATFORM_IPHONE
#   ifdef __OBJC__
@interface AppDelegate : NSObject <UIApplicationDelegate>
{
    NSTimer *mTimer;
    OgreBites::SampleBrowser sb;
}

- (void)go;
- (void)renderOneFrame:(id)sender;

@property (retain) NSTimer *mTimer;

@end

@implementation AppDelegate

@synthesize mTimer;

- (void)go {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    try {
        sb.initApp();

        mTimer = [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)(1.0f / 60.0f)
                                                  target:self
                                                selector:@selector(renderOneFrame:)
                                                userInfo:nil
                                                 repeats:YES];
    } catch( Ogre::Exception& e ) {
        std::cerr << "An exception has occurred: " <<
        e.getFullDescription().c_str() << std::endl;
    }

    [pool release];
}

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    // Hide the status bar
    [[UIApplication sharedApplication] setStatusBarHidden:YES];

    [self go];
}

- (void)renderOneFrame:(id)sender
{
    [sb.mGestureView becomeFirstResponder];

    Root::getSingleton().renderOneFrame((Real)[mTimer timeInterval]);
}

- (void)applicationWillTerminate:(UIApplication *)application {
    Ogre::Root::getSingleton().queueEndRendering();
}

//- (void)applicationWillResignActive:(UIApplication *)application
//{
//    // Pause FrameListeners and rendering
//}
//
//- (void)applicationDidBecomeActive:(UIApplication *)application
//{
//    // Resume FrameListeners and rendering
//}

- (void)dealloc {
    [mTimer release];

    [super dealloc];
}

@end
#   endif

#endif
<commit_msg>iPhone: Shutdown the SampleBrowser properly<commit_after>/*
 -----------------------------------------------------------------------------
 This source file is part of OGRE
 (Object-oriented Graphics Rendering Engine)
 For the latest info, see http://www.ogre3d.org/

 Copyright (c) 2000-2009 Torus Knot Software Ltd

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 -----------------------------------------------------------------------------
 */
#include "OgrePlatform.h"
#if OGRE_PLATFORM == OGRE_PLATFORM_SYMBIAN
#include <coecntrl.h>
#endif

#include "SampleBrowser.h"

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#elif OGRE_PLATFORM == OGRE_PLATFORM_IPHONE
#import <UIKit/UIKit.h>
#endif

#if OGRE_PLATFORM != OGRE_PLATFORM_SYMBIAN

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
INT WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, INT)
#else
int main(int argc, char *argv[])
#endif
{
#if OGRE_PLATFORM == OGRE_PLATFORM_IPHONE
	NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
	int retVal = UIApplicationMain(argc, argv, @"UIApplication", @"AppDelegate");
	[pool release];
	return retVal;
#else

	try
	{
		OgreBites::SampleBrowser sb;
		sb.go();
	}
	catch (Ogre::Exception& e)
	{
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
		MessageBoxA(NULL, e.getFullDescription().c_str(), "An exception has occurred!", MB_ICONERROR | MB_TASKMODAL);
#else
		std::cerr << "An exception has occurred: " << e.getFullDescription().c_str() << std::endl;
#endif
	}

#endif
	return 0;
}

#endif // OGRE_PLATFORM != OGRE_PLATFORM_SYMBIAN

#if OGRE_PLATFORM == OGRE_PLATFORM_IPHONE
#   ifdef __OBJC__
@interface AppDelegate : NSObject <UIApplicationDelegate>
{
    NSTimer *mTimer;
    OgreBites::SampleBrowser sb;
}

- (void)go;
- (void)renderOneFrame:(id)sender;

@property (retain) NSTimer *mTimer;

@end

@implementation AppDelegate

@synthesize mTimer;

- (void)go {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    try {
        sb.initApp();

        mTimer = [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)(1.0f / 60.0f)
                                                  target:self
                                                selector:@selector(renderOneFrame:)
                                                userInfo:nil
                                                 repeats:YES];
    } catch( Ogre::Exception& e ) {
        std::cerr << "An exception has occurred: " <<
        e.getFullDescription().c_str() << std::endl;
    }

    [pool release];
}

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    // Hide the status bar
    [[UIApplication sharedApplication] setStatusBarHidden:YES];

    [self go];
}

- (void)renderOneFrame:(id)sender
{
    [sb.mGestureView becomeFirstResponder];

    Root::getSingleton().renderOneFrame((Real)[mTimer timeInterval]);
}

- (void)applicationWillTerminate:(UIApplication *)application {
    sb.closeApp();
}

- (void)dealloc {
    [mTimer release];

    [super dealloc];
}

@end
#   endif

#endif
<|endoftext|>


<commit_before>/**
 *  For conditions of distribution and use, see copyright notice in license.txt
 *
 *  @file   AssetsWindow.cpp
 *  @brief
 *
 *          Detailed.
 */

#include "StableHeaders.h"
#include "AssetsWindow.h"

#include "Framework.h"
#include "AssetAPI.h"
#include "IAsset.h"

AssetsWindow::AssetsWindow(Foundation::Framework *fw) :
    framework(fw)
{
    setAttribute(Qt::WA_DeleteOnClose);
    setWindowTitle(tr("Assets"));
    resize(300, 400);

    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->setContentsMargins(5, 5, 5, 5);
    setLayout(layout);

//    QLabel *entityLabel = new QLabel(tr("The following entities will be created:"));

    treeWidget = new QTreeWidget;
    treeWidget->setHeaderHidden(true);
//    treeWidget ->setColumnCount(3);
//    treeWidget ->setHeaderLabels(QStringList(QStringList() << tr("Create") << tr("ID") << tr("Name")));
//    treeWidget ->header()->setResizeMode(QHeaderView::ResizeToContents);

    layout->addWidget(treeWidget);

    PopulateTreeWidget();
}

AssetsWindow::~AssetsWindow()
{
    // Disable ResizeToContents, Qt goes sometimes into eternal loop after
    // ~AddContentWindow() if we have lots (hudreds or thousands) of items.
    treeWidget->header()->setResizeMode(QHeaderView::Interactive);

    QTreeWidgetItemIterator it(treeWidget);
    while(*it)
    {
        QTreeWidgetItem *item = *it;
        SAFE_DELETE(item);
        ++it;
    }
}

void AssetsWindow::PopulateTreeWidget()
{
    std::pair<QString, AssetPtr> pair;
    foreach(pair, framework->Asset()->GetAllAssets())
    {
        QTreeWidgetItem *item = new QTreeWidgetItem;
        item->setText(0, pair.first);
        treeWidget->addTopLevelItem(item);
    }
}
<commit_msg>Show asset storages as top-level items in Assets window tree widget and add assets as children to them.<commit_after>/**
 *  For conditions of distribution and use, see copyright notice in license.txt
 *
 *  @file   AssetsWindow.cpp
 *  @brief
 *
 *          Detailed.
 */

#include "StableHeaders.h"
#include "AssetsWindow.h"
#include "DebugOperatorNew.h"

#include "Framework.h"
#include "AssetAPI.h"
#include "IAsset.h"
#include "IAssetStorage.h"

#include "MemoryLeakCheck.h"

AssetsWindow::AssetsWindow(Foundation::Framework *fw) :
    framework(fw)
{
    setAttribute(Qt::WA_DeleteOnClose);
    setWindowTitle(tr("Assets"));
    resize(300, 400);

    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->setContentsMargins(5, 5, 5, 5);
    setLayout(layout);

//    QLabel *entityLabel = new QLabel(tr("The following entities will be created:"));

    treeWidget = new QTreeWidget;
    treeWidget->setHeaderHidden(true);
//    treeWidget ->setColumnCount(3);
//    treeWidget ->setHeaderLabels(QStringList(QStringList() << tr("Create") << tr("ID") << tr("Name")));
//    treeWidget ->header()->setResizeMode(QHeaderView::ResizeToContents);

    layout->addWidget(treeWidget);

    PopulateTreeWidget();
}

AssetsWindow::~AssetsWindow()
{
    // Disable ResizeToContents, Qt goes sometimes into eternal loop after
    // ~AddContentWindow() if we have lots (hudreds or thousands) of items.
    treeWidget->header()->setResizeMode(QHeaderView::Interactive);

    QTreeWidgetItemIterator it(treeWidget);
    while(*it)
    {
        QTreeWidgetItem *item = *it;
        SAFE_DELETE(item);
        ++it;
    }
}

void AssetsWindow::PopulateTreeWidget()
{
    foreach(AssetStoragePtr storage, framework->Asset()->GetAssetStorages())
    {
        QTreeWidgetItem *item = new QTreeWidgetItem;
        item->setText(0, storage->Name());
        treeWidget->addTopLevelItem(item);
    }

    // Create "No provider" for assets without storage.
    QTreeWidgetItem *noProviderItem = new QTreeWidgetItem;
    noProviderItem->setText(0, tr("No provider"));
    treeWidget->addTopLevelItem(noProviderItem);

    std::pair<QString, AssetPtr> pair;
    foreach(pair, framework->Asset()->GetAllAssets())
    {
        QTreeWidgetItem *item = new QTreeWidgetItem;
        item->setText(0, pair.first);

        AssetStoragePtr storage = pair.second->GetAssetStorage();
        bool storageFound = false;
        if (storage)
            for (int i = 0; i < treeWidget->topLevelItemCount(); ++i)
            {
                QTreeWidgetItem *storageItem = treeWidget->topLevelItem(i);
                if (storageItem->text(0) == storage->Name())
                {
                    storageItem->addChild(item);
                    storageFound = true;
                    break;
                }
            }

        if (!storageFound)
            noProviderItem->addChild(item);
    }

    if (noProviderItem->childCount() == 0)
        SAFE_DELETE(noProviderItem);
}
<|endoftext|>


<commit_before>// LoadModel.cpp
// author: Frank C. Anderson
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

#include <string>
#include <iostream>
#include <OpenSim/Tools/IO.h>
#include "LoadModel.h"
#include <OpenSim/Simulation/SIMM/ActuatorSet.h>
#include "ContactForceSet.h"

#ifdef __linux__
// Current solution for linux compatibility is to remap LoadLibrary/GetProcAddress to dlopen/dlsym
// using macros.  Also use macros for portable handles.
#include <dlfcn.h>
#define PORTABLE_HMODULE void *
#define PORTABLE_HINSTANCE void *
#define WINAPI
#define LoadLibrary(name) dlopen(name, RTLD_LAZY)
#define GetProcAddress(handle, proc) dlsym(handle, proc)
#else
#define PORTABLE_HMODULE HMODULE
#define PORTABLE_HINSTANCE HINSTANCE
#endif

using namespace OpenSim;
using namespace std;

extern "C" {

// Type definition for the CreateModel() function
// This is necessary to create a pointer that can properly point to the
// CreateModel() function.
typedef OpenSim::AbstractModel* (*CREATEMODEL)();
typedef OpenSim::AbstractModel* (*CREATEMODEL_FILE)(const string &);
typedef OpenSim::AbstractModel* (*CREATEMODEL_ActuatorsContacts)(OpenSim::ActuatorSet*,OpenSim::ContactForceSet*);
typedef OpenSim::AbstractModel* (*CREATEMODEL_ParamsActuatorsContacts)(const string&,OpenSim::ActuatorSet*,OpenSim::ContactForceSet*);

}

//_____________________________________________________________________________
/**
 * A wrapper around Window's LoadLibrary that implements library naming
 * convention and loading policy on windows which follows:
 * If you're loading rdSimulation_D and other libraries that do not have a
 * trailing _D an _D is appended to the library file name.  If loading of that
 * fails, we revert to using the non _D file instead, if that fails we give
 * error and return 0. A reciprocal treatment for release libraries is
 * implemented. I tried to keep this function in the same file to try
 * to localize platform specific code. -Ayman
 *
 * @param lpLibFileName Name of the library without either the .lib or .dll
 * extension.
 * @return Pointer to the loaded library, NULL on error.
 */

RDSIMULATION_API
PORTABLE_HMODULE
WINAPI
LoadOpenSimLibrary(const char *lpLibFileName)
{
	string libraryExtension;
#ifdef __linux__
	libraryExtension=".so";
#endif
	string fixedLibFileName = IO::FixSlashesInFilePath(lpLibFileName);
	string actualLibFileName(fixedLibFileName+libraryExtension);
	string debugSuffix="_d";
	char *locationOf_D=strstr(fixedLibFileName.c_str(), debugSuffix.c_str());
	bool hasDebugSuffix = (locationOf_D!= 0) && (strcmp(locationOf_D, debugSuffix.c_str())==0);

	PORTABLE_HINSTANCE libraryHandle = NULL;
#ifdef _DEBUG
	// NO _D SUFFIX
	// if library name has no trailing _D try to append it and load
	// find locaion of _D in lpLibFileName and make sure it's trailing
	if (!hasDebugSuffix) {
		// Append _D to lpLibFileName;
		cout << "WARNING: SUSPECT LOADING RELEASE LIB INTO DEBUG Simulation library." << endl;
		cout << "Trying to load a debug version ..." << endl;
		actualLibFileName = fixedLibFileName+debugSuffix+libraryExtension;
		// if that fails we'll try the one with no _D
		if ((libraryHandle = LoadLibrary(actualLibFileName.c_str()))==0){
			cout << "Loading of Debug library " << actualLibFileName << " Failed. Trying " << fixedLibFileName << endl;
			// library with _D loading failed, try non _D version
			actualLibFileName = fixedLibFileName+libraryExtension;
			if ((libraryHandle = LoadLibrary(actualLibFileName.c_str()))!=0){
				cout << "Loaded library " << actualLibFileName << endl;
			}
			else
				cout << "Failed to load either debug or release library " << actualLibFileName << endl;
		}
		else
			cout << "Loaded library " << actualLibFileName << endl;

	// HAS _D SUFFIX
	} else {
		libraryHandle = LoadLibrary(actualLibFileName.c_str());
	}

#else
	// HAS _D SUFFIX
	// Here we're in release mode, highly unlikely to have a trailing _D intentionally!
	if (hasDebugSuffix){

		// try stripping the trailing _D first
		cout << "WARNING: SUSPECT LOADING DEBUG LIB INTO RELEASE rdSimulation";
		cout << "Trying ";
		if ((libraryHandle = LoadLibrary(actualLibFileName.c_str()))==0){
			*locationOf_D = '\0';	// Strip trailing _D and retry (can we do that with const!)
			if ((libraryHandle = LoadLibrary(actualLibFileName.c_str()))!=0){
				cout << "Loaded library " << actualLibFileName << endl;
			}
			else
				cout << "Failed to load either debug or release library " << actualLibFileName << endl;

		}
		else
			cout << "Loaded library " << actualLibFileName << endl;

	// NO _D SUFFIX
	} else {
		libraryHandle = LoadLibrary(actualLibFileName.c_str());
	}
#endif
	return libraryHandle;
}

//_____________________________________________________________________________
/**
 * A function for loading libraries specified in a command line.
 * LoadOpenSimLibrary() is used to load each library.
 *
 * @param argc Number of command-line arguments.
 * @param argv Array of command-line arguments.
 * @see LoadOpenSimLibrary()
 */

RDSIMULATION_API void
LoadOpenSimLibraries(int argc,char **argv)
{
	int i;
	string option,value;
	PORTABLE_HINSTANCE library;
	for(i=0;i<argc;i++) {
		if(argv[i][0]!='-') continue;
		option = argv[i];
		if((i+1)>=argc) break;  // no more arguments.
		if((option=="-Library")||(option=="-L")) {
			string libraryName = argv[i+1];
			library = LoadOpenSimLibrary(libraryName.c_str());
			if(library==NULL) {
				cout<<"ERROR- library "<<value<<" could not be loaded.\n\n";
			} else {
				i++;
			}
		}
	}
}

//_____________________________________________________________________________
/**
 * Load and create a model from a dynamically loaded library (DLL).
 *
 * @param aModelLibraryName Name of the model DLL (e.g., rdBlock_D).  Do not
 * include the library (.lib) or DLL (.dll) extension in the name of the
 * model library.
 * @param aModelFileName Name of the model xml file (optional).
 * @return Pointer to an intance of the model, NULL if no model was created.
 */
RDSIMULATION_API AbstractModel* LoadModel(const string &aModelLibraryName, const string &aModelFileName)
{
	// LOAD MODEL LIBRARY
	PORTABLE_HINSTANCE modelLibrary = LoadOpenSimLibrary(aModelLibraryName.c_str());
	if(modelLibrary==NULL) {
		cout<<"ERROR- library for model "<<aModelLibraryName<<" could not be loaded.\n\n";
		return(NULL);
	}

	AbstractModel *model=NULL;
	if(aModelFileName!="") {
		// GET POINTER TO THE CreateModel_File() FUNCTION
		CREATEMODEL_FILE createModelFunction = (CREATEMODEL_FILE)GetProcAddress(modelLibrary,"CreateModel_File");
		if(createModelFunction==NULL) {
			cout<<"ERROR- function CreateModel_File() was not found in library "<<aModelLibraryName<<".\n\n";
			return(NULL);
		}

		// CREATE THE MODEL
		model = createModelFunction(aModelFileName);
		if(model==NULL) {
			cout<<"ERROR- model "<<aModelLibraryName<<" was not created.\n\n";
			return(NULL);
		}
	} else {
		// GET POINTER TO THE CreateModel() FUNCTION
		CREATEMODEL createModelFunction = (CREATEMODEL)GetProcAddress(modelLibrary,"CreateModel");
		if(createModelFunction==NULL) {
			cout<<"ERROR- function CreateModel() was not found in library "<<aModelLibraryName<<".\n\n";
			return(NULL);
		}

		// CALL THE CreatModel() FUNCTION
		model = createModelFunction();
		if(model==NULL) {
			cout<<"ERROR- model "<<aModelLibraryName<<" was not created.\n\n";
			return(NULL);
		}
	}

	return(model);
}
<commit_msg>In linux, use dlerror to print out useful error message to explain why library could not be loaded<commit_after>// LoadModel.cpp
// author: Frank C. Anderson
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

#include <string>
#include <iostream>
#include <OpenSim/Tools/IO.h>
#include "LoadModel.h"
#include <OpenSim/Simulation/SIMM/ActuatorSet.h>
#include "ContactForceSet.h"

#ifdef __linux__
// Current solution for linux compatibility is to remap LoadLibrary/GetProcAddress to dlopen/dlsym
// using macros.  Also use macros for portable handles.
#include <dlfcn.h>
#define PORTABLE_HMODULE void *
#define PORTABLE_HINSTANCE void *
#define WINAPI
#define LoadLibrary(name) dlopen(name, RTLD_LAZY)
#define GetProcAddress(handle, proc) dlsym(handle, proc)
#define LoadLibraryError() { char* err=dlerror(); if(err) cout<<"dlerror: "<<err<<endl; }
#else
#define PORTABLE_HMODULE HMODULE
#define PORTABLE_HINSTANCE HINSTANCE
#define LoadLibraryError()
#endif

using namespace OpenSim;
using namespace std;

extern "C" {

// Type definition for the CreateModel() function
// This is necessary to create a pointer that can properly point to the
// CreateModel() function.
typedef OpenSim::AbstractModel* (*CREATEMODEL)();
typedef OpenSim::AbstractModel* (*CREATEMODEL_FILE)(const string &);
typedef OpenSim::AbstractModel* (*CREATEMODEL_ActuatorsContacts)(OpenSim::ActuatorSet*,OpenSim::ContactForceSet*);
typedef OpenSim::AbstractModel* (*CREATEMODEL_ParamsActuatorsContacts)(const string&,OpenSim::ActuatorSet*,OpenSim::ContactForceSet*);

}

//_____________________________________________________________________________
/**
 * A wrapper around Window's LoadLibrary that implements library naming
 * convention and loading policy on windows which follows:
 * If you're loading rdSimulation_D and other libraries that do not have a
 * trailing _D an _D is appended to the library file name.  If loading of that
 * fails, we revert to using the non _D file instead, if that fails we give
 * error and return 0. A reciprocal treatment for release libraries is
 * implemented. I tried to keep this function in the same file to try
 * to localize platform specific code. -Ayman
 *
 * @param lpLibFileName Name of the library without either the .lib or .dll
 * extension.
 * @return Pointer to the loaded library, NULL on error.
 */

RDSIMULATION_API
PORTABLE_HMODULE
WINAPI
LoadOpenSimLibrary(const char *lpLibFileName)
{
	string libraryExtension;
#ifdef __linux__
	libraryExtension=".so";
#endif
	string fixedLibFileName = IO::FixSlashesInFilePath(lpLibFileName);
	string actualLibFileName(fixedLibFileName+libraryExtension);
	string debugSuffix="_d";
	char *locationOf_D=strstr(fixedLibFileName.c_str(), debugSuffix.c_str());
	bool hasDebugSuffix = (locationOf_D!= 0) && (strcmp(locationOf_D, debugSuffix.c_str())==0);

	PORTABLE_HINSTANCE libraryHandle = NULL;
#ifdef _DEBUG
	// NO _D SUFFIX
	// if library name has no trailing _D try to append it and load
	// find locaion of _D in lpLibFileName and make sure it's trailing
	if (!hasDebugSuffix) {
		// Append _D to lpLibFileName;
		cout << "WARNING: SUSPECT LOADING RELEASE LIB INTO DEBUG Simulation library." << endl;
		cout << "Trying to load a debug version ..." << endl;
		actualLibFileName = fixedLibFileName+debugSuffix+libraryExtension;
		// if that fails we'll try the one with no _D
		if ((libraryHandle = LoadLibrary(actualLibFileName.c_str()))==0){
			cout << "Loading of Debug library " << actualLibFileName << " Failed. Trying " << fixedLibFileName << endl;
			LoadLibraryError();
			// library with _D loading failed, try non _D version
			actualLibFileName = fixedLibFileName+libraryExtension;
			if ((libraryHandle = LoadLibrary(actualLibFileName.c_str()))!=0){
				cout << "Loaded library " << actualLibFileName << endl;
			}
			else {
				cout << "Failed to load either debug or release library " << actualLibFileName << endl;
				LoadLibraryError();
			}
		}
		else
			cout << "Loaded library " << actualLibFileName << endl;

	// HAS _D SUFFIX
	} else {
		libraryHandle = LoadLibrary(actualLibFileName.c_str());
	}

#else
	// HAS _D SUFFIX
	// Here we're in release mode, highly unlikely to have a trailing _D intentionally!
	if (hasDebugSuffix){

		// try stripping the trailing _D first
		cout << "WARNING: SUSPECT LOADING DEBUG LIB INTO RELEASE rdSimulation";
		cout << "Trying ";
		if ((libraryHandle = LoadLibrary(actualLibFileName.c_str()))==0){
			*locationOf_D = '\0';	// Strip trailing _D and retry (can we do that with const!)
			if ((libraryHandle = LoadLibrary(actualLibFileName.c_str()))!=0){
				cout << "Loaded library " << actualLibFileName << endl;
			}
			else {
				cout << "Failed to load either debug or release library " << actualLibFileName << endl;
				LoadLibraryError();
			}

		}
		else
			cout << "Loaded library " << actualLibFileName << endl;

	// NO _D SUFFIX
	} else {
		libraryHandle = LoadLibrary(actualLibFileName.c_str());
	}
#endif
	return libraryHandle;
}

//_____________________________________________________________________________
/**
 * A function for loading libraries specified in a command line.
 * LoadOpenSimLibrary() is used to load each library.
 *
 * @param argc Number of command-line arguments.
 * @param argv Array of command-line arguments.
 * @see LoadOpenSimLibrary()
 */

RDSIMULATION_API void
LoadOpenSimLibraries(int argc,char **argv)
{
	int i;
	string option,value;
	PORTABLE_HINSTANCE library;
	for(i=0;i<argc;i++) {
		if(argv[i][0]!='-') continue;
		option = argv[i];
		if((i+1)>=argc) break;  // no more arguments.
		if((option=="-Library")||(option=="-L")) {
			string libraryName = argv[i+1];
			library = LoadOpenSimLibrary(libraryName.c_str());
			if(library==NULL) {
				cout<<"ERROR- library "<<value<<" could not be loaded.\n\n";
			} else {
				i++;
			}
		}
	}
}

//_____________________________________________________________________________
/**
 * Load and create a model from a dynamically loaded library (DLL).
 *
 * @param aModelLibraryName Name of the model DLL (e.g., rdBlock_D).  Do not
 * include the library (.lib) or DLL (.dll) extension in the name of the
 * model library.
 * @param aModelFileName Name of the model xml file (optional).
 * @return Pointer to an intance of the model, NULL if no model was created.
 */
RDSIMULATION_API AbstractModel* LoadModel(const string &aModelLibraryName, const string &aModelFileName)
{
	// LOAD MODEL LIBRARY
	PORTABLE_HINSTANCE modelLibrary = LoadOpenSimLibrary(aModelLibraryName.c_str());
	if(modelLibrary==NULL) {
		cout<<"ERROR- library for model "<<aModelLibraryName<<" could not be loaded.\n\n";
		return(NULL);
	}

	AbstractModel *model=NULL;
	if(aModelFileName!="") {
		// GET POINTER TO THE CreateModel_File() FUNCTION
		CREATEMODEL_FILE createModelFunction = (CREATEMODEL_FILE)GetProcAddress(modelLibrary,"CreateModel_File");
		if(createModelFunction==NULL) {
			cout<<"ERROR- function CreateModel_File() was not found in library "<<aModelLibraryName<<".\n\n";
			return(NULL);
		}

		// CREATE THE MODEL
		model = createModelFunction(aModelFileName);
		if(model==NULL) {
			cout<<"ERROR- model "<<aModelLibraryName<<" was not created.\n\n";
			return(NULL);
		}
	} else {
		// GET POINTER TO THE CreateModel() FUNCTION
		CREATEMODEL createModelFunction = (CREATEMODEL)GetProcAddress(modelLibrary,"CreateModel");
		if(createModelFunction==NULL) {
			cout<<"ERROR- function CreateModel() was not found in library "<<aModelLibraryName<<".\n\n";
			return(NULL);
		}

		// CALL THE CreatModel() FUNCTION
		model = createModelFunction();
		if(model==NULL) {
			cout<<"ERROR- model "<<aModelLibraryName<<" was not created.\n\n";
			return(NULL);
		}
	}

	return(model);
}
<|endoftext|>


<commit_before>//
//  ArrayBuilder.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 17/11/2016.
//  Copyright © 2016 Thomas Harte. All rights reserved.
//

#ifndef ArrayBuilder_hpp
#define ArrayBuilder_hpp

#include <vector>
#include <mutex>
#include <memory>

#include "OpenGL.hpp"

namespace Outputs {
namespace CRT {

/*!
	Owns two array buffers, an 'input' and an 'output' and vends pointers to allow an owner to write provisional data into those
	plus a flush function to lock provisional data into place. Also supplies a submit method to transfer all currently locked
	data to the GPU and bind_input/output methods to bind the internal buffers.

	It is safe for one thread to communicate via the get_*_storage and flush inputs asynchronously from another that is making
	use of the bind and submit outputs.
*/
class ArrayBuilder {
	public:
		/// Creates an instance of ArrayBuilder with @c output_size bytes of storage for the output buffer and
		/// @c input_size bytes of storage for the input buffer.
		ArrayBuilder(size_t input_size, size_t output_size);

		/// Creates an instance of ArrayBuilder with @c output_size bytes of storage for the output buffer and
		/// @c input_size bytes of storage for the input buffer that, rather than using OpenGL, will submit data
		/// to the @c submission_function. [Teleological: this is provided as a testing hook.]
		ArrayBuilder(size_t input_size, size_t output_size, std::function<void(bool is_input, uint8_t *, size_t)> submission_function);

		/// Attempts to add @c size bytes
		uint8_t *get_input_storage(size_t size);
		uint8_t *reget_input_storage(size_t &size);

		uint8_t *get_output_storage(size_t size);
		uint8_t *reget_output_storage(size_t &size);

		bool is_full();
		void flush();

		void bind_input();
		void bind_output();

		struct Submission {
			size_t input_size, output_size;
		};
		Submission submit();

	private:
		struct Buffer {
			Buffer(size_t size, std::function<void(bool is_input, uint8_t *, size_t)> submission_function);
			~Buffer();

			std::vector<uint8_t> data;
			size_t allocated_data;
			size_t flushed_data;
			size_t submitted_data;
			bool is_full, was_reset;
			GLuint buffer;

			uint8_t *get_storage(size_t size);
			uint8_t *reget_storage(size_t &size);

			void flush();
			size_t submit(bool is_input);
			void bind();
			void reset();
			std::function<void(bool is_input, uint8_t *, size_t)> submission_function_;
		} output_, input_;
		uint8_t *get_storage(size_t size, Buffer &buffer);

		std::mutex buffer_mutex_;
		bool is_full_;
		;
};

}
}

#endif /* ArrayBuilder_hpp */
<commit_msg>This thing has clearly becoma a real class.<commit_after>//
//  ArrayBuilder.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 17/11/2016.
//  Copyright © 2016 Thomas Harte. All rights reserved.
//

#ifndef ArrayBuilder_hpp
#define ArrayBuilder_hpp

#include <vector>
#include <mutex>
#include <memory>

#include "OpenGL.hpp"

namespace Outputs {
namespace CRT {

/*!
	Owns two array buffers, an 'input' and an 'output' and vends pointers to allow an owner to write provisional data into those
	plus a flush function to lock provisional data into place. Also supplies a submit method to transfer all currently locked
	data to the GPU and bind_input/output methods to bind the internal buffers.

	It is safe for one thread to communicate via the get_*_storage and flush inputs asynchronously from another that is making
	use of the bind and submit outputs.
*/
class ArrayBuilder {
	public:
		/// Creates an instance of ArrayBuilder with @c output_size bytes of storage for the output buffer and
		/// @c input_size bytes of storage for the input buffer.
		ArrayBuilder(size_t input_size, size_t output_size);

		/// Creates an instance of ArrayBuilder with @c output_size bytes of storage for the output buffer and
		/// @c input_size bytes of storage for the input buffer that, rather than using OpenGL, will submit data
		/// to the @c submission_function. [Teleological: this is provided as a testing hook.]
		ArrayBuilder(size_t input_size, size_t output_size, std::function<void(bool is_input, uint8_t *, size_t)> submission_function);

		/// Attempts to add @c size bytes
		uint8_t *get_input_storage(size_t size);
		uint8_t *reget_input_storage(size_t &size);

		uint8_t *get_output_storage(size_t size);
		uint8_t *reget_output_storage(size_t &size);

		bool is_full();
		void flush();

		void bind_input();
		void bind_output();

		struct Submission {
			size_t input_size, output_size;
		};
		Submission submit();

	private:
		class Buffer {
			public:
				Buffer(size_t size, std::function<void(bool is_input, uint8_t *, size_t)> submission_function);
				~Buffer();

				uint8_t *get_storage(size_t size);
				uint8_t *reget_storage(size_t &size);

				void flush();
				size_t submit(bool is_input);
				void bind();
				void reset();

			private:
				bool is_full, was_reset;
				GLuint buffer;
				std::function<void(bool is_input, uint8_t *, size_t)> submission_function_;
				std::vector<uint8_t> data;
				size_t allocated_data;
				size_t flushed_data;
				size_t submitted_data;
		} output_, input_;
		uint8_t *get_storage(size_t size, Buffer &buffer);

		std::mutex buffer_mutex_;
		bool is_full_;
		;
};

}
}

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


<commit_before>//=====================================================================//
/*! @file
    @brief  RX65N SIDE
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/renesas.hpp"
#include "common/fixed_fifo.hpp"
#include "common/sci_io.hpp"
#include "common/format.hpp"
#include "common/command.hpp"
#include "common/spi_io2.hpp"
#include "common/sdc_man.hpp"
#include "common/tpu_io.hpp"
#include "sound/sound_out.hpp"

#include "chip/FAMIPAD.hpp"

#include "spinv.hpp"

namespace {

	typedef device::PORT<device::PORT7, device::bitpos::B0> LED;
// オーディオの D/A として使用
//	typedef device::PORT<device::PORT0, device::bitpos::B5> SW2;

	// Famicon PAD (CMOS 4021B Shift Register)
	// 電源は、微小なので、接続を簡単に行う為、ポートを使う
	typedef device::PORT<device::PORT6, device::bitpos::B0> PAD_VCC;
	typedef device::PORT<device::PORT6, device::bitpos::B1> PAD_GND;
	typedef device::PORT<device::PORT6, device::bitpos::B2> PAD_P_S;
	typedef device::PORT<device::PORT6, device::bitpos::B5> PAD_CLK;
	typedef device::PORT<device::PORT7, device::bitpos::B3> PAD_OUT;
	typedef chip::FAMIPAD<PAD_P_S, PAD_CLK, PAD_OUT> FAMIPAD;
	FAMIPAD		famipad_;

	typedef device::system_io<12000000> SYSTEM_IO;

	typedef utils::fixed_fifo<char, 512>  RECV_BUFF;
	typedef utils::fixed_fifo<char, 1024> SEND_BUFF;
	typedef device::sci_io<device::SCI9, RECV_BUFF, SEND_BUFF> SCI;
	SCI			sci_;

	typedef device::PORT<device::PORT6, device::bitpos::B3> LCD_DISP;
	typedef device::PORT<device::PORT6, device::bitpos::B6> LCD_LIGHT;
	static const int16_t LCD_X = 480;
	static const int16_t LCD_Y = 272;
	static void* LCD_ORG = reinterpret_cast<void*>(0x00000100);
	static const auto PIX = graphics::pixel::TYPE::RGB565;
	typedef device::glcdc_io<device::GLCDC, LCD_X, LCD_Y, PIX> GLCDC_IO;
	GLCDC_IO	glcdc_io_(nullptr, LCD_ORG);

	// カード電源制御は使わない場合、「device::NULL_PORT」を指定する。
//	typedef device::PORT<device::PORT6, device::bitpos::B4> SDC_POWER;
	typedef device::NULL_PORT SDC_POWER;

#ifdef SDHI_IF
	// RX65N Envision Kit の SDHI ポートは、候補３になっている
	typedef fatfs::sdhi_io<device::SDHI, SDC_POWER, device::port_map::option::THIRD> SDHI;
	SDHI		sdh_;
#else
	// Soft SDC 用　SPI 定義（SPI）
	typedef device::PORT<device::PORT2, device::bitpos::B2> MISO;  // DAT0
	typedef device::PORT<device::PORT2, device::bitpos::B0> MOSI;  // CMD
	typedef device::PORT<device::PORT2, device::bitpos::B1> SPCK;  // CLK

	typedef device::spi_io2<MISO, MOSI, SPCK> SPI;  ///< Soft SPI 定義

	SPI			spi_;

	typedef device::PORT<device::PORT1, device::bitpos::B7> SDC_SELECT;  // DAT3 カード選択信号
	typedef device::PORT<device::PORT2, device::bitpos::B5> SDC_DETECT;  // CD   カード検出

	typedef fatfs::mmc_io<SPI, SDC_SELECT, SDC_POWER, SDC_DETECT> MMC;   // ハードウェアー定義

	MMC			sdh_(spi_, 35000000);
#endif
	typedef utils::sdc_man SDC;
	SDC			sdc_;

	volatile uint32_t	wpos_;

	/// DMAC 終了割り込み
	class dmac_term_task {
	public:
		void operator() () {
			device::DMAC0::DMCNT.DTE = 1;  // DMA を再スタート
			wpos_ = 0;
		}
	};

	typedef device::dmac_mgr<device::DMAC0, dmac_term_task> DMAC_MGR;
	DMAC_MGR	dmac_mgr_;

	uint32_t get_wave_pos_() { return (dmac_mgr_.get_count() & 0x3ff) ^ 0x3ff; }

	typedef device::R12DA DAC;
	typedef device::dac_out<DAC> DAC_OUT;
	DAC_OUT		dac_out_;

	typedef utils::sound_out<1024, 256> SOUND_OUT;
	SOUND_OUT	sound_out_;

	class tpu_task {
	public:
		void operator() () {
			uint32_t tmp = wpos_;
			++wpos_;
			if((tmp ^ wpos_) & 64) {
				sound_out_.service(64);
			}
		}
	};

	typedef device::tpu_io<device::TPU0, tpu_task> TPU0;
	TPU0		tpu0_;

	typedef emu::spinv SPINV;
	SPINV		spinv_;

	utils::command<256> cmd_;

	bool check_mount_() {
		auto f = sdc_.get_mount();
		if(!f) {
			utils::format("SD card not mount.\n");
		}
		return f;
	}

	void command_()
	{
		if(!cmd_.service()) {
			return;
		}

		uint8_t cmdn = cmd_.get_words();
		if(cmdn >= 1) {
			bool f = false;
			if(cmd_.cmp_word(0, "dir")) {  // dir [xxx]
				if(check_mount_()) {
					if(cmdn >= 2) {
						char tmp[128];
						cmd_.get_word(1, tmp, sizeof(tmp));
						sdc_.dir(tmp);
					} else {
						sdc_.dir("");
					}
				}
				f = true;
			} else if(cmd_.cmp_word(0, "cd")) {  // cd [xxx]
				if(check_mount_()) {
					if(cmdn >= 2) {
						char tmp[128];
						cmd_.get_word(1, tmp, sizeof(tmp));
						sdc_.cd(tmp);
					} else {
						sdc_.cd("/");
					}
				}
				f = true;
			} else if(cmd_.cmp_word(0, "pwd")) { // pwd
				utils::format("%s\n") % sdc_.get_current();
				f = true;
			} else if(cmd_.cmp_word(0, "help")) {
				utils::format("    dir [path]\n");
				utils::format("    cd [path]\n");
				utils::format("    pwd\n");
				f = true;
			}
			if(!f) {
				char tmp[128];
				if(cmd_.get_word(0, tmp, sizeof(tmp))) {
					utils::format("Command error: '%s'\n") % tmp;
				}
			}
		}
	}
}

extern "C" {

	uint8_t get_fami_pad()
	{
		return famipad_.update();
	}

	void set_sample_rate(uint32_t freq)
	{
		uint8_t intr_level = 5;
		if(!tpu0_.start(freq, intr_level)) {
			utils::format("TPU0 start error...\n");
		}
	}

	void sci_putch(char ch)
	{
		sci_.putch(ch);
	}

	void sci_puts(const char* str)
	{
		sci_.puts(str);
	}

	char sci_getch(void)
	{
		return sci_.getch();
	}

	uint16_t sci_length()
	{
		return sci_.recv_length();
	}

	DSTATUS disk_initialize(BYTE drv) {
		return sdh_.disk_initialize(drv);
	}

	DSTATUS disk_status(BYTE drv) {
		return sdh_.disk_status(drv);
	}

	DRESULT disk_read(BYTE drv, BYTE* buff, DWORD sector, UINT count) {
		return sdh_.disk_read(drv, buff, sector, count);
	}

	DRESULT disk_write(BYTE drv, const BYTE* buff, DWORD sector, UINT count) {
		return sdh_.disk_write(drv, buff, sector, count);
	}

	DRESULT disk_ioctl(BYTE drv, BYTE ctrl, void* buff) {
		return sdh_.disk_ioctl(drv, ctrl, buff);
	}

	DWORD get_fattime(void) {
		time_t t = 0;
///		rtc_.get_time(t);
		return utils::str::get_fattime(t);
	}

	int fatfs_get_mount() {
		return sdc_.get_mount();
	}

	int make_full_path(const char* src, char* dst, uint16_t len)
	{
		return sdc_.make_full_path(src, dst, len);
	}
}

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

int main(int argc, char** argv)
{
	SYSTEM_IO::setup_system_clock();

	{  // 内臓１２ビット D/A の設定
		bool amp_ena = true;
		dac_out_.start(DAC_OUT::output::CH0_CH1, amp_ena);
		dac_out_.out0(0x8000);
		dac_out_.out1(0x8000);
	}

	{  // SCI 設定
		static const uint8_t sci_level = 2;
		sci_.start(115200, sci_level);
	}

	{  // SD カード・クラスの初期化
		sdh_.start();
		sdc_.start();
	}

	// 波形メモリーの無音状態初期化
	sound_out_.mute();

	{  // サンプリング・タイマー設定
		set_sample_rate(11127);
	}

	{  // DMAC マネージャー開始
		uint8_t intr_level = 4;
		bool cpu_intr = true;
		auto ret = dmac_mgr_.start(tpu0_.get_intr_vec(), DMAC_MGR::trans_type::SP_DN_32,
			reinterpret_cast<uint32_t>(sound_out_.get_wave()), DAC::DADR0.address(),
			sound_out_.size(), intr_level, cpu_intr);
		if(!ret) {
			utils::format("DMAC Not start...\n");
		}
	}

	utils::format("\rRTK5RX65N Start for Space Invaders\n");

	cmd_.set_prompt("# ");

	{  // GLCDC 初期化
		LCD_DISP::DIR  = 1;
		LCD_LIGHT::DIR = 1;
		LCD_DISP::P  = 0;  // DISP Disable
		LCD_LIGHT::P = 0;  // BackLight Disable (No PWM)
		if(glcdc_io_.start()) {
			utils::format("Start GLCDC\n");
			LCD_DISP::P  = 1;  // DISP Enable
			LCD_LIGHT::P = 1;  // BackLight Enable (No PWM)
			if(!glcdc_io_.control(GLCDC_IO::CONTROL_CMD::START_DISPLAY)) {
				utils::format("GLCDC ctrl fail...\n");
			}
		} else {
			utils::format("Fail GLCDC\n");
		}
	}

	LED::DIR = 1;

	{
		PAD_VCC::DIR = 1;
		PAD_VCC::P = 1;
		PAD_GND::DIR = 1;
		PAD_GND::P = 0;
		famipad_.start();
	}

	uint32_t delay_inv = 120;
	uint8_t n = 0;
	while(1) {
		glcdc_io_.sync_vpos();

		if(delay_inv > 0) {
			--delay_inv;
			if(delay_inv == 0) {
				if(sdc_.get_mount()) {
					if(spinv_.start("/inv_roms", "/inv_wavs")) {
						utils::format("Space Invaders start...\n");
					} else {
						utils::format("Space Invaders not start...(fail)\n");
					}
				} else {
					delay_inv = 60;
					utils::format("SD card not mount\n");
				}
			}
		} else {
			spinv_.service(LCD_ORG, GLCDC_IO::width, GLCDC_IO::height);

			SPINV::SND_MGR& snd = spinv_.at_sound();
			uint32_t len = snd.get_length();
			const int16_t* wav = snd.get_buffer();
			for(uint32_t i = 0; i < len; ++i) {
				while((sound_out_.at_fifo().size() - sound_out_.at_fifo().length()) < 8) {
				}
				sound::wave_t t;
				t.l_ch = t.r_ch = *wav++;
				sound_out_.at_fifo().put(t);
			}
		}

		sdc_.service(sdh_.service());

		command_();

		++n;
		if(n >= 30) {
			n = 0;
		}
		if(n < 10) {
			LED::P = 0;
		} else {
			LED::P = 1;
		}
	}
}
<commit_msg>Update: ff13c mmc driver path<commit_after>//=====================================================================//
/*! @file
    @brief  RX65N SIDE
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/renesas.hpp"
#include "common/fixed_fifo.hpp"
#include "common/sci_io.hpp"
#include "common/format.hpp"
#include "common/command.hpp"
#include "common/spi_io2.hpp"
#include "ff13c/mmc_io.hpp"
#include "common/sdc_man.hpp"
#include "common/tpu_io.hpp"
#include "sound/sound_out.hpp"

#include "chip/FAMIPAD.hpp"

#include "spinv.hpp"

namespace {

	typedef device::PORT<device::PORT7, device::bitpos::B0> LED;
// オーディオの D/A として使用
//	typedef device::PORT<device::PORT0, device::bitpos::B5> SW2;

	// Famicon PAD (CMOS 4021B Shift Register)
	// 電源は、微小なので、接続を簡単に行う為、ポートを使う
	typedef device::PORT<device::PORT6, device::bitpos::B0> PAD_VCC;
	typedef device::PORT<device::PORT6, device::bitpos::B1> PAD_GND;
	typedef device::PORT<device::PORT6, device::bitpos::B2> PAD_P_S;
	typedef device::PORT<device::PORT6, device::bitpos::B5> PAD_CLK;
	typedef device::PORT<device::PORT7, device::bitpos::B3> PAD_OUT;
	typedef chip::FAMIPAD<PAD_P_S, PAD_CLK, PAD_OUT> FAMIPAD;
	FAMIPAD		famipad_;

	typedef device::system_io<12000000> SYSTEM_IO;

	typedef utils::fixed_fifo<char, 512>  RECV_BUFF;
	typedef utils::fixed_fifo<char, 1024> SEND_BUFF;
	typedef device::sci_io<device::SCI9, RECV_BUFF, SEND_BUFF> SCI;
	SCI			sci_;

	typedef device::PORT<device::PORT6, device::bitpos::B3> LCD_DISP;
	typedef device::PORT<device::PORT6, device::bitpos::B6> LCD_LIGHT;
	static const int16_t LCD_X = 480;
	static const int16_t LCD_Y = 272;
	static void* LCD_ORG = reinterpret_cast<void*>(0x00000100);
	static const auto PIX = graphics::pixel::TYPE::RGB565;
	typedef device::glcdc_io<device::GLCDC, LCD_X, LCD_Y, PIX> GLCDC_IO;
	GLCDC_IO	glcdc_io_(nullptr, LCD_ORG);

	// カード電源制御は使わない場合、「device::NULL_PORT」を指定する。
//	typedef device::PORT<device::PORT6, device::bitpos::B4> SDC_POWER;
	typedef device::NULL_PORT SDC_POWER;

#ifdef SDHI_IF
	// RX65N Envision Kit の SDHI ポートは、候補３になっている
	typedef fatfs::sdhi_io<device::SDHI, SDC_POWER, device::port_map::option::THIRD> SDHI;
	SDHI		sdh_;
#else
	// Soft SDC 用　SPI 定義（SPI）
	typedef device::PORT<device::PORT2, device::bitpos::B2> MISO;  // DAT0
	typedef device::PORT<device::PORT2, device::bitpos::B0> MOSI;  // CMD
	typedef device::PORT<device::PORT2, device::bitpos::B1> SPCK;  // CLK

	typedef device::spi_io2<MISO, MOSI, SPCK> SPI;  ///< Soft SPI 定義

	SPI			spi_;

	typedef device::PORT<device::PORT1, device::bitpos::B7> SDC_SELECT;  // DAT3 カード選択信号
	typedef device::PORT<device::PORT2, device::bitpos::B5> SDC_DETECT;  // CD   カード検出

	typedef fatfs::mmc_io<SPI, SDC_SELECT, SDC_POWER, SDC_DETECT> MMC;   // ハードウェアー定義

	MMC			sdh_(spi_, 35000000);
#endif
	typedef utils::sdc_man SDC;
	SDC			sdc_;

	volatile uint32_t	wpos_;

	/// DMAC 終了割り込み
	class dmac_term_task {
	public:
		void operator() () {
			device::DMAC0::DMCNT.DTE = 1;  // DMA を再スタート
			wpos_ = 0;
		}
	};

	typedef device::dmac_mgr<device::DMAC0, dmac_term_task> DMAC_MGR;
	DMAC_MGR	dmac_mgr_;

	uint32_t get_wave_pos_() { return (dmac_mgr_.get_count() & 0x3ff) ^ 0x3ff; }

	typedef device::R12DA DAC;
	typedef device::dac_out<DAC> DAC_OUT;
	DAC_OUT		dac_out_;

	typedef utils::sound_out<1024, 256> SOUND_OUT;
	SOUND_OUT	sound_out_;

	class tpu_task {
	public:
		void operator() () {
			uint32_t tmp = wpos_;
			++wpos_;
			if((tmp ^ wpos_) & 64) {
				sound_out_.service(64);
			}
		}
	};

	typedef device::tpu_io<device::TPU0, tpu_task> TPU0;
	TPU0		tpu0_;

	typedef emu::spinv SPINV;
	SPINV		spinv_;

	utils::command<256> cmd_;

	bool check_mount_() {
		auto f = sdc_.get_mount();
		if(!f) {
			utils::format("SD card not mount.\n");
		}
		return f;
	}

	void command_()
	{
		if(!cmd_.service()) {
			return;
		}

		uint8_t cmdn = cmd_.get_words();
		if(cmdn >= 1) {
			bool f = false;
			if(cmd_.cmp_word(0, "dir")) {  // dir [xxx]
				if(check_mount_()) {
					if(cmdn >= 2) {
						char tmp[128];
						cmd_.get_word(1, tmp, sizeof(tmp));
						sdc_.dir(tmp);
					} else {
						sdc_.dir("");
					}
				}
				f = true;
			} else if(cmd_.cmp_word(0, "cd")) {  // cd [xxx]
				if(check_mount_()) {
					if(cmdn >= 2) {
						char tmp[128];
						cmd_.get_word(1, tmp, sizeof(tmp));
						sdc_.cd(tmp);
					} else {
						sdc_.cd("/");
					}
				}
				f = true;
			} else if(cmd_.cmp_word(0, "pwd")) { // pwd
				utils::format("%s\n") % sdc_.get_current();
				f = true;
			} else if(cmd_.cmp_word(0, "help")) {
				utils::format("    dir [path]\n");
				utils::format("    cd [path]\n");
				utils::format("    pwd\n");
				f = true;
			}
			if(!f) {
				char tmp[128];
				if(cmd_.get_word(0, tmp, sizeof(tmp))) {
					utils::format("Command error: '%s'\n") % tmp;
				}
			}
		}
	}
}

extern "C" {

	uint8_t get_fami_pad()
	{
		return famipad_.update();
	}

	void set_sample_rate(uint32_t freq)
	{
		uint8_t intr_level = 5;
		if(!tpu0_.start(freq, intr_level)) {
			utils::format("TPU0 start error...\n");
		}
	}

	void sci_putch(char ch)
	{
		sci_.putch(ch);
	}

	void sci_puts(const char* str)
	{
		sci_.puts(str);
	}

	char sci_getch(void)
	{
		return sci_.getch();
	}

	uint16_t sci_length()
	{
		return sci_.recv_length();
	}

	DSTATUS disk_initialize(BYTE drv) {
		return sdh_.disk_initialize(drv);
	}

	DSTATUS disk_status(BYTE drv) {
		return sdh_.disk_status(drv);
	}

	DRESULT disk_read(BYTE drv, BYTE* buff, DWORD sector, UINT count) {
		return sdh_.disk_read(drv, buff, sector, count);
	}

	DRESULT disk_write(BYTE drv, const BYTE* buff, DWORD sector, UINT count) {
		return sdh_.disk_write(drv, buff, sector, count);
	}

	DRESULT disk_ioctl(BYTE drv, BYTE ctrl, void* buff) {
		return sdh_.disk_ioctl(drv, ctrl, buff);
	}

	DWORD get_fattime(void) {
		time_t t = 0;
///		rtc_.get_time(t);
		return utils::str::get_fattime(t);
	}

	int fatfs_get_mount() {
		return sdc_.get_mount();
	}

	int make_full_path(const char* src, char* dst, uint16_t len)
	{
		return sdc_.make_full_path(src, dst, len);
	}
}

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

int main(int argc, char** argv)
{
	SYSTEM_IO::setup_system_clock();

	{  // 内臓１２ビット D/A の設定
		bool amp_ena = true;
		dac_out_.start(DAC_OUT::output::CH0_CH1, amp_ena);
		dac_out_.out0(0x8000);
		dac_out_.out1(0x8000);
	}

	{  // SCI 設定
		static const uint8_t sci_level = 2;
		sci_.start(115200, sci_level);
	}

	{  // SD カード・クラスの初期化
		sdh_.start();
		sdc_.start();
	}

	// 波形メモリーの無音状態初期化
	sound_out_.mute();

	{  // サンプリング・タイマー設定
		set_sample_rate(11127);
	}

	{  // DMAC マネージャー開始
		uint8_t intr_level = 4;
		bool cpu_intr = true;
		auto ret = dmac_mgr_.start(tpu0_.get_intr_vec(), DMAC_MGR::trans_type::SP_DN_32,
			reinterpret_cast<uint32_t>(sound_out_.get_wave()), DAC::DADR0.address(),
			sound_out_.size(), intr_level, cpu_intr);
		if(!ret) {
			utils::format("DMAC Not start...\n");
		}
	}

	utils::format("\rRTK5RX65N Start for Space Invaders\n");

	cmd_.set_prompt("# ");

	{  // GLCDC 初期化
		LCD_DISP::DIR  = 1;
		LCD_LIGHT::DIR = 1;
		LCD_DISP::P  = 0;  // DISP Disable
		LCD_LIGHT::P = 0;  // BackLight Disable (No PWM)
		if(glcdc_io_.start()) {
			utils::format("Start GLCDC\n");
			LCD_DISP::P  = 1;  // DISP Enable
			LCD_LIGHT::P = 1;  // BackLight Enable (No PWM)
			if(!glcdc_io_.control(GLCDC_IO::CONTROL_CMD::START_DISPLAY)) {
				utils::format("GLCDC ctrl fail...\n");
			}
		} else {
			utils::format("Fail GLCDC\n");
		}
	}

	LED::DIR = 1;

	{
		PAD_VCC::DIR = 1;
		PAD_VCC::P = 1;
		PAD_GND::DIR = 1;
		PAD_GND::P = 0;
		famipad_.start();
	}

	uint32_t delay_inv = 120;
	uint8_t n = 0;
	while(1) {
		glcdc_io_.sync_vpos();

		if(delay_inv > 0) {
			--delay_inv;
			if(delay_inv == 0) {
				if(sdc_.get_mount()) {
					if(spinv_.start("/inv_roms", "/inv_wavs")) {
						utils::format("Space Invaders start...\n");
					} else {
						utils::format("Space Invaders not start...(fail)\n");
					}
				} else {
					delay_inv = 60;
					utils::format("SD card not mount\n");
				}
			}
		} else {
			spinv_.service(LCD_ORG, GLCDC_IO::width, GLCDC_IO::height);

			SPINV::SND_MGR& snd = spinv_.at_sound();
			uint32_t len = snd.get_length();
			const int16_t* wav = snd.get_buffer();
			for(uint32_t i = 0; i < len; ++i) {
				while((sound_out_.at_fifo().size() - sound_out_.at_fifo().length()) < 8) {
				}
				sound::wave_t t;
				t.l_ch = t.r_ch = *wav++;
				sound_out_.at_fifo().put(t);
			}
		}

		sdc_.service(sdh_.service());

		command_();

		++n;
		if(n >= 30) {
			n = 0;
		}
		if(n < 10) {
			LED::P = 0;
		} else {
			LED::P = 1;
		}
	}
}
<|endoftext|>


<commit_before>#include "reportcontroller.h"
#include "../settings.h"
#include "../report/reportscheduler.h"
#include "../log/logger.h"
#include "../types.h"

#include "../webrequester.h"
#include "../network/requests/request.h"
#include "../response.h"

#include <QPointer>

LOGGER(ReportController);

class ReportPost : public Request
{
    Q_OBJECT
    Q_CLASSINFO("path", "/send_results")

public:
    ReportPost(QObject* parent = 0)
    : Request(parent)
    {
    }

    void setReports(const ReportList& reports) {
        m_reports = reports;
    }

    ReportList reports() const {
        return m_reports;
    }

    // Request interface
    QVariant toVariant() const {
        QVariantMap map;
        map.insert("session_id", sessionId());
        map.insert("reports", ptrListToVariant(m_reports));
        return map;
    }

protected:
    ReportList m_reports;
};

class ReportResponse : public Response
{
    Q_OBJECT

public:
    ReportResponse(QObject* parent = 0)
    : Response(parent)
    {
    }

    QStringList taskIds;

    // Response interface
    bool fillFromVariant(const QVariantMap &variant) {
        this->taskIds.clear();

        QVariantList taskIds = variant.value("successful_task_ids").toList();
        foreach(const QVariant& id, taskIds)
            this->taskIds.append(id.toString());

        return true;
    }

    void finished() {
    }
};

class ReportController::Private : public QObject
{
    Q_OBJECT

public:
    Private(ReportController* q)
    : q(q)
    {
        connect(&requester, SIGNAL(statusChanged(Status)), q, SIGNAL(statusChanged()));
        connect(&requester, SIGNAL(finished()), this, SLOT(onFinished()));
        connect(&requester, SIGNAL(error()), this, SLOT(onError()));

        requester.setRequest(&post);
        requester.setResponse(&response);
    }

    ReportController* q;

    // Properties
    QPointer<ReportScheduler> scheduler;
    QPointer<Settings> settings;

    WebRequester requester;
    ReportPost post;
    ReportResponse response;

public slots:
    void onFinished();
    void onError();
};

void ReportController::Private::onFinished()
{
    QStringList taskIds = response.taskIds;
    LOG_INFO(QString("%1 Reports successfully sent").arg(taskIds.size()));

    foreach(const QString& taskId, taskIds) {
        ReportPtr report = scheduler->reportByTaskId(taskId);
        if ( report.isNull() ) {
            LOG_ERROR(QString("No task with id %1 found.").arg(taskId));
        } else {
            scheduler->removeReport(report);
        }
    }
}

void ReportController::Private::onError()
{
    LOG_INFO(QString("Failed to send reports: %1").arg(requester.errorString()));
}

ReportController::ReportController(QObject *parent)
: Controller(parent)
, d(new Private(this))
{
}

ReportController::~ReportController()
{
    delete d;
}

ReportController::Status ReportController::status() const
{
    return (Status)d->requester.status();
}

bool ReportController::init(ReportScheduler *scheduler, Settings *settings)
{
    d->scheduler = scheduler;
    d->settings = settings;
    return true;
}

QString ReportController::errorString() const
{
    return d->requester.errorString();
}

void ReportController::sendReports()
{
    ReportList reports = d->scheduler->reports();

    if ( reports.isEmpty() ) {
        LOG_INFO("No reports to send");
        return;
    }

    LOG_INFO(QString("Sending %1 reports").arg(reports.size()));

    d->post.setReports(reports);
    d->requester.start();
}

#include "reportcontroller.moc"
<commit_msg>Forgot include #2<commit_after>#include "reportcontroller.h"
#include "../settings.h"
#include "../report/reportscheduler.h"
#include "../log/logger.h"
#include "../types.h"

#include "../webrequester.h"
#include "../network/requests/request.h"
#include "../response.h"

#include <QPointer>
#include <QStringList>

LOGGER(ReportController);

class ReportPost : public Request
{
    Q_OBJECT
    Q_CLASSINFO("path", "/send_results")

public:
    ReportPost(QObject* parent = 0)
    : Request(parent)
    {
    }

    void setReports(const ReportList& reports) {
        m_reports = reports;
    }

    ReportList reports() const {
        return m_reports;
    }

    // Request interface
    QVariant toVariant() const {
        QVariantMap map;
        map.insert("session_id", sessionId());
        map.insert("reports", ptrListToVariant(m_reports));
        return map;
    }

protected:
    ReportList m_reports;
};

class ReportResponse : public Response
{
    Q_OBJECT

public:
    ReportResponse(QObject* parent = 0)
    : Response(parent)
    {
    }

    QStringList taskIds;

    // Response interface
    bool fillFromVariant(const QVariantMap &variant) {
        this->taskIds.clear();

        QVariantList taskIds = variant.value("successful_task_ids").toList();
        foreach(const QVariant& id, taskIds)
            this->taskIds.append(id.toString());

        return true;
    }

    void finished() {
    }
};

class ReportController::Private : public QObject
{
    Q_OBJECT

public:
    Private(ReportController* q)
    : q(q)
    {
        connect(&requester, SIGNAL(statusChanged(Status)), q, SIGNAL(statusChanged()));
        connect(&requester, SIGNAL(finished()), this, SLOT(onFinished()));
        connect(&requester, SIGNAL(error()), this, SLOT(onError()));

        requester.setRequest(&post);
        requester.setResponse(&response);
    }

    ReportController* q;

    // Properties
    QPointer<ReportScheduler> scheduler;
    QPointer<Settings> settings;

    WebRequester requester;
    ReportPost post;
    ReportResponse response;

public slots:
    void onFinished();
    void onError();
};

void ReportController::Private::onFinished()
{
    QStringList taskIds = response.taskIds;
    LOG_INFO(QString("%1 Reports successfully sent").arg(taskIds.size()));

    foreach(const QString& taskId, taskIds) {
        ReportPtr report = scheduler->reportByTaskId(taskId);
        if ( report.isNull() ) {
            LOG_ERROR(QString("No task with id %1 found.").arg(taskId));
        } else {
            scheduler->removeReport(report);
        }
    }
}

void ReportController::Private::onError()
{
    LOG_INFO(QString("Failed to send reports: %1").arg(requester.errorString()));
}

ReportController::ReportController(QObject *parent)
: Controller(parent)
, d(new Private(this))
{
}

ReportController::~ReportController()
{
    delete d;
}

ReportController::Status ReportController::status() const
{
    return (Status)d->requester.status();
}

bool ReportController::init(ReportScheduler *scheduler, Settings *settings)
{
    d->scheduler = scheduler;
    d->settings = settings;
    return true;
}

QString ReportController::errorString() const
{
    return d->requester.errorString();
}

void ReportController::sendReports()
{
    ReportList reports = d->scheduler->reports();

    if ( reports.isEmpty() ) {
        LOG_INFO("No reports to send");
        return;
    }

    LOG_INFO(QString("Sending %1 reports").arg(reports.size()));

    d->post.setReports(reports);
    d->requester.start();
}

#include "reportcontroller.moc"
<|endoftext|>