<commit_before>/*
 * Copyright (C) 2007-2014 Frank Mertens.
 *
 * Use of this source is governed by a BSD-style license that can be
 * found in the LICENSE file.
 *
 */

#include <flux/stdio.h>
#include <flux/Glob.h>
#include <flux/Dir.h>
#include <flux/ResourceGuard.h>
#include <flux/yason.h>
#include <flux/Arguments.h>
#include "DependencyCache.h"
#include "GnuToolChain.h"
#include "JobScheduler.h"
#include "RecipeProtocol.h"
#include "BuildPlan.h"

namespace fluxmake
{

Ref<BuildPlan> BuildPlan::create(int argc, char **argv)
{
	return new BuildPlan(argc, argv);
}

Ref<BuildPlan> BuildPlan::create(String projectPath)
{
	BuildPlan *plan = 0;
	if (buildMap_->lookup(String(projectPath->absolutePath()), &plan)) return plan;
	return new BuildPlan(projectPath, this);
}

#define FLUXMAKE_BUILDPLAN_COMPONENTS_INIT \
	shell_(this), \
	configureStage_(this), \
	analyseStage_(this), \
	compileLinkStage_(this), \
	testRunStage_(this), \
	installStage_(this), \
	uninstallStage_(this), \
	cleanStage_(this)

BuildPlan::BuildPlan(int argc, char **argv)
	: projectPath_("."),
	  concurrency_(-1),
	  buildMap_(BuildMap::create()),
	  FLUXMAKE_BUILDPLAN_COMPONENTS_INIT
{
	Ref<Arguments> arguments = Arguments::parse(argc, argv);
	StringList *items = arguments->items();

	if (items->count() > 0) {
		if (items->count() > 1)
			throw UsageError("Handling multiple source directories at once is not supported");
		projectPath_ = items->at(0);
	}

	projectPath_ = projectPath_->absolutePath()->canonicalPath();

	ResourceGuard context(recipePath());
	recipe_ = yason::parse(File::open(recipePath())->map(), recipeProtocol());
	arguments->validate(recipe_);
	arguments->override(recipe_);

	readRecipe();

	toolChain_ = GnuToolChain::create(compiler());
	if (optimize_ == "") optimize_ = toolChain_->defaultOptimization(this);

	buildMap_->insert(projectPath_, this);
}

BuildPlan::BuildPlan(String projectPath, BuildPlan *parentPlan)
	: toolChain_(parentPlan->toolChain_),
	  projectPath_(projectPath),
	  concurrency_(parentPlan->concurrency_),
	  buildMap_(parentPlan->buildMap_),
	  FLUXMAKE_BUILDPLAN_COMPONENTS_INIT
{
	recipe_ = yason::parse(File::open(recipePath(projectPath_))->map(), recipeProtocol());
	readRecipe(parentPlan);
	buildMap_->insert(projectPath_, this);
}

void BuildPlan::readRecipe(BuildPlan *parentPlan)
{
	name_ = recipe_->value("name");
	alias_ = recipe_->value("alias");
	version_ = recipe_->value("version");
	installPrefix_ = recipe_->value("prefix");

	options_ = 0;

	if (recipe_->className() == "Application")  options_ |= Application;
	else if (recipe_->className() == "Library") options_ |= Library;
	else if (recipe_->className() == "Tools")   options_ |= Tools;
	else if (recipe_->className() == "Tests")   options_ |= Tools | Tests;
	else if (recipe_->className() == "Package") options_ |= Package;

	if (recipe_->value("debug"))     options_ |= Debug;
	if (recipe_->value("release"))   options_ |= Release;
	if (recipe_->value("simulate"))  options_ |= Simulate;
	if (recipe_->value("blindfold")) options_ |= Blindfold;
	if (recipe_->value("bootstrap")) options_ |= Bootstrap | Simulate | Blindfold;
	if (recipe_->value("test"))      options_ |= BuildTests;
	if (recipe_->value("test-run"))  options_ |= BuildTests;
	if (recipe_->value("clean"))     options_ |= BuildTests;
	if (recipe_->value("verbose"))   options_ |= Verbose;

	concurrency_ = recipe_->value("concurrency");

	if (parentPlan) {
		options_ &= ~GlobalOptions;
		options_ |= parentPlan->options() & GlobalOptions;
		concurrency_ = parentPlan->concurrency_;
		installPrefix_ = parentPlan->installPrefix_;
	}

	BuildParameters::read(recipe_, this);

	if (recipe_->hasChildren()) {
		for (int i = 0; i < recipe_->children()->count(); ++i) {
			MetaObject *object = recipe_->children()->at(i);
			if (object->className() == "SystemPrerequisite") {
				Ref<SystemPrerequisite> p = SystemPrerequisite::read(object, this);
				Ref<SystemPrerequisiteList> l;
				if (!systemPrerequisitesByName_)
					systemPrerequisitesByName_ = SystemPrerequisitesByName::create();
				if (!systemPrerequisitesByName_->lookup(p->name(), &l))
					systemPrerequisitesByName_->insert(p->name(), l = SystemPrerequisiteList::create());
				l->append(p);
			}
			else if (object->className() == "Usage") {
				usage_ = BuildParameters::create();
				usage_->read(object, this);
				BuildParameters::readSpecific(usage_);
			}
		}
	}

	if (parentPlan) {
		optimize_ = parentPlan->optimize();
		linkStatic_ = parentPlan->linkStatic();
	}
}

int BuildPlan::run()
{
	readPrerequisites();
	globSources();
	initModules();

	if (options_ & Bootstrap) {
		fout(
			"#!/bin/sh -ex\n"
			"SOURCE=$1\n"
			"MACHINE=$(%%)\n"
		) << toolChain_->machineCommand();
	}

	if (!configureStage()->run()) return 1;
	if (!analyseStage()->run()) return 1;

	if (recipe_->value("clean")) return !cleanStage()->run();
	if (recipe_->value("uninstall")) return !uninstallStage()->run();

	if (!compileLinkStage()->run()) return 1;

	if (recipe_->value("test-run")) {
		if (!testRunStage()->run())
			return testRunStage()->status();
	}

	if (recipe_->value("install")) return !installStage()->run();

	return 0;
}

String BuildPlan::sourcePath(String source) const
{
	if (projectPath_ == ".") return source;
	return projectPath_ + "/" + source;
}

String BuildPlan::modulePath(String object) const
{
	return modulePath_ + "/" + object;
}

String BuildPlan::installPath(String relativeInstallPath) const
{
	return installPrefix_ + "/" + relativeInstallPath;
}

void BuildPlan::use(BuildPlan *plan)
{
	if (plan->options() & Library) {
		String path = plan->projectPath();
		path = path->reducePath();
		while (Dir::count(path) == 1)
			path = path->reducePath();
		if (!includePaths_->contains(path))
			includePaths_->append(path);
		if (!libraryPaths_->contains("."))
			libraryPaths_->append(".");
		libraries_->append(plan->name());

		if (plan->usage()) BuildParameters::readSpecific(plan->usage());
	}
	else if (plan->options() & Package) {
		for (int i = 0; i < plan->prerequisites()->count(); ++i)
			use(plan->prerequisites()->at(i));
	}
	// else if FIXME: warn/error when using Application or Tools
}

String BuildPlan::findPrerequisite(String prerequisitePath) const
{
	if (prerequisitePath->isAbsolutePath()) {
		if (File::exists(recipePath(prerequisitePath))) return prerequisitePath;
		return String();
	}
	for (String path = projectPath_; path != "/"; path = path->reducePath()) {
		String candidatePath = path + "/" + prerequisitePath;
		if (File::exists(recipePath(candidatePath))) {
			candidatePath = candidatePath->canonicalPath();
			if (candidatePath == projectPath_) continue;
			return candidatePath;
		}
	}
	return String();
}

void BuildPlan::readPrerequisites()
{
	if (prerequisites_) return;

	prerequisites_ = BuildPlanList::create();

	if ((options_ & Tests) && !(options_ & BuildTests)) return;

	StringList *prerequisitePaths = cast<StringList>(recipe_->value("use"));

	for (int i = 0; i < prerequisitePaths->count(); ++i) {
		String path = findPrerequisite(prerequisitePaths->at(i));
		if (path == "")
			throw UsageError(Format() << recipePath() << ": Failed to locate prerequisite \"" << prerequisitePaths->at(i) << "\"");
		Ref<BuildPlan> plan = BuildPlan::create(path);
		plan->readPrerequisites();
		use(plan);
		prerequisites_->append(plan);
	}
}

Ref<StringList> BuildPlan::globSources(StringList *pattern) const
{
	Ref<StringList> sources = StringList::create();
	for (int i = 0; i < pattern->count(); ++i) {
		Ref<Glob> glob = Glob::open(sourcePath(pattern->at(i)));
		for (String path; glob->read(&path);)
			sources->append(path);
	}
	sources = sources->sort();
	return sources;
}

void BuildPlan::globSources()
{
	if (sources_) return;

	if ((options_ & Tests) && !(options_ & BuildTests)) return;

	if (recipe_->contains("source"))
		sources_ = globSources(cast<StringList>(recipe_->value("source")));
	else
		sources_ = StringList::create();

	sourcePrefix_ = buildMap_->commonPrefix('/');
	if (sourcePrefix_ == "") sourcePrefix_ = projectPath_;
	else sourcePrefix_ = sourcePrefix_->canonicalPath();

	containsCPlusPlus_ = false;
	for (int i = 0; i < sources_->count(); ++i) {
		String suffix = sources_->at(i)->suffix();
		if (suffix == "cpp" || suffix == "cc" || suffix == "cxx" || suffix == "mm") {
			containsCPlusPlus_ = true;
			break;
		}
	}

	if (recipe_->contains("bundle"))
		bundle_ = globSources(cast<StringList>(recipe_->value("bundle")));
	else
		bundle_ = StringList::create();

	for (int i = 0; i < prerequisites_->count(); ++i)
		prerequisites_->at(i)->globSources();
}

void BuildPlan::initModules()
{
	if (modules_) return;

	if ((options_ & Tests) && !(options_ & BuildTests)) return;

	modules_ = ModuleList::create();

	Format f;
	f << ".modules";
	{
		Format h;
		String path = projectPath_->absolutePath();
		String topLevel = sourcePrefix_->absolutePath();
		while (path != topLevel && path != "/") {
			h << path->fileName();
			path = path->reducePath();
		}
		h << topLevel->fileName();
		f << h->reverse()->join("_");
	}
	if (version_ != "") f << version_;
	if (linkStatic_) f << "static";
	if (options_ & Debug) f << "debug";
	if (options_ & Release) f << "release";
	if (optimize_ != "") f << "O" + optimize_;
	if (options_ & Bootstrap)
		f << "$MACHINE";
	else
		f << toolChain_->machine();
	modulePath_ = f->join("-");

	for (int i = 0; i < prerequisites_->count(); ++i)
		prerequisites_->at(i)->initModules();
}

} // namespace fluxmake
<commit_msg>Intermediate solution for redundant include paths.<commit_after>/*
 * Copyright (C) 2007-2014 Frank Mertens.
 *
 * Use of this source is governed by a BSD-style license that can be
 * found in the LICENSE file.
 *
 */

#include <flux/stdio.h>
#include <flux/Glob.h>
#include <flux/Dir.h>
#include <flux/ResourceGuard.h>
#include <flux/yason.h>
#include <flux/Arguments.h>
#include "DependencyCache.h"
#include "GnuToolChain.h"
#include "JobScheduler.h"
#include "RecipeProtocol.h"
#include "BuildPlan.h"

