<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the tools applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtGui>
#include <QtDebug>

#include <private/qpaintengineex_p.h>
#include <private/qpaintbuffer_p.h>

class ReplayWidget : public QWidget
{
    Q_OBJECT
public:
    ReplayWidget(const QString &filename);

    void paintEvent(QPaintEvent *event);

public slots:
    void updateRect();

public:
    QList<QRegion> updates;
    QPaintBuffer buffer;

    int currentFrame;
    int currentIteration;
    QTime timer;

    QList<uint> iterationTimes;
    QString filename;
};

void ReplayWidget::updateRect()
{
    if (!updates.isEmpty())
        update(updates.at(currentFrame));
}

void ReplayWidget::paintEvent(QPaintEvent *)
{
    QPainter p(this);

//    p.setClipRegion(frames.at(currentFrame).updateRegion);

    buffer.draw(&p, currentFrame);

    ++currentFrame;
    if (currentFrame >= buffer.numFrames()) {
        currentFrame = 0;
        ++currentIteration;

        if (currentIteration == 3)
            timer.start();
        else if (currentIteration > 3) {
            iterationTimes << timer.elapsed();
            timer.restart();

            if (iterationTimes.size() >= 3) {
                qreal mean = 0;
                qreal stddev = 0;
                uint min = INT_MAX;

                for (int i = 0; i < iterationTimes.size(); ++i) {
                    mean += iterationTimes.at(i);
                    min = qMin(min, iterationTimes.at(i));
                }

                mean /= qreal(iterationTimes.size());

                for (int i = 0; i < iterationTimes.size(); ++i) {
                    qreal delta = iterationTimes.at(i) - mean;
                    stddev += delta * delta;
                }

                stddev = qSqrt(stddev / iterationTimes.size());

                qSort(iterationTimes.begin(), iterationTimes.end());
                uint median = iterationTimes.at(iterationTimes.size() / 2);

                stddev = 100 * stddev / mean;

                if (iterationTimes.size() >= 10 || stddev < 4) {
                    printf("%s, iterations: %d, frames: %d, min(ms): %d, median(ms): %d, stddev: %f %%, max(fps): %f\n", qPrintable(filename),
                            iterationTimes.size(), updates.size(), min, median, stddev, 1000. * updates.size() / min);
                    deleteLater();
                    return;
                }
            }
        }
    }

    QTimer::singleShot(0, this, SLOT(updateRect()));
}

ReplayWidget::ReplayWidget(const QString &filename_)
    : currentFrame(0)
    , currentIteration(0)
    , filename(filename_)
{
    setWindowTitle(filename);
    QFile file(filename);

    QRect bounds;
    if (!file.open(QIODevice::ReadOnly)) {
        printf("Failed to load input file '%s'\n", qPrintable(filename_));
        return;
    }

    QDataStream in(&file);

    char *data;
    uint size;
    in.readBytes(data, size);
    bool isTraceFile = size == 7 && qstrncmp(data, "qttrace", 7) == 0;
    delete [] data;
    if (!isTraceFile) {
        printf("File '%s' is not a trace file\n", qPrintable(filename_));
        return;
    }

    in >> buffer >> updates;
    printf("Read paint buffer with %d frames\n", buffer.numFrames());

    resize(buffer.boundingRect().size().toSize());

    setAutoFillBackground(false);
    setAttribute(Qt::WA_NoSystemBackground);

    QTimer::singleShot(10, this, SLOT(updateRect()));
}

int main(int argc, char **argv)
{
    QApplication app(argc, argv);

    if (argc <= 1 || qstrcmp(argv[1], "-h") == 0 || qstrcmp(argv[1], "--help") == 0) {
        printf("Replays a tracefile generated with '-graphicssystem trace'\n");
        printf("Usage:\n  > %s [traceFile]\n", argv[0]);
        return 1;
    }

    QFile file(argv[1]);
    if (!file.exists()) {
        printf("%s does not exist\n", argv[1]);
        return 1;
    }

    ReplayWidget *widget = new ReplayWidget(argv[1]);

    if (!widget->updates.isEmpty()) {
        widget->show();
        return app.exec();
    }

}
#include "main.moc"
<commit_msg>Made the trace replayer handle limited resolution cases better.<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the tools applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtGui>
#include <QtDebug>

#include <private/qpaintengineex_p.h>
#include <private/qpaintbuffer_p.h>

class ReplayWidget : public QWidget
{
    Q_OBJECT
public:
    ReplayWidget(const QString &filename);

    void paintEvent(QPaintEvent *event);
    void resizeEvent(QResizeEvent *event);

public slots:
    void updateRect();

public:
    QList<QRegion> updates;
    QPaintBuffer buffer;

    int currentFrame;
    int currentIteration;
    QTime timer;

    QList<uint> visibleUpdates;
    QList<uint> iterationTimes;
    QString filename;
};

void ReplayWidget::updateRect()
{
    if (!visibleUpdates.isEmpty())
        update(updates.at(visibleUpdates.at(currentFrame)));
}

void ReplayWidget::paintEvent(QPaintEvent *)
{
    QPainter p(this);

//    p.setClipRegion(frames.at(currentFrame).updateRegion);

    buffer.draw(&p, visibleUpdates.at(currentFrame));

    ++currentFrame;
    if (currentFrame >= visibleUpdates.size()) {
        currentFrame = 0;
        ++currentIteration;

        if (currentIteration == 3)
            timer.start();
        else if (currentIteration > 3) {
            iterationTimes << timer.elapsed();
            timer.restart();

            if (iterationTimes.size() >= 3) {
                qreal mean = 0;
                qreal stddev = 0;
                uint min = INT_MAX;

                for (int i = 0; i < iterationTimes.size(); ++i) {
                    mean += iterationTimes.at(i);
                    min = qMin(min, iterationTimes.at(i));
                }

                mean /= qreal(iterationTimes.size());

                for (int i = 0; i < iterationTimes.size(); ++i) {
                    qreal delta = iterationTimes.at(i) - mean;
                    stddev += delta * delta;
                }

                stddev = qSqrt(stddev / iterationTimes.size());

                qSort(iterationTimes.begin(), iterationTimes.end());
                uint median = iterationTimes.at(iterationTimes.size() / 2);

                stddev = 100 * stddev / mean;

                if (iterationTimes.size() >= 10 || stddev < 4) {
                    printf("%s, iterations: %d, frames: %d, min(ms): %d, median(ms): %d, stddev: %f %%, max(fps): %f\n", qPrintable(filename),
                            iterationTimes.size(), visibleUpdates.size(), min, median, stddev, 1000. * visibleUpdates.size() / min);
                    deleteLater();
                    return;
                }
            }
        }
    }

    QTimer::singleShot(0, this, SLOT(updateRect()));
}

void ReplayWidget::resizeEvent(QResizeEvent *event)
{
    visibleUpdates.clear();

    QRect bounds = rect();
    for (int i = 0; i < updates.size(); ++i) {
        if (updates.at(i).intersects(bounds))
            visibleUpdates << i;
    }

    if (visibleUpdates.size() != updates.size())
        printf("Warning: skipped %d frames due to limited resolution\n", updates.size() - visibleUpdates.size());

}

ReplayWidget::ReplayWidget(const QString &filename_)
    : currentFrame(0)
    , currentIteration(0)
    , filename(filename_)
{
    setWindowTitle(filename);
    QFile file(filename);

    if (!file.open(QIODevice::ReadOnly)) {
        printf("Failed to load input file '%s'\n", qPrintable(filename_));
        return;
    }

    QDataStream in(&file);

    char *data;
    uint size;
    in.readBytes(data, size);
    bool isTraceFile = size == 7 && qstrncmp(data, "qttrace", 7) == 0;
    delete [] data;
    if (!isTraceFile) {
        printf("File '%s' is not a trace file\n", qPrintable(filename_));
        return;
    }

    in >> buffer >> updates;
    printf("Read paint buffer with %d frames\n", buffer.numFrames());

    resize(buffer.boundingRect().size().toSize());

    setAutoFillBackground(false);
    setAttribute(Qt::WA_NoSystemBackground);

    QTimer::singleShot(10, this, SLOT(updateRect()));
}

int main(int argc, char **argv)
{
    QApplication app(argc, argv);

    if (argc <= 1 || qstrcmp(argv[1], "-h") == 0 || qstrcmp(argv[1], "--help") == 0) {
        printf("Replays a tracefile generated with '-graphicssystem trace'\n");
        printf("Usage:\n  > %s [traceFile]\n", argv[0]);
        return 1;
    }

    QFile file(argv[1]);
    if (!file.exists()) {
        printf("%s does not exist\n", argv[1]);
        return 1;
    }

    ReplayWidget *widget = new ReplayWidget(argv[1]);

    if (!widget->updates.isEmpty()) {
        widget->show();
        return app.exec();
    }

}
#include "main.moc"
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "Parser.h"
#include "ExpressionParser.h"
#include "Core/Misc.h"
#include "Commands/CommandSequence.h"
#include "Commands/CAssemblerLabel.h"
#include "Core/Common.h"
#include "Util/Util.h"

inline bool isPartOfList(const std::wstring& value, std::initializer_list<wchar_t*>& terminators)
{
	for (wchar_t* term: terminators)
	{
		if (value == term)
			return true;
	}

	return false;
}

Parser::Parser()
{
	initializingMacro = false;
	clearError();
}

Expression Parser::parseExpression()
{
	return ::parseExpression(*getTokenizer());
}

bool Parser::parseExpressionList(std::vector<Expression>& list, int min, int max)
{
	bool valid = true;
	list.clear();

	const Token& start = peekToken();

	Expression exp = parseExpression();
	list.push_back(exp);

	if (exp.isLoaded() == false)
	{
		printError(start,L"Parameter failure");
		getTokenizer()->skipLookahead();
		valid = false;
	}

	while (peekToken().type == TokenType::Comma)
	{
		eatToken();

		exp = parseExpression();
		list.push_back(exp);

		if (exp.isLoaded() == false)
		{
			printError(start,L"Parameter failure");
			getTokenizer()->skipLookahead();
			valid = false;
		}
	}

	if (list.size() < (size_t) min)
	{
		printError(start,L"Not enough parameters (min %d)",min);
		return false;
	}

	if (max != -1 && (size_t) max < list.size())
	{
		printError(start,L"Too many parameters (max %d)",max);
		return false;
	}

	return valid;
}

bool Parser::parseIdentifier(std::wstring& dest)
{
	const Token& tok = nextToken();
	if (tok.type != TokenType::Identifier)
		return false;

	dest = tok.getStringValue();
	return true;
}

CAssemblerCommand* Parser::parseCommandSequence(wchar_t indicator, std::initializer_list<wchar_t*> terminators)
{
	CommandSequence* sequence = new CommandSequence();

	while (atEnd() == false)
	{
		const Token &next = peekToken();
		if (next.stringValueStartsWith(indicator) && isPartOfList(next.getStringValue(), terminators))
			break;

		CAssemblerCommand* cmd = parseCommand();
		sequence->addCommand(cmd);
	}

	return sequence;
}

CAssemblerCommand* Parser::parseFile(TextFile& file)
{
	FileTokenizer tokenizer;
	if (tokenizer.init(&file) == false)
		return nullptr;

	int oldNum = Global.FileInfo.FileNum;
	Global.FileInfo.FileNum = (int) Global.FileInfo.FileList.size();
	Global.FileInfo.FileList.push_back(file.getFileName());
	Global.FileInfo.LineNumber = 0;

	CAssemblerCommand* result = parse(&tokenizer);
	Global.FileInfo.FileNum = oldNum;
	return result;
}

CAssemblerCommand* Parser::parseString(const std::wstring& text)
{
	TextFile file;
	file.openMemory(text);
	return parseFile(file);
}

CAssemblerCommand* Parser::parseTemplate(const std::wstring& text, std::initializer_list<AssemblyTemplateArgument> variables)
{
	std::wstring fullText = text;

	for (auto& arg: variables)
	{
		size_t count = replaceAll(fullText,arg.variableName,arg.value);

#ifdef _DEBUG
		if (count != 0 && arg.value.empty())
			Logger::printError(Logger::Warning,L"Empty replacement for %s",arg.variableName);
#endif
	}

	return parseString(fullText);
}