namespace fluxmake
{

Ref<BuildPlan> BuildPlan::create(int argc, char **argv)
{
	return new BuildPlan(argc, argv);
}

Ref<BuildPlan> BuildPlan::create(String projectPath)
{
	BuildPlan *plan = 0;
	if (buildMap_->lookup(String(projectPath->absolutePath()), &plan)) return plan;
	return new BuildPlan(projectPath, this);
}

#define FLUXMAKE_BUILDPLAN_COMPONENTS_INIT \
	shell_(this), \
	configureStage_(this), \
	analyseStage_(this), \
	compileLinkStage_(this), \
	testRunStage_(this), \
	installStage_(this), \
	uninstallStage_(this), \
	cleanStage_(this)

BuildPlan::BuildPlan(int argc, char **argv)
	: projectPath_("."),
	  concurrency_(-1),
	  buildMap_(BuildMap::create()),
	  FLUXMAKE_BUILDPLAN_COMPONENTS_INIT
{
	Ref<Arguments> arguments = Arguments::parse(argc, argv);
	StringList *items = arguments->items();

	if (items->count() > 0) {
		if (items->count() > 1)
			throw UsageError("Handling multiple source directories at once is not supported");
		projectPath_ = items->at(0);
	}

	projectPath_ = projectPath_->absolutePath()->canonicalPath();

	ResourceGuard context(recipePath());
	recipe_ = yason::parse(File::open(recipePath())->map(), recipeProtocol());
	arguments->validate(recipe_);
	arguments->override(recipe_);

	readRecipe();

	toolChain_ = GnuToolChain::create(compiler());
	if (optimize_ == "") optimize_ = toolChain_->defaultOptimization(this);

	buildMap_->insert(projectPath_, this);
}

BuildPlan::BuildPlan(String projectPath, BuildPlan *parentPlan)
	: toolChain_(parentPlan->toolChain_),
	  projectPath_(projectPath),
	  concurrency_(parentPlan->concurrency_),
	  buildMap_(parentPlan->buildMap_),
	  FLUXMAKE_BUILDPLAN_COMPONENTS_INIT
{
	recipe_ = yason::parse(File::open(recipePath(projectPath_))->map(), recipeProtocol());
	readRecipe(parentPlan);
	buildMap_->insert(projectPath_, this);
}

void BuildPlan::readRecipe(BuildPlan *parentPlan)
{
	name_ = recipe_->value("name");
	alias_ = recipe_->value("alias");
	version_ = recipe_->value("version");
	installPrefix_ = recipe_->value("prefix");

	options_ = 0;

	if (recipe_->className() == "Application")  options_ |= Application;
	else if (recipe_->className() == "Library") options_ |= Library;
	else if (recipe_->className() == "Tools")   options_ |= Tools;
	else if (recipe_->className() == "Tests")   options_ |= Tools | Tests;
	else if (recipe_->className() == "Package") options_ |= Package;

	if (recipe_->value("debug"))     options_ |= Debug;
	if (recipe_->value("release"))   options_ |= Release;
	if (recipe_->value("simulate"))  options_ |= Simulate;
	if (recipe_->value("blindfold")) options_ |= Blindfold;
	if (recipe_->value("bootstrap")) options_ |= Bootstrap | Simulate | Blindfold;
	if (recipe_->value("test"))      options_ |= BuildTests;
	if (recipe_->value("test-run"))  options_ |= BuildTests;
	if (recipe_->value("clean"))     options_ |= BuildTests;
	if (recipe_->value("verbose"))   options_ |= Verbose;

	concurrency_ = recipe_->value("concurrency");

	if (parentPlan) {
		options_ &= ~GlobalOptions;
		options_ |= parentPlan->options() & GlobalOptions;
		concurrency_ = parentPlan->concurrency_;
		installPrefix_ = parentPlan->installPrefix_;
	}

	BuildParameters::read(recipe_, this);

	if (recipe_->hasChildren()) {
		for (int i = 0; i < recipe_->children()->count(); ++i) {
			MetaObject *object = recipe_->children()->at(i);
			if (object->className() == "SystemPrerequisite") {
				Ref<SystemPrerequisite> p = SystemPrerequisite::read(object, this);
				Ref<SystemPrerequisiteList> l;
				if (!systemPrerequisitesByName_)
					systemPrerequisitesByName_ = SystemPrerequisitesByName::create();
				if (!systemPrerequisitesByName_->lookup(p->name(), &l))
					systemPrerequisitesByName_->insert(p->name(), l = SystemPrerequisiteList::create());
				l->append(p);
			}
			else if (object->className() == "Usage") {
				usage_ = BuildParameters::create();
				usage_->read(object, this);
				BuildParameters::readSpecific(usage_);
			}
		}
	}

	if (parentPlan) {
		optimize_ = parentPlan->optimize();
		linkStatic_ = parentPlan->linkStatic();
	}
}

int BuildPlan::run()
{
	readPrerequisites();
	globSources();
	initModules();

	if (options_ & Bootstrap) {
		fout(
			"#!/bin/sh -ex\n"
			"SOURCE=$1\n"
			"MACHINE=$(%%)\n"
		) << toolChain_->machineCommand();
	}

	if (!configureStage()->run()) return 1;
	if (!analyseStage()->run()) return 1;

	if (recipe_->value("clean")) return !cleanStage()->run();
	if (recipe_->value("uninstall")) return !uninstallStage()->run();

	if (!compileLinkStage()->run()) return 1;

	if (recipe_->value("test-run")) {
		if (!testRunStage()->run())
			return testRunStage()->status();
	}

	if (recipe_->value("install")) return !installStage()->run();

	return 0;
}

String BuildPlan::sourcePath(String source) const
{
	if (projectPath_ == ".") return source;
	return projectPath_ + "/" + source;
}

String BuildPlan::modulePath(String object) const
{
	return modulePath_ + "/" + object;
}

String BuildPlan::installPath(String relativeInstallPath) const
{
	return installPrefix_ + "/" + relativeInstallPath;
}

void BuildPlan::use(BuildPlan *plan)
{
	if (plan->options() & Library) {
		String path = plan->projectPath();
		if (!includePaths_->contains(path))
			includePaths_->append(path);
		{
			path = path->reducePath();
			while (Dir::count(path) == 1)
				path = path->reducePath();
			if (!includePaths_->contains(path))
				includePaths_->append(path);
		} // FIXME: obsolete HACK
		if (!libraryPaths_->contains("."))
			libraryPaths_->append(".");
		libraries_->append(plan->name());

		if (plan->usage()) BuildParameters::readSpecific(plan->usage());
	}
	else if (plan->options() & Package) {
		for (int i = 0; i < plan->prerequisites()->count(); ++i)
			use(plan->prerequisites()->at(i));
	}
	// else if FIXME: warn/error when using Application or Tools
}

String BuildPlan::findPrerequisite(String prerequisitePath) const
{
	if (prerequisitePath->isAbsolutePath()) {
		if (File::exists(recipePath(prerequisitePath))) return prerequisitePath;
		return String();
	}
	for (String path = projectPath_; path != "/"; path = path->reducePath()) {
		String candidatePath = path + "/" + prerequisitePath;
		if (File::exists(recipePath(candidatePath))) {
			candidatePath = candidatePath->canonicalPath();
			if (candidatePath == projectPath_) continue;
			return candidatePath;
		}
	}
	return String();
}

void BuildPlan::readPrerequisites()
{
	if (prerequisites_) return;

	prerequisites_ = BuildPlanList::create();

	if ((options_ & Tests) && !(options_ & BuildTests)) return;

	StringList *prerequisitePaths = cast<StringList>(recipe_->value("use"));

	for (int i = 0; i < prerequisitePaths->count(); ++i) {
		String path = findPrerequisite(prerequisitePaths->at(i));
		if (path == "")
			throw UsageError(Format() << recipePath() << ": Failed to locate prerequisite \"" << prerequisitePaths->at(i) << "\"");
		Ref<BuildPlan> plan = BuildPlan::create(path);
		plan->readPrerequisites();
		use(plan);
		prerequisites_->append(plan);
	}
}

Ref<StringList> BuildPlan::globSources(StringList *pattern) const
{
	Ref<StringList> sources = StringList::create();
	for (int i = 0; i < pattern->count(); ++i) {
		Ref<Glob> glob = Glob::open(sourcePath(pattern->at(i)));
		for (String path; glob->read(&path);)
			sources->append(path);
	}
	sources = sources->sort();
	return sources;
}

void BuildPlan::globSources()
{
	if (sources_) return;

	if ((options_ & Tests) && !(options_ & BuildTests)) return;

	if (recipe_->contains("source"))
		sources_ = globSources(cast<StringList>(recipe_->value("source")));
	else
		sources_ = StringList::create();

	sourcePrefix_ = buildMap_->commonPrefix('/');
	if (sourcePrefix_ == "") sourcePrefix_ = projectPath_;
	else sourcePrefix_ = sourcePrefix_->canonicalPath();

	containsCPlusPlus_ = false;
	for (int i = 0; i < sources_->count(); ++i) {
		String suffix = sources_->at(i)->suffix();
		if (suffix == "cpp" || suffix == "cc" || suffix == "cxx" || suffix == "mm") {
			containsCPlusPlus_ = true;
			break;
		}
	}

	if (recipe_->contains("bundle"))
		bundle_ = globSources(cast<StringList>(recipe_->value("bundle")));
	else
		bundle_ = StringList::create();

	for (int i = 0; i < prerequisites_->count(); ++i)
		prerequisites_->at(i)->globSources();
}

void BuildPlan::initModules()
{
	if (modules_) return;

	if ((options_ & Tests) && !(options_ & BuildTests)) return;

	modules_ = ModuleList::create();

	Format f;
	f << ".modules";
	{
		Format h;
		String path = projectPath_->absolutePath();
		String topLevel = sourcePrefix_->absolutePath();
		while (path != topLevel && path != "/") {
			h << path->fileName();
			path = path->reducePath();
		}
		h << topLevel->fileName();
		f << h->reverse()->join("_");
	}
	if (version_ != "") f << version_;
	if (linkStatic_) f << "static";
	if (options_ & Debug) f << "debug";
	if (options_ & Release) f << "release";
	if (optimize_ != "") f << "O" + optimize_;
	if (options_ & Bootstrap)
		f << "$MACHINE";
	else
		f << toolChain_->machine();
	modulePath_ = f->join("-");

	for (int i = 0; i < prerequisites_->count(); ++i)
		prerequisites_->at(i)->initModules();
}

} // namespace fluxmake
<|endoftext|>


<commit_before>#include <PageFrameAllocator.hh>
#include <Parameters.hh>
#include <Memory.hh>
#include <Multiboot.hh>
#include <Debug.hh>
#include <Templates.hh>
#include <Modules.hh>
#include <Memory.hh>
#include <Hal.hh>

#include <X86/ThreadContext.hh>

#include <cstring>

#undef DEBUG

#ifdef DEBUG
# define D(x) x
#else
# define D(x)
#endif

namespace
{
   uintptr_t heapEnd = HeapStart;
   uintptr_t stackEnd = StackStart;
   uintptr_t mapEnd = MapStart;

   MemorySegment memoryMap[MemoryMapMax];
   unsigned int memoryMapCount = 0;

   PageCluster usedPages;
   PageCluster freePages;

   spinlock_softirq_t pagesLock;
   spinlock_softirq_t memoryMapLock;
};

void
Memory::addMemoryMapEntry(uintptr_t start, size_t length)
{
   KASSERT(memoryMapCount < MemoryMapMax);

   memoryMap[memoryMapCount].address = start;
   memoryMap[memoryMapCount].size = length;
   memoryMapCount++;
}

void
Memory::init()
{
   printf("Listing Kernel sections:\n");
   printf(".text: %p-%p\n", &__start_text, &__end_text);
   printf(".data: %p-%p\n", &__start_data, &__end_data);
   printf(".rodata: %p-%p\n", &__start_rodata, &__end_rodata);
   printf(".bss: %p-%p\n", &__start_bss, &__end_bss);

   printf("Page size: %u, PhysicalPage structure size: %zu\n", PageSize, sizeof(PhysicalPage));

   spinlock_softirq_init(&pagesLock);
   spinlock_softirq_init(&memoryMapLock);

   usedPages.init();
   freePages.init();

   uintptr_t firstUsableMemory = max((uintptr_t )&__end_kernel, __end_modules);
   uintptr_t firstFreePage = roundTo<uintptr_t>(firstUsableMemory, PageSize) + PageSize * PageFrameCount;

   // init page clusters
   PhysicalPage* bootstrapPage = (PhysicalPage* )firstFreePage;
   bootstrapPage->init((uintptr_t )bootstrapPage - KernelVirtualBase);

   printf("Inserting bootstrap page to used pages cluster: %p\n", (void* )bootstrapPage->getAddress());
   usedPages.insert(bootstrapPage);

   unsigned int freeStructures = PageSize / sizeof (PhysicalPage) - 1;

   KASSERT(freeStructures > 0);
   printf("Free structures: %u\n", freeStructures);

   PhysicalPage* p = bootstrapPage + 1;
   for (unsigned int i = 0; i < memoryMapCount; i++)
   {
      printf("Adding memory range %p-%p (%zu)\n",
	     (void* )memoryMap[i].address,
	     (void* )(memoryMap[i].address + memoryMap[i].size),
	     memoryMap[i].size);

      for (uintptr_t addr = memoryMap[i].address;
	   addr < memoryMap[i].address + memoryMap[i].size;
	   addr += PageSize)
      {
	 if (freeStructures == 0)
	 {
	    D(printf("Allocating new page structure\n"));
	    //p = (PhysicalPage* )sbrk(PageSize)
	    uintptr_t ppage = getPage();
	    KASSERT(ppage != 0);
	    p = (PhysicalPage* )mapAnonymousPage(ppage); // XXX make a function for this
	    KASSERT(p != 0);
	    freeStructures = PageSize / sizeof (PhysicalPage);
	 }

	 p->init(addr);
	 if ((addr >= KernelLoadAddress) && (addr < firstFreePage - KernelVirtualBase))
	 {
	    D(printf("Found used page: %p\n", (void* )addr));
	    usedPages.insert(p);
	 }
	 else
	 {
	    D(printf("Inserting free page: %p\n", (void* )addr));
	    freePages.insert(p);
	 }

	 p++;
	 freeStructures--;
      }
   }

   uintptr_t start = stackEnd;
   printf("Creating initial kernel stack: %p-%p (%u)\n", (void* )start, (void* )(start - StackSize), StackSize);

   for (uintptr_t stackAddress = (start - StackSize);
	stackAddress < start;
	stackAddress += PageSize)
   {
      uintptr_t stackPage = getPage();
      KASSERT(stackPage != 0);

      bool success = mapPage(stackAddress, stackPage);
      KASSERT(success);
   }

   // add one unmapped page as guard
   stackEnd = start - StackSize - PageSize;

//   KASSERT(success);

//    printf("Freeing initial kernel stack: %p-%p\n", (void* )(initial_stack - InitialStackSize), (void* )initial_stack);
//    for (uintptr_t oldStack = initial_stack - InitialStackSize;
// 	oldStack < initial_stack;
// 	oldStack += PageSize)
//    {
//      unmap(oldStack);
//    }
}

// XXX curently this overlaps anon mappings, se we can only give one anon
// mapped page as the kernel stack area
#if 0
bool
Memory::createKernelStack(uintptr_t& start)
{
   start = stackEnd;

   printf("Creating new kernel stack: %p-%p (%u)\n", (void* )start, (void* )(start - StackSize), StackSize);

   for (uintptr_t stackAddress = (start - StackSize);
	stackAddress < start;
	stackAddress += PageSize)
   {
      uintptr_t stackPage = getPage();
      KASSERT(stackPage != 0);

      bool success = mapPage(stackAddress, stackPage);
      KASSERT(success);
   }

   // add one unmapped page as guard
   stackEnd = start - StackSize - PageSize;

   return true;
}
#else
bool
Memory::createKernelStack(uintptr_t& top)
{
   uintptr_t stackPage = getPage();
   KASSERT(stackPage != 0);

   uintptr_t bottom = mapAnonymousPage(stackPage);
   KASSERT(bottom != 0);

   top = bottom + PageSize;

   printf("Creating new kernel stack: %p-%p (%u)\n", (void* )top, (void* )(bottom), PageSize);

   uintptr_t newStack = Hal::initKernelStack(top);

   top = newStack;

   return true;
}
#endif

bool
Memory::mapPage(uintptr_t address, uintptr_t phys, int flags)
{
   bool success = Hal::mapPage(address, phys, flags);

   return success;
}

bool
Memory::unmapPage(uintptr_t page)
{
   bool success = Hal::unmapPage(page);
   // TODO we need to know where to mark the vaddr free!

   return success;
}

// anonymous mapping of a physical page
//
uintptr_t
Memory::mapAnonymousPage(uintptr_t phys, int flags)
{
   spinlock_softirq_enter(&memoryMapLock);

   mapEnd -= PageSize;
   uintptr_t virt = mapEnd;

   spinlock_softirq_exit(&memoryMapLock);

   if (virt <= (uintptr_t)&__end_kernel)
//   if (virt <= heapEnd)
   {
      printf("%p <= %p\n", (void*)virt, (void*)heapEnd);
      Debug::panic("Memory::mapPage: Kernel map namespace exhausted.");
   }

//   Debug::info("Mapping anonymous page: %p to %p\n", phys, mapEnd);
   bool success = mapPage(virt, phys, flags);
   if (!success)
   {
      return 0;
   }

   return virt;
}

// anonymous memory mapping
//
uintptr_t Memory::mapAnonymousRegion(size_t size, int flags)
{
   std::size_t rsize = roundTo<uintptr_t>(size, PageSize);

   spinlock_softirq_enter(&memoryMapLock);

   mapEnd -= rsize;
   uintptr_t vaddr = mapEnd;

   spinlock_softirq_exit(&memoryMapLock);

   if (vaddr <= (uintptr_t)&__end_kernel)
//   if (vaddr <= heapEnd)
   {
      printf("%p <= %p\n", (void*)vaddr, (void*)heapEnd);
      Debug::panic("Memory::mapAnonymousRegion: Kernel map name space exhausted.");
   }

   for (std::size_t i = 0; i < rsize / PageSize; i++, vaddr += PageSize)
   {
      uintptr_t emptyPage = getPage();
      KASSERT(emptyPage != 0);
      bool success = mapPage(vaddr, emptyPage, flags);
      if (!success)
      {
         Debug::panic("mapRegion unsuccesful.");
         // XXX unmap and return error
         //return 0;
      }
   }

   return mapEnd + rsize;
}

// anonymous mapping of a memory region
//
uintptr_t Memory::mapRegion(uintptr_t paddr, size_t size, int flags)
{
   uintptr_t firstPage = roundDown(paddr, PageSize);
   uintptr_t lastPage = roundTo(paddr + size, PageSize);
   size_t rsize = lastPage - firstPage;

   D(printf("Memory::mapRegion: %p-%p\n", (void*)paddr, (void*)(paddr + size)));
   D(printf("Memory::mapRegion: mapping: %p-%p (%zu)\n", (void*)firstPage, (void*)lastPage, rsize));

   spinlock_softirq_enter(&memoryMapLock);

   mapEnd -= rsize;
   uintptr_t vaddr = mapEnd;

   spinlock_softirq_exit(&memoryMapLock);

   uintptr_t offset = paddr - firstPage;

   if (vaddr <= (uintptr_t)&__end_kernel)
//   if (vaddr <= heapEnd)
   {
      printf("%p <= %p\n", (void*)vaddr, (void*)heapEnd);
      Debug::panic("Memory::mapRegion: Kernel map namespace exhausted.");
   }

   for (uintptr_t page = firstPage; page != lastPage; page += PageSize, vaddr += PageSize)
   {
      bool success = mapPage(vaddr, page, flags);
      if (!success)
      {
	 Debug::panic("mapRegion unsuccesful.");
	 // XXX unmap and return error
	 //return 0;
      }
   }

   return mapEnd + offset;
}

bool
Memory::unmapRegion(uintptr_t paddr, std::size_t size)
{
   std::size_t rsize = roundTo<uintptr_t>(size, PageSize);
   uintptr_t firstPage = roundDown(paddr, PageSize);

   for (uintptr_t page = firstPage;
	page < firstPage + rsize;
	page += PageSize)
   {
      bool success = unmapPage(page);
      if (!success)
      {
	 Debug::panic("unmapRegion unsuccesful.");
      }
   }

   return true;
}

// get a free physical page
//
uintptr_t
Memory::getPage()
{
   D(printf("Memory::getPage\n"));

   uintptr_t address = 0;

   spinlock_softirq_enter(&pagesLock);

   PhysicalPage* page = freePages.get();
   if (page != 0)
   {
      usedPages.insert(page);
      address = page->getAddress();
   }

   spinlock_softirq_exit(&pagesLock);

   D(printf("Memory::getPage done: %p\n", (void*)address));

   return address;
}

// free a physical page
//
void
Memory::putPage(uintptr_t address)
{
   D(printf("Memory::putPage: %p\n", (void*)address));

   spinlock_softirq_enter(&pagesLock);

   PhysicalPage* page = usedPages.find(address);

   if (page == 0)
   {
      spinlock_softirq_exit(&pagesLock);
      Debug::panic("Trying to free an unallocated physical page: %p\n", (void* )address);
   }

   usedPages.remove(page);
   freePages.insert(page);

   spinlock_softirq_exit(&pagesLock);
}

void*
Memory::readPhysicalMemory(void* destination, const void* source, std::size_t size)
{
   uintptr_t mapFirst = roundDown(uintptr_t(source), PageSize);
   uintptr_t mapLast = roundTo(uintptr_t(source), PageSize);

   uintptr_t mapped = mapRegion(mapFirst, mapLast - mapFirst);

   std::memcpy(destination, reinterpret_cast<void*>(mapped + (uintptr_t(source) - mapFirst)), size);

   unmapRegion(mapped, mapLast - mapFirst);

   return destination;
}
<commit_msg>MM cleanup<commit_after>#include <PageFrameAllocator.hh>
#include <Parameters.hh>
#include <Memory.hh>
#include <Multiboot.hh>
#include <Debug.hh>
#include <Templates.hh>
#include <Modules.hh>
#include <Memory.hh>
#include <Hal.hh>

#include <X86/ThreadContext.hh>

#include <cstring>

#undef DEBUG

#ifdef DEBUG
# define D(x) x
#else
# define D(x)
#endif

namespace
{
   uintptr_t heapEnd = HeapStart;
   uintptr_t stackEnd = StackStart;
   uintptr_t mapEnd = MapStart;

   MemorySegment memoryMap[MemoryMapMax];
   unsigned int memoryMapCount = 0;

   PageCluster usedPages;
   PageCluster freePages;

   spinlock_softirq_t pagesLock;
   spinlock_softirq_t memoryMapLock;
};

void
Memory::addMemoryMapEntry(uintptr_t start, size_t length)
{
   KASSERT(memoryMapCount < MemoryMapMax);

   memoryMap[memoryMapCount].address = start;
   memoryMap[memoryMapCount].size = length;
   memoryMapCount++;
}