CAssemblerCommand* Parser::parseDirective(const DirectiveMap &directiveSet)
{
	const Token &tok = peekToken();
	if (tok.type != TokenType::Identifier)
		return nullptr;

	const std::wstring stringValue = tok.getStringValue();

	auto matchRange = directiveSet.equal_range(stringValue);
	for (auto it = matchRange.first; it != matchRange.second; ++it)
	{
		const DirectiveEntry &directive = it->second;

		if (directive.flags & DIRECTIVE_DISABLED)
			return nullptr;
		if ((directive.flags & DIRECTIVE_NOCASHOFF) && Global.nocash == true)
			return nullptr;
		if ((directive.flags & DIRECTIVE_NOCASHON) && Global.nocash == false)
			return nullptr;
		if ((directive.flags & DIRECTIVE_NOTINMEMORY) && Global.memoryMode == true)
			return nullptr;

		if (directive.flags & DIRECTIVE_MIPSRESETDELAY)
			Arch->NextSection();

		eatToken();
		CAssemblerCommand* result = directive.function(*this,directive.flags);
		if (result == nullptr)
		{
			if (hasError() == false)
				printError(tok,L"Directive parameter failure");
			return nullptr;
		}

		return result;
	}

	return nullptr;
}

bool Parser::matchToken(TokenType type, bool optional)
{
	if (optional)
	{
		const Token& token = peekToken();
		if (token.type == type)
			eatToken();
		return true;
	}

	return nextToken().type == type;
}

CAssemblerCommand* Parser::parse(Tokenizer* tokenizer)
{
	entries.push_back(tokenizer);

	CAssemblerCommand* sequence = parseCommandSequence();
	entries.pop_back();

	return sequence;
}

bool Parser::checkEquLabel()
{
	const Token& start = peekToken();
	if (start.type == TokenType::Identifier)
	{
		int pos = 1;
		if (peekToken(pos).type == TokenType::Colon)
			pos++;

		if (peekToken(pos).type == TokenType::Equ &&
			peekToken(pos+1).type == TokenType::EquValue)
		{
			std::wstring name = peekToken(0).getStringValue();
			std::wstring value = peekToken(pos+1).getStringValue();
			eatTokens(pos+2);

			// equs are not allowed in macros
			if (initializingMacro)
			{
				printError(start,L"equ not allowed in macro");
				return true;
			}

			if (Global.symbolTable.isValidSymbolName(name) == false)
			{
				printError(start,L"Invalid equation name %s",name);
				return true;
			}

			if (Global.symbolTable.symbolExists(name,Global.FileInfo.FileNum,Global.Section))
			{
				printError(start,L"Equation name %s already defined",name);
				return true;
			}

			// parse value string
			TextFile f;
			f.openMemory(value);

			FileTokenizer tok;
			tok.init(&f);

			TokenizerPosition start = tok.getPosition();
			while (tok.atEnd() == false)
				tok.nextToken();

			// extract tokens
			TokenizerPosition end = tok.getPosition();
			std::vector<Token> tokens = tok.getTokens(start,end);
			size_t index = Tokenizer::addEquValue(tokens);

			for (Tokenizer* tokenizer: entries)
				tokenizer->resetLookaheadCheckMarks();

			// register equation
			Global.symbolTable.addEquation(name,Global.FileInfo.FileNum,Global.Section,index);

			return true;
		}
	}

	return false;
}

bool Parser::checkMacroDefinition()
{
	const Token& first = peekToken();
	if (first.type != TokenType::Identifier)
		return false;

	if (!first.stringValueStartsWith(L'.') || first.getStringValue() != L".macro")
		return false;

	eatToken();

	// nested macro definitions are not allowed
	if (initializingMacro)
	{
		printError(first,L"Nested macro definitions not allowed");
		while (!atEnd())
		{
			const Token& token = nextToken();
			if (token.type == TokenType::Identifier && token.getStringValue() == L".endmacro")
				break;
		}

		return true;
	}

	std::vector<Expression> parameters;
	if (parseExpressionList(parameters,1,-1) == false)
		return false;

	// load name
	std::wstring macroName;
	if (parameters[0].evaluateIdentifier(macroName) == false)
		return false;

	// duplicate check the macro
	ParserMacro &macro = macros[macroName];
	if (macro.name.length() != 0)
	{
		printError(first,L"Macro \"%s\" already defined",macro.name);
		return false;
	}

	// and register it
	macro.name = macroName;
	macro.counter = 0;

	// load parameters
	for (size_t i = 1; i < parameters.size(); i++)
	{
		std::wstring name;
		if (parameters[i].evaluateIdentifier(name) == false)
			return false;

		macro.parameters.push_back(name);
	}

	// load macro content

	TokenizerPosition start = getTokenizer()->getPosition();
	bool valid = false;
	while (atEnd() == false)
	{
		const Token& tok = nextToken();
		if (tok.type == TokenType::Identifier && tok.getStringValue() == L".endmacro")
		{
			valid = true;
			break;
		}
	}

	// no .endmacro, not valid
	if (valid == false)
		return true;

	// get content
	TokenizerPosition end = getTokenizer()->getPosition().previous();
	macro.content = getTokenizer()->getTokens(start,end);

	return true;
}

CAssemblerCommand* Parser::parseMacroCall()
{
	const Token& start = peekToken();
	if (start.type != TokenType::Identifier)
		return nullptr;

	auto it = macros.find(start.getStringValue());
	if (it == macros.end())
		return nullptr;

	ParserMacro& macro = it->second;
	eatToken();

	// create a token stream for the macro content,
	// registering replacements for parameter values
	TokenStreamTokenizer macroTokenizer;

	for (size_t i = 0; i < macro.parameters.size(); i++)
	{
		if (i != 0)
		{
			if (nextToken().type != TokenType::Comma)
				return nullptr;
		}

		if (i == macro.parameters.size())
		{
			size_t count = macro.parameters.size();
			while (peekToken().type == TokenType::Comma)
			{
				eatToken();
				parseExpression();
			}

			printError(start,L"Not enough macro arguments (%d vs %d)",count,macro.parameters.size());
			return nullptr;
		}

		TokenizerPosition startPos = getTokenizer()->getPosition();
		Expression exp = parseExpression();
		if (exp.isLoaded() == false)
			return false;

		TokenizerPosition endPos = getTokenizer()->getPosition();
		std::vector<Token> tokens = getTokenizer()->getTokens(startPos,endPos);

		// give them as a replacement to new tokenizer
		macroTokenizer.registerReplacement(macro.parameters[i],tokens);
	}

	if (peekToken().type == TokenType::Comma)
	{
		size_t count = macro.parameters.size();
		while (peekToken().type == TokenType::Comma)
		{
			eatToken();
			parseExpression();
			count++;
		}

		printError(start,L"Too many macro arguments (%d vs %d)",count,macro.parameters.size());
		return nullptr;
	}

	// a macro is fully parsed once when it's loaded
	// to gather all labels. it's not necessary to
	// instantiate other macros at that time
	if (initializingMacro)
		return new DummyCommand();

	// the first time a macro is instantiated, it needs to be analyzed
	// for labels
	if (macro.counter == 0)
	{
		initializingMacro = true;

		// parse the short lived next command
		macroTokenizer.init(macro.content);
		CAssemblerCommand* command =  parse(&macroTokenizer);
		delete command;

		macro.labels = macroLabels;
		macroLabels.clear();

		initializingMacro = false;
	}

	// register labels and replacements
	for (const std::wstring& label: macro.labels)
	{
		std::wstring fullName = formatString(L"%s_%s_%08X",macro.name,label,macro.counter);
		macroTokenizer.registerReplacement(label,fullName);
	}

	macroTokenizer.init(macro.content);
	macro.counter++;

	return parse(&macroTokenizer);
}

CAssemblerCommand* Parser::parseLabel()
{
	const Token& start = peekToken(0);

	if (peekToken(0).type == TokenType::Identifier &&
		peekToken(1).type == TokenType::Colon)
	{
		const std::wstring name = peekToken(0).getStringValue();
		eatTokens(2);

		if (initializingMacro)
			macroLabels.insert(name);

		if (Global.symbolTable.isValidSymbolName(name) == false)
		{
			printError(start,L"Invalid label name");
			return nullptr;
		}

		return new CAssemblerLabel(name);
	}

	return nullptr;
}

CAssemblerCommand* Parser::handleError()
{
	// skip the rest of the line
	const Token& token = nextToken();
	while (peekToken().line == token.line)
		eatToken();

	clearError();
	return new InvalidCommand();
}

CAssemblerCommand* Parser::parseCommand()
{
	CAssemblerCommand* command;

	while (checkEquLabel() || checkMacroDefinition())
	{
		// do nothing, just parse all the equs and macros there are
		if (hasError())
			return handleError();
	}

	if (atEnd())
		return new DummyCommand();

	if ((command = parseLabel()) != nullptr)
		return command;
	if (hasError())
		return handleError();

	if ((command = parseMacroCall()) != nullptr)
		return command;
	if (hasError())
		return handleError();

	if ((command = Arch->parseDirective(*this)) != nullptr)
		return command;
	if (hasError())
		return handleError();

	if ((command = parseDirective(directives)) != nullptr)
		return command;
	if (hasError())
		return handleError();

	if ((command = Arch->parseOpcode(*this)) != nullptr)
		return command;
	if (hasError())
		return handleError();

	const Token& token = peekToken();
	printError(token,L"Parse error '%s'",token.getOriginalText());
	return handleError();
}

void TokenSequenceParser::addEntry(int result, TokenSequence tokens, TokenValueSequence values)
{
	Entry entry = { tokens, values, result };
	entries.push_back(entry);
}

bool TokenSequenceParser::parse(Parser& parser, int& result)
{
	for (Entry& entry: entries)
	{
		TokenizerPosition pos = parser.getTokenizer()->getPosition();
		auto values = entry.values.begin();

		bool valid = true;
		for (TokenType type: entry.tokens)
		{
			// check of token type matches
			const Token& token = parser.nextToken();
			if (token.type != type)
			{
				valid = false;
				break;
			}

			// if necessary, check if the value of the token also matches
			if (type == TokenType::Identifier)
			{
				if (values == entry.values.end() || values->textValue != token.getStringValue())
				{
					valid = false;
					break;
				}

				values++;
			} else if (type == TokenType::Integer)
			{
				if (values == entry.values.end() || values->intValue != token.intValue)
				{
					valid = false;
					break;
				}

				values++;
			}
		}

		if (valid && values == entry.values.end())
		{
			result = entry.result;
			return true;
		}

		parser.getTokenizer()->setPosition(pos);
	}

	return false;
}
<commit_msg>Fix directive parsing when the first alternative is disabled<commit_after>#include "stdafx.h"
#include "Parser.h"
#include "ExpressionParser.h"
#include "Core/Misc.h"
#include "Commands/CommandSequence.h"
#include "Commands/CAssemblerLabel.h"
#include "Core/Common.h"
#include "Util/Util.h"

inline bool isPartOfList(const std::wstring& value, std::initializer_list<wchar_t*>& terminators)
{
	for (wchar_t* term: terminators)
	{
		if (value == term)
			return true;
	}

	return false;
}

Parser::Parser()
{
	initializingMacro = false;
	clearError();
}

Expression Parser::parseExpression()
{
	return ::parseExpression(*getTokenizer());
}

bool Parser::parseExpressionList(std::vector<Expression>& list, int min, int max)
{
	bool valid = true;
	list.clear();

	const Token& start = peekToken();

	Expression exp = parseExpression();
	list.push_back(exp);

	if (exp.isLoaded() == false)
	{
		printError(start,L"Parameter failure");
		getTokenizer()->skipLookahead();
		valid = false;
	}

	while (peekToken().type == TokenType::Comma)
	{
		eatToken();

		exp = parseExpression();
		list.push_back(exp);

		if (exp.isLoaded() == false)
		{
			printError(start,L"Parameter failure");
			getTokenizer()->skipLookahead();
			valid = false;
		}
	}

	if (list.size() < (size_t) min)
	{
		printError(start,L"Not enough parameters (min %d)",min);
		return false;
	}

	if (max != -1 && (size_t) max < list.size())
	{
		printError(start,L"Too many parameters (max %d)",max);
		return false;
	}

	return valid;
}