void
Memory::init()
{
   printf("Listing Kernel sections:\n");
   printf(".text: %p-%p\n", &__start_text, &__end_text);
   printf(".data: %p-%p\n", &__start_data, &__end_data);
   printf(".rodata: %p-%p\n", &__start_rodata, &__end_rodata);
   printf(".bss: %p-%p\n", &__start_bss, &__end_bss);

   printf("Page size: %u, PhysicalPage structure size: %zu\n", PageSize, sizeof(PhysicalPage));

   spinlock_softirq_init(&pagesLock);
   spinlock_softirq_init(&memoryMapLock);

   usedPages.init();
   freePages.init();

   uintptr_t firstUsableMemory = max((uintptr_t )&__end_kernel, __end_modules);
   uintptr_t firstFreePage = roundTo<uintptr_t>(firstUsableMemory, PageSize) + PageSize * PageFrameCount;

   // init page clusters
   PhysicalPage* bootstrapPage = (PhysicalPage* )firstFreePage;
   bootstrapPage->init((uintptr_t )bootstrapPage - KernelVirtualBase);

   printf("Inserting bootstrap page to used pages cluster: %p\n", (void* )bootstrapPage->getAddress());
   usedPages.insert(bootstrapPage);

   unsigned int freeStructures = PageSize / sizeof (PhysicalPage) - 1;

   KASSERT(freeStructures > 0);
   printf("Free structures: %u\n", freeStructures);

   PhysicalPage* p = bootstrapPage + 1;
   for (unsigned int i = 0; i < memoryMapCount; i++)
   {
      printf("Adding memory range %p-%p (%zu)\n",
	     (void* )memoryMap[i].address,
	     (void* )(memoryMap[i].address + memoryMap[i].size),
	     memoryMap[i].size);

      for (uintptr_t addr = memoryMap[i].address;
	   addr < memoryMap[i].address + memoryMap[i].size;
	   addr += PageSize)
      {
	 if (freeStructures == 0)
	 {
	    D(printf("Allocating new page structure\n"));
	    //p = (PhysicalPage* )sbrk(PageSize)
	    uintptr_t ppage = getPage();
	    KASSERT(ppage != 0);
	    p = (PhysicalPage* )mapAnonymousPage(ppage); // XXX make a function for this
	    KASSERT(p != 0);
	    freeStructures = PageSize / sizeof (PhysicalPage);
	 }

	 p->init(addr);
	 if ((addr >= KernelLoadAddress) && (addr < firstFreePage - KernelVirtualBase))
	 {
	    D(printf("Found used page: %p\n", (void* )addr));
	    usedPages.insert(p);
	 }
	 else
	 {
	    D(printf("Inserting free page: %p\n", (void* )addr));
	    freePages.insert(p);
	 }

	 p++;
	 freeStructures--;
      }
   }

   uintptr_t start = stackEnd;
   printf("Creating initial kernel stack: %p-%p (%u)\n", (void* )start, (void* )(start - StackSize), StackSize);

   for (uintptr_t stackAddress = (start - StackSize);
	stackAddress < start;
	stackAddress += PageSize)
   {
      uintptr_t stackPage = getPage();
      KASSERT(stackPage != 0);

      bool success = mapPage(stackAddress, stackPage);
      KASSERT(success);
   }

   // add one unmapped page as guard
   stackEnd = start - StackSize - PageSize;

//   KASSERT(success);

//    printf("Freeing initial kernel stack: %p-%p\n", (void* )(initial_stack - InitialStackSize), (void* )initial_stack);
//    for (uintptr_t oldStack = initial_stack - InitialStackSize;
// 	oldStack < initial_stack;
// 	oldStack += PageSize)
//    {
//      unmap(oldStack);
//    }
}

// XXX curently this overlaps anon mappings, se we can only give one anon
// mapped page as the kernel stack area
#if 0
bool
Memory::createKernelStack(uintptr_t& start)
{
   start = stackEnd;

   printf("Creating new kernel stack: %p-%p (%u)\n", (void* )start, (void* )(start - StackSize), StackSize);

   for (uintptr_t stackAddress = (start - StackSize);
	stackAddress < start;
	stackAddress += PageSize)
   {
      uintptr_t stackPage = getPage();
      KASSERT(stackPage != 0);

      bool success = mapPage(stackAddress, stackPage);
      KASSERT(success);
   }

   // add one unmapped page as guard
   stackEnd = start - StackSize - PageSize;

   return true;
}
#else
bool
Memory::createKernelStack(uintptr_t& top)
{
   uintptr_t stackPage = getPage();
   KASSERT(stackPage != 0);

   uintptr_t bottom = mapAnonymousPage(stackPage);
   KASSERT(bottom != 0);

   top = bottom + PageSize;

   printf("Creating new kernel stack: %p-%p (%u)\n", (void* )top, (void* )(bottom), PageSize);

   uintptr_t newStack = Hal::initKernelStack(top);

   top = newStack;

   return true;
}
#endif

bool
Memory::mapPage(uintptr_t address, uintptr_t phys, int flags)
{
   bool success = Hal::mapPage(address, phys, flags);

   return success;
}

bool
Memory::unmapPage(uintptr_t page)
{
   bool success = Hal::unmapPage(page);
   // TODO we need to know where to mark the vaddr free!

   return success;
}

// anonymous mapping of a physical page
//
uintptr_t
Memory::mapAnonymousPage(uintptr_t phys, int flags)
{
   spinlock_softirq_enter(&memoryMapLock);

   mapEnd -= PageSize;
   uintptr_t virt = mapEnd;

   spinlock_softirq_exit(&memoryMapLock);

   if (virt <= (uintptr_t)&__end_kernel)
//   if (virt <= heapEnd)
   {
      printf("%p <= %p\n", (void*)virt, (void*)heapEnd);
      Debug::panic("Memory::mapPage: Kernel map namespace exhausted.");
   }

//   Debug::info("Mapping anonymous page: %p to %p\n", phys, mapEnd);
   bool success = mapPage(virt, phys, flags);
   if (!success)
   {
      return 0;
   }

   return virt;
}

// anonymous memory mapping
//
uintptr_t Memory::mapAnonymousRegion(size_t size, int flags)
{
   size_t rsize = roundTo<uintptr_t>(size, PageSize);

   spinlock_softirq_enter(&memoryMapLock);

   mapEnd -= rsize;
   uintptr_t vaddr = mapEnd;

   spinlock_softirq_exit(&memoryMapLock);

   if (vaddr <= (uintptr_t)&__end_kernel)
//   if (vaddr <= heapEnd)
   {
      printf("%p <= %p\n", (void*)vaddr, (void*)heapEnd);
      Debug::panic("Memory::mapAnonymousRegion: Kernel map name space exhausted.");
   }

   for (size_t page = 0; page < rsize; page += PageSize)
   {
      uintptr_t emptyPage = getPage();
      KASSERT(emptyPage != 0);
      bool success = mapPage(vaddr + page, emptyPage, flags);
      if (!success)
      {
         Debug::panic("mapRegion unsuccesful.");
         // XXX unmap and return error
         //return 0;
      }
   }

   return vaddr;
}

// anonymous mapping of a memory region
//
uintptr_t Memory::mapRegion(uintptr_t paddr, size_t size, int flags)
{
   uintptr_t firstPage = roundDown(paddr, PageSize);
   uintptr_t lastPage = roundTo(paddr + size, PageSize);
   size_t rsize = lastPage - firstPage;

   D(printf("Memory::mapRegion: %p-%p\n", (void*)paddr, (void*)(paddr + size)));
   D(printf("Memory::mapRegion: mapping: %p-%p (%zu)\n", (void*)firstPage, (void*)lastPage, rsize));

   spinlock_softirq_enter(&memoryMapLock);

   mapEnd -= rsize;
   uintptr_t vaddr = mapEnd;

   spinlock_softirq_exit(&memoryMapLock);

   uintptr_t offset = paddr - firstPage;

   if (vaddr <= (uintptr_t)&__end_kernel)
//   if (vaddr <= heapEnd)
   {
      printf("%p <= %p\n", (void*)vaddr, (void*)heapEnd);
      Debug::panic("Memory::mapRegion: Kernel map namespace exhausted.");
   }

   for (uintptr_t page = firstPage; page != lastPage; page += PageSize, vaddr += PageSize)
   {
      bool success = mapPage(vaddr, page, flags);
      if (!success)
      {
	 Debug::panic("mapRegion unsuccesful.");
	 // XXX unmap and return error
	 //return 0;
      }
   }

   return mapEnd + offset;
}

bool
Memory::unmapRegion(uintptr_t paddr, std::size_t size)
{
   uintptr_t firstPage = roundDown(paddr, PageSize);
   uintptr_t lastPage = roundTo(paddr + size, PageSize);

   for (uintptr_t page = firstPage; page != lastPage; page += PageSize)
   {
      bool success = unmapPage(page);
      if (!success)
      {
	 Debug::panic("unmapRegion unsuccesful.");
      }
   }

   return true;
}

// get a free physical page
//
uintptr_t
Memory::getPage()
{
   D(printf("Memory::getPage\n"));

   uintptr_t address = 0;

   spinlock_softirq_enter(&pagesLock);

   PhysicalPage* page = freePages.get();
   if (page != 0)
   {
      usedPages.insert(page);
      address = page->getAddress();
   }

   spinlock_softirq_exit(&pagesLock);

   D(printf("Memory::getPage done: %p\n", (void*)address));

   return address;
}

// free a physical page
//
void
Memory::putPage(uintptr_t address)
{
   D(printf("Memory::putPage: %p\n", (void*)address));

   spinlock_softirq_enter(&pagesLock);

   PhysicalPage* page = usedPages.find(address);

   if (page == 0)
   {
      spinlock_softirq_exit(&pagesLock);
      Debug::panic("Trying to free an unallocated physical page: %p\n", (void* )address);
   }

   usedPages.remove(page);
   freePages.insert(page);

   spinlock_softirq_exit(&pagesLock);
}

void*
Memory::readPhysicalMemory(void* destination, const void* source, std::size_t size)
{
   uintptr_t mapFirst = roundDown(uintptr_t(source), PageSize);
   uintptr_t mapLast = roundTo(uintptr_t(source), PageSize);

   uintptr_t mapped = mapRegion(mapFirst, mapLast - mapFirst);

   std::memcpy(destination, reinterpret_cast<void*>(mapped + (uintptr_t(source) - mapFirst)), size);

   unmapRegion(mapped, mapLast - mapFirst);

   return destination;
}
<|endoftext|>


<commit_before>#include <Arduino.h>
#include <SoftwareSerial.h>
#include "Adafruit_BNO055.h"
#include "Adafruit_DRV2605.h"

extern "C" {
	//#include "pfleury/uart.h"
};

FUSES =
{
	.low = 0xFF,	//0xFF
	.high = FUSE_SPIEN & FUSE_BOOTSZ0 & FUSE_BOOTRST,	//0xDC
	.extended = FUSE_BODLEVEL1	//0xFD
};
LOCKBITS = LB_MODE_3;	//0xFC

#define UART_BAUD_RATE	115200
#define FILTER_LOG2		4		// power of two

Adafruit_BNO055 bno = Adafruit_BNO055(55);
Adafruit_DRV2605 drv = Adafruit_DRV2605();

SoftwareSerial SoftSerial(2, 3);
unsigned char buffer[64];
#define ID_LENGTH 12
unsigned char last[ID_LENGTH];
uint8_t listcnt = 0;
uint8_t ledcnt = 0;
#define VIB_CNT 15
#define VIB_BIB 1
#define VIB_NR 14
uint8_t vibcnt = 0;
uint8_t vibr[] = {14, 15, 16, 47, 48, 54, 64, 70, 73, 74};
#define KEY	6
#define SWITCH	7
#define CAPSENS	8
#define MYOSENS A6

void process_rfid(uint8_t c)
{
	static int count = 0;
	if (c == 0x02)
	{
		count = 0;
	}
	else if (c == 0x03)
	{
		ledcnt = 0;
		if (memcmp(buffer, last, sizeof(last)) != 0)
		{
			memcpy(last, buffer, sizeof(last));
			drv.setWaveform(VIB_BIB, VIB_NR);
			drv.go();
			vibcnt = VIB_CNT;
		}
	}
	else if(count < 64)
	{
		buffer[count++] = c;
	}
}

inline void set_led(void)
{
	if (ledcnt < 10)
	{
		if (ledcnt == 0)
		{
			digitalWrite(LED_BUILTIN, HIGH);
		}
		ledcnt++;
	}
	else
	{
		digitalWrite(LED_BUILTIN, LOW);
	}
}

inline void process_cmd(uint8_t cmd)
{
	if (cmd >= '0' && cmd <= '9' && cmd - '0' < (uint8_t) sizeof(vibr))
	{
		drv.setWaveform(VIB_BIB, vibr[cmd - '0']);
		drv.go();
	}
}

inline void set_vib_2nd(void)
{
	if (vibcnt != 0)
	{
		vibcnt--;
		if (vibcnt == 0)
		{
			drv.setWaveform(VIB_BIB, VIB_NR);
			drv.go();
		}
	}
}

inline void print_bno(void)
{
	sensors_event_t event;
	bno.getEvent(&event);
	imu::Vector<3> vec = bno.getVector(Adafruit_BNO055::VECTOR_LINEARACCEL);

	Serial.print("{\"rfid\":\"");
	Serial.write(buffer,ID_LENGTH);
	Serial.print("\",\"imu\":{\"e\":{\"x\":");
	Serial.print(event.orientation.x, 4);
	Serial.print(",\"y\":");
	Serial.print(event.orientation.y, 4);
	Serial.print(",\"z\":");
	Serial.print(event.orientation.z, 4);
	Serial.print("},\"a\":{\"x\":");
	Serial.print(vec.x(), 4);
	Serial.print(",\"y\":");
	Serial.print(vec.y(), 4);
	Serial.print(",\"z\":");
	Serial.print(vec.z(), 4);
	Serial.print("}}");
}

inline void print_dig(void)
{
	Serial.print(",\"key\" :");
	Serial.print(digitalRead(KEY) ? '1' : '0');
	Serial.print(",\"switch\" :");
	Serial.print(digitalRead(SWITCH) ? '1' : '0');
	Serial.print(",\"capsens\" :");
	Serial.print(digitalRead(CAPSENS) ? '1' : '0');
}

inline void print_ana(void)
{
	Serial.print(",\"myo\" :");
	Serial.print(analogRead(MYOSENS));
	Serial.print("}\n");
}

void setup()
{
	pinMode(LED_BUILTIN, OUTPUT);
	pinMode(KEY, INPUT_PULLUP);
	pinMode(SWITCH, INPUT_PULLUP);
	pinMode(CAPSENS, INPUT_PULLUP);
	Serial.begin(115200);
	SoftSerial.begin(9600);
	if(!bno.begin())
	{
		//uart_puts("Ooops, no BNO055 detected ... Check your wiring or I2C ADDR!");
		while(1);
	}
	delay(1000);
	bno.setExtCrystalUse(true);

	drv.begin();
	drv.useERM();
	drv.selectLibrary(2);
	drv.setWaveform(VIB_BIB, VIB_NR);

	sei();
}

void loop()
{
	print_bno();
	print_dig();
	print_ana();

	set_led();

	delay(20);

	while(SoftSerial.available())
	{
		process_rfid(SoftSerial.read());
	}
	if (Serial.available())
	{
		process_cmd(Serial.read());
	}
	set_vib_2nd();
}
<commit_msg>Add 2nd RFID<commit_after>#include <Arduino.h>
#include <SoftwareSerial.h>
#include "Adafruit_BNO055.h"
#include "Adafruit_DRV2605.h"

extern "C" {
	//#include "pfleury/uart.h"
};

FUSES =
{
	.low = 0xFF,	//0xFF
	.high = FUSE_SPIEN & FUSE_BOOTSZ0 & FUSE_BOOTRST,	//0xDC
	.extended = FUSE_BODLEVEL1	//0xFD
};
LOCKBITS = LB_MODE_3;	//0xFC

#define UART_BAUD_RATE	115200

Adafruit_BNO055 bno = Adafruit_BNO055(55);
Adafruit_DRV2605 drv = Adafruit_DRV2605();

SoftwareSerial RFID_1(2, 3);
SoftwareSerial RFID_2(4, 5);
uint8_t switchcnt;
unsigned char buffer[64];
#define ID_LENGTH 12
unsigned char last[ID_LENGTH];
uint8_t lastnr = 0;
uint8_t listcnt = 0;
uint8_t ledcnt = 0;
#define VIB_CNT 15
#define VIB_BIB 1
#define VIB_NR 14
uint8_t vibcnt = 0;
uint8_t vibr[] = {14, 15, 16, 47, 48, 54, 64, 70, 73, 74};
#define KEY	6
#define SWITCH	7
#define CAPSENS	8
#define MYOSENS A6

void process_rfid(uint8_t c)
{
	static int count = 0;
	if (c == 0x02)
	{
		count = 0;
	}
	else if (c == 0x03)
	{
		ledcnt = 0;
		if (memcmp(buffer, last, sizeof(last)) != 0)
		{
			memcpy(last, buffer, sizeof(last));
			drv.setWaveform(VIB_BIB, VIB_NR);
			drv.go();
			vibcnt = VIB_CNT;
		}
	}
	else if(count < 64)
	{
		buffer[count++] = c;
	}
}

inline void set_led(void)
{
	if (ledcnt < 10)
	{
		if (ledcnt == 0)
		{
			digitalWrite(LED_BUILTIN, HIGH);
		}
		ledcnt++;
	}
	else
	{
		digitalWrite(LED_BUILTIN, LOW);
	}
}

inline void process_cmd(uint8_t cmd)
{
	if (cmd >= '0' && cmd <= '9' && cmd - '0' < (uint8_t) sizeof(vibr))
	{
		drv.setWaveform(VIB_BIB, vibr[cmd - '0']);
		drv.go();
	}
}

inline void set_vib_2nd(void)
{
	if (vibcnt != 0)
	{
		vibcnt--;
		if (vibcnt == 0)
		{
			drv.setWaveform(VIB_BIB, VIB_NR);
			drv.go();
		}
	}
}

inline void print_rfid(void)
{
	Serial.print("{\"rfid\":{\"id\":\"");
	Serial.write(last, ID_LENGTH);
	Serial.print("\",\"nr\":");
	Serial.print(lastnr);
	Serial.print('}');

}

inline void print_bno(void)
{
	sensors_event_t event;
	bno.getEvent(&event);
	imu::Vector<3> vec = bno.getVector(Adafruit_BNO055::VECTOR_LINEARACCEL);

	Serial.print(",\"imu\":{\"e\":{\"x\":");
	Serial.print(event.orientation.x, 4);
	Serial.print(",\"y\":");
	Serial.print(event.orientation.y, 4);
	Serial.print(",\"z\":");
	Serial.print(event.orientation.z, 4);
	Serial.print("},\"a\":{\"x\":");
	Serial.print(vec.x(), 4);
	Serial.print(",\"y\":");
	Serial.print(vec.y(), 4);
	Serial.print(",\"z\":");
	Serial.print(vec.z(), 4);
	Serial.print("}}");
}

inline void print_dig(void)
{
	Serial.print(",\"key\" :");
	Serial.print(digitalRead(KEY) ? '1' : '0');
	Serial.print(",\"switch\" :");
	Serial.print(digitalRead(SWITCH) ? '1' : '0');
	Serial.print(",\"capsens\" :");
	Serial.print(digitalRead(CAPSENS) ? '1' : '0');
}

inline void print_ana(void)
{
	Serial.print(",\"myo\" :");
	Serial.print(analogRead(MYOSENS));
	Serial.print("}\n");
}

void setup()
{
	pinMode(LED_BUILTIN, OUTPUT);
	pinMode(KEY, INPUT_PULLUP);
	pinMode(SWITCH, INPUT_PULLUP);
	pinMode(CAPSENS, INPUT_PULLUP);
	Serial.begin(115200);
	RFID_1.begin(9600);
	RFID_2.begin(9600);
	if(!bno.begin())
	{
		//uart_puts("Ooops, no BNO055 detected ... Check your wiring or I2C ADDR!");
		while(1);
	}
	delay(1000);
	bno.setExtCrystalUse(true);

	drv.begin();
	drv.useERM();
	drv.selectLibrary(2);
	drv.setWaveform(VIB_BIB, VIB_NR);

	sei();
}

void loop()
{
	print_rfid();
	print_bno();
	print_dig();
	print_ana();

	set_led();

	delay(20);

	if (switchcnt++ % 10 < 5)
	{
		RFID_1.listen();
		while(RFID_1.available() > 0)
		{
			lastnr = 0;
			process_rfid(RFID_1.read());
		}
	} else {
		RFID_2.listen();
		while(RFID_2.available() > 0)
		{
			lastnr = 1;
			process_rfid(RFID_2.read());
		}
	}
	if (Serial.available())
	{
		process_cmd(Serial.read());
	}
	set_vib_2nd();
}
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/
/*
$Log$
Revision 1.4  2000/06/29 12:34:09  morsch
AliMUONSegmentation class has been made independent of AliMUONChamber. This makes
it usable with any other geometry class. The link to the object to which it belongs is
established via an index. This assumes that there exists a global geometry manager
from which the pointer to the parent object can be obtained (in our case gAlice).

Revision 1.3  2000/06/28 15:16:35  morsch
(1) Client code adapted to new method signatures in AliMUONSegmentation (see comments there)
to allow development of slat-muon chamber simulation and reconstruction code in the MUON
framework. The changes should have no side effects (mostly dummy arguments).
(2) Hit disintegration uses 3-dim hit coordinates to allow simulation
of chambers with overlapping modules (MakePadHits, Disintegration).

Revision 1.2  2000/06/15 07:58:48  morsch
Code from MUON-dev joined

Revision 1.1.2.5  2000/06/09 21:27:01  morsch
Most coding rule violations corrected.

Revision 1.1.2.4  2000/05/05 11:34:12  morsch
Log inside comments.

Revision 1.1.2.3  2000/05/05 10:09:52  morsch
Log messages included
*/

#include "AliMUONChamber.h"
#include "AliMUONResponse.h"

#include "TMath.h"
ClassImp(AliMUONChamber)

    AliMUONChamber::AliMUONChamber()
{
// Default constructor
    fSegmentation = new TObjArray(2);
    (*fSegmentation)[0] = 0;
    (*fSegmentation)[1] = 0;
    fResponse=0;
    fnsec=1;
    fReconstruction=0;
    fId=0;
}

    AliMUONChamber::AliMUONChamber(Int_t id)
{
// Construtor with chamber id
    fSegmentation = new TObjArray(2);
    (*fSegmentation)[0] = 0;
    (*fSegmentation)[1] = 0;
    fResponse=0;
    fnsec=1;
    fReconstruction=0;
    fId=id;
}

AliMUONChamber::~AliMUONChamber()
{
// Destructor
    if (fSegmentation) delete fSegmentation;
}

AliMUONChamber::AliMUONChamber(const AliMUONChamber& rChamber)
{
// Dummy copy constructor
    ;
}

void AliMUONChamber::Init()
{
// Initalisation ..
//
// ... for chamber segmentation
    if ((*fSegmentation)[0])
    ((AliSegmentation *) (*fSegmentation)[0])->Init(fId);

    if (fnsec==2) {
	if ((*fSegmentation)[1])
	((AliSegmentation *) (*fSegmentation)[1])->Init(fId);
    }
}

Int_t   AliMUONChamber::SigGenCond(Float_t x, Float_t y, Float_t z)
{
// Ask segmentation if signal should be generated
    if (fnsec==1) {
	return ((AliSegmentation*) (*fSegmentation)[0])
	    ->SigGenCond(x, y, z) ;
    } else {
	return (((AliSegmentation*) (*fSegmentation)[0])
		->SigGenCond(x, y, z)) ||
	    (((AliSegmentation*) (*fSegmentation)[1])
	     ->SigGenCond(x, y, z)) ;
    }
}

void    AliMUONChamber::SigGenInit(Float_t x, Float_t y, Float_t z)
{
//
// Initialisation of segmentation for hit
//
    if (fnsec==1) {
	((AliSegmentation*) (*fSegmentation)[0])->SigGenInit(x, y, z) ;
    } else {
	((AliSegmentation*) (*fSegmentation)[0])->SigGenInit(x, y, z) ;
	((AliSegmentation*) (*fSegmentation)[1])->SigGenInit(x, y, z) ;
    }
}