bool Parser::parseIdentifier(std::wstring& dest)
{
	const Token& tok = nextToken();
	if (tok.type != TokenType::Identifier)
		return false;

	dest = tok.getStringValue();
	return true;
}

CAssemblerCommand* Parser::parseCommandSequence(wchar_t indicator, std::initializer_list<wchar_t*> terminators)
{
	CommandSequence* sequence = new CommandSequence();

	while (atEnd() == false)
	{
		const Token &next = peekToken();
		if (next.stringValueStartsWith(indicator) && isPartOfList(next.getStringValue(), terminators))
			break;

		CAssemblerCommand* cmd = parseCommand();
		sequence->addCommand(cmd);
	}

	return sequence;
}

CAssemblerCommand* Parser::parseFile(TextFile& file)
{
	FileTokenizer tokenizer;
	if (tokenizer.init(&file) == false)
		return nullptr;

	int oldNum = Global.FileInfo.FileNum;
	Global.FileInfo.FileNum = (int) Global.FileInfo.FileList.size();
	Global.FileInfo.FileList.push_back(file.getFileName());
	Global.FileInfo.LineNumber = 0;

	CAssemblerCommand* result = parse(&tokenizer);
	Global.FileInfo.FileNum = oldNum;
	return result;
}

CAssemblerCommand* Parser::parseString(const std::wstring& text)
{
	TextFile file;
	file.openMemory(text);
	return parseFile(file);
}

CAssemblerCommand* Parser::parseTemplate(const std::wstring& text, std::initializer_list<AssemblyTemplateArgument> variables)
{
	std::wstring fullText = text;

	for (auto& arg: variables)
	{
		size_t count = replaceAll(fullText,arg.variableName,arg.value);

#ifdef _DEBUG
		if (count != 0 && arg.value.empty())
			Logger::printError(Logger::Warning,L"Empty replacement for %s",arg.variableName);
#endif
	}

	return parseString(fullText);
}

CAssemblerCommand* Parser::parseDirective(const DirectiveMap &directiveSet)
{
	const Token &tok = peekToken();
	if (tok.type != TokenType::Identifier)
		return nullptr;

	const std::wstring stringValue = tok.getStringValue();

	auto matchRange = directiveSet.equal_range(stringValue);
	for (auto it = matchRange.first; it != matchRange.second; ++it)
	{
		const DirectiveEntry &directive = it->second;

		if (directive.flags & DIRECTIVE_DISABLED)
			continue;
		if ((directive.flags & DIRECTIVE_NOCASHOFF) && Global.nocash == true)
			continue;
		if ((directive.flags & DIRECTIVE_NOCASHON) && Global.nocash == false)
			continue;
		if ((directive.flags & DIRECTIVE_NOTINMEMORY) && Global.memoryMode == true)
			continue;

		if (directive.flags & DIRECTIVE_MIPSRESETDELAY)
			Arch->NextSection();

		eatToken();
		CAssemblerCommand* result = directive.function(*this,directive.flags);
		if (result == nullptr)
		{
			if (hasError() == false)
				printError(tok,L"Directive parameter failure");
			return nullptr;
		}

		return result;
	}

	return nullptr;
}

bool Parser::matchToken(TokenType type, bool optional)
{
	if (optional)
	{
		const Token& token = peekToken();
		if (token.type == type)
			eatToken();
		return true;
	}

	return nextToken().type == type;
}

CAssemblerCommand* Parser::parse(Tokenizer* tokenizer)
{
	entries.push_back(tokenizer);

	CAssemblerCommand* sequence = parseCommandSequence();
	entries.pop_back();

	return sequence;
}

bool Parser::checkEquLabel()
{
	const Token& start = peekToken();
	if (start.type == TokenType::Identifier)
	{
		int pos = 1;
		if (peekToken(pos).type == TokenType::Colon)
			pos++;

		if (peekToken(pos).type == TokenType::Equ &&
			peekToken(pos+1).type == TokenType::EquValue)
		{
			std::wstring name = peekToken(0).getStringValue();
			std::wstring value = peekToken(pos+1).getStringValue();
			eatTokens(pos+2);

			// equs are not allowed in macros
			if (initializingMacro)
			{
				printError(start,L"equ not allowed in macro");
				return true;
			}

			if (Global.symbolTable.isValidSymbolName(name) == false)
			{
				printError(start,L"Invalid equation name %s",name);
				return true;
			}

			if (Global.symbolTable.symbolExists(name,Global.FileInfo.FileNum,Global.Section))
			{
				printError(start,L"Equation name %s already defined",name);
				return true;
			}

			// parse value string
			TextFile f;
			f.openMemory(value);

			FileTokenizer tok;
			tok.init(&f);

			TokenizerPosition start = tok.getPosition();
			while (tok.atEnd() == false)
				tok.nextToken();

			// extract tokens
			TokenizerPosition end = tok.getPosition();
			std::vector<Token> tokens = tok.getTokens(start,end);
			size_t index = Tokenizer::addEquValue(tokens);

			for (Tokenizer* tokenizer: entries)
				tokenizer->resetLookaheadCheckMarks();

			// register equation
			Global.symbolTable.addEquation(name,Global.FileInfo.FileNum,Global.Section,index);

			return true;
		}
	}

	return false;
}

bool Parser::checkMacroDefinition()
{
	const Token& first = peekToken();
	if (first.type != TokenType::Identifier)
		return false;

	if (!first.stringValueStartsWith(L'.') || first.getStringValue() != L".macro")
		return false;

	eatToken();

	// nested macro definitions are not allowed
	if (initializingMacro)
	{
		printError(first,L"Nested macro definitions not allowed");
		while (!atEnd())
		{
			const Token& token = nextToken();
			if (token.type == TokenType::Identifier && token.getStringValue() == L".endmacro")
				break;
		}

		return true;
	}

	std::vector<Expression> parameters;
	if (parseExpressionList(parameters,1,-1) == false)
		return false;

	// load name
	std::wstring macroName;
	if (parameters[0].evaluateIdentifier(macroName) == false)
		return false;

	// duplicate check the macro
	ParserMacro &macro = macros[macroName];
	if (macro.name.length() != 0)
	{
		printError(first,L"Macro \"%s\" already defined",macro.name);
		return false;
	}

	// and register it
	macro.name = macroName;
	macro.counter = 0;

	// load parameters
	for (size_t i = 1; i < parameters.size(); i++)
	{
		std::wstring name;
		if (parameters[i].evaluateIdentifier(name) == false)
			return false;

		macro.parameters.push_back(name);
	}

	// load macro content

	TokenizerPosition start = getTokenizer()->getPosition();
	bool valid = false;
	while (atEnd() == false)
	{
		const Token& tok = nextToken();
		if (tok.type == TokenType::Identifier && tok.getStringValue() == L".endmacro")
		{
			valid = true;
			break;
		}
	}

	// no .endmacro, not valid
	if (valid == false)
		return true;

	// get content
	TokenizerPosition end = getTokenizer()->getPosition().previous();
	macro.content = getTokenizer()->getTokens(start,end);

	return true;
}

CAssemblerCommand* Parser::parseMacroCall()
{
	const Token& start = peekToken();
	if (start.type != TokenType::Identifier)
		return nullptr;

	auto it = macros.find(start.getStringValue());
	if (it == macros.end())
		return nullptr;

	ParserMacro& macro = it->second;
	eatToken();

	// create a token stream for the macro content,
	// registering replacements for parameter values
	TokenStreamTokenizer macroTokenizer;

	for (size_t i = 0; i < macro.parameters.size(); i++)
	{
		if (i != 0)
		{
			if (nextToken().type != TokenType::Comma)
				return nullptr;
		}

		if (i == macro.parameters.size())
		{
			size_t count = macro.parameters.size();
			while (peekToken().type == TokenType::Comma)
			{
				eatToken();
				parseExpression();
			}

			printError(start,L"Not enough macro arguments (%d vs %d)",count,macro.parameters.size());
			return nullptr;
		}

		TokenizerPosition startPos = getTokenizer()->getPosition();
		Expression exp = parseExpression();
		if (exp.isLoaded() == false)
			return false;

		TokenizerPosition endPos = getTokenizer()->getPosition();
		std::vector<Token> tokens = getTokenizer()->getTokens(startPos,endPos);

		// give them as a replacement to new tokenizer
		macroTokenizer.registerReplacement(macro.parameters[i],tokens);
	}

	if (peekToken().type == TokenType::Comma)
	{
		size_t count = macro.parameters.size();
		while (peekToken().type == TokenType::Comma)
		{
			eatToken();
			parseExpression();
			count++;
		}

		printError(start,L"Too many macro arguments (%d vs %d)",count,macro.parameters.size());
		return nullptr;
	}

	// a macro is fully parsed once when it's loaded
	// to gather all labels. it's not necessary to
	// instantiate other macros at that time
	if (initializingMacro)
		return new DummyCommand();

	// the first time a macro is instantiated, it needs to be analyzed
	// for labels
	if (macro.counter == 0)
	{
		initializingMacro = true;

		// parse the short lived next command
		macroTokenizer.init(macro.content);
		CAssemblerCommand* command =  parse(&macroTokenizer);
		delete command;

		macro.labels = macroLabels;
		macroLabels.clear();

		initializingMacro = false;
	}

	// register labels and replacements
	for (const std::wstring& label: macro.labels)
	{
		std::wstring fullName = formatString(L"%s_%s_%08X",macro.name,label,macro.counter);
		macroTokenizer.registerReplacement(label,fullName);
	}

	macroTokenizer.init(macro.content);
	macro.counter++;

	return parse(&macroTokenizer);
}

CAssemblerCommand* Parser::parseLabel()
{
	const Token& start = peekToken(0);

	if (peekToken(0).type == TokenType::Identifier &&
		peekToken(1).type == TokenType::Colon)
	{
		const std::wstring name = peekToken(0).getStringValue();
		eatTokens(2);

		if (initializingMacro)
			macroLabels.insert(name);

		if (Global.symbolTable.isValidSymbolName(name) == false)
		{
			printError(start,L"Invalid label name");
			return nullptr;
		}

		return new CAssemblerLabel(name);
	}

	return nullptr;
}

CAssemblerCommand* Parser::handleError()
{
	// skip the rest of the line
	const Token& token = nextToken();
	while (peekToken().line == token.line)
		eatToken();

	clearError();
	return new InvalidCommand();
}

CAssemblerCommand* Parser::parseCommand()
{
	CAssemblerCommand* command;

	while (checkEquLabel() || checkMacroDefinition())
	{
		// do nothing, just parse all the equs and macros there are
		if (hasError())
			return handleError();
	}

	if (atEnd())
		return new DummyCommand();

	if ((command = parseLabel()) != nullptr)
		return command;
	if (hasError())
		return handleError();

	if ((command = parseMacroCall()) != nullptr)
		return command;
	if (hasError())
		return handleError();

	if ((command = Arch->parseDirective(*this)) != nullptr)
		return command;
	if (hasError())
		return handleError();

	if ((command = parseDirective(directives)) != nullptr)
		return command;
	if (hasError())
		return handleError();

	if ((command = Arch->parseOpcode(*this)) != nullptr)
		return command;
	if (hasError())
		return handleError();

	const Token& token = peekToken();
	printError(token,L"Parse error '%s'",token.getOriginalText());
	return handleError();
}

void TokenSequenceParser::addEntry(int result, TokenSequence tokens, TokenValueSequence values)
{
	Entry entry = { tokens, values, result };
	entries.push_back(entry);
}

bool TokenSequenceParser::parse(Parser& parser, int& result)
{
	for (Entry& entry: entries)
	{
		TokenizerPosition pos = parser.getTokenizer()->getPosition();
		auto values = entry.values.begin();

		bool valid = true;
		for (TokenType type: entry.tokens)
		{
			// check of token type matches
			const Token& token = parser.nextToken();
			if (token.type != type)
			{
				valid = false;
				break;
			}

			// if necessary, check if the value of the token also matches
			if (type == TokenType::Identifier)
			{
				if (values == entry.values.end() || values->textValue != token.getStringValue())
				{
					valid = false;
					break;
				}

				values++;
			} else if (type == TokenType::Integer)
			{
				if (values == entry.values.end() || values->intValue != token.intValue)
				{
					valid = false;
					break;
				}

				values++;
			}
		}

		if (valid && values == entry.values.end())
		{
			result = entry.result;
			return true;
		}

		parser.getTokenizer()->setPosition(pos);
	}

	return false;
}
<|endoftext|>


<commit_before>#include <limits>
#include "Skeletonize.h"
#include <vigra/multi_distance.hxx>
#include <vigra/multi_gridgraph.hxx>
#include <vigra/multi_labeling.hxx>
#include <vigra/multi_impex.hxx>
#include <util/timing.h>
#include <util/ProgramOptions.h>
#include <util/Logger.h>

util::ProgramOption optionSkeletonBoundaryWeight(
		util::_long_name        = "skeletonBoundaryWeight",
		util::_description_text = "The weight of the boundary term to find the tube's skeletons.",
		util::_default_value    = 1);

util::ProgramOption optionSkeletonMaxNumSegments(
		util::_long_name        = "skeletonMaxNumSegments",
		util::_description_text = "The maximal number of segments to extract for a skeleton.",
		util::_default_value    = 10);

util::ProgramOption optionSkeletonMinSegmentLength(
		util::_long_name        = "skeletonMinSegmentLength",
		util::_description_text = "The mininal length of a segment (including the boundary penalty) to extract for a skeleton.",
		util::_default_value    = 0);

util::ProgramOption optionSkeletonMinSegmentLengthRatio(
		util::_long_name        = "skeletonMinSegmentLengthRatio",
		util::_description_text = "The mininal length of a segment (including the boundary penalty) as the ratio of the largest segment extracted for a skeleton.",
		util::_default_value    = 1);

util::ProgramOption optionSkeletonSkipExplainedNodes(
		util::_long_name        = "skeletonSkipExplainedNodes",
		util::_description_text = "Don't add segments to nodes that are already explained by the current skeleton. "
		                          "Nodes are explained, if they fall within a sphere around any current skeleton node. "
		                          "The size of the sphere is determined by boundary distance * skeletonExplanationWeight.");

util::ProgramOption optionSkeletonExplanationWeight(
		util::_long_name        = "skeletonExplanationWeight",
		util::_description_text = "A factor to multiply with the boundary distance to create 'explanation spheres'. "
		                          "See skeletonSkipExplainedNodes.",
		util::_default_value    = 1);

logger::LogChannel skeletonizelog("skeletonizelog", "[Skeletonize] ");

Skeletonize::Skeletonize(const GraphVolume& graphVolume) :
	_boundaryDistance(
			vigra::Shape3(
					graphVolume.getDiscreteBoundingBox().width(),
					graphVolume.getDiscreteBoundingBox().height(),
					graphVolume.getDiscreteBoundingBox().depth()
			)),
	_graphVolume(graphVolume),
	_distanceMap(_graphVolume.graph()),
	_boundaryWeight(optionSkeletonBoundaryWeight),
	_dijkstra(_graphVolume.graph(), _distanceMap),
	_nodeLabels(_graphVolume.graph(), Inside),
	_minSegmentLength(optionSkeletonMinSegmentLength),
	_minSegmentLengthRatio(optionSkeletonMinSegmentLengthRatio),
	_skipExplainedNodes(optionSkeletonSkipExplainedNodes),
	_explanationWeight(optionSkeletonExplanationWeight) {}

Skeleton
Skeletonize::getSkeleton() {

	UTIL_TIME_METHOD;

	findBoundaryNodes();

	initializeEdgeMap();

	findRoot();

	int maxNumSegments = optionSkeletonMaxNumSegments;
	int segmentsFound = 0;
	while (extractLongestSegment() && ++segmentsFound < maxNumSegments) {}

	return parseVolumeSkeleton();
}

void
Skeletonize::findBoundaryNodes() {

	for (GraphVolume::NodeIt node(_graphVolume.graph()); node != lemon::INVALID; ++node) {

		int numNeighbors = 0;
		for (GraphVolume::IncEdgeIt e(_graphVolume.graph(), node); e != lemon::INVALID; ++e)
			numNeighbors++;

		if (numNeighbors != GraphVolume::NumNeighbors) {

			_boundary.push_back(node);
			_nodeLabels[node] = Boundary;
		}
	}
}

void
Skeletonize::initializeEdgeMap() {

	// We assume the pitch vigra needs is the number of measurements per unit.
	// Our units are nm, and the volume tells us via getResolution?() the size
	// of a pixel. Hence, the number of measurements per nm in either direction
	// is 1/resolution of this direction.
	float pitch[3];
	pitch[0] = 1.0/_graphVolume.getResolutionX();
	pitch[1] = 1.0/_graphVolume.getResolutionY();
	pitch[2] = 1.0/_graphVolume.getResolutionZ();

	_boundaryDistance = 0;
	for (GraphVolume::NodeIt n(_graphVolume.graph()); n != lemon::INVALID; ++n)
		boundaryDistance(_graphVolume.positions()[n]) = 1.0;

	vigra::separableMultiDistSquared(
			_boundaryDistance,
			_boundaryDistance,
			false,  /* compute distance from object (non-zero) to background (0) */
			pitch);

	// find center point with maximal boundary distance
	_maxBoundaryDistance2 = 0;
	for (GraphVolume::NodeIt node(_graphVolume.graph()); node != lemon::INVALID; ++node) {

		const Position& pos = _graphVolume.positions()[node];
		if (boundaryDistance(pos) > _maxBoundaryDistance2) {

			_center = node;
			_maxBoundaryDistance2 = boundaryDistance(pos);
		}
	}

	// create initial edge map from boundary penalty
	for (GraphVolume::EdgeIt e(_graphVolume.graph()); e != lemon::INVALID; ++e)
		_distanceMap[e] = boundaryPenalty(
				0.5*(
						boundaryDistance(_graphVolume.positions()[_graphVolume.graph().u(e)]) +
						boundaryDistance(_graphVolume.positions()[_graphVolume.graph().v(e)])));

	// multiply with Euclidean node distances
	//
	// The TEASAR paper suggests to add the Euclidean distances. However, for
	// the penalty to be meaningful in anistotropic volumes, it should be
	// multiplied with the Euclidean distance between the nodes (otherwise, it
	// is more expensive to move in the high-resolution dimensions). Therefore,
	// the final value is
	//
	//   penalty*euclidean + euclidean = euclidean*(penalty + 1)

	float nodeDistances[8];
	nodeDistances[0] = 0;
	nodeDistances[1] = _graphVolume.getResolutionZ();
	nodeDistances[2] = _graphVolume.getResolutionY();
	nodeDistances[3] = sqrt(pow(_graphVolume.getResolutionY(), 2) + pow(_graphVolume.getResolutionZ(), 2));
	nodeDistances[4] = _graphVolume.getResolutionX();
	nodeDistances[5] = sqrt(pow(_graphVolume.getResolutionX(), 2) + pow(_graphVolume.getResolutionZ(), 2));
	nodeDistances[6] = sqrt(pow(_graphVolume.getResolutionX(), 2) + pow(_graphVolume.getResolutionY(), 2));
	nodeDistances[7] = sqrt(pow(_graphVolume.getResolutionX(), 2) + pow(_graphVolume.getResolutionY(), 2) + pow(_graphVolume.getResolutionZ(), 2));

	for (GraphVolume::EdgeIt e(_graphVolume.graph()); e != lemon::INVALID; ++e) {

		Position u = _graphVolume.positions()[_graphVolume.graph().u(e)];
		Position v = _graphVolume.positions()[_graphVolume.graph().v(e)];

		int i = 0;
		if (u[0] != v[0]) i |= 4;
		if (u[1] != v[1]) i |= 2;
		if (u[2] != v[2]) i |= 1;

		_distanceMap[e] = nodeDistances[i]*(_distanceMap[e] + 1);
	}
}

void
Skeletonize::findRoot() {

	_dijkstra.run(_center);

	// find furthest point on boundary
	_root = GraphVolume::NodeIt(_graphVolume.graph());
	float maxValue = -1;
	for (GraphVolume::Node n : _boundary) {
		if (_dijkstra.distMap()[n] > maxValue) {

			_root    = n;
			maxValue = _dijkstra.distMap()[n];
		}
	}

	if (maxValue == -1)
		UTIL_THROW_EXCEPTION(
				NoNodeFound,
				"could not find a root boundary point");

	// mark root as being part of skeleton
	_nodeLabels[_root] = OnSkeleton;
}

bool
Skeletonize::extractLongestSegment() {

	_dijkstra.run(_root);

	// find furthest point on boundary
	GraphVolume::Node furthest = GraphVolume::NodeIt(_graphVolume.graph());
	float maxValue = -1;
	for (GraphVolume::Node n : _boundary) {

		if (_skipExplainedNodes && _nodeLabels[n] == Explained)
			continue;

		if (_dijkstra.distMap()[n] > maxValue) {

			furthest = n;
			maxValue = _dijkstra.distMap()[n];
		}
	}

	// no more points or length smaller then min segment length
	if (maxValue == -1 || maxValue < _minSegmentLength)
		return false;

	LOG_DEBUG(skeletonizelog) << "extracting segment with length " << maxValue << std::endl;

	GraphVolume::Node n = furthest;

	// walk backwards to next skeleton point
	while (_nodeLabels[n] != OnSkeleton) {

		_nodeLabels[n] = OnSkeleton;

		if (_skipExplainedNodes)
			drawExplanationSphere(_graphVolume.positions()[n]);

		GraphVolume::Edge pred = _dijkstra.predMap()[n];
		GraphVolume::Node u = _graphVolume.graph().u(pred);
		GraphVolume::Node v = _graphVolume.graph().v(pred);

		n = (u == n ? v : u);

		_distanceMap[pred] = 0.0;
	}

	// first segment?
	if (n == _root) {

		LOG_DEBUG(skeletonizelog) << "longest segment has length " << maxValue << std::endl;

		_minSegmentLength = std::max(_minSegmentLength, _minSegmentLengthRatio*maxValue);

		LOG_DEBUG(skeletonizelog) << "setting min segment length to " << _minSegmentLength << std::endl;
	}

	return true;
}

void
Skeletonize::drawExplanationSphere(const Position& center) {

	double radius2 = boundaryDistance(center)*pow(_explanationWeight, 2);

	double resX2 = pow(_graphVolume.getResolutionX(), 2);
	double resY2 = pow(_graphVolume.getResolutionY(), 2);
	double resZ2 = pow(_graphVolume.getResolutionZ(), 2);

	for (GraphVolume::Node n : _boundary) {

		const Position& pos = _graphVolume.positions()[n];
		double distance2 =
				resX2*pow(pos[0] - center[0], 2) +
				resY2*pow(pos[1] - center[1], 2) +
				resZ2*pow(pos[2] - center[2], 2);

		if (distance2 <= radius2)
			if (_nodeLabels[n] != OnSkeleton)
				_nodeLabels[n] = Explained;
	}
}

double
Skeletonize::boundaryPenalty(double boundaryDistance) {

	// penalty = w*(1.0 - bd/max_bd)
	//
	//   w     : boundary weight
	//   bd    : boundary distance
	//   max_bd: max boundary distance
	return _boundaryWeight*(1.0 - sqrt(boundaryDistance/_maxBoundaryDistance2));
}

Skeleton
Skeletonize::parseVolumeSkeleton() {

	Skeleton skeleton;

	skeleton.setOffset(_graphVolume.getOffset());
	skeleton.setResolution(_graphVolume.getResolution());

	traverse(_root, skeleton);

	return skeleton;
}