void AliMUONChamber::DisIntegration(Float_t eloss, Float_t tof,
				    Float_t xhit, Float_t yhit, Float_t zhit,
				    Int_t& nnew,Float_t newclust[6][500])
{
//
//  Generates pad hits (simulated cluster)
//  using the segmentation and the response model
    Float_t dx, dy;
    //
    // Width of the integration area
    //
    dx=fResponse->SigmaIntegration()*fResponse->ChargeSpreadX();
    dy=fResponse->SigmaIntegration()*fResponse->ChargeSpreadY();
    //
    // Get pulse height from energy loss
    Float_t qtot = fResponse->IntPH(eloss);
    //
    // Loop Over Pads

    Float_t qcheck=0, qp;
    nnew=0;
    for (Int_t i=1; i<=fnsec; i++) {
	qcheck=0;
	AliSegmentation * segmentation=
	    (AliSegmentation *) (*fSegmentation)[i-1];
	for (segmentation->FirstPad(xhit, yhit, zhit, dx, dy);
	     segmentation->MorePads();
	     segmentation->NextPad())
	{
	    qp=fResponse->IntXY(segmentation);
	    qp=TMath::Abs(qp);

//
//
	    if (qp > 1.e-4) {
		qcheck+=qp;
	    //
	    // --- store signal information
		newclust[0][nnew]=qtot;                     // total charge
		newclust[1][nnew]=segmentation->Ix();       // ix-position of pad
		newclust[2][nnew]=segmentation->Iy();       // iy-position of pad
		newclust[3][nnew]=qp * qtot;                // charge on pad
		newclust[4][nnew]=segmentation->ISector();  // sector id
		newclust[5][nnew]=(Float_t) i;              // counter
		nnew++;
	    }
	} // Pad loop
    } // Cathode plane loop
}

void AliMUONChamber::InitGeo(Float_t zpos)
{
//    sensitive gas gap
      fdGas= 0.5;
//    3% radiation length of aluminum (X0=8.9 cm)
      fdAlu= 3.0/100*8.9;
}

AliMUONChamber & AliMUONChamber::operator =(const AliMUONChamber& rhs)
{
// Dummy assignment operator
    return *this;
}
<commit_msg>Double inclusion of AliResponse removed.<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/
/*
$Log$
Revision 1.5  2000/07/03 11:54:57  morsch
AliMUONSegmentation and AliMUONHitMap have been replaced by AliSegmentation and AliHitMap in STEER
The methods GetPadIxy and GetPadXxy of AliMUONSegmentation have changed name to GetPadI and GetPadC.

Revision 1.4  2000/06/29 12:34:09  morsch
AliMUONSegmentation class has been made independent of AliMUONChamber. This makes
it usable with any other geometry class. The link to the object to which it belongs is
established via an index. This assumes that there exists a global geometry manager
from which the pointer to the parent object can be obtained (in our case gAlice).

Revision 1.3  2000/06/28 15:16:35  morsch
(1) Client code adapted to new method signatures in AliMUONSegmentation (see comments there)
to allow development of slat-muon chamber simulation and reconstruction code in the MUON
framework. The changes should have no side effects (mostly dummy arguments).
(2) Hit disintegration uses 3-dim hit coordinates to allow simulation
of chambers with overlapping modules (MakePadHits, Disintegration).

Revision 1.2  2000/06/15 07:58:48  morsch
Code from MUON-dev joined

Revision 1.1.2.5  2000/06/09 21:27:01  morsch
Most coding rule violations corrected.

Revision 1.1.2.4  2000/05/05 11:34:12  morsch
Log inside comments.

Revision 1.1.2.3  2000/05/05 10:09:52  morsch
Log messages included
*/

#include "AliMUONChamber.h"

#include "TMath.h"
ClassImp(AliMUONChamber)

    AliMUONChamber::AliMUONChamber()
{
// Default constructor
    fSegmentation = new TObjArray(2);
    (*fSegmentation)[0] = 0;
    (*fSegmentation)[1] = 0;
    fResponse=0;
    fnsec=1;
    fReconstruction=0;
    fId=0;
}

    AliMUONChamber::AliMUONChamber(Int_t id)
{
// Construtor with chamber id
    fSegmentation = new TObjArray(2);
    (*fSegmentation)[0] = 0;
    (*fSegmentation)[1] = 0;
    fResponse=0;
    fnsec=1;
    fReconstruction=0;
    fId=id;
}

AliMUONChamber::~AliMUONChamber()
{
// Destructor
    if (fSegmentation) delete fSegmentation;
}

AliMUONChamber::AliMUONChamber(const AliMUONChamber& rChamber)
{
// Dummy copy constructor
    ;
}

void AliMUONChamber::Init()
{
// Initalisation ..
//
// ... for chamber segmentation
    if ((*fSegmentation)[0])
    ((AliSegmentation *) (*fSegmentation)[0])->Init(fId);

    if (fnsec==2) {
	if ((*fSegmentation)[1])
	((AliSegmentation *) (*fSegmentation)[1])->Init(fId);
    }
}

Int_t   AliMUONChamber::SigGenCond(Float_t x, Float_t y, Float_t z)
{
// Ask segmentation if signal should be generated
    if (fnsec==1) {
	return ((AliSegmentation*) (*fSegmentation)[0])
	    ->SigGenCond(x, y, z) ;
    } else {
	return (((AliSegmentation*) (*fSegmentation)[0])
		->SigGenCond(x, y, z)) ||
	    (((AliSegmentation*) (*fSegmentation)[1])
	     ->SigGenCond(x, y, z)) ;
    }
}

void    AliMUONChamber::SigGenInit(Float_t x, Float_t y, Float_t z)
{
//
// Initialisation of segmentation for hit
//
    if (fnsec==1) {
	((AliSegmentation*) (*fSegmentation)[0])->SigGenInit(x, y, z) ;
    } else {
	((AliSegmentation*) (*fSegmentation)[0])->SigGenInit(x, y, z) ;
	((AliSegmentation*) (*fSegmentation)[1])->SigGenInit(x, y, z) ;
    }
}

void AliMUONChamber::DisIntegration(Float_t eloss, Float_t tof,
				    Float_t xhit, Float_t yhit, Float_t zhit,
				    Int_t& nnew,Float_t newclust[6][500])
{
//
//  Generates pad hits (simulated cluster)
//  using the segmentation and the response model
    Float_t dx, dy;
    //
    // Width of the integration area
    //
    dx=fResponse->SigmaIntegration()*fResponse->ChargeSpreadX();
    dy=fResponse->SigmaIntegration()*fResponse->ChargeSpreadY();
    //
    // Get pulse height from energy loss
    Float_t qtot = fResponse->IntPH(eloss);
    //
    // Loop Over Pads

    Float_t qcheck=0, qp;
    nnew=0;

    for (Int_t i=1; i<=fnsec; i++) {
	qcheck=0;
	AliSegmentation * segmentation=
	    (AliSegmentation *) (*fSegmentation)[i-1];
	for (segmentation->FirstPad(xhit, yhit, zhit, dx, dy);
	     segmentation->MorePads();
	     segmentation->NextPad())
	{
	    qp=fResponse->IntXY(segmentation);
	    qp=TMath::Abs(qp);
//
//
	    if (qp > 1.e-4) {
		qcheck+=qp*qtot;
	    //
	    // --- store signal information
		newclust[0][nnew]=qtot;                     // total charge
		newclust[1][nnew]=segmentation->Ix();       // ix-position of pad
		newclust[2][nnew]=segmentation->Iy();       // iy-position of pad
		newclust[3][nnew]=qp * qtot;                // charge on pad
		newclust[4][nnew]=segmentation->ISector();  // sector id
		newclust[5][nnew]=(Float_t) i;              // counter
		nnew++;
//		if (i==2) printf("\n i, nnew, q %d %d %f", i, nnew, qp*qtot);

	    }
	} // Pad loop

    } // Cathode plane loop
}

void AliMUONChamber::InitGeo(Float_t zpos)
{
//    sensitive gas gap
      fdGas= 0.5;
//    3% radiation length of aluminum (X0=8.9 cm)
      fdAlu= 3.0/100*8.9;
}

AliMUONChamber & AliMUONChamber::operator =(const AliMUONChamber& rhs)
{
// Dummy assignment operator
    return *this;
}
<|endoftext|>


<commit_before>/*
 *  Author:
 *     Guido Tack <guido.tack@monash.edu>
 *
 *  Copyright:
 *     NICTA 2013
 */

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "project.h"
#include "ui_mainwindow.h"

#include <QFileInfo>
#include <QDir>
#include <QDebug>

Project::Project(Ui::MainWindow *ui0) : ui(ui0)
{
    projectFile = new QStandardItem("Untitled Project");
    invisibleRootItem()->appendRow(projectFile);
    mzn = new QStandardItem("Models");
    QFont font = mzn->font();
    font.setBold(true);
    mzn->setFont(font);
    invisibleRootItem()->appendRow(mzn);
    dzn = new QStandardItem("Data (right-click to run)");
    dzn->setFont(font);
    invisibleRootItem()->appendRow(dzn);
    other = new QStandardItem("Other");
    other->setFont(font);
    invisibleRootItem()->appendRow(other);
    _isModified = false;
}

void Project::setRoot(QTreeView* treeView, const QString &fileName)
{
    if (fileName == projectRoot)
        return;
    _isModified = true;
    projectFile->setText(QFileInfo(fileName).fileName());
    projectFile->setIcon(QIcon(":/images/mznicon.png"));
    QStringList allFiles = files();
    if (mzn->rowCount() > 0)
        mzn->removeRows(0,mzn->rowCount());
    if (dzn->rowCount() > 0)
        dzn->removeRows(0,dzn->rowCount());
    if (other->rowCount() > 0)
        other->removeRows(0,other->rowCount());
    projectRoot = fileName;
    _files.clear();
    for (QStringList::iterator it = allFiles.begin(); it != allFiles.end(); ++it) {
        addFile(treeView, *it);
    }
}

void Project::addFile(QTreeView* treeView, const QString &fileName)
{
    if (_files.contains(fileName))
        return;
    QFileInfo fi(fileName);
    QString absFileName = fi.absoluteFilePath();
    QString relFileName;
    if (!projectRoot.isEmpty()) {
        QDir projectDir(QFileInfo(projectRoot).absoluteDir());
        relFileName = projectDir.relativeFilePath(absFileName);
    } else {
        relFileName = absFileName;
    }

    QStringList path = relFileName.split(QDir::separator());
    while (path.first().isEmpty()) {
        path.pop_front();
    }
    QStandardItem* curItem;
    bool isMiniZinc = true;
    if (fi.suffix()=="mzn") {
        curItem = mzn;
    } else if (fi.suffix()=="dzn") {
        curItem = dzn;
    } else if (fi.suffix()=="fzn") {
        return;
    } else {
        curItem = other;
        isMiniZinc = false;
    }
    setModified(true, true);
    QStandardItem* prevItem = curItem;
    treeView->expand(curItem->index());
    curItem = curItem->child(0);
    int i=0;
    while (curItem != NULL) {
        if (curItem->text() == path.first()) {
            path.pop_front();
            treeView->expand(curItem->index());
            prevItem = curItem;
            curItem = curItem->child(0);
            i = 0;
        } else {
            i += 1;
            curItem = curItem->parent()->child(i);
        }
    }
    for (int i=0; i<path.size(); i++) {
        QStandardItem* newItem = new QStandardItem(path[i]);
        prevItem->appendRow(newItem);
        if (i<path.size()-1) {
            newItem->setIcon(QIcon(":/icons/images/folder.png"));
        } else {
            _files.insert(absFileName,newItem->index());
            if (isMiniZinc) {
                newItem->setIcon(QIcon(":/images/mznicon.png"));
            }
        }
        treeView->expand(newItem->index());
        prevItem = newItem;
    }
}