void
Skeletonize::traverse(const GraphVolume::Node& n, Skeleton& skeleton) {

	Position pos = _graphVolume.positions()[n];

	_nodeLabels[n] = Visited;

	int neighbors = numNeighbors(n);
	bool isNode = (neighbors != 2);

	if (isNode)
		skeleton.openNode(pos);
	else
		skeleton.extendEdge(pos);

	for (GraphVolume::IncEdgeIt e(_graphVolume.graph(), n); e != lemon::INVALID && neighbors > 0; ++e) {

		GraphVolume::Node neighbor = (_graphVolume.graph().u(e) == n ? _graphVolume.graph().v(e) : _graphVolume.graph().u(e));

		if (_nodeLabels[neighbor] >= OnSkeleton) {

			neighbors--;

			if (_nodeLabels[neighbor] != Visited) {

				traverse(neighbor, skeleton);
			}
		}
	}

	if (isNode)
		skeleton.closeNode();
}

int
Skeletonize::numNeighbors(const GraphVolume::Node& n) {

	int num = 0;

	for (GraphVolume::IncEdgeIt e(_graphVolume.graph(), n); e != lemon::INVALID; ++e) {

		GraphVolume::Node neighbor = (_graphVolume.graph().u(e) == n ? _graphVolume.graph().v(e) : _graphVolume.graph().u(e));

		if (_nodeLabels[neighbor] >= OnSkeleton)
			num++;
	}

	return num;
}

<commit_msg>bugfix: root node in Skeletonize can have two neighbors, but should be considered a skeleton node anyway<commit_after>#include <limits>
#include "Skeletonize.h"
#include <vigra/multi_distance.hxx>
#include <vigra/multi_gridgraph.hxx>
#include <vigra/multi_labeling.hxx>
#include <vigra/multi_impex.hxx>
#include <util/timing.h>
#include <util/ProgramOptions.h>
#include <util/Logger.h>

util::ProgramOption optionSkeletonBoundaryWeight(
		util::_long_name        = "skeletonBoundaryWeight",
		util::_description_text = "The weight of the boundary term to find the tube's skeletons.",
		util::_default_value    = 1);

util::ProgramOption optionSkeletonMaxNumSegments(
		util::_long_name        = "skeletonMaxNumSegments",
		util::_description_text = "The maximal number of segments to extract for a skeleton.",
		util::_default_value    = 10);

util::ProgramOption optionSkeletonMinSegmentLength(
		util::_long_name        = "skeletonMinSegmentLength",
		util::_description_text = "The mininal length of a segment (including the boundary penalty) to extract for a skeleton.",
		util::_default_value    = 0);

util::ProgramOption optionSkeletonMinSegmentLengthRatio(
		util::_long_name        = "skeletonMinSegmentLengthRatio",
		util::_description_text = "The mininal length of a segment (including the boundary penalty) as the ratio of the largest segment extracted for a skeleton.",
		util::_default_value    = 1);

util::ProgramOption optionSkeletonSkipExplainedNodes(
		util::_long_name        = "skeletonSkipExplainedNodes",
		util::_description_text = "Don't add segments to nodes that are already explained by the current skeleton. "
		                          "Nodes are explained, if they fall within a sphere around any current skeleton node. "
		                          "The size of the sphere is determined by boundary distance * skeletonExplanationWeight.");

util::ProgramOption optionSkeletonExplanationWeight(
		util::_long_name        = "skeletonExplanationWeight",
		util::_description_text = "A factor to multiply with the boundary distance to create 'explanation spheres'. "
		                          "See skeletonSkipExplainedNodes.",
		util::_default_value    = 1);

logger::LogChannel skeletonizelog("skeletonizelog", "[Skeletonize] ");

Skeletonize::Skeletonize(const GraphVolume& graphVolume) :
	_boundaryDistance(
			vigra::Shape3(
					graphVolume.getDiscreteBoundingBox().width(),
					graphVolume.getDiscreteBoundingBox().height(),
					graphVolume.getDiscreteBoundingBox().depth()
			)),
	_graphVolume(graphVolume),
	_distanceMap(_graphVolume.graph()),
	_boundaryWeight(optionSkeletonBoundaryWeight),
	_dijkstra(_graphVolume.graph(), _distanceMap),
	_nodeLabels(_graphVolume.graph(), Inside),
	_minSegmentLength(optionSkeletonMinSegmentLength),
	_minSegmentLengthRatio(optionSkeletonMinSegmentLengthRatio),
	_skipExplainedNodes(optionSkeletonSkipExplainedNodes),
	_explanationWeight(optionSkeletonExplanationWeight) {}

Skeleton
Skeletonize::getSkeleton() {

	UTIL_TIME_METHOD;

	findBoundaryNodes();

	initializeEdgeMap();

	findRoot();

	int maxNumSegments = optionSkeletonMaxNumSegments;
	int segmentsFound = 0;
	while (extractLongestSegment() && ++segmentsFound < maxNumSegments) {}

	return parseVolumeSkeleton();
}

void
Skeletonize::findBoundaryNodes() {

	for (GraphVolume::NodeIt node(_graphVolume.graph()); node != lemon::INVALID; ++node) {

		int numNeighbors = 0;
		for (GraphVolume::IncEdgeIt e(_graphVolume.graph(), node); e != lemon::INVALID; ++e)
			numNeighbors++;

		if (numNeighbors != GraphVolume::NumNeighbors) {

			_boundary.push_back(node);
			_nodeLabels[node] = Boundary;
		}
	}
}

void
Skeletonize::initializeEdgeMap() {

	// We assume the pitch vigra needs is the number of measurements per unit.
	// Our units are nm, and the volume tells us via getResolution?() the size
	// of a pixel. Hence, the number of measurements per nm in either direction
	// is 1/resolution of this direction.
	float pitch[3];
	pitch[0] = 1.0/_graphVolume.getResolutionX();
	pitch[1] = 1.0/_graphVolume.getResolutionY();
	pitch[2] = 1.0/_graphVolume.getResolutionZ();

	_boundaryDistance = 0;
	for (GraphVolume::NodeIt n(_graphVolume.graph()); n != lemon::INVALID; ++n)
		boundaryDistance(_graphVolume.positions()[n]) = 1.0;

	vigra::separableMultiDistSquared(
			_boundaryDistance,
			_boundaryDistance,
			false,  /* compute distance from object (non-zero) to background (0) */
			pitch);

	// find center point with maximal boundary distance
	_maxBoundaryDistance2 = 0;
	for (GraphVolume::NodeIt node(_graphVolume.graph()); node != lemon::INVALID; ++node) {

		const Position& pos = _graphVolume.positions()[node];
		if (boundaryDistance(pos) > _maxBoundaryDistance2) {

			_center = node;
			_maxBoundaryDistance2 = boundaryDistance(pos);
		}
	}

	// create initial edge map from boundary penalty
	for (GraphVolume::EdgeIt e(_graphVolume.graph()); e != lemon::INVALID; ++e)
		_distanceMap[e] = boundaryPenalty(
				0.5*(
						boundaryDistance(_graphVolume.positions()[_graphVolume.graph().u(e)]) +
						boundaryDistance(_graphVolume.positions()[_graphVolume.graph().v(e)])));

	// multiply with Euclidean node distances
	//
	// The TEASAR paper suggests to add the Euclidean distances. However, for
	// the penalty to be meaningful in anistotropic volumes, it should be
	// multiplied with the Euclidean distance between the nodes (otherwise, it
	// is more expensive to move in the high-resolution dimensions). Therefore,
	// the final value is
	//
	//   penalty*euclidean + euclidean = euclidean*(penalty + 1)

	float nodeDistances[8];
	nodeDistances[0] = 0;
	nodeDistances[1] = _graphVolume.getResolutionZ();
	nodeDistances[2] = _graphVolume.getResolutionY();
	nodeDistances[3] = sqrt(pow(_graphVolume.getResolutionY(), 2) + pow(_graphVolume.getResolutionZ(), 2));
	nodeDistances[4] = _graphVolume.getResolutionX();
	nodeDistances[5] = sqrt(pow(_graphVolume.getResolutionX(), 2) + pow(_graphVolume.getResolutionZ(), 2));
	nodeDistances[6] = sqrt(pow(_graphVolume.getResolutionX(), 2) + pow(_graphVolume.getResolutionY(), 2));
	nodeDistances[7] = sqrt(pow(_graphVolume.getResolutionX(), 2) + pow(_graphVolume.getResolutionY(), 2) + pow(_graphVolume.getResolutionZ(), 2));

	for (GraphVolume::EdgeIt e(_graphVolume.graph()); e != lemon::INVALID; ++e) {

		Position u = _graphVolume.positions()[_graphVolume.graph().u(e)];
		Position v = _graphVolume.positions()[_graphVolume.graph().v(e)];

		int i = 0;
		if (u[0] != v[0]) i |= 4;
		if (u[1] != v[1]) i |= 2;
		if (u[2] != v[2]) i |= 1;

		_distanceMap[e] = nodeDistances[i]*(_distanceMap[e] + 1);
	}
}

void
Skeletonize::findRoot() {

	_dijkstra.run(_center);

	// find furthest point on boundary
	_root = GraphVolume::NodeIt(_graphVolume.graph());
	float maxValue = -1;
	for (GraphVolume::Node n : _boundary) {
		if (_dijkstra.distMap()[n] > maxValue) {

			_root    = n;
			maxValue = _dijkstra.distMap()[n];
		}
	}

	if (maxValue == -1)
		UTIL_THROW_EXCEPTION(
				NoNodeFound,
				"could not find a root boundary point");

	// mark root as being part of skeleton
	_nodeLabels[_root] = OnSkeleton;
}

bool
Skeletonize::extractLongestSegment() {

	_dijkstra.run(_root);

	// find furthest point on boundary
	GraphVolume::Node furthest = GraphVolume::NodeIt(_graphVolume.graph());
	float maxValue = -1;
	for (GraphVolume::Node n : _boundary) {

		if (_skipExplainedNodes && _nodeLabels[n] == Explained)
			continue;

		if (_dijkstra.distMap()[n] > maxValue) {

			furthest = n;
			maxValue = _dijkstra.distMap()[n];
		}
	}

	// no more points or length smaller then min segment length
	if (maxValue == -1 || maxValue < _minSegmentLength)
		return false;

	LOG_DEBUG(skeletonizelog) << "extracting segment with length " << maxValue << std::endl;

	GraphVolume::Node n = furthest;

	// walk backwards to next skeleton point
	while (_nodeLabels[n] != OnSkeleton) {

		_nodeLabels[n] = OnSkeleton;

		if (_skipExplainedNodes)
			drawExplanationSphere(_graphVolume.positions()[n]);

		GraphVolume::Edge pred = _dijkstra.predMap()[n];
		GraphVolume::Node u = _graphVolume.graph().u(pred);
		GraphVolume::Node v = _graphVolume.graph().v(pred);

		n = (u == n ? v : u);

		_distanceMap[pred] = 0.0;
	}

	// first segment?
	if (n == _root) {

		LOG_DEBUG(skeletonizelog) << "longest segment has length " << maxValue << std::endl;

		_minSegmentLength = std::max(_minSegmentLength, _minSegmentLengthRatio*maxValue);

		LOG_DEBUG(skeletonizelog) << "setting min segment length to " << _minSegmentLength << std::endl;
	}

	return true;
}

void
Skeletonize::drawExplanationSphere(const Position& center) {

	double radius2 = boundaryDistance(center)*pow(_explanationWeight, 2);

	double resX2 = pow(_graphVolume.getResolutionX(), 2);
	double resY2 = pow(_graphVolume.getResolutionY(), 2);
	double resZ2 = pow(_graphVolume.getResolutionZ(), 2);

	for (GraphVolume::Node n : _boundary) {

		const Position& pos = _graphVolume.positions()[n];
		double distance2 =
				resX2*pow(pos[0] - center[0], 2) +
				resY2*pow(pos[1] - center[1], 2) +
				resZ2*pow(pos[2] - center[2], 2);

		if (distance2 <= radius2)
			if (_nodeLabels[n] != OnSkeleton)
				_nodeLabels[n] = Explained;
	}
}

double
Skeletonize::boundaryPenalty(double boundaryDistance) {

	// penalty = w*(1.0 - bd/max_bd)
	//
	//   w     : boundary weight
	//   bd    : boundary distance
	//   max_bd: max boundary distance
	return _boundaryWeight*(1.0 - sqrt(boundaryDistance/_maxBoundaryDistance2));
}

Skeleton
Skeletonize::parseVolumeSkeleton() {

	Skeleton skeleton;

	skeleton.setOffset(_graphVolume.getOffset());
	skeleton.setResolution(_graphVolume.getResolution());

	traverse(_root, skeleton);

	return skeleton;
}

void
Skeletonize::traverse(const GraphVolume::Node& n, Skeleton& skeleton) {

	Position pos = _graphVolume.positions()[n];

	_nodeLabels[n] = Visited;

	int neighbors = numNeighbors(n);
	bool isNode = (neighbors != 2);

	if (isNode || n == _root)
		skeleton.openNode(pos);
	else
		skeleton.extendEdge(pos);

	for (GraphVolume::IncEdgeIt e(_graphVolume.graph(), n); e != lemon::INVALID && neighbors > 0; ++e) {

		GraphVolume::Node neighbor = (_graphVolume.graph().u(e) == n ? _graphVolume.graph().v(e) : _graphVolume.graph().u(e));

		if (_nodeLabels[neighbor] >= OnSkeleton) {

			neighbors--;

			if (_nodeLabels[neighbor] != Visited) {

				traverse(neighbor, skeleton);
			}
		}
	}

	if (isNode)
		skeleton.closeNode();
}

int
Skeletonize::numNeighbors(const GraphVolume::Node& n) {

	int num = 0;

	for (GraphVolume::IncEdgeIt e(_graphVolume.graph(), n); e != lemon::INVALID; ++e) {

		GraphVolume::Node neighbor = (_graphVolume.graph().u(e) == n ? _graphVolume.graph().v(e) : _graphVolume.graph().u(e));

		if (_nodeLabels[neighbor] >= OnSkeleton)
			num++;
	}

	return num;
}

<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015
 * 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.
 */

#pragma once
#include <libhackrf/hackrf.h>
#include <string>
#include <mutex>
#include <condition_variable>
#include <SoapySDR/Device.hpp>
#include <SoapySDR/Logger.hpp>

#define BUF_LEN			262144
#define BUF_NUM			15
#define BYTES_PER_SAMPLE	2

enum HackRF_Format {
	HACKRF_FORMAT_FLOAT32	=0,
	HACKRF_FORMAT_INT16	=1,
	HACKRF_FORMAT_INT8	=2,
};

class SoapyHackRF : public SoapySDR::Device
{
public:
	SoapyHackRF( const SoapySDR::Kwargs & args );

	~SoapyHackRF( void );

	/*******************************************************************
	 * Identification API
	 ******************************************************************/

	std::string getDriverKey( void ) const;

	std::string getHardwareKey( void ) const;

	SoapySDR::Kwargs getHardwareInfo( void ) const;

	/*******************************************************************
	 * Channels API
	 ******************************************************************/

	size_t getNumChannels( const int ) const;

	bool getFullDuplex( const int direction, const size_t channel ) const;

	/*******************************************************************
	 * Stream API
	 ******************************************************************/

	SoapySDR::Stream *setupStream(
		const int direction,
		const std::string &format,
		const std::vector<size_t> &channels = std::vector<size_t>(),
		const SoapySDR::Kwargs &args = SoapySDR::Kwargs() );

	void closeStream( SoapySDR::Stream *stream );

	size_t getStreamMTU( SoapySDR::Stream *stream ) const;

	int activateStream(
		SoapySDR::Stream *stream,
		const int flags = 0,
		const long long timeNs = 0,
		const size_t numElems = 0 );

	int deactivateStream(
		SoapySDR::Stream *stream,
		const int flags = 0,
		const long long timeNs = 0 );

	int readStream(
		SoapySDR::Stream *stream,
		void * const *buffs,
		const size_t numElems,
		int &flags,
		long long &timeNs,
		const long timeoutUs = 100000 );

	int writeStream(
		SoapySDR::Stream *stream,
		void * const *buffs,
		const size_t numElems,
		int &flags,
		long long &timeNs,
		const long timeoutUs = 100000 );

	/*******************************************************************
	 * Antenna API
	 ******************************************************************/

	std::vector<std::string> listAntennas( const int direction, const size_t channel ) const;

	void setAntenna( const int direction, const size_t channel, const std::string &name );

	std::string getAntenna( const int direction, const size_t channel ) const;

	/*******************************************************************
	 * Frontend corrections API
	 ******************************************************************/

	bool hasDCOffsetMode( const int direction, const size_t channel ) const;

	/*******************************************************************
	 * Gain API
	 ******************************************************************/

	std::vector<std::string> listGains( const int direction, const size_t channel ) const;

	void setGainMode( const int direction, const size_t channel, const bool automatic );

	bool getGainMode( const int direction, const size_t channel ) const;

	void setGain( const int direction, const size_t channel, const double value );

	void setGain( const int direction, const size_t channel, const std::string &name, const double value );

	double getGain( const int direction, const size_t channel, const std::string &name ) const;

	SoapySDR::Range getGainRange( const int direction, const size_t channel, const std::string &name ) const;

	/*******************************************************************
	 * Frequency API
	 ******************************************************************/

	void setFrequency( const int direction, const size_t channel, const std::string &name, const double frequency, const SoapySDR::Kwargs &args = SoapySDR::Kwargs() );

	double getFrequency( const int direction, const size_t channel, const std::string &name ) const;

	std::vector<std::string> listFrequencies( const int direction, const size_t channel ) const;

	SoapySDR::RangeList getFrequencyRange( const int direction, const size_t channel, const std::string &name ) const;

	/*******************************************************************
	 * Sample Rate API
	 ******************************************************************/

	void setSampleRate( const int direction, const size_t channel, const double rate );

	double getSampleRate( const int direction, const size_t channel ) const;

	std::vector<double> listSampleRates( const int direction, const size_t channel ) const;

	void setBandwidth( const int direction, const size_t channel, const double bw );

	double getBandwidth( const int direction, const size_t channel ) const;

	std::vector<double> listBandwidths( const int direction, const size_t channel ) const;

	/*******************************************************************
	 * HackRF callback
	 ******************************************************************/
	int hackrf_tx_callback( int8_t *buffer, int32_t length );

	int hackrf_rx_callback( int8_t *buffer, int32_t length );

private:
	bool _running;

	hackrf_device * _dev;

	double _frequency;

	uint32_t _rx_vga_gain;

	uint32_t _rx_lna_gain;

	uint32_t _tx_vga_gain;

	double _samplerate;

	uint32_t _bandwidth;

	uint8_t _amp;

	uint32_t _format;

	int32_t _id;

	int8_t		**_buf;
	uint32_t	_buf_num;
	uint32_t	_buf_len;
	uint32_t	_buf_head;
	uint32_t	_buf_tail;
	uint32_t	_buf_count;
	uint32_t	_buf_offset;

	int32_t _samp_avail;

	std::mutex		_buf_mutex;
	std::condition_variable _buf_cond;

};
<commit_msg>include update<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015
 * 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.
 */

#pragma once
#include <libhackrf/hackrf.h>
#include <string.h>
#include <mutex>
#include <condition_variable>
#include <SoapySDR/Device.hpp>
#include <SoapySDR/Logger.hpp>

#define BUF_LEN			262144
#define BUF_NUM			15
#define BYTES_PER_SAMPLE	2

enum HackRF_Format {
	HACKRF_FORMAT_FLOAT32	=0,
	HACKRF_FORMAT_INT16	=1,
	HACKRF_FORMAT_INT8	=2,
};

class SoapyHackRF : public SoapySDR::Device
{
public:
	SoapyHackRF( const SoapySDR::Kwargs & args );

	~SoapyHackRF( void );

	/*******************************************************************
	 * Identification API
	 ******************************************************************/

	std::string getDriverKey( void ) const;

	std::string getHardwareKey( void ) const;

	SoapySDR::Kwargs getHardwareInfo( void ) const;

	/*******************************************************************
	 * Channels API
	 ******************************************************************/

	size_t getNumChannels( const int ) const;

	bool getFullDuplex( const int direction, const size_t channel ) const;

	/*******************************************************************
	 * Stream API
	 ******************************************************************/

	SoapySDR::Stream *setupStream(
		const int direction,
		const std::string &format,
		const std::vector<size_t> &channels = std::vector<size_t>(),
		const SoapySDR::Kwargs &args = SoapySDR::Kwargs() );

	void closeStream( SoapySDR::Stream *stream );

	size_t getStreamMTU( SoapySDR::Stream *stream ) const;

	int activateStream(
		SoapySDR::Stream *stream,
		const int flags = 0,
		const long long timeNs = 0,
		const size_t numElems = 0 );

	int deactivateStream(
		SoapySDR::Stream *stream,
		const int flags = 0,
		const long long timeNs = 0 );

	int readStream(
		SoapySDR::Stream *stream,
		void * const *buffs,
		const size_t numElems,
		int &flags,
		long long &timeNs,
		const long timeoutUs = 100000 );

	int writeStream(
		SoapySDR::Stream *stream,
		void * const *buffs,
		const size_t numElems,
		int &flags,
		long long &timeNs,
		const long timeoutUs = 100000 );

	/*******************************************************************
	 * Antenna API
	 ******************************************************************/

	std::vector<std::string> listAntennas( const int direction, const size_t channel ) const;

	void setAntenna( const int direction, const size_t channel, const std::string &name );

	std::string getAntenna( const int direction, const size_t channel ) const;

	/*******************************************************************
	 * Frontend corrections API
	 ******************************************************************/

	bool hasDCOffsetMode( const int direction, const size_t channel ) const;

	/*******************************************************************
	 * Gain API
	 ******************************************************************/

	std::vector<std::string> listGains( const int direction, const size_t channel ) const;

	void setGainMode( const int direction, const size_t channel, const bool automatic );

	bool getGainMode( const int direction, const size_t channel ) const;

	void setGain( const int direction, const size_t channel, const double value );

	void setGain( const int direction, const size_t channel, const std::string &name, const double value );

	double getGain( const int direction, const size_t channel, const std::string &name ) const;

	SoapySDR::Range getGainRange( const int direction, const size_t channel, const std::string &name ) const;

	/*******************************************************************
	 * Frequency API
	 ******************************************************************/

	void setFrequency( const int direction, const size_t channel, const std::string &name, const double frequency, const SoapySDR::Kwargs &args = SoapySDR::Kwargs() );

	double getFrequency( const int direction, const size_t channel, const std::string &name ) const;

	std::vector<std::string> listFrequencies( const int direction, const size_t channel ) const;

	SoapySDR::RangeList getFrequencyRange( const int direction, const size_t channel, const std::string &name ) const;

	/*******************************************************************
	 * Sample Rate API
	 ******************************************************************/

	void setSampleRate( const int direction, const size_t channel, const double rate );

	double getSampleRate( const int direction, const size_t channel ) const;

	std::vector<double> listSampleRates( const int direction, const size_t channel ) const;

	void setBandwidth( const int direction, const size_t channel, const double bw );

	double getBandwidth( const int direction, const size_t channel ) const;

	std::vector<double> listBandwidths( const int direction, const size_t channel ) const;

	/*******************************************************************
	 * HackRF callback
	 ******************************************************************/
	int hackrf_tx_callback( int8_t *buffer, int32_t length );

	int hackrf_rx_callback( int8_t *buffer, int32_t length );

private:
	bool _running;

	hackrf_device * _dev;

	double _frequency;

	uint32_t _rx_vga_gain;

	uint32_t _rx_lna_gain;

	uint32_t _tx_vga_gain;

	double _samplerate;

	uint32_t _bandwidth;

	uint8_t _amp;

	uint32_t _format;

	int32_t _id;

	int8_t		**_buf;
	uint32_t	_buf_num;
	uint32_t	_buf_len;
	uint32_t	_buf_head;
	uint32_t	_buf_tail;
	uint32_t	_buf_count;
	uint32_t	_buf_offset;

	int32_t _samp_avail;

	std::mutex		_buf_mutex;
	std::condition_variable _buf_cond;

};
<|endoftext|>


<commit_before>#include "INTC.h"
#include "Log.h"
#include "RegisterStateFile.h"