QString Project::fileAtIndex(const QModelIndex &index)
{
    QStandardItem* item = itemFromIndex(index);
    if (item->hasChildren())
        return "";
    QString fileName;
    while (item != NULL && item->parent() != NULL && item->parent() != invisibleRootItem() ) {
        if (fileName.isEmpty())
            fileName = item->text();
        else
            fileName = item->text()+"/"+fileName;
        item = item->parent();
    }
    if (fileName.isEmpty())
        return "";
    if (!projectRoot.isEmpty()) {
        fileName = QFileInfo(projectRoot).absolutePath()+"/"+fileName;
    }
    QFileInfo fi(fileName);
    if (fi.canonicalFilePath().isEmpty())
        fileName = "/"+fileName;
    fileName = QFileInfo(fileName).canonicalFilePath();
    return fileName;
}

Qt::ItemFlags Project::flags(const QModelIndex& index) const
{
    if (index==editable) {
        return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
    } else {
        QStandardItem* item = itemFromIndex(index);
        if (!item->hasChildren() && (item==mzn || item==dzn || item==other) )
            return Qt::ItemIsSelectable;
        return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
    }
}

QStringList Project::dataFiles(void) const
{
    QStringList ret;
    for (QMap<QString,QModelIndex>::const_iterator it = _files.begin(); it != _files.end(); ++it) {
        if (it.key().endsWith(".dzn"))
            ret << it.key();
    }
    return ret;
}

void Project::removeFile(const QString &fileName)
{
    if (fileName.isEmpty())
        return;
    if (!_files.contains(fileName)) {
        qDebug() << "Internal error: file " << fileName << " not in project";
        return;
    }
    setModified(true, true);
    QModelIndex index = _files[fileName];
    _files.remove(fileName);
    QStandardItem* cur = itemFromIndex(index);
    while (cur->parent() != NULL && cur->parent() != invisibleRootItem() && !cur->hasChildren()) {
        int row = cur->row();
        cur = cur->parent();
        cur->removeRow(row);
    }
}

void Project::setEditable(const QModelIndex &index)
{
    editable = index;
}

void Project::setModified(bool flag, bool files)
{
    if (!projectRoot.isEmpty()) {
        if (_isModified != flag) {
            emit modificationChanged(flag);
            _isModified = flag;
            if (files) {
                _filesModified = _isModified;
            }
            if (!_isModified) {
                currentDataFileIndex(currentDataFileIndex(),true);
                haveExtraArgs(haveExtraArgs(),true);
                extraArgs(extraArgs(),true);
                mzn2fznVerbose(mzn2fznVerbose(),true);
                mzn2fznOptimize(mzn2fznOptimize(),true);
                currentSolver(currentSolver(),true);
                n_solutions(n_solutions(),true);
                printAll(printAll(),true);
                printStats(printStats(),true);
                haveSolverFlags(haveSolverFlags(),true);
                solverFlags(solverFlags(),true);
                n_threads(n_threads(),true);
                haveSeed(haveSeed(),true);
                seed(seed(),true);
                timeLimit(timeLimit(),true);
                solverVerbose(solverVerbose(),true);
            }
        }
    }
}

bool Project::setData(const QModelIndex& index, const QVariant& value, int role)
{
    editable = QModelIndex();
    QString oldName = itemFromIndex(index)->text();
    if (oldName==value.toString())
        return false;
    QString filePath = QFileInfo(fileAtIndex(index)).canonicalPath();
    bool success = QFile::rename(filePath+"/"+oldName,filePath+"/"+value.toString());
    if (success) {
        _files[value.toString()] = _files[oldName];
        _files.remove(oldName);
        emit fileRenamed(filePath+"/"+oldName,filePath+"/"+value.toString());
        return QStandardItemModel::setData(index,value,role);
    } else {
        return false;
    }
}

bool Project::haveExtraArgs(void) const
{
    return ui->conf_have_cmd_params->isChecked();
}
QString Project::extraArgs(void) const
{
    return ui->conf_cmd_params->text();
}
bool Project::mzn2fznVerbose(void) const
{
    return ui->conf_verbose->isChecked();
}
bool Project::mzn2fznOptimize(void) const
{
    return ui->conf_optimize->isChecked();
}
QString Project::currentSolver(void) const
{
    return ui->conf_solver->currentText();
}
int Project::n_solutions(void) const
{
    return ui->conf_nsol->value();
}
bool Project::printAll(void) const
{
    return ui->conf_printall->isChecked();
}
bool Project::printStats(void) const
{
    return ui->conf_stats->isChecked();
}
bool Project::haveSolverFlags(void) const
{
    return ui->conf_have_solverFlags->isChecked();
}
QString Project::solverFlags(void) const
{
    return ui->conf_solverFlags->text();
}
int Project::n_threads(void) const
{
    return ui->conf_nthreads->value();
}
bool Project::haveSeed(void) const
{
    return ui->conf_have_seed->isChecked();
}
QString Project::seed(void) const
{
    return ui->conf_seed->text();
}
int Project::timeLimit(void) const
{
    return ui->conf_timeLimit->value();
}
bool Project::solverVerbose(void) const
{
    return ui->conf_solver_verbose->isChecked();
}

void Project::currentDataFileIndex(int i, bool init)
{
    if (init) {
        _currentDatafileIndex = i;
        ui->conf_data_file->setCurrentIndex(i);
    } else {
        checkModified();
    }
}

void Project::haveExtraArgs(bool b, bool init)
{
    if (init) {
        _haveExtraArgs = b;
        ui->conf_have_cmd_params->setChecked(b);
    } else {
        checkModified();
    }
}

void Project::extraArgs(const QString& a, bool init)
{
    if (init) {
        _extraArgs = a;
        ui->conf_cmd_params->setText(a);
    } else {
        checkModified();
    }
}

void Project::mzn2fznVerbose(bool b, bool init)
{
    if (init) {
        _mzn2fzn_verbose= b;
        ui->conf_verbose->setChecked(b);
    } else {
        checkModified();
    }
}

void Project::mzn2fznOptimize(bool b, bool init)
{
    if (init) {
        _mzn2fzn_optimize = b;
        ui->conf_optimize->setChecked(b);
    } else {
        checkModified();
    }
}

void Project::currentSolver(const QString& s, bool init)
{
    if (init) {
        _currentSolver = s;
        ui->conf_solver->setCurrentText(s);
    } else {
        checkModified();
    }
}

void Project::n_solutions(int n, bool init)
{
    if (init) {
        _n_solutions = n;
        ui->conf_nsol->setValue(n);
    } else {
        checkModified();
    }
}

void Project::printAll(bool b, bool init)
{
    if (init) {
        _printAll = b;
        ui->conf_printall->setChecked(b);
    } else {
        checkModified();
    }
}

void Project::printStats(bool b, bool init)
{
    if (init) {
        _printStats = b;
        ui->conf_stats->setChecked(b);
    } else {
        checkModified();
    }
}

void Project::haveSolverFlags(bool b, bool init)
{
    if (init) {
        _haveSolverFlags = b;
        ui->conf_have_solverFlags->setChecked(b);
    } else {
        checkModified();
    }
}

void Project::solverFlags(const QString& s, bool init)
{
    if (init) {
        _solverFlags = s;
        ui->conf_solverFlags->setText(s);
    } else {
        checkModified();
    }
}

void Project::n_threads(int n, bool init)
{
    if (init) {
        _n_threads = n;
        ui->conf_nthreads->setValue(n);
    } else {
        checkModified();
    }
}

void Project::haveSeed(bool b, bool init)
{
    if (init) {
        _haveSeed = b;
        ui->conf_have_seed->setChecked(b);
    } else {
        checkModified();
    }
}

void Project::seed(const QString& s, bool init)
{
    if (init) {
        _seed = s;
        ui->conf_seed->setText(s);
    } else {
        checkModified();
    }
}

void Project::timeLimit(int n, bool init)
{
    if (init) {
        _timeLimit = n;
        ui->conf_timeLimit->setValue(n);
    } else {
        checkModified();
    }
}

void Project::solverVerbose(bool b, bool init)
{
    if (init) {
        _solverVerbose = b;
        ui->conf_solver_verbose->setChecked(b);
    } else {
        checkModified();
    }
}

int Project::currentDataFileIndex(void) const
{
    return ui->conf_data_file->currentIndex();
}

QString Project::currentDataFile(void) const
{
    return ui->conf_data_file->currentText();
}

void Project::checkModified()
{
    if (projectRoot.isEmpty() || _filesModified)
        return;
    if (currentDataFileIndex() != ui->conf_data_file->currentIndex()) {
        setModified(true);
        return;
    }
    if (haveExtraArgs() != ui->conf_have_cmd_params->isChecked()) {
        setModified(true);
        return;
    }
    if (extraArgs() != ui->conf_cmd_params->text()) {
        setModified(true);
        return;
    }
    if (mzn2fznVerbose() != ui->conf_verbose->isChecked()) {
        setModified(true);
        return;
    }
    if (mzn2fznOptimize() != ui->conf_optimize->isChecked()) {
        setModified(true);
        return;
    }
    if (currentSolver() != ui->conf_solver->currentText()) {
        setModified(true);
        return;
    }
    if (n_solutions() != ui->conf_nsol->value()) {
        setModified(true);
        return;
    }
    if (printAll() != ui->conf_printall->isChecked()) {
        setModified(true);
        return;
    }
    if (printStats() != ui->conf_stats->isChecked()) {
        setModified(true);
        return;
    }
    if (haveSolverFlags() != ui->conf_have_solverFlags->isChecked()) {
        setModified(true);
        return;
    }
    if (solverFlags() != ui->conf_solverFlags->text()) {
        setModified(true);
        return;
    }
    if (n_threads() != ui->conf_nthreads->value()) {
        setModified(true);
        return;
    }
    if (haveSeed() != ui->conf_have_seed->isChecked()) {
        setModified(true);
        return;
    }
    if (seed() != ui->conf_seed->text()) {
        setModified(true);
        return;
    }
    if (timeLimit() != ui->conf_timeLimit->value()) {
        setModified(true);
        return;
    }
    if (solverVerbose() != ui->conf_solver_verbose->isChecked()) {
        setModified(true);
        return;
    }
    setModified(false);
}
<commit_msg>Fix check for whether project is modified<commit_after>/*
 *  Author:
 *     Guido Tack <guido.tack@monash.edu>
 *
 *  Copyright:
 *     NICTA 2013
 */

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "project.h"
#include "ui_mainwindow.h"

#include <QFileInfo>
#include <QDir>
#include <QDebug>

Project::Project(Ui::MainWindow *ui0) : ui(ui0)
{
    projectFile = new QStandardItem("Untitled Project");
    invisibleRootItem()->appendRow(projectFile);
    mzn = new QStandardItem("Models");
    QFont font = mzn->font();
    font.setBold(true);
    mzn->setFont(font);
    invisibleRootItem()->appendRow(mzn);
    dzn = new QStandardItem("Data (right-click to run)");
    dzn->setFont(font);
    invisibleRootItem()->appendRow(dzn);
    other = new QStandardItem("Other");
    other->setFont(font);
    invisibleRootItem()->appendRow(other);
    _isModified = false;
}

void Project::setRoot(QTreeView* treeView, const QString &fileName)
{
    if (fileName == projectRoot)
        return;
    _isModified = true;
    projectFile->setText(QFileInfo(fileName).fileName());
    projectFile->setIcon(QIcon(":/images/mznicon.png"));
    QStringList allFiles = files();
    if (mzn->rowCount() > 0)
        mzn->removeRows(0,mzn->rowCount());
    if (dzn->rowCount() > 0)
        dzn->removeRows(0,dzn->rowCount());
    if (other->rowCount() > 0)
        other->removeRows(0,other->rowCount());
    projectRoot = fileName;
    _files.clear();
    for (QStringList::iterator it = allFiles.begin(); it != allFiles.end(); ++it) {
        addFile(treeView, *it);
    }
}