#define LOG_NAME        ("intc")

#define STATE_REGS_XML  ("intc/regs.xml")

using namespace Framework;

CINTC::CINTC(CDMAC& dmac) :
m_INTC_STAT(0),
m_INTC_MASK(0),
m_dmac(dmac)
{

}

CINTC::~CINTC()
{

}

void CINTC::Reset()
{
	m_INTC_STAT = 0;
	m_INTC_MASK = 0;
}

bool CINTC::IsInterruptPending()
{
	if(m_dmac.IsInterruptPending())
	{
		m_INTC_STAT |= 0x02;
	}

	return (m_INTC_STAT & m_INTC_MASK) != 0;
}

uint32 CINTC::GetRegister(uint32 nAddress)
{
	switch(nAddress)
	{
	case 0x1000F000:
		return m_INTC_STAT | 0x04;
		break;
	case 0x1000F010:
		return m_INTC_MASK;
		break;
	default:
		CLog::GetInstance().Print(LOG_NAME, "Read an unhandled register (0x%0.8X).\r\n", nAddress);
		break;
	}

	return 0;
}

void CINTC::SetRegister(uint32 nAddress, uint32 nValue)
{
	switch(nAddress)
	{
	case 0x1000F000:
		m_INTC_STAT &= ~nValue;
		break;
	case 0x1000F010:
		m_INTC_MASK ^= nValue;
		break;
	default:
        CLog::GetInstance().Print(LOG_NAME, "Wrote to an unhandled register (0x%0.8X).\r\n", nAddress);
		break;
	}
}

void CINTC::AssertLine(uint32 nLine)
{
	m_INTC_STAT |= (1 << nLine);
}

void CINTC::LoadState(CZipArchiveReader& archive)
{
    CRegisterStateFile registerFile(*archive.BeginReadFile(STATE_REGS_XML));
    m_INTC_STAT = registerFile.GetRegister32("INTC_STAT");
    m_INTC_MASK = registerFile.GetRegister32("INTC_MASK");
}

void CINTC::SaveState(CZipArchiveWriter& archive)
{
    CRegisterStateFile* registerFile = new CRegisterStateFile(STATE_REGS_XML);
    registerFile->SetRegister32("INTC_STAT", m_INTC_STAT);
    registerFile->SetRegister32("INTC_MASK", m_INTC_MASK);
    archive.InsertFile(registerFile);
}
<commit_msg>Removed hack in INTC.<commit_after>#include "INTC.h"
#include "Log.h"
#include "RegisterStateFile.h"

#define LOG_NAME        ("intc")

#define STATE_REGS_XML  ("intc/regs.xml")

using namespace Framework;

CINTC::CINTC(CDMAC& dmac) :
m_INTC_STAT(0),
m_INTC_MASK(0),
m_dmac(dmac)
{

}

CINTC::~CINTC()
{

}

void CINTC::Reset()
{
	m_INTC_STAT = 0;
	m_INTC_MASK = 0;
}

bool CINTC::IsInterruptPending()
{
	if(m_dmac.IsInterruptPending())
	{
		m_INTC_STAT |= 0x02;
	}

	return (m_INTC_STAT & m_INTC_MASK) != 0;
}

uint32 CINTC::GetRegister(uint32 nAddress)
{
	switch(nAddress)
	{
	case 0x1000F000:
		return m_INTC_STAT;
		break;
	case 0x1000F010:
		return m_INTC_MASK;
		break;
	default:
		CLog::GetInstance().Print(LOG_NAME, "Read an unhandled register (0x%0.8X).\r\n", nAddress);
		break;
	}

	return 0;
}

void CINTC::SetRegister(uint32 nAddress, uint32 nValue)
{
	switch(nAddress)
	{
	case 0x1000F000:
		m_INTC_STAT &= ~nValue;
		break;
	case 0x1000F010:
		m_INTC_MASK ^= nValue;
		break;
	default:
        CLog::GetInstance().Print(LOG_NAME, "Wrote to an unhandled register (0x%0.8X).\r\n", nAddress);
		break;
	}
}

void CINTC::AssertLine(uint32 nLine)
{
	m_INTC_STAT |= (1 << nLine);
}

void CINTC::LoadState(CZipArchiveReader& archive)
{
    CRegisterStateFile registerFile(*archive.BeginReadFile(STATE_REGS_XML));
    m_INTC_STAT = registerFile.GetRegister32("INTC_STAT");
    m_INTC_MASK = registerFile.GetRegister32("INTC_MASK");
}

void CINTC::SaveState(CZipArchiveWriter& archive)
{
    CRegisterStateFile* registerFile = new CRegisterStateFile(STATE_REGS_XML);
    registerFile->SetRegister32("INTC_STAT", m_INTC_STAT);
    registerFile->SetRegister32("INTC_MASK", m_INTC_MASK);
    archive.InsertFile(registerFile);
}
<|endoftext|>


<commit_before>#if defined( DEBUG ) || defined( _DEBUG)
	#include "vld.h"
#endif

#ifndef _WIN32

#include "WindowsContainer.h"
int WINAPI WinMain(
	HINSTANCE	hInstance,
	HINSTANCE	hPrevInstance,
	LPSTR		lpCmdLine,
	int			nCmdShow)
{
	WindowsContainer win;
	win.main(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

	return 0;
}

#else

#include "LinuxContainer.h"
int main(int argc, char** argv)
{
	LinuxContainer* linuxContainer = new LinuxContainer();
	linuxContainer->mainContainer(argc, argv);
	DELETE_NULL(linuxContainer);

	return 0;
}
#endif //_WIN32
<commit_msg>redundant<commit_after>#if defined( DEBUG ) || defined( _DEBUG)
	#include "vld.h"
#endif

#ifndef _WIN32

#include "WindowsContainer.h"
int WINAPI WinMain(
	HINSTANCE	hInstance,
	HINSTANCE	hPrevInstance,
	LPSTR		lpCmdLine,
	int			nCmdShow)
{
	WindowsContainer win;
	win.main(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

	return 0;
}

#else

#include "LinuxContainer.h"
int main(int argc, char** argv)
{
	LinuxContainer* linuxContainer = new LinuxContainer();
	linuxContainer->mainContainer(argc, argv);
	DELETE_NULL(linuxContainer);

	return 0;
}

#endif //_WIN32
<|endoftext|>


<commit_before>/*
T0 DA for online calibration

Contact: Michal.Oledzki@cern.ch
Link: http://users.jyu.fi/~mioledzk/
Run Type: PHYSICS
DA Type: MON
Number of events needed: 500000
Input Files: inPhys.dat, external parameters
Output Files: daPhys.root, to be exported to the DAQ FXS
Trigger types used: PHYSICS_EVENT
------------------------------Alla
Now trigger type changed to CALICRATION_EVENT
to have data during test.
SOULD BE CHANGED BACK BEFORE BEAM
------------------------------- Alla
*/

#define FILE_OUT "daPhys.root"
#define FILE_IN "inPhys.dat"
#include <daqDA.h>
#include <event.h>
#include <monitor.h>

#include <Riostream.h>
#include <stdio.h>
#include <stdlib.h>

//AliRoot
#include <AliRawReaderDate.h>
#include <AliRawReader.h>
#include <AliT0RawReader.h>

//ROOT
#include "TROOT.h"
#include "TPluginManager.h"
#include "TFile.h"
#include "TKey.h"
#include "TObject.h"
#include "TBenchmark.h"
#include "TString.h"
#include "TH1.h"
#include "TSpectrum.h"
#include "TMath.h"

/* Main routine
      Arguments:
      1- monitoring data source
*/
int main(int argc, char **argv) {
//int main(){
  int status;

  /* magic line */
  gROOT->GetPluginManager()->AddHandler("TVirtualStreamerInfo",
                                        "*",
                                        "TStreamerInfo",
                                        "RIO",
                                        "TStreamerInfo()");

  if(daqDA_DB_getFile(FILE_IN, FILE_IN)){
    printf("Couldn't get input file >>inPhys.dat<< from DAQ_DB !!!\n");
    return -1;
  }

  FILE *inp;
  char c;
  inp = fopen(FILE_IN, "r");
  if(!inp){
    printf("Input file >>inPhys.dat<< not found !!!\n");
    return -1;
  }
  int  kcbx, kt0bx, knpmtA, knpmtC;
  float kclx,kcmx, kt0lx, kt0hx;

  while((c=getc(inp))!=EOF) {
    switch(c) {
    case 'a': {fscanf(inp, "%d", &kcbx ); break;} //N of X bins hCFD1_CFD
    case 'b': {fscanf(inp, "%f", &kclx ); break;} //Low x hCFD1_CFD
    case 'c': {fscanf(inp, "%f", &kcmx ); break;} //High x hCFD1_CF
    case 'd': {fscanf(inp, "%d", &knpmtC ); break;} //number of reference PMTC
    case 'e': {fscanf(inp, "%d", &knpmtA ); break;} //number of reference PMTA
    case 'f': {fscanf(inp, "%d", &kt0bx ); break;} //N of X bins hT0
    case 'g': {fscanf(inp, "%f", &kt0lx ); break;} //Low x hT0
    case 'k': {fscanf(inp, "%f", &kt0hx ); break;} //High x hT0
    }
  }
  fclose(inp);

  if (argc!=2) {
    printf("Wrong number of arguments\n");
    return -1;
  }

  /* define data source : this is argument 1 */
  status=monitorSetDataSource( argv[1] );
  if (status!=0) {
    printf("monitorSetDataSource() failed : %s\n",monitorDecodeError(status));
    return -1;
  }

  /* declare monitoring program */
  status=monitorDeclareMp( __FILE__ );
  if (status!=0) {
    printf("monitorDeclareMp() failed : %s\n",monitorDecodeError(status));
    return -1;
  }

  /* define wait event timeout - 1s max */
  monitorSetNowait();
  monitorSetNoWaitNetworkTimeout(1000);

  /* log start of process */
  printf("T0 monitoring program started\n");

  // Allocation of histograms - start

  TH1F *hCFD1minCFD[24];

  for(Int_t ic=0; ic<24; ic++) {
    hCFD1minCFD[ic] = new TH1F(Form("CFD1minCFD%d",ic+1),"CFD-CFD",kcbx,kclx,kcmx);
    hCFD[ic] = new TH1F(Form("CFD1minCFD%d",ic+1),"CFD",kt0bx,kt0lx,kt0hx);
  }
  TH1F *hVertex = new TH1F("hVertex","T0 time",kt0bx,kt0lx,kt0hx);

   // Allocation of histograms - end

  Int_t iev=0;
  /* main loop (infinite) */
  for(;;) {
    struct eventHeaderStruct *event;
    eventTypeType eventT;

    /* check shutdown condition */
    if (daqDA_checkShutdown()) {break;}

    /* get next event (blocking call until timeout) */
    status=monitorGetEventDynamic((void **)&event);
    if (status==(int)MON_ERR_EOF) {
      printf ("End of File detected\n");
      break; /* end of monitoring file has been reached */
    }

    if (status!=0) {
      printf("monitorGetEventDynamic() failed : %s\n",monitorDecodeError(status));
      break;
    }

    /* retry if got no event */
    if (event==NULL) {
      continue;
    }

    /* use event - here, just write event id to result file */
    eventT=event->eventType;

    switch (event->eventType){

    case START_OF_RUN:
      break;

    case END_OF_RUN:
      break;

    case PHYSICS_EVENT:
	  //    case CALIBRATION_EVENT:
      iev++;

      if(iev==1){
	printf("First event - %i\n",iev);
      }

      // Initalize raw-data reading and decoding
      AliRawReader *reader = new AliRawReaderDate((void*)event);

      // Enable the following two lines in case of real-data
      reader->RequireHeader(kTRUE);
      AliT0RawReader *start = new AliT0RawReader(reader, kTRUE);

      // Read raw data
      Int_t allData[110][5];
      for(Int_t i0=0;i0<107;i0++)
      	for(Int_t j0=0;j0<5;j0++)
	  allData[i0][j0] = 0;

      if(start->Next()){
	for (Int_t i=0; i<107; i++) {
	  for(Int_t iHit=0;iHit<5;iHit++){
	    allData[i][iHit]= start->GetData(i,iHit);
	  }
	}
      }

      // Fill the histograms
      Float_t besttimeA=9999999;
      Float_t besttimeC=9999999;
      Float_t time[24];
       Float_t meanShift[24];
       for (Int_t ik = 0; ik<24; ik++)
	 {
	   if(allData[ik+1][0]>0 ) hCFD[ik]->Fill(allData[ik+1][0]);
	   if(ik<12 && allData[ik+1][0]>0 && allData[knpmtC][0]>0 ){
	     hCFD1minCFD[ik]->Fill(allData[ik+1][0]-allData[knpmtC][0]);
	   }

	   if(ik>11 && allData[ik+45][0]>0 && allData[56+knpmtA][0]>0 )
	     {
	     hCFD1minCFD[ik]->Fill(allData[ik+45][0]-allData[56+knpmtA][0]);
	     }
	   if(iev == 10000) {
	     meanShift[ik] =  hCFD1minCFD[ik]->GetMean();
	     if(ik==knpmtC || ik==(56+knpmtA)) meanShift[ik]=0;
	   }
	 }
      //fill  mean time _ fast reconstruction
      if (iev > 10000 )
	{
	  for (Int_t in=0; in<12; in++)
	    {
	      time[in] = allData[in+1][0] - meanShift[in]  ;
	      time[in+12] = allData[in+56+1][0] ;
	    }
	  for (Int_t ipmt=0; ipmt<12; ipmt++){
	    if(time[ipmt] > 1 ) {
	      if(time[ipmt]<besttimeC)
		besttimeC=time[ipmt]; //timeC
	    }
	  }
	   for ( Int_t ipmt=12; ipmt<24; ipmt++){
	     if(time[ipmt] > 1) {
	       if(time[ipmt]<besttimeA)
		 besttimeA=time[ipmt]; //timeA
	     }
	   }
	   if(besttimeA<9999999 &&besttimeC< 9999999) {
	     Float_t t0 =0.001* 24.4 * Float_t( besttimeA+besttimeC)/2.;
	     hVertex->Fill(t0);
	   }
	}

     delete start;
     start = 0x0;
     delete reader;
     reader= 0x0;
      // End of fill histograms

    }

    /* free resources */
    free(event);

    /* exit when last event received, no need to wait for TERM signal */
    if (eventT==END_OF_RUN) {
      printf("EOR event detected\n");
      printf("Number of events processed - %i\n ",iev);
      break;
    }
  }
  printf("After loop, before writing histos\n");
  // write a file with the histograms

  TFile hist(FILE_OUT,"RECREATE");

  for(Int_t j=0;j<24;j++){
    hCFD1minCFD[j]->SetDirectory(&hist);
    hCFD1minCFD[j]->Write();
    hCFD[j]->Write();

  }
  hVertex->Write();
  hist.Close();
  //delete hist;

  status=0;

  /* export file to FXS */
  if (daqDA_FES_storeFile(FILE_OUT, "PHYSICS")) {
    status=-2;
  }

  return status;
}

<commit_msg> Phys DA , works on DAQ tst machine<commit_after>/*
T0 DA for online calibration

Contact: Michal.Oledzki@cern.ch
Link: http://users.jyu.fi/~mioledzk/
Run Type: PHYSICS
DA Type: MON
Number of events needed: 500000
Input Files: inPhys.dat, external parameters
Output Files: daPhys.root, to be exported to the DAQ FXS
Trigger types used: PHYSICS_EVENT
------------------------------Alla
Now trigger type changed to CALICRATION_EVENT
to have data during test.
SOULD BE CHANGED BACK BEFORE BEAM
------------------------------- Alla
*/

#define FILE_OUT "daPhys.root"
#define FILE_IN "inPhys.dat"
#include <daqDA.h>
#include <event.h>
#include <monitor.h>

#include <Riostream.h>
#include <stdio.h>
#include <stdlib.h>

//AliRoot
#include <AliRawReaderDate.h>
#include <AliRawReader.h>
#include <AliT0RawReader.h>

//ROOT
#include "TROOT.h"
#include "TPluginManager.h"
#include "TFile.h"
#include "TKey.h"
#include "TObject.h"
#include "TBenchmark.h"
#include "TString.h"
#include "TH1.h"
#include "TSpectrum.h"
#include "TMath.h"

/* Main routine
      Arguments:
      1- monitoring data source
*/
int main(int argc, char **argv) {
//int main(){
  int status;

  /* magic line */
  gROOT->GetPluginManager()->AddHandler("TVirtualStreamerInfo",
                                        "*",
                                        "TStreamerInfo",
                                        "RIO",
                                        "TStreamerInfo()");

  if(daqDA_DB_getFile(FILE_IN, FILE_IN)){
    printf("Couldn't get input file >>inPhys.dat<< from DAQ_DB !!!\n");
    return -1;
  }

  FILE *inp;
  char c;
  inp = fopen(FILE_IN, "r");
  if(!inp){
    printf("Input file >>inPhys.dat<< not found !!!\n");
    return -1;
  }
  int  kcbx, kt0bx, knpmtA, knpmtC;
  float kclx,kcmx, kt0lx, kt0hx;

  while((c=getc(inp))!=EOF) {
    switch(c) {
    case 'a': {fscanf(inp, "%d", &kcbx ); break;} //N of X bins hCFD1_CFD
    case 'b': {fscanf(inp, "%f", &kclx ); break;} //Low x hCFD1_CFD
    case 'c': {fscanf(inp, "%f", &kcmx ); break;} //High x hCFD1_CF
    case 'd': {fscanf(inp, "%d", &knpmtC ); break;} //number of reference PMTC
    case 'e': {fscanf(inp, "%d", &knpmtA ); break;} //number of reference PMTA
    case 'f': {fscanf(inp, "%d", &kt0bx ); break;} //N of X bins hT0
    case 'g': {fscanf(inp, "%f", &kt0lx ); break;} //Low x hT0
    case 'k': {fscanf(inp, "%f", &kt0hx ); break;} //High x hT0
    }
  }
  fclose(inp);

  if (argc!=2) {
    printf("Wrong number of arguments\n");
    return -1;
  }

  /* define data source : this is argument 1 */
  status=monitorSetDataSource( argv[1] );
  if (status!=0) {
    printf("monitorSetDataSource() failed : %s\n",monitorDecodeError(status));
    return -1;
  }

  /* declare monitoring program */
  status=monitorDeclareMp( __FILE__ );
  if (status!=0) {
    printf("monitorDeclareMp() failed : %s\n",monitorDecodeError(status));
    return -1;
  }

  /* define wait event timeout - 1s max */
  monitorSetNowait();
  monitorSetNoWaitNetworkTimeout(1000);

  /* log start of process */
  printf("T0 monitoring program started\n");

  // Allocation of histograms - start

  TH1F *hCFD1minCFD[24];
  TH1F *hCFD[24];

  for(Int_t ic=0; ic<24; ic++) {
    hCFD1minCFD[ic] = new TH1F(Form("CFD1minCFD%d",ic+1),"CFD-CFD",kcbx,kclx,kcmx);
    hCFD[ic] = new TH1F(Form("CFD%d",ic+1),"CFD",kt0bx,kt0lx,kt0hx);
  }
  TH1F *hVertex = new TH1F("hVertex","T0 time",kt0bx,kt0lx,kt0hx);

   // Allocation of histograms - end

  Int_t iev=0;
  /* main loop (infinite) */
  for(;;) {
    struct eventHeaderStruct *event;
    eventTypeType eventT;

    /* check shutdown condition */
    if (daqDA_checkShutdown()) {break;}

    /* get next event (blocking call until timeout) */
    status=monitorGetEventDynamic((void **)&event);
    if (status==(int)MON_ERR_EOF) {
      printf ("End of File detected\n");
      break; /* end of monitoring file has been reached */
    }

    if (status!=0) {
      printf("monitorGetEventDynamic() failed : %s\n",monitorDecodeError(status));
      break;
    }

    /* retry if got no event */
    if (event==NULL) {
      continue;
    }

    /* use event - here, just write event id to result file */
    eventT=event->eventType;

    switch (event->eventType){

    case START_OF_RUN:
      break;

    case END_OF_RUN:
      break;

    case PHYSICS_EVENT:
	  //    case CALIBRATION_EVENT:
      iev++;

      if(iev==1){
	printf("First event - %i\n",iev);
      }

      // Initalize raw-data reading and decoding
      AliRawReader *reader = new AliRawReaderDate((void*)event);

      // Enable the following two lines in case of real-data
      reader->RequireHeader(kTRUE);
      AliT0RawReader *start = new AliT0RawReader(reader, kTRUE);

      // Read raw data
      Int_t allData[110][5];
      for(Int_t i0=0;i0<107;i0++)
      	for(Int_t j0=0;j0<5;j0++)
	  allData[i0][j0] = 0;

      if(start->Next()){
	for (Int_t i=0; i<107; i++) {
	  for(Int_t iHit=0;iHit<5;iHit++){
	    allData[i][iHit]= start->GetData(i,iHit);
	  }
	}
      }

      // Fill the histograms
      Float_t besttimeA=9999999;
      Float_t besttimeC=9999999;
      Float_t time[24];
       Float_t meanShift[24];
       for (Int_t ik = 0; ik<24; ik++)
	 {
	   if(ik<12 && allData[ik+1][0]>0 && allData[knpmtC][0]>0 ){
	     hCFD1minCFD[ik]->Fill(allData[ik+1][0]-allData[knpmtC][0]);
	     if(allData[ik+1][0]>0 ) hCFD[ik]->Fill(allData[ik+1][0]);
	   }

	   if(ik>11 && allData[ik+45][0]>0 && allData[56+knpmtA][0]>0 )
	     {
	     hCFD1minCFD[ik]->Fill(allData[ik+45][0]-allData[56+knpmtA][0]);
	     if(allData[ik+1][0]>0 ) hCFD[ik]->Fill(allData[ik+45][0]);
	     }
	   if(iev == 10000) {
	     meanShift[ik] =  hCFD1minCFD[ik]->GetMean();
	     if(ik==knpmtC || ik==(56+knpmtA)) meanShift[ik]=0;
	   }
	 }
      //fill  mean time _ fast reconstruction
      if (iev > 10000 )
	{
	  for (Int_t in=0; in<12; in++)
	    {
	      time[in] = allData[in+1][0] - meanShift[in]  ;
	      time[in+12] = allData[in+56+1][0] ;
	    }
	  for (Int_t ipmt=0; ipmt<12; ipmt++){
	    if(time[ipmt] > 1 ) {
	      if(time[ipmt]<besttimeC)
		besttimeC=time[ipmt]; //timeC
	    }
	  }
	   for ( Int_t ipmt=12; ipmt<24; ipmt++){
	     if(time[ipmt] > 1) {
	       if(time[ipmt]<besttimeA)
		 besttimeA=time[ipmt]; //timeA
	     }
	   }
	   if(besttimeA<9999999 &&besttimeC< 9999999) {
	     Float_t t0 =0.001* 24.4 * Float_t( besttimeA+besttimeC)/2.;
	     hVertex->Fill(t0);
	   }
	}

     delete start;
     start = 0x0;
     delete reader;
     reader= 0x0;
      // End of fill histograms

    }

    /* free resources */
    free(event);

    /* exit when last event received, no need to wait for TERM signal */
    if (eventT==END_OF_RUN) {
      printf("EOR event detected\n");
      printf("Number of events processed - %i\n ",iev);
      break;
    }
  }
  printf("After loop, before writing histos\n");
  // write a file with the histograms

  TFile hist(FILE_OUT,"RECREATE");

  for(Int_t j=0;j<24;j++){
    hCFD1minCFD[j]->SetDirectory(&hist);
    hCFD1minCFD[j]->Write();
    hCFD[j]->Write();

  }
  hVertex->Write();
  hist.Close();
  //delete hist;

  status=0;

  /* export file to FXS */
  if (daqDA_FES_storeFile(FILE_OUT, "PHYSICS")) {
    status=-2;
  }

  return status;
}

<|endoftext|>