void Project::addFile(QTreeView* treeView, const QString &fileName)
{
    if (_files.contains(fileName))
        return;
    QFileInfo fi(fileName);
    QString absFileName = fi.absoluteFilePath();
    QString relFileName;
    if (!projectRoot.isEmpty()) {
        QDir projectDir(QFileInfo(projectRoot).absoluteDir());
        relFileName = projectDir.relativeFilePath(absFileName);
    } else {
        relFileName = absFileName;
    }

    QStringList path = relFileName.split(QDir::separator());
    while (path.first().isEmpty()) {
        path.pop_front();
    }
    QStandardItem* curItem;
    bool isMiniZinc = true;
    if (fi.suffix()=="mzn") {
        curItem = mzn;
    } else if (fi.suffix()=="dzn") {
        curItem = dzn;
    } else if (fi.suffix()=="fzn") {
        return;
    } else {
        curItem = other;
        isMiniZinc = false;
    }
    setModified(true, true);
    QStandardItem* prevItem = curItem;
    treeView->expand(curItem->index());
    curItem = curItem->child(0);
    int i=0;
    while (curItem != NULL) {
        if (curItem->text() == path.first()) {
            path.pop_front();
            treeView->expand(curItem->index());
            prevItem = curItem;
            curItem = curItem->child(0);
            i = 0;
        } else {
            i += 1;
            curItem = curItem->parent()->child(i);
        }
    }
    for (int i=0; i<path.size(); i++) {
        QStandardItem* newItem = new QStandardItem(path[i]);
        prevItem->appendRow(newItem);
        if (i<path.size()-1) {
            newItem->setIcon(QIcon(":/icons/images/folder.png"));
        } else {
            _files.insert(absFileName,newItem->index());
            if (isMiniZinc) {
                newItem->setIcon(QIcon(":/images/mznicon.png"));
            }
        }
        treeView->expand(newItem->index());
        prevItem = newItem;
    }
}

QString Project::fileAtIndex(const QModelIndex &index)
{
    QStandardItem* item = itemFromIndex(index);
    if (item->hasChildren())
        return "";
    QString fileName;
    while (item != NULL && item->parent() != NULL && item->parent() != invisibleRootItem() ) {
        if (fileName.isEmpty())
            fileName = item->text();
        else
            fileName = item->text()+"/"+fileName;
        item = item->parent();
    }
    if (fileName.isEmpty())
        return "";
    if (!projectRoot.isEmpty()) {
        fileName = QFileInfo(projectRoot).absolutePath()+"/"+fileName;
    }
    QFileInfo fi(fileName);
    if (fi.canonicalFilePath().isEmpty())
        fileName = "/"+fileName;
    fileName = QFileInfo(fileName).canonicalFilePath();
    return fileName;
}

Qt::ItemFlags Project::flags(const QModelIndex& index) const
{
    if (index==editable) {
        return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
    } else {
        QStandardItem* item = itemFromIndex(index);
        if (!item->hasChildren() && (item==mzn || item==dzn || item==other) )
            return Qt::ItemIsSelectable;
        return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
    }
}

QStringList Project::dataFiles(void) const
{
    QStringList ret;
    for (QMap<QString,QModelIndex>::const_iterator it = _files.begin(); it != _files.end(); ++it) {
        if (it.key().endsWith(".dzn"))
            ret << it.key();
    }
    return ret;
}

void Project::removeFile(const QString &fileName)
{
    if (fileName.isEmpty())
        return;
    if (!_files.contains(fileName)) {
        qDebug() << "Internal error: file " << fileName << " not in project";
        return;
    }
    setModified(true, true);
    QModelIndex index = _files[fileName];
    _files.remove(fileName);
    QStandardItem* cur = itemFromIndex(index);
    while (cur->parent() != NULL && cur->parent() != invisibleRootItem() && !cur->hasChildren()) {
        int row = cur->row();
        cur = cur->parent();
        cur->removeRow(row);
    }
}

void Project::setEditable(const QModelIndex &index)
{
    editable = index;
}

void Project::setModified(bool flag, bool files)
{
    if (!projectRoot.isEmpty()) {
        if (_isModified != flag) {
            emit modificationChanged(flag);
            _isModified = flag;
            if (files) {
                _filesModified = _isModified;
            }
            if (!_isModified) {
                currentDataFileIndex(currentDataFileIndex(),true);
                haveExtraArgs(haveExtraArgs(),true);
                extraArgs(extraArgs(),true);
                mzn2fznVerbose(mzn2fznVerbose(),true);
                mzn2fznOptimize(mzn2fznOptimize(),true);
                currentSolver(currentSolver(),true);
                n_solutions(n_solutions(),true);
                printAll(printAll(),true);
                printStats(printStats(),true);
                haveSolverFlags(haveSolverFlags(),true);
                solverFlags(solverFlags(),true);
                n_threads(n_threads(),true);
                haveSeed(haveSeed(),true);
                seed(seed(),true);
                timeLimit(timeLimit(),true);
                solverVerbose(solverVerbose(),true);
            }
        }
    }
}

bool Project::setData(const QModelIndex& index, const QVariant& value, int role)
{
    editable = QModelIndex();
    QString oldName = itemFromIndex(index)->text();
    if (oldName==value.toString())
        return false;
    QString filePath = QFileInfo(fileAtIndex(index)).canonicalPath();
    bool success = QFile::rename(filePath+"/"+oldName,filePath+"/"+value.toString());
    if (success) {
        _files[value.toString()] = _files[oldName];
        _files.remove(oldName);
        emit fileRenamed(filePath+"/"+oldName,filePath+"/"+value.toString());
        return QStandardItemModel::setData(index,value,role);
    } else {
        return false;
    }
}

bool Project::haveExtraArgs(void) const
{
    return ui->conf_have_cmd_params->isChecked();
}
QString Project::extraArgs(void) const
{
    return ui->conf_cmd_params->text();
}
bool Project::mzn2fznVerbose(void) const
{
    return ui->conf_verbose->isChecked();
}
bool Project::mzn2fznOptimize(void) const
{
    return ui->conf_optimize->isChecked();
}
QString Project::currentSolver(void) const
{
    return ui->conf_solver->currentText();
}
int Project::n_solutions(void) const
{
    return ui->conf_nsol->value();
}
bool Project::printAll(void) const
{
    return ui->conf_printall->isChecked();
}
bool Project::printStats(void) const
{
    return ui->conf_stats->isChecked();
}
bool Project::haveSolverFlags(void) const
{
    return ui->conf_have_solverFlags->isChecked();
}
QString Project::solverFlags(void) const
{
    return ui->conf_solverFlags->text();
}
int Project::n_threads(void) const
{
    return ui->conf_nthreads->value();
}
bool Project::haveSeed(void) const
{
    return ui->conf_have_seed->isChecked();
}
QString Project::seed(void) const
{
    return ui->conf_seed->text();
}
int Project::timeLimit(void) const
{
    return ui->conf_timeLimit->value();
}
bool Project::solverVerbose(void) const
{
    return ui->conf_solver_verbose->isChecked();
}

void Project::currentDataFileIndex(int i, bool init)
{
    if (init) {
        _currentDatafileIndex = i;
        ui->conf_data_file->setCurrentIndex(i);
    } else {
        checkModified();
    }
}

void Project::haveExtraArgs(bool b, bool init)
{
    if (init) {
        _haveExtraArgs = b;
        ui->conf_have_cmd_params->setChecked(b);
    } else {
        checkModified();
    }
}

void Project::extraArgs(const QString& a, bool init)
{
    if (init) {
        _extraArgs = a;
        ui->conf_cmd_params->setText(a);
    } else {
        checkModified();
    }
}

void Project::mzn2fznVerbose(bool b, bool init)
{
    if (init) {
        _mzn2fzn_verbose= b;
        ui->conf_verbose->setChecked(b);
    } else {
        checkModified();
    }
}

void Project::mzn2fznOptimize(bool b, bool init)
{
    if (init) {
        _mzn2fzn_optimize = b;
        ui->conf_optimize->setChecked(b);
    } else {
        checkModified();
    }
}

void Project::currentSolver(const QString& s, bool init)
{
    if (init) {
        _currentSolver = s;
        ui->conf_solver->setCurrentText(s);
    } else {
        checkModified();
    }
}

void Project::n_solutions(int n, bool init)
{
    if (init) {
        _n_solutions = n;
        ui->conf_nsol->setValue(n);
    } else {
        checkModified();
    }
}

void Project::printAll(bool b, bool init)
{
    if (init) {
        _printAll = b;
        ui->conf_printall->setChecked(b);
    } else {
        checkModified();
    }
}

void Project::printStats(bool b, bool init)
{
    if (init) {
        _printStats = b;
        ui->conf_stats->setChecked(b);
    } else {
        checkModified();
    }
}

void Project::haveSolverFlags(bool b, bool init)
{
    if (init) {
        _haveSolverFlags = b;
        ui->conf_have_solverFlags->setChecked(b);
    } else {
        checkModified();
    }
}

void Project::solverFlags(const QString& s, bool init)
{
    if (init) {
        _solverFlags = s;
        ui->conf_solverFlags->setText(s);
    } else {
        checkModified();
    }
}

void Project::n_threads(int n, bool init)
{
    if (init) {
        _n_threads = n;
        ui->conf_nthreads->setValue(n);
    } else {
        checkModified();
    }
}

void Project::haveSeed(bool b, bool init)
{
    if (init) {
        _haveSeed = b;
        ui->conf_have_seed->setChecked(b);
    } else {
        checkModified();
    }
}

void Project::seed(const QString& s, bool init)
{
    if (init) {
        _seed = s;
        ui->conf_seed->setText(s);
    } else {
        checkModified();
    }
}

void Project::timeLimit(int n, bool init)
{
    if (init) {
        _timeLimit = n;
        ui->conf_timeLimit->setValue(n);
    } else {
        checkModified();
    }
}

void Project::solverVerbose(bool b, bool init)
{
    if (init) {
        _solverVerbose = b;
        ui->conf_solver_verbose->setChecked(b);
    } else {
        checkModified();
    }
}

int Project::currentDataFileIndex(void) const
{
    return ui->conf_data_file->currentIndex();
}

QString Project::currentDataFile(void) const
{
    return ui->conf_data_file->currentText();
}

void Project::checkModified()
{
    if (projectRoot.isEmpty() || _filesModified)
        return;
    if (currentDataFileIndex() != _currentDatafileIndex) {
        setModified(true);
        return;
    }
    if (haveExtraArgs() != _haveExtraArgs) {
        setModified(true);
        return;
    }
    if (extraArgs() != _extraArgs) {
        setModified(true);
        return;
    }
    if (mzn2fznVerbose() != _mzn2fzn_verbose) {
        setModified(true);
        return;
    }
    if (mzn2fznOptimize() != _mzn2fzn_optimize) {
        setModified(true);
        return;
    }
    if (currentSolver() != _currentSolver) {
        setModified(true);
        return;
    }
    if (n_solutions() != _n_solutions) {
        setModified(true);
        return;
    }
    if (printAll() != _printAll) {
        setModified(true);
        return;
    }
    if (printStats() != _printStats) {
        setModified(true);
        return;
    }
    if (haveSolverFlags() != _haveSolverFlags) {
        setModified(true);
        return;
    }
    if (solverFlags() != _solverFlags) {
        setModified(true);
        return;
    }
    if (n_threads() != _n_threads) {
        setModified(true);
        return;
    }
    if (haveSeed() != _haveSeed) {
        setModified(true);
        return;
    }
    if (seed() != _seed) {
        setModified(true);
        return;
    }
    if (timeLimit() != _timeLimit) {
        setModified(true);
        return;
    }
    if (solverVerbose() != _solverVerbose) {
        setModified(true);
        return;
    }
    setModified(false);
}
<|endoftext|>