<commit_before>#include "TargetBigramFeature.h"
#include "InputFileStream.h"

namespace Moses {

using namespace std;

TargetBigramFeature::TargetBigramFeature(ScoreIndexManager &scoreIndexManager)
{
}

bool TargetBigramFeature::Load(const std::string &filePath)
{
  InputFileStream inFile(filePath);
  if (!inFile)
      return false;

  std::string line;
  while (getline(inFile, line)) {
      m_wordSet.insert(line);
  }

  inFile.Close();
}

//static size_t TargetBigramFeature::GetWordIndex(const std::string &word) const
//{
 // m_wordSet.find(word);
//}

size_t TargetBigramFeature::GetNumScoreComponents() const
{
	// TODO
	return 0;
}

string TargetBigramFeature::GetScoreProducerDescription() const
{
	// TODO
	return "";
}

string TargetBigramFeature::GetScoreProducerWeightShortName() const
{
	// TODO
	return "";
}

size_t TargetBigramFeature::GetNumInputScores() const
{
	// TODO
	return 0;
}

const FFState* TargetBigramFeature::EmptyHypothesisState(const InputType &input) const
{
	// TODO
	return 0;
}

FFState* TargetBigramFeature::Evaluate(const Hypothesis& cur_hypo,
                                       const FFState* prev_state,
                                       ScoreComponentCollection* accumulator) const
{
	// TODO
	return 0;
}

}
<commit_msg>Implemented simple methods in TargetBigramFeature.<commit_after>#include "TargetBigramFeature.h"
#include "InputFileStream.h"

namespace Moses {

using namespace std;

TargetBigramFeature::TargetBigramFeature(ScoreIndexManager &scoreIndexManager)
{
}

bool TargetBigramFeature::Load(const std::string &filePath)
{
  InputFileStream inFile(filePath);
  if (!inFile)
      return false;

  std::string line;
  while (getline(inFile, line)) {
      m_wordSet.insert(line);
  }

  inFile.Close();
}

//static size_t TargetBigramFeature::GetWordIndex(const std::string &word) const
//{
 // m_wordSet.find(word);
//}

size_t TargetBigramFeature::GetNumScoreComponents() const
{
	return m_wordSet.size() * m_wordSet.size();
}

string TargetBigramFeature::GetScoreProducerDescription() const
{
	return "TargetBigramFeature";
}

string TargetBigramFeature::GetScoreProducerWeightShortName() const
{
	return "tbf";
}

size_t TargetBigramFeature::GetNumInputScores() const
{
	return 0;
}

const FFState* TargetBigramFeature::EmptyHypothesisState(const InputType &input) const
{
	return NULL;
}

FFState* TargetBigramFeature::Evaluate(const Hypothesis& cur_hypo,
                                       const FFState* prev_state,
                                       ScoreComponentCollection* accumulator) const
{
	return NULL;
}

}
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>

#include <google/protobuf/util/json_util.h>

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

#include "interop_pb.pb.h"

using namespace std;

using namespace google::protobuf::util;

void usage(const char* argv0) {
    cerr << "usage: " << argv0 << " <subcommand>\n";
}

vector<char> read_stdin_to_end() {
    vector<char> r;
    size_t size = 0;
    for (;;) {
        r.resize(size * 2 + 100);
        auto re = read(STDIN_FILENO, r.data() + size, r.size() - size);
        if (re == 0) {
            r.resize(size);
            return r;
        }
        if (re < 0) {
            perror("read");
            _exit(1);
        }
        size += re;
    }
}

int main(int argc, const char** argv) {
    if (argc <= 1) {
        usage(argv[0]);
        _exit(1);
    }

    if (!strcmp(argv[1], "self-test")) {
        cerr << "interop OK\n";
        return 0;
    }

    if (!strcmp(argv[1], "json-encode")) {
        InteropMessageList m;

        auto parse_ok = m.ParseFromFileDescriptor(STDIN_FILENO);
        if (!parse_ok) {
            cerr << "failed to ParseFromFileDescriptor\n";
            _exit(21);
        }

        string json_output;
        auto json_ok = MessageToJsonString(m, &json_output);
        if (!json_ok.ok()) {
            cerr << "failed to MessageToJsonString\n";
            _exit(22);
        }

        cout << json_output << "\n";
        return 0;
    }

    if (!strcmp(argv[1], "json-decode")) {
        InteropMessageList m;

        auto json_text_vec = read_stdin_to_end();
        string json_text(json_text_vec.data(), json_text_vec.size());
        if (json_text.empty()) {
            cerr << "empty\n";
            _exit(31);
        }
        auto json_ok = JsonStringToMessage(json_text, &m);
        if (!json_ok.ok()) {
            cerr << "failed to JsonStringToMessage: " << json_ok.error_message() << "\n";
            _exit(32);
        }

        auto message_ok = m.SerializeToFileDescriptor(STDOUT_FILENO);
        if (!message_ok) {
            cerr << "failed to SerializeToFileDescriptor\n";
            _exit(33);
        }

        return 0;
    }

    usage(argv[0]);
    return 1;
}

// vim: set ts=4 sw=4 et:
<commit_msg>Trying to fix interop binary compilation<commit_after>#include <iostream>
#include <vector>

#include <google/protobuf/util/json_util.h>

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

#include "interop_pb.pb.h"

using namespace std;

using namespace google::protobuf::util;

void usage(const char* argv0) {
    cerr << "usage: " << argv0 << " <subcommand>\n";
}

vector<char> read_stdin_to_end() {
    vector<char> r;
    size_t size = 0;
    for (;;) {
        r.resize(size * 2 + 100);
        auto re = read(STDIN_FILENO, r.data() + size, r.size() - size);
        if (re == 0) {
            r.resize(size);
            return r;
        }
        if (re < 0) {
            perror("read");
            _exit(1);
        }
        size += re;
    }
}

int main(int argc, const char** argv) {
    if (argc <= 1) {
        usage(argv[0]);
        _exit(1);
    }

    if (!strcmp(argv[1], "self-test")) {
        cerr << "interop OK\n";
        return 0;
    }

    if (!strcmp(argv[1], "json-encode")) {
        InteropMessageList m;

        auto parse_ok = m.ParseFromFileDescriptor(STDIN_FILENO);
        if (!parse_ok) {
            cerr << "failed to ParseFromFileDescriptor\n";
            _exit(21);
        }

        string json_output;
        auto json_ok = MessageToJsonString(m, &json_output);
        if (!json_ok.ok()) {
            cerr << "failed to MessageToJsonString\n";
            _exit(22);
        }

        cout << json_output << "\n";
        return 0;
    }

    if (!strcmp(argv[1], "json-decode")) {
        InteropMessageList m;

        auto json_text_vec = read_stdin_to_end();
        string json_text(json_text_vec.data(), json_text_vec.size());
        if (json_text.empty()) {
            cerr << "empty\n";
            _exit(31);
        }
        auto json_ok = JsonStringToMessage(json_text, &m);
        if (!json_ok.ok()) {
            cerr << "failed to JsonStringToMessage: " << json_ok.message() << "\n";
            _exit(32);
        }

        auto message_ok = m.SerializeToFileDescriptor(STDOUT_FILENO);
        if (!message_ok) {
            cerr << "failed to SerializeToFileDescriptor\n";
            _exit(33);
        }

        return 0;
    }

    usage(argv[0]);
    return 1;
}

// vim: set ts=4 sw=4 et:
<|endoftext|>


<commit_before>#pragma once

#include <string>
#include <sys/stat.h>

class filesystem final {
public:
  static bool is_directory(const std::string& path) {
    struct stat s;
    if (stat(path.c_str(), &s) == 0) {
      return S_ISDIR(s.st_mode);
    }
    return false;
  }
};
<commit_msg>add filesystem::realpath<commit_after>#pragma once

#include <string>
#include <sys/stat.h>

class filesystem final {
public:
  static bool is_directory(const std::string& path) {
    struct stat s;
    if (stat(path.c_str(), &s) == 0) {
      return S_ISDIR(s.st_mode);
    }
    return false;
  }

  static std::string realpath(const std::string& path) {
    std::string result;
    if (auto p = ::realpath(path.c_str(), nullptr)) {
      result = p;
      free(p);
    }
    return result;
  }
};
<|endoftext|>


<commit_before>//=================================================================================================
/*!
//  \file src/util/logging/FunctionTrace.cpp
//  \brief Source file for the FunctionTrace class
//
//  Copyright (C) 2011 Klaus Iglberger - All Rights Reserved
//
//  This file is part of the Blaze library. This library is free software; you can redistribute
//  it and/or modify it under the terms of the GNU General Public License as published by the
//  Free Software Foundation; either version 3, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
//  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//  See the GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License along with a special
//  exception for linking and compiling against the Blaze library, the so-called "runtime
//  exception"; see the file COPYING. If not, see http://www.gnu.org/licenses/.
*/
//=================================================================================================

//*************************************************************************************************
// Platform/compiler-specific includes
//*************************************************************************************************

#include <blaze/system/WarningDisable.h>

//*************************************************************************************************
// Includes
//*************************************************************************************************

#include <sstream>
#include <boost/format.hpp>
#include <blaze/util/logging/FunctionTrace.h>
#include <blaze/util/logging/Logger.h>
#include <blaze/util/SystemClock.h>

namespace blaze {

namespace logging {

//=================================================================================================
//
//  CONSTRUCTORS
//
//=================================================================================================

//*************************************************************************************************
/*!\brief Constructor for the FunctionTrace class.
//
// \param level The level of the log section.
*/
FunctionTrace::FunctionTrace( const std::string& file, const std::string& function )
   : file_    ( file     )  // The file name the traced function is contained in
   , function_( function )  // The name of the traced function
{
   // Writing the trace information
   std::ostringstream oss;
   oss << "[TRACE   ]";

   // Writing the elapsed time
   const time_t elapsed( theSystemClock()->elapsed() );
   const time_t hours  ( elapsed / time_t( 3600 ) );
   const time_t minutes( ( elapsed % time_t( 3600 ) ) / time_t( 60 ) );
   const time_t seconds( elapsed % time_t( 60 ) );
   oss << boost::format( "[%03d:%02d:%02d]" ) % hours % minutes % seconds;

   // Writing the message string
   oss << " + Entering function '" << function_ << "' in file '" << file_ << "'\n";

   // Logging the message string
   boost::shared_ptr<Logger> logger( Logger::instance() );
   logger->log( oss.str() );
}
//*************************************************************************************************

//=================================================================================================
//
//  DESTRUCTOR
//
//=================================================================================================

//*************************************************************************************************
/*!\brief Destructor for the FunctionTrace class.
*/
FunctionTrace::~FunctionTrace()
{
   // Writing the trace information
   std::ostringstream oss;
   oss << "[TRACE   ]";

   // Writing the elapsed time
   const time_t elapsed( theSystemClock()->elapsed() );
   const time_t hours  ( elapsed / time_t( 3600 ) );
   const time_t minutes( ( elapsed % time_t( 3600 ) ) / time_t( 60 ) );
   const time_t seconds( elapsed % time_t( 60 ) );
   oss << boost::format( "[%03d:%02d:%02d]" ) % hours % minutes % seconds;

   // Writing the message string
   oss << " - Leaving function '" << function_ << "' in file '" << file_ << "'\n";

   // Logging the message string
   boost::shared_ptr<Logger> logger( Logger::instance() );
   logger->log( oss.str() );
}
//*************************************************************************************************

} // namespace logging

} // namespace blaze
<commit_msg>Fix the doxygen documentation of the 'FunctionTrace' constructor<commit_after>//=================================================================================================
/*!
//  \file src/util/logging/FunctionTrace.cpp
//  \brief Source file for the FunctionTrace class
//
//  Copyright (C) 2011 Klaus Iglberger - All Rights Reserved
//
//  This file is part of the Blaze library. This library is free software; you can redistribute
//  it and/or modify it under the terms of the GNU General Public License as published by the
//  Free Software Foundation; either version 3, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
//  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//  See the GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License along with a special
//  exception for linking and compiling against the Blaze library, the so-called "runtime
//  exception"; see the file COPYING. If not, see http://www.gnu.org/licenses/.
*/
//=================================================================================================

//*************************************************************************************************
// Platform/compiler-specific includes
//*************************************************************************************************

#include <blaze/system/WarningDisable.h>

//*************************************************************************************************
// Includes
//*************************************************************************************************

#include <sstream>
#include <boost/format.hpp>
#include <blaze/util/logging/FunctionTrace.h>
#include <blaze/util/logging/Logger.h>
#include <blaze/util/SystemClock.h>

namespace blaze {

namespace logging {

//=================================================================================================
//
//  CONSTRUCTORS
//
//=================================================================================================

//*************************************************************************************************
/*!\brief Constructor for the FunctionTrace class.
//
// \param file The name of the file the traced function is contained in
// \param function The name of the traced function
*/
FunctionTrace::FunctionTrace( const std::string& file, const std::string& function )
   : file_    ( file     )  // The file name the traced function is contained in
   , function_( function )  // The name of the traced function
{
   // Writing the trace information
   std::ostringstream oss;
   oss << "[TRACE   ]";

   // Writing the elapsed time
   const time_t elapsed( theSystemClock()->elapsed() );
   const time_t hours  ( elapsed / time_t( 3600 ) );
   const time_t minutes( ( elapsed % time_t( 3600 ) ) / time_t( 60 ) );
   const time_t seconds( elapsed % time_t( 60 ) );
   oss << boost::format( "[%03d:%02d:%02d]" ) % hours % minutes % seconds;

   // Writing the message string
   oss << " + Entering function '" << function_ << "' in file '" << file_ << "'\n";

   // Logging the message string
   boost::shared_ptr<Logger> logger( Logger::instance() );
   logger->log( oss.str() );
}
//*************************************************************************************************

//=================================================================================================
//
//  DESTRUCTOR
//
//=================================================================================================

//*************************************************************************************************
/*!\brief Destructor for the FunctionTrace class.
*/
FunctionTrace::~FunctionTrace()
{
   // Writing the trace information
   std::ostringstream oss;
   oss << "[TRACE   ]";

   // Writing the elapsed time
   const time_t elapsed( theSystemClock()->elapsed() );
   const time_t hours  ( elapsed / time_t( 3600 ) );
   const time_t minutes( ( elapsed % time_t( 3600 ) ) / time_t( 60 ) );
   const time_t seconds( elapsed % time_t( 60 ) );
   oss << boost::format( "[%03d:%02d:%02d]" ) % hours % minutes % seconds;

   // Writing the message string
   oss << " - Leaving function '" << function_ << "' in file '" << file_ << "'\n";

   // Logging the message string
   boost::shared_ptr<Logger> logger( Logger::instance() );
   logger->log( oss.str() );
}
//*************************************************************************************************

} // namespace logging

} // namespace blaze
<|endoftext|>


<commit_before>/*
 *  alarmlistview.cpp  -  widget showing list of alarms
 *  Program:  kalarm
 *  Copyright © 2007 by David Jarvie <software@astrojar.org.uk>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include "kalarm.h"

#include <QHeaderView>
#include <QMouseEvent>
#include <QApplication>

#include "eventlistmodel.h"
#include "alarmlistfiltermodel.h"
#include "alarmlistview.moc"

AlarmListView::AlarmListView(QWidget* parent)
	: EventListView(parent)
{
}

void AlarmListView::setModel(QAbstractItemModel* model)
{
	EventListView::setModel(model);
	header()->setMovable(true);
	header()->setStretchLastSection(false);
	header()->setResizeMode(EventListModel::TimeColumn, QHeaderView::ResizeToContents);
	header()->setResizeMode(EventListModel::TimeToColumn, QHeaderView::ResizeToContents);
	header()->setResizeMode(EventListModel::RepeatColumn, QHeaderView::ResizeToContents);
	header()->setResizeMode(EventListModel::ColourColumn, QHeaderView::Fixed);
	header()->setResizeMode(EventListModel::TypeColumn, QHeaderView::Fixed);
	header()->setResizeMode(EventListModel::TextColumn, QHeaderView::Stretch);
	const int margin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin);
	header()->resizeSection(EventListModel::ColourColumn, viewOptions().fontMetrics.lineSpacing() * 3 / 4);
	header()->resizeSection(EventListModel::TypeColumn, EventListModel::iconWidth() + 2*margin + 2);
#warning Time column shrinks when Show Archived Alarms is selected
}

void AlarmListView::setColumnOrder(const QList<int>& order)
{
	// Set the column order
	if (order.count() >= AlarmListFilterModel::ColumnCount)
	{
		// The column order is specified
		int posn[AlarmListFilterModel::ColumnCount];
		int i;
		for (i = 0;  i < AlarmListFilterModel::ColumnCount;  ++i)
			posn[i] = -1;
		for (i = 0;  i < AlarmListFilterModel::ColumnCount;  ++i)
		{
			int ord = order[i];
			if (ord < AlarmListFilterModel::ColumnCount  &&  ord >= 0)
				posn[i] = ord;
		}
		bool ok = true;
		for (i = 0;  i < AlarmListFilterModel::ColumnCount;  ++i)
			if (posn[i] < 0)
				ok = false;    // no column is specified at this position
		if (ok  &&  posn[EventListModel::TextColumn] != EventListModel::TextColumn)
		{
			// Shift the message column to be last, since otherwise
			// column widths get screwed up.
			int messageCol = posn[EventListModel::TextColumn];
			for (i = 0;  i < AlarmListFilterModel::ColumnCount;  ++i)
				if (posn[i] > messageCol)
					--posn[i];
			posn[EventListModel::TextColumn] = EventListModel::TextColumn;
		}
		if (ok)
		{
			// Check whether the columns need to be reordered
			for (i = 0;  i < AlarmListFilterModel::ColumnCount;  ++i)
				if (posn[i] != i)
				{
					ok = false;
					break;
				}
			if (!ok)
			{
				// Reorder the columns
				for (i = 0;  i < AlarmListFilterModel::ColumnCount;  ++i)
				{
#warning Reorder the columns
			//		int j = posn.indexOf(i);
			//		moveSection(j, i);
				}
			}
		}
	}
}

/******************************************************************************
* Return the column order.
*/
QList<int> AlarmListView::columnOrder() const
{
	int order[AlarmListFilterModel::ColumnCount];
	QHeaderView* head = header();
	order[EventListModel::TimeColumn]   = head->visualIndex(EventListModel::TimeColumn);
	order[EventListModel::TimeToColumn] = head->visualIndex(EventListModel::TimeToColumn);
	order[EventListModel::RepeatColumn] = head->visualIndex(EventListModel::RepeatColumn);
	order[EventListModel::ColourColumn] = head->visualIndex(EventListModel::ColourColumn);
	order[EventListModel::TypeColumn]   = head->visualIndex(EventListModel::TypeColumn);
	order[EventListModel::TextColumn]   = head->visualIndex(EventListModel::TextColumn);
	QList<int> orderList;
	for (int i = 0;  i < AlarmListFilterModel::ColumnCount;  ++i)
		orderList += order[i];
	return orderList;
}

/******************************************************************************
* Set which time columns are to be displayed.
*/
void AlarmListView::selectTimeColumns(bool time, bool timeTo)
{
	if (!time  &&  !timeTo)
		return;       // always show at least one time column
//	bool changed = false;
	bool hidden = header()->isSectionHidden(EventListModel::TimeColumn);
	if (time  &&  hidden)
	{
		// Unhide the time column
		header()->setSectionHidden(EventListModel::TimeColumn, false);
//		changed = true;
	}
	else if (!time  &&  !hidden)
	{
		// Hide the time column
		header()->setSectionHidden(EventListModel::TimeColumn, true);
//		changed = true;
	}
	hidden = header()->isSectionHidden(EventListModel::TimeToColumn);
	if (timeTo  &&  hidden)
	{
		// Unhide the time-to-alarm column
		header()->setSectionHidden(EventListModel::TimeToColumn, false);
//		changed = true;
	}
	else if (!timeTo  &&  !hidden)
	{
		// Hide the time-to-alarm column
		header()->setSectionHidden(EventListModel::TimeToColumn, true);
//		changed = true;
	}
//	if (changed)
//	{
//		resizeLastColumn();
//		triggerUpdate();   // ensure scroll bar appears if needed
//	}
}

void AlarmListView::dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
{
/*	for (int col = topLeft.column();  col < bottomRight.column();  ++col)
	{
		if (col != header()->resizeMode(col) == QHeaderView::ResizeToContents)
			resizeColumnToContents(col);
	}*/
}
<commit_msg>Make column sizing work<commit_after>/*
 *  alarmlistview.cpp  -  widget showing list of alarms
 *  Program:  kalarm
 *  Copyright © 2007 by David Jarvie <software@astrojar.org.uk>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include "kalarm.h"

#include <QHeaderView>
#include <QMouseEvent>
#include <QApplication>

#include "eventlistmodel.h"
#include "alarmlistfiltermodel.h"
#include "alarmlistview.moc"

AlarmListView::AlarmListView(QWidget* parent)
	: EventListView(parent)
{
}

void AlarmListView::setModel(QAbstractItemModel* model)
{
	EventListView::setModel(model);
	header()->setMovable(true);
	header()->setStretchLastSection(false);
	header()->setResizeMode(EventListModel::TimeColumn, QHeaderView::ResizeToContents);
	header()->setResizeMode(EventListModel::TimeToColumn, QHeaderView::ResizeToContents);
	header()->setResizeMode(EventListModel::RepeatColumn, QHeaderView::ResizeToContents);
	header()->setResizeMode(EventListModel::ColourColumn, QHeaderView::Fixed);
	header()->setResizeMode(EventListModel::TypeColumn, QHeaderView::Fixed);
	header()->setResizeMode(EventListModel::TextColumn, QHeaderView::Stretch);
	header()->setStretchLastSection(true);   // necessary to ensure ResizeToContents columns do resize to contents!
	const int margin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin);
	header()->resizeSection(EventListModel::ColourColumn, viewOptions().fontMetrics.lineSpacing() * 3 / 4);
	header()->resizeSection(EventListModel::TypeColumn, EventListModel::iconWidth() + 2*margin + 2);
}

void AlarmListView::setColumnOrder(const QList<int>& order)
{
	// Set the column order
	if (order.count() >= AlarmListFilterModel::ColumnCount)
	{
		// The column order is specified
		int posn[AlarmListFilterModel::ColumnCount];
		int i;
		for (i = 0;  i < AlarmListFilterModel::ColumnCount;  ++i)
			posn[i] = -1;
		for (i = 0;  i < AlarmListFilterModel::ColumnCount;  ++i)
		{
			int ord = order[i];
			if (ord < AlarmListFilterModel::ColumnCount  &&  ord >= 0)
				posn[i] = ord;
		}
		bool ok = true;
		for (i = 0;  i < AlarmListFilterModel::ColumnCount;  ++i)
			if (posn[i] < 0)
				ok = false;    // no column is specified at this position
		if (ok  &&  posn[EventListModel::TextColumn] != EventListModel::TextColumn)
		{
			// Shift the message column to be last, since otherwise
			// column widths get screwed up.
			int messageCol = posn[EventListModel::TextColumn];
			for (i = 0;  i < AlarmListFilterModel::ColumnCount;  ++i)
				if (posn[i] > messageCol)
					--posn[i];
			posn[EventListModel::TextColumn] = EventListModel::TextColumn;
		}
		if (ok)
		{
			// Check whether the columns need to be reordered
			for (i = 0;  i < AlarmListFilterModel::ColumnCount;  ++i)
				if (posn[i] != i)
				{
					ok = false;
					break;
				}
			if (!ok)
			{
				// Reorder the columns
				for (i = 0;  i < AlarmListFilterModel::ColumnCount;  ++i)
				{
#warning Reorder the columns
			//		int j = posn.indexOf(i);
			//		moveSection(j, i);
				}
			}
		}
	}
}

/******************************************************************************
* Return the column order.
*/
QList<int> AlarmListView::columnOrder() const
{
	int order[AlarmListFilterModel::ColumnCount];
	QHeaderView* head = header();
	order[EventListModel::TimeColumn]   = head->visualIndex(EventListModel::TimeColumn);
	order[EventListModel::TimeToColumn] = head->visualIndex(EventListModel::TimeToColumn);
	order[EventListModel::RepeatColumn] = head->visualIndex(EventListModel::RepeatColumn);
	order[EventListModel::ColourColumn] = head->visualIndex(EventListModel::ColourColumn);
	order[EventListModel::TypeColumn]   = head->visualIndex(EventListModel::TypeColumn);
	order[EventListModel::TextColumn]   = head->visualIndex(EventListModel::TextColumn);
	QList<int> orderList;
	for (int i = 0;  i < AlarmListFilterModel::ColumnCount;  ++i)
		orderList += order[i];
	return orderList;
}

/******************************************************************************
* Set which time columns are to be displayed.
*/
void AlarmListView::selectTimeColumns(bool time, bool timeTo)
{
	if (!time  &&  !timeTo)
		return;       // always show at least one time column
//	bool changed = false;
	bool hidden = header()->isSectionHidden(EventListModel::TimeColumn);
	if (time  &&  hidden)
	{
		// Unhide the time column
		header()->setSectionHidden(EventListModel::TimeColumn, false);
//		changed = true;
	}
	else if (!time  &&  !hidden)
	{
		// Hide the time column
		header()->setSectionHidden(EventListModel::TimeColumn, true);
//		changed = true;
	}
	hidden = header()->isSectionHidden(EventListModel::TimeToColumn);
	if (timeTo  &&  hidden)
	{
		// Unhide the time-to-alarm column
		header()->setSectionHidden(EventListModel::TimeToColumn, false);
//		changed = true;
	}
	else if (!timeTo  &&  !hidden)
	{
		// Hide the time-to-alarm column
		header()->setSectionHidden(EventListModel::TimeToColumn, true);
//		changed = true;
	}
//	if (changed)
//	{
//		resizeLastColumn();
//		triggerUpdate();   // ensure scroll bar appears if needed
//	}
}

void AlarmListView::dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
{
/*	for (int col = topLeft.column();  col < bottomRight.column();  ++col)
	{
		if (col != header()->resizeMode(col) == QHeaderView::ResizeToContents)
			resizeColumnToContents(col);
	}*/
}
<|endoftext|>


<commit_before>#include "Bingot.h"
#include <cryptlib.h>
#include <osrng.h>
#include <eccrypto.h>
#include <oids.h>
#include <QDebug>

#include <QCryptographicHash>

const unsigned int protocol_version = 1;

Bingot::Bingot(QObject *parent) :
    QObject(parent),
    m_candidateBlock(0),
    m_networkEngine()
{
}

void Bingot::initialize()
{
    m_networkEngine = new NetworkEngine();
    m_networkEngine->listen(QHostAddress::Any, 42231);
    generateECDSAKeyPair();
    generateWalletAddress();
}

void Bingot::generateECDSAKeyPair()
{
    CryptoPP::AutoSeededRandomPool autoSeededRandomPool;

    CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256>::PrivateKey privateKey;

    privateKey.Initialize(autoSeededRandomPool, CryptoPP::ASN1::secp160r1());

    bool result = privateKey.Validate( autoSeededRandomPool, 3 );
    if( !result )
    {
        qDebug() << "private key is not valid!";
        return;
    }

    const CryptoPP::Integer &privateKeyInteger = privateKey.GetPrivateExponent();

    QByteArray privateKeyByteArray((int)privateKeyInteger.ByteCount(), 0);
    privateKeyInteger.Encode((byte*)privateKeyByteArray.data(), privateKeyInteger.ByteCount());
    m_privateKey = privateKeyByteArray;

    qDebug() << "private key:" << m_privateKey.size() << m_privateKey.toHex();
    // Generating matching public key
    CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256>::PublicKey publicKey;
    privateKey.MakePublicKey(publicKey);

    result = publicKey.Validate( autoSeededRandomPool, 3 );
    if( !result )
    {
        qDebug() << "public key is not valid!";
        return;
    }

    const CryptoPP::ECP::Point& point = publicKey.GetPublicElement();

    QByteArray publicKeyXByteArray((int)point.x.ByteCount(), 0);
    point.x.Encode((byte*)publicKeyXByteArray.data(), point.x.ByteCount());

    QByteArray publicKeyYByteArray((int)point.y.ByteCount(), 0);
    point.y.Encode((byte*)publicKeyYByteArray.data(), point.y.ByteCount());

    m_publicKey.clear();
    m_publicKey.append(publicKeyXByteArray);
    m_publicKey.append(publicKeyYByteArray);

    qDebug() << "public key:" << m_publicKey.size() << m_publicKey.toHex();
}

void Bingot::generateWalletAddress()
{
    QCryptographicHash hasher1(QCryptographicHash::Sha3_512);

    hasher1.addData(m_publicKey);

    QByteArray a1 = hasher1.result();
    a1.prepend((const char*)&protocol_version, sizeof(protocol_version));

    qDebug() << "hash result:" << a1.toHex();

    QCryptographicHash hasher2(QCryptographicHash::Sha256);

    hasher2.addData(a1);
    QByteArray a2 = hasher2.result();

    qDebug() << "hash result:" << a2.toHex();

    QCryptographicHash hasher3(QCryptographicHash::Sha3_256);

    hasher3.addData(a2);

    QByteArray a3 = hasher3.result();

    qDebug() << "cehcksum:" << a3.toHex();

    a1.append(a3.mid(0,4));

    qDebug() << "with checksum" << a1.toHex();

    m_address = a1.toBase64();
    qDebug() << "final address" << m_address;
}

void Bingot::Transfer(const QByteArray &toAddress, unsigned int amount)
{
    if (toAddress == m_address)
    {
        return;
    }

    int total = m_blockChain.getAccountAmount(m_address);

    foreach(const Transaction &t, m_suggestedTransactions)
    {
        if ((t.getType() != Transaction::REWARD) && (t.getFromAddress() == m_address))
        {
            total -= t.getAmount();
        }
    }

    const QHash<QByteArray, Transaction> &candidateTransactions = m_candidateBlock.getTransactions();

    for(QHash<QByteArray, Transaction>::const_iterator iter = candidateTransactions.begin(); iter != candidateTransactions.end(); ++iter)
    {
        if ((iter->getType() != Transaction::REWARD && (iter->getFromAddress() == m_address)))
        {
            total -= iter->getAmount();
        }
    }

    if (amount <= total)
    {
        Transaction t(address(), toAddress, amount);
        t.signTransaction(privateKey(), publicKey());
        m_suggestedTransactions.insert(t.getSignature(), t);
        m_networkEngine->sendMessage(t.getMessageJson());
    }
}

void Bingot::startNewMiningRound()
{
    Block newCandidateBlock(m_blockChain.size(), m_suggestedTransactions, m_blockChain.getLastBlockHash());

    m_candidateBlock = newCandidateBlock;
    m_candidateBlock.addTransaction(Transaction(address()));

    m_suggestedTransactions.clear();

    const unsigned int workerThreadCount = QThread::idealThreadCount();

    quint64 value = Q_UINT64_C(932838457459459);
    quint64 chunk = value/workerThreadCount;

    foreach(Miner *miner, m_miners)
    {
        miner->quit(); //is this enough to stop miner?
        miner->deleteLater();
    }

    for(unsigned int i = 0; i < workerThreadCount; ++i)
    {
        Miner *miner = new Miner(m_candidateBlock, chunk*i, chunk*(1+i));
        miner->moveToThread(miner);
        m_miners.push_back(miner);
        miner->start();
    }
}

void Bingot::newBlockReceived(Block b)
{
    if (b.isValid())
    {
        if (b.getIndex() == m_blockChain.size())
        {
           if( m_blockChain.add(b))
           {
                //recycle m_candidateBlock to m_suggestedTransactions;
               const QHash<QByteArray, Transaction> &transactions = m_candidateBlock.getTransactions();

                for(QHash<QByteArray, Transaction>::const_iterator t = transactions.begin(); t != transactions.end(); ++t)
                {
                    m_suggestedTransactions.insert(t.key(), t.value());
                }

                //remove m_suggestedTransactions that are in blockChain already

                QVector<Transaction> keepTransactions;

                foreach(Transaction &t, m_suggestedTransactions)
                {
                    unsigned int total = 0;
                    BlockChain::TransactionState ts = m_blockChain.getTransactionState(t, total);

                    if (ts == BlockChain::VALID)
                    {
                        foreach(const Transaction &tr, m_suggestedTransactions)
                        {
                            if ((tr.getType() != Transaction::REWARD) && (tr.getFromAddress() == m_address))
                            {
                                total -= tr.getAmount();
                            }
                        }

                        const QHash<QByteArray, Transaction> &candidateTransactions = m_candidateBlock.getTransactions();

                        for(QHash<QByteArray, Transaction>::const_iterator iter = candidateTransactions.begin(); iter != candidateTransactions.end(); ++iter)
                        {
                            if ((iter->getType() != Transaction::REWARD && (iter->getFromAddress() == m_address)))
                            {
                                total -= iter->getAmount();
                            }
                        }

                        if (total > t.getAmount())
                        {
                            //accept;
                            keepTransactions.push_back(t);
                        }

                    }
                }

                m_suggestedTransactions.clear();

                foreach(Transaction t, keepTransactions)
                {
                   m_suggestedTransactions.insert(t.getSignature(), t);
                }

                startNewMiningRound();
           }

        }
        else if(b.getIndex() < m_blockChain.size())
        {
            m_blockChain.add(b);
        }
        else if(b.getIndex() > m_blockChain.size())
        {
            //ask for blocks
        }
    }
}

void Bingot::newBlockSolved(Block b)
{
    if(m_blockChain.add(b))
    {
        m_networkEngine->sendMessage(b.toMessageJson());
    }
}

void Bingot::onNewTransaction(Transaction t)
{
    if (t.getType() == Transaction::REWARD)
    {
        return; //reward transaction can only be part of solved block.
    }

    if (t.getToAddress() == t.getFromAddress())
    {
        return; //can't self transfer;
    }

    if (!t.verifySignature())
    {
        return;
    }

    //check transaction uniqueness,
    unsigned int total = 0;
    BlockChain::TransactionState ts = m_blockChain.getTransactionState(t, total);

    if (ts == BlockChain::EXISITING || ts == BlockChain::NOT_ENOUGH_MONEY)
    {
        return;
    }

    if (ts == BlockChain::VALID)
    {
        foreach(const Transaction &tr, m_suggestedTransactions)
        {
            if (tr.getSignature() == t.getSignature())
            {
                return;
            }
            if ((tr.getType() != Transaction::REWARD) && (tr.getFromAddress() == m_address))
            {
                total -= tr.getAmount();
            }
        }

        const QHash<QByteArray, Transaction> &candidateTransactions = m_candidateBlock.getTransactions();

        for(QHash<QByteArray, Transaction>::const_iterator iter = candidateTransactions.begin(); iter != candidateTransactions.end(); ++iter)
        {
            if (iter->getSignature() == t.getSignature())
            {
                return;
            }
            if ((iter->getType() != Transaction::REWARD && (iter->getFromAddress() == m_address)))
            {
                total -= iter->getAmount();
            }
        }

        if (total > t.getAmount())
        {
            //accept;
            m_suggestedTransactions.insert(t.getSignature(), t);
            //need to figure out a way to avoid sending this message to where it is from
            m_networkEngine->sendMessage(t.getMessageJson());
        }

    }
}

void Bingot::queryForBlock(int index)
{

}
<commit_msg>update todo list<commit_after>#include "Bingot.h"
#include <cryptlib.h>
#include <osrng.h>
#include <eccrypto.h>
#include <oids.h>
#include <QDebug>

#include <QCryptographicHash>

//large integer
//count binary 0 instead of hex 0
//parse receive block
//request block
//verify thread can stop
//ui

const unsigned int protocol_version = 1;

Bingot::Bingot(QObject *parent) :
    QObject(parent),
    m_candidateBlock(0),
    m_networkEngine()
{
}

void Bingot::initialize()
{
    m_networkEngine = new NetworkEngine();
    m_networkEngine->listen(QHostAddress::Any, 42231);
    generateECDSAKeyPair();
    generateWalletAddress();
}

void Bingot::generateECDSAKeyPair()
{
    CryptoPP::AutoSeededRandomPool autoSeededRandomPool;

    CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256>::PrivateKey privateKey;

    privateKey.Initialize(autoSeededRandomPool, CryptoPP::ASN1::secp160r1());

    bool result = privateKey.Validate( autoSeededRandomPool, 3 );
    if( !result )
    {
        qDebug() << "private key is not valid!";
        return;
    }

    const CryptoPP::Integer &privateKeyInteger = privateKey.GetPrivateExponent();

    QByteArray privateKeyByteArray((int)privateKeyInteger.ByteCount(), 0);
    privateKeyInteger.Encode((byte*)privateKeyByteArray.data(), privateKeyInteger.ByteCount());
    m_privateKey = privateKeyByteArray;

    qDebug() << "private key:" << m_privateKey.size() << m_privateKey.toHex();
    // Generating matching public key
    CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256>::PublicKey publicKey;
    privateKey.MakePublicKey(publicKey);

    result = publicKey.Validate( autoSeededRandomPool, 3 );
    if( !result )
    {
        qDebug() << "public key is not valid!";
        return;
    }

    const CryptoPP::ECP::Point& point = publicKey.GetPublicElement();

    QByteArray publicKeyXByteArray((int)point.x.ByteCount(), 0);
    point.x.Encode((byte*)publicKeyXByteArray.data(), point.x.ByteCount());

    QByteArray publicKeyYByteArray((int)point.y.ByteCount(), 0);
    point.y.Encode((byte*)publicKeyYByteArray.data(), point.y.ByteCount());

    m_publicKey.clear();
    m_publicKey.append(publicKeyXByteArray);
    m_publicKey.append(publicKeyYByteArray);

    qDebug() << "public key:" << m_publicKey.size() << m_publicKey.toHex();
}

void Bingot::generateWalletAddress()
{
    QCryptographicHash hasher1(QCryptographicHash::Sha3_512);

    hasher1.addData(m_publicKey);

    QByteArray a1 = hasher1.result();
    a1.prepend((const char*)&protocol_version, sizeof(protocol_version));

    qDebug() << "hash result:" << a1.toHex();

    QCryptographicHash hasher2(QCryptographicHash::Sha256);

    hasher2.addData(a1);
    QByteArray a2 = hasher2.result();

    qDebug() << "hash result:" << a2.toHex();

    QCryptographicHash hasher3(QCryptographicHash::Sha3_256);

    hasher3.addData(a2);

    QByteArray a3 = hasher3.result();

    qDebug() << "cehcksum:" << a3.toHex();

    a1.append(a3.mid(0,4));

    qDebug() << "with checksum" << a1.toHex();

    m_address = a1.toBase64();
    qDebug() << "final address" << m_address;
}

void Bingot::Transfer(const QByteArray &toAddress, unsigned int amount)
{
    if (toAddress == m_address)
    {
        return;
    }

    int total = m_blockChain.getAccountAmount(m_address);

    foreach(const Transaction &t, m_suggestedTransactions)
    {
        if ((t.getType() != Transaction::REWARD) && (t.getFromAddress() == m_address))
        {
            total -= t.getAmount();
        }
    }

    const QHash<QByteArray, Transaction> &candidateTransactions = m_candidateBlock.getTransactions();

    for(QHash<QByteArray, Transaction>::const_iterator iter = candidateTransactions.begin(); iter != candidateTransactions.end(); ++iter)
    {
        if ((iter->getType() != Transaction::REWARD && (iter->getFromAddress() == m_address)))
        {
            total -= iter->getAmount();
        }
    }

    if (amount <= total)
    {
        Transaction t(address(), toAddress, amount);
        t.signTransaction(privateKey(), publicKey());
        m_suggestedTransactions.insert(t.getSignature(), t);
        m_networkEngine->sendMessage(t.getMessageJson());
    }
}

void Bingot::startNewMiningRound()
{
    Block newCandidateBlock(m_blockChain.size(), m_suggestedTransactions, m_blockChain.getLastBlockHash());

    m_candidateBlock = newCandidateBlock;
    m_candidateBlock.addTransaction(Transaction(address()));

    m_suggestedTransactions.clear();

    const unsigned int workerThreadCount = QThread::idealThreadCount();

    quint64 value = Q_UINT64_C(932838457459459);
    quint64 chunk = value/workerThreadCount;

    foreach(Miner *miner, m_miners)
    {
        miner->quit(); //is this enough to stop miner?
        miner->deleteLater();
    }

    for(unsigned int i = 0; i < workerThreadCount; ++i)
    {
        Miner *miner = new Miner(m_candidateBlock, chunk*i, chunk*(1+i));
        miner->moveToThread(miner);
        m_miners.push_back(miner);
        miner->start();
    }
}

void Bingot::newBlockReceived(Block b)
{
    if (b.isValid())
    {
        if (b.getIndex() == m_blockChain.size())
        {
           if( m_blockChain.add(b))
           {
                //recycle m_candidateBlock to m_suggestedTransactions;
               const QHash<QByteArray, Transaction> &transactions = m_candidateBlock.getTransactions();

                for(QHash<QByteArray, Transaction>::const_iterator t = transactions.begin(); t != transactions.end(); ++t)
                {
                    m_suggestedTransactions.insert(t.key(), t.value());
                }

                //remove m_suggestedTransactions that are in blockChain already

                QVector<Transaction> keepTransactions;

                foreach(Transaction &t, m_suggestedTransactions)
                {
                    unsigned int total = 0;
                    BlockChain::TransactionState ts = m_blockChain.getTransactionState(t, total);

                    if (ts == BlockChain::VALID)
                    {
                        foreach(const Transaction &tr, m_suggestedTransactions)
                        {
                            if ((tr.getType() != Transaction::REWARD) && (tr.getFromAddress() == m_address))
                            {
                                total -= tr.getAmount();
                            }
                        }

                        const QHash<QByteArray, Transaction> &candidateTransactions = m_candidateBlock.getTransactions();

                        for(QHash<QByteArray, Transaction>::const_iterator iter = candidateTransactions.begin(); iter != candidateTransactions.end(); ++iter)
                        {
                            if ((iter->getType() != Transaction::REWARD && (iter->getFromAddress() == m_address)))
                            {
                                total -= iter->getAmount();
                            }
                        }

                        if (total > t.getAmount())
                        {
                            //accept;
                            keepTransactions.push_back(t);
                        }

                    }
                }

                m_suggestedTransactions.clear();

                foreach(Transaction t, keepTransactions)
                {
                   m_suggestedTransactions.insert(t.getSignature(), t);
                }

                startNewMiningRound();
           }

        }
        else if(b.getIndex() < m_blockChain.size())
        {
            m_blockChain.add(b);
        }
        else if(b.getIndex() > m_blockChain.size())
        {
            //ask for blocks
        }
    }
}

void Bingot::newBlockSolved(Block b)
{
    if(b.getIndex()==size() && m_blockChain.add(b))
    {
        m_networkEngine->sendMessage(b.toMessageJson());
    }
}

void Bingot::onNewTransaction(Transaction t)
{
    if (t.getType() == Transaction::REWARD)
    {
        return; //reward transaction can only be part of solved block.
    }

    if (t.getToAddress() == t.getFromAddress())
    {
        return; //can't self transfer;
    }

    if (!t.verifySignature())
    {
        return;
    }

    //check transaction uniqueness,
    unsigned int total = 0;
    BlockChain::TransactionState ts = m_blockChain.getTransactionState(t, total);

    if (ts == BlockChain::EXISITING || ts == BlockChain::NOT_ENOUGH_MONEY)
    {
        return;
    }

    if (ts == BlockChain::VALID)
    {
        foreach(const Transaction &tr, m_suggestedTransactions)
        {
            if (tr.getSignature() == t.getSignature())
            {
                return;
            }
            if ((tr.getType() != Transaction::REWARD) && (tr.getFromAddress() == m_address))
            {
                total -= tr.getAmount();
            }
        }

        const QHash<QByteArray, Transaction> &candidateTransactions = m_candidateBlock.getTransactions();

        for(QHash<QByteArray, Transaction>::const_iterator iter = candidateTransactions.begin(); iter != candidateTransactions.end(); ++iter)
        {
            if (iter->getSignature() == t.getSignature())
            {
                return;
            }
            if ((iter->getType() != Transaction::REWARD && (iter->getFromAddress() == m_address)))
            {
                total -= iter->getAmount();
            }
        }

        if (total > t.getAmount())
        {
            //accept;
            m_suggestedTransactions.insert(t.getSignature(), t);
            //need to figure out a way to avoid sending this message to where it is from
            m_networkEngine->sendMessage(t.getMessageJson());
        }

    }
}

void Bingot::queryForBlock(int index)
{

}
<|endoftext|>


<commit_before>#include<AD5934.h>
#include<Arduino.h>

AD5934::AD5934(int ClockPin, long ExtClock) {
	Wire.begin();
	pinMode(ClockPin, OUTPUT);
	_extClock = ExtClock;
	//setExtClock(true);
	//Timer1.initialize(1e6/_extClock);
	//Timer1.pwm(ClockPin, 512);
}
/*Status functions
The following set of functions define the status of the AD5934 and are typically set to the Control Registers 0x80 and 0x81. The following functions are available:
reSet()				writes bit D4 and should place device in standby mode. (needs confirmation);
standBy()			writes 0xB0 to 0x80 (control register 1) without changing the voltage range, gain or clock settings.
powerDown() 		writes 0xA0 to control register 1. The device should be placed in this mode when it is not in use to reduce energy requirement.
initializeSweep() 	this function enables the frequency output with the programmed start frequency. The output will remain on indefinitely until a sweep is started (typically after a user defined settling time.
startSweep()		a frequency sweep with the programmed parameters for settlings cycles, start frequency, frequency increment and number of increments is started. Values for the complex impedance will be stored in the according registers. The status register must be polled to know if valid data are available in the storage registers and if the sweep is complete. The jump to the next higher frequency has to be triggered with the function incrementFrequency()
repeatFrequency()	measures the same frequency again to allow averaging
incrementFrequency()	sets the output to the next higher frequency and records result data in real and imaginary storage registers
*/

void AD5934::reSet() {
	writeData(CtrlReg2, 0x10);
}

void AD5934::standBy() {
  // Standby '10110000' Mask D8-10 to avoid tampering with range, gain or clock
  writeData(CtrlReg1, (readData(CtrlReg1) & 0x07) | 0xB0);
  #if debug
  Serial.println("Standby");
  #endif
}

void AD5934::powerDown() {
  writeData(CtrlReg1, 0xA0);
  Serial.println("Power down");
}

void AD5934::initializeSweep() {
  writeData(CtrlReg1, (readData(CtrlReg1) & 0x07) | 0x10);
  Serial.println("Initialised with start frequency");
}

void AD5934::startSweep() {
  writeData(CtrlReg1, (readData(CtrlReg1) & 0x07 | 0x20));
  Serial.println("Start frequency sweep");
}

void AD5934::repeatFrequency() {
  writeData(CtrlReg1, (readData(CtrlReg1) & 0x07 )| 0x40);
  #if debug
  Serial.println("Repeat frequency");
  #endif
}

void AD5934::incrementFrequency(){
  writeData(CtrlReg1, (readData(CtrlReg1) & 0x07) | 0x30);
  #if debug
  Serial.println("Increment frequency");
  #endif
}

int AD5934::readData(int address) {
  int data;
  Wire.beginTransmission(SlaveAddress);
  Wire.write(AddrPointer);
  Wire.write(address);
  Wire.endTransmission();
  delay(1);
  Wire.requestFrom(SlaveAddress, 1);
  if (Wire.available() >= 1) {
    data = Wire.read();
  }
  else {
    data = -1;
  }
  delay(1);
  return data;
}

void AD5934::writeData(int address, int data) {
  Wire.beginTransmission(SlaveAddress);
  Wire.write(address);
  Wire.write(data);
  Wire.endTransmission();
  delay(1);
}

void AD5934::setRange(int range) {
  //reset D10 and D9
  writeData(CtrlReg1, readData(CtrlReg1) & 0xF9);
  //set the voltage range:
  switch (range) {
    // range 1: 2.0 Vp-p
    case 1:
      writeData(CtrlReg1, readData(CtrlReg1) | 0x00);
      break;

    // range 2: 1.0 Vp-p
    case 2:
      writeData(CtrlReg1, readData(CtrlReg1) | 0x06);
      break;

    // range 3: 200 mVp-p
    case 3:
      writeData(CtrlReg1, readData(CtrlReg1) | 0x02);
      break;

    // range 4: 400 mVp-p
    case 4:
      writeData(CtrlReg1, readData(CtrlReg1) | 0x04);
      break;

    default:
      break;
  }
}

void AD5934::setPGA(int PGA) {
  //clear D8
  writeData(CtrlReg1, readData(CtrlReg1) & 0xFE);

  switch (PGA) {
    //set programmable gain to 1
    case 1:
      writeData(CtrlReg1, readData(CtrlReg1) | 0x01);
      break;

    //set programmable gain to 5
    case 5:
      writeData(CtrlReg1, readData(CtrlReg1) | 0x00);
      break;

    default:
      break;
  }
}

void AD5934::setExtClock(bool clk) {
  byte cl;
  if (clk) {
    cl = 0x04; //Use external clock
    _opClock = _extClock;
  }
  else {
    cl = 0x00; //Use internal clock
    _opClock = 16776000;
  }
  //write to control register
  return writeData(CtrlReg2, cl);
}

int AD5934::setStartFrequency(float freq) {
	_StartFreq = freq;
	writeData(StartFreq1, getFrequency(freq, 1));
	writeData(StartFreq2, getFrequency(freq, 2));
	writeData(StartFreq3, getFrequency(freq, 3));
}

byte AD5934::getFrequency(float freq, int n) {
  long val = long((freq / (_opClock / 16)) * pow(2, 27));
  byte code;
  if (val > 0xFFFFFF) {
    Serial.println("Frequency too high!");
	Serial.println(freq);
  }
  else {
    switch (n) {
      case 1:
        code = (val & 0xFF0000) >> 0x10;
        break;

      case 2:
        code = (val & 0x00FF00) >> 0x08;
        break;

      case 3:
        code = (val & 0x0000FF);
        break;

      default:
        code = 0;
    }
  }
  return code;
}

int AD5934::setFrequencyIncrement(float freq) {
	_FreqIncrement = freq;
	writeData(FreqIncrement1, getFrequency(freq, 1));
	writeData(FreqIncrement2, getFrequency(freq, 2));
	writeData(FreqIncrement3, getFrequency(freq, 3));
}

int AD5934::setNumberIncrements(int nInc) {
	_NumberIncrements = nInc;
  writeData(NumberIncrements1, (nInc & 0x001F00) >> 0x08);
  writeData(NumberIncrements2, (nInc & 0x0000FF));
}

int AD5934::measureZ(int nRepeats){
	int n = 0;
	int i = 1;
	float f;
	float magnitude;
	float phase;
	//Print header line
	Serial.println("Frequency\tMagnitude\tPhase\tResistance\tReactance");
	//Check if frequency sweep is completed
	while (i < nRepeats || (readData(StatusReg) & 0x04) !=0x04){
		//Pause between measurements
		delay(100);
		//If valid data are available, print them to serial out
		if((readData(StatusReg) & 0x02) == 2){
			//Read real register
			byte Re1 = readData(ReData1);
			byte Re2	= readData(ReData2);
			float real = (Re1 << 8) | Re2;

			//Read imaginary register
			byte Im1 = readData(ImData1);
			byte Im2 = readData(ImData2);
			float imag = (Im1 << 8) | Im2;

			//Calculate current frequency, impedance magnitude and phase
			f = _StartFreq + n*_FreqIncrement;
			magnitude = sqrt(pow(real,2) + pow(imag,2));
			phase = atan(imag/real)*180/3.141592;

			//Print results
			Serial.print(f);
			Serial.print("\t");
			Serial.print(magnitude,3);
			Serial.print("\t");
			Serial.print(phase,1);
			Serial.print("\t");
			Serial.print((int)real);
			//Serial.print(Re1,HEX);
			//Serial.print(Re2,HEX);
			Serial.print("\t");
			Serial.println((int)imag);
			//Serial.print(Im1,HEX);
			//Serial.println(Im2,HEX);

			if (i < nRepeats){
			repeatFrequency();
			i++;
			}
			else{
				//Next frequency
				if((readData(StatusReg) & 0x07) < 4 ){
					incrementFrequency();
					n++;
					if ( n == _NumberIncrements){
						i = 0;
					}
					else {
						i = 1;
					}
				}
			}
		}
	}
	Serial.println("Done");
}

int AD5934::measureZnew(int nRepeats){
	int n = 0;	//Counter for frequency calculations
	int i = 1;	//Counter for repeats
	const long t0 = millis(); 	//starting time reference
	long t1 = 0;				//time of respective measurement
	int interResult [2][nRepeats];	//Array with intermediate results for averaging
	float f;
	bool flag;
	//Print header line
	Serial.println("Time\tFrequency\tMagnitude\tPhase\tResistance\tReactance");
	//Check if frequency sweep is completed
	while (i < nRepeats || (readData(StatusReg) & 0x04) !=0x04 || flag !=true){
		//Pause between measurements
		delay(100);
		//If valid data are available, print them to serial out
		if((readData(StatusReg) & 0x02) == 2){
			//Read real register
			byte Re1 = readData(ReData1);
			byte Re2 = readData(ReData2);
			interResult [0][n] = (Re1 << 8) | Re2; 	//Write real value to first column in array

			//Read imaginary register
			byte Im1 = readData(ImData1);
			byte Im2 = readData(ImData2);
			interResult [1][n] = (Im1 << 8) | Im2;	//Write imaginary value to second column in array

			if (i < nRepeats){
			repeatFrequency();
			i++;
			flag = false;
			}
			else{
				flag = true;
				f = _StartFreq + n*_FreqIncrement;
				//Next frequency
				if((readData(StatusReg) & 0x07) < 4 ){
					incrementFrequency();
					n++;
					if ( n == _NumberIncrements){
						i = 0;
					}
					else {
						i = 1;
					}
				}
			}
			if (flag){
			//Calculate average values for real and imaginary values
			long sum[] = {0,0};	//Array of sums of intermediate results. Column 1 = real, column 2 = imaginary
			for (int m = 0; m < nRepeats; m++){
				sum[0]+= interResult[0][m];
				sum[1]+= interResult[1][m];
			}
			float real = sum[0]/nRepeats;
			float imag = sum[1]/nRepeats;

			//Calculate current frequency, impedance magnitude and phase

			float magnitude = sqrt(square(real) + square(imag));
			float phase = atan(imag/real)*180/3.141592;

			//Get time elapsed since entering this routine
			t1 = millis() - t0;

			//Print results
			Serial.print(t1);
			Serial.print("\t");
			Serial.print(f);
			Serial.print("\t");
			Serial.print(magnitude,3);
			Serial.print("\t");
			Serial.print(phase,1);
			Serial.print("\t");
			Serial.print((int)real);
			//Serial.print(Re1,HEX);
			//Serial.print(Re2,HEX);
			Serial.print("\t");
			Serial.println((int)imag);
			//Serial.print(Im1,HEX);
			//Serial.println(Im2,HEX);
			}
		}
	}
	Serial.println("Done");
}

int AD5934::setSettlingCycles(int nCyc){
  int lowerHex = nCyc % 256;
  int upperHex = ((nCyc - lowerHex)>> 8) % 2;
  writeData(NumberSettlingCycles1, upperHex);
  writeData(NumberSettlingCycles2, lowerHex);
}

bool AD5934::readDFTStatus(){
  while ((readData(StatusReg) & 0x02) != 0x02){
    delay(100);
  }
}

bool AD5934::readSweepStatus(){
  while ((readData(StatusReg) & 0x04) != 0x04){
    incrementFrequency();
  }
}
			<commit_msg>improvements to new measurement routine<commit_after>#include<AD5934.h>
#include<Arduino.h>

AD5934::AD5934(int ClockPin, long ExtClock) {
	Wire.begin();
	pinMode(ClockPin, OUTPUT);
	_extClock = ExtClock;
	//setExtClock(true);
	//Timer1.initialize(1e6/_extClock);
	//Timer1.pwm(ClockPin, 512);
}
/*Status functions
The following set of functions define the status of the AD5934 and are typically set to the Control Registers 0x80 and 0x81. The following functions are available:
reSet()				writes bit D4 and should place device in standby mode. (needs confirmation);
standBy()			writes 0xB0 to 0x80 (control register 1) without changing the voltage range, gain or clock settings.
powerDown() 		writes 0xA0 to control register 1. The device should be placed in this mode when it is not in use to reduce energy requirement.
initializeSweep() 	this function enables the frequency output with the programmed start frequency. The output will remain on indefinitely until a sweep is started (typically after a user defined settling time.
startSweep()		a frequency sweep with the programmed parameters for settlings cycles, start frequency, frequency increment and number of increments is started. Values for the complex impedance will be stored in the according registers. The status register must be polled to know if valid data are available in the storage registers and if the sweep is complete. The jump to the next higher frequency has to be triggered with the function incrementFrequency()
repeatFrequency()	measures the same frequency again to allow averaging
incrementFrequency()	sets the output to the next higher frequency and records result data in real and imaginary storage registers
*/

void AD5934::reSet() {
	writeData(CtrlReg2, 0x10);
}

void AD5934::standBy() {
  // Standby '10110000' Mask D8-10 to avoid tampering with range, gain or clock
  writeData(CtrlReg1, (readData(CtrlReg1) & 0x07) | 0xB0);
  #if debug
  Serial.println("Standby");
  #endif
}

void AD5934::powerDown() {
  writeData(CtrlReg1, 0xA0);
  Serial.println("Power down");
}

void AD5934::initializeSweep() {
  writeData(CtrlReg1, (readData(CtrlReg1) & 0x07) | 0x10);
  Serial.println("Initialised with start frequency");
}

void AD5934::startSweep() {
  writeData(CtrlReg1, (readData(CtrlReg1) & 0x07 | 0x20));
  Serial.println("Start frequency sweep");
}

void AD5934::repeatFrequency() {
  writeData(CtrlReg1, (readData(CtrlReg1) & 0x07 )| 0x40);
  #if debug
  Serial.println("Repeat frequency");
  #endif
}

void AD5934::incrementFrequency(){
  writeData(CtrlReg1, (readData(CtrlReg1) & 0x07) | 0x30);
  #if debug
  Serial.println("Increment frequency");
  #endif
}

int AD5934::readData(int address) {
  int data;
  Wire.beginTransmission(SlaveAddress);
  Wire.write(AddrPointer);
  Wire.write(address);
  Wire.endTransmission();
  delay(1);
  Wire.requestFrom(SlaveAddress, 1);
  if (Wire.available() >= 1) {
    data = Wire.read();
  }
  else {
    data = -1;
  }
  delay(1);
  return data;
}

void AD5934::writeData(int address, int data) {
  Wire.beginTransmission(SlaveAddress);
  Wire.write(address);
  Wire.write(data);
  Wire.endTransmission();
  delay(1);
}

void AD5934::setRange(int range) {
  //reset D10 and D9
  writeData(CtrlReg1, readData(CtrlReg1) & 0xF9);
  //set the voltage range:
  switch (range) {
    // range 1: 2.0 Vp-p
    case 1:
      writeData(CtrlReg1, readData(CtrlReg1) | 0x00);
      break;

    // range 2: 1.0 Vp-p
    case 2:
      writeData(CtrlReg1, readData(CtrlReg1) | 0x06);
      break;

    // range 3: 200 mVp-p
    case 3:
      writeData(CtrlReg1, readData(CtrlReg1) | 0x02);
      break;

    // range 4: 400 mVp-p
    case 4:
      writeData(CtrlReg1, readData(CtrlReg1) | 0x04);
      break;

    default:
      break;
  }
}

void AD5934::setPGA(int PGA) {
  //clear D8
  writeData(CtrlReg1, readData(CtrlReg1) & 0xFE);

  switch (PGA) {
    //set programmable gain to 1
    case 1:
      writeData(CtrlReg1, readData(CtrlReg1) | 0x01);
      break;

    //set programmable gain to 5
    case 5:
      writeData(CtrlReg1, readData(CtrlReg1) | 0x00);
      break;

    default:
      break;
  }
}

void AD5934::setExtClock(bool clk) {
  byte cl;
  if (clk) {
    cl = 0x04; //Use external clock
    _opClock = _extClock;
  }
  else {
    cl = 0x00; //Use internal clock
    _opClock = 16776000;
  }
  //write to control register
  return writeData(CtrlReg2, cl);
}

int AD5934::setStartFrequency(float freq) {
	_StartFreq = freq;
	writeData(StartFreq1, getFrequency(freq, 1));
	writeData(StartFreq2, getFrequency(freq, 2));
	writeData(StartFreq3, getFrequency(freq, 3));
}

byte AD5934::getFrequency(float freq, int n) {
  long val = long((freq / (_opClock / 16)) * pow(2, 27));
  byte code;
  if (val > 0xFFFFFF) {
    Serial.println("Frequency too high!");
	Serial.println(freq);
  }
  else {
    switch (n) {
      case 1:
        code = (val & 0xFF0000) >> 0x10;
        break;

      case 2:
        code = (val & 0x00FF00) >> 0x08;
        break;

      case 3:
        code = (val & 0x0000FF);
        break;

      default:
        code = 0;
    }
  }
  return code;
}

int AD5934::setFrequencyIncrement(float freq) {
	_FreqIncrement = freq;
	writeData(FreqIncrement1, getFrequency(freq, 1));
	writeData(FreqIncrement2, getFrequency(freq, 2));
	writeData(FreqIncrement3, getFrequency(freq, 3));
}

int AD5934::setNumberIncrements(int nInc) {
	_NumberIncrements = nInc;
  writeData(NumberIncrements1, (nInc & 0x001F00) >> 0x08);
  writeData(NumberIncrements2, (nInc & 0x0000FF));
}

int AD5934::measureZ(int nRepeats){
	int n = 0;
	int i = 1;
	const long t0 = millis(); 	//starting time reference
	long t1 = 0;				//time of respective measurement
	float f;
	float magnitude;
	float phase;
	//Print header line
	Serial.println("Time\tFrequency\tMagnitude\tPhase\tResistance\tReactance");
	//Check if frequency sweep is completed
	while (i < nRepeats || (readData(StatusReg) & 0x04) !=0x04){
		//Pause between measurements
		delay(100);
		//If valid data are available, print them to serial out
		if((readData(StatusReg) & 0x02) == 2){
			//Read real register
			byte Re1 = readData(ReData1);
			byte Re2	= readData(ReData2);
			float real = (Re1 << 8) | Re2;

			//Read imaginary register
			byte Im1 = readData(ImData1);
			byte Im2 = readData(ImData2);
			float imag = (Im1 << 8) | Im2;

			//Calculate current frequency, impedance magnitude and phase
			f = _StartFreq + n*_FreqIncrement;
			magnitude = sqrt(pow(real,2) + pow(imag,2));
			phase = atan(imag/real)*180/3.141592;

			//Get time elapsed since entering this routine
			t1 = millis() - t0;

			//Print results
			Serial.print(t1);
			Serial.print("\t");
			Serial.print(f);
			Serial.print("\t");
			Serial.print(magnitude,3);
			Serial.print("\t");
			Serial.print(phase,1);
			Serial.print("\t");
			Serial.print((int)real);
			//Serial.print(Re1,HEX);
			//Serial.print(Re2,HEX);
			Serial.print("\t");
			Serial.println((int)imag);
			//Serial.print(Im1,HEX);
			//Serial.println(Im2,HEX);

			if (i < nRepeats){
			repeatFrequency();
			i++;
			}
			else{
				//Next frequency
				if((readData(StatusReg) & 0x07) < 4 ){
					incrementFrequency();
					n++;
					if ( n == _NumberIncrements){
						i = 0;
					}
					else {
						i = 1;
					}
				}
			}
		}
	}
	Serial.println("Done");
}

int AD5934::measureZnew(int nRepeats){
	int n = 0;	//Counter for frequency calculations
	int i = 1;	//Counter for repeats
	const long t0 = millis(); 	//starting time reference
	long t1 = 0;				//time of respective measurement
	int interResult [2][nRepeats];	//Array with intermediate results for averaging
	float f;
	bool flag;
	//Print header line
	Serial.println("Time\tFrequency\tMagnitude\tPhase\tResistance\tReactance");
	//Check if frequency sweep is completed
	while (i < nRepeats || (readData(StatusReg) & 0x04) !=0x04 || flag !=true){
		//Pause between measurements
		delay(100);
		//If valid data are available, print them to serial out
		if((readData(StatusReg) & 0x02) == 2){
			//Read real register
			byte Re1 = readData(ReData1);
			byte Re2 = readData(ReData2);
			interResult [0][i-1] = (Re1 << 8) | Re2; 	//Write real value to first column in array

			//Read imaginary register
			byte Im1 = readData(ImData1);
			byte Im2 = readData(ImData2);
			interResult [1][i-1] = (Im1 << 8) | Im2;	//Write imaginary value to second column in array

			if (i < nRepeats){
			repeatFrequency();
			i++;
			flag = false;
			}
			else{
				flag = true;
				f = _StartFreq + n*_FreqIncrement;
				//Next frequency
				if((readData(StatusReg) & 0x07) < 4 ){
					incrementFrequency();
					n++;
					if ( n == _NumberIncrements){
						i = 0;
					}
					else {
						i = 1;
					}
				}
			}
			if (flag){
			//Calculate average values for real and imaginary values
			long sum[2] = {};	//Array of sums of intermediate results. Column 1 = real, column 2 = imaginary
			for (int m = 0; m < nRepeats; m++){
				sum[0]+= interResult[0][m];
				sum[1]+= interResult[1][m];
			}
			float real = sum[0]/nRepeats;
			float imag = sum[1]/nRepeats;

			//Calculate current frequency, impedance magnitude and phase

			float magnitude = sqrt(square(real) + square(imag));
			float phase = atan(imag/real)*180/3.141592;

			//Get time elapsed since entering this routine
			t1 = millis() - t0;

			//Print results
			Serial.print(t1);
			Serial.print("\t");
			Serial.print(f);
			Serial.print("\t");
			Serial.print(magnitude,3);
			Serial.print("\t");
			Serial.print(phase,1);
			Serial.print("\t");
			Serial.print((int)real);
			//Serial.print(Re1,HEX);
			//Serial.print(Re2,HEX);
			Serial.print("\t");
			Serial.println((int)imag);
			//Serial.print(Im1,HEX);
			//Serial.println(Im2,HEX);
			}
		}
	}
	Serial.println("Done");
}

int AD5934::setSettlingCycles(int nCyc){
  int lowerHex = nCyc % 256;
  int upperHex = ((nCyc - lowerHex)>> 8) % 2;
  writeData(NumberSettlingCycles1, upperHex);
  writeData(NumberSettlingCycles2, lowerHex);
}

bool AD5934::readDFTStatus(){
  while ((readData(StatusReg) & 0x02) != 0x02){
    delay(100);
  }
}

bool AD5934::readSweepStatus(){
  while ((readData(StatusReg) & 0x04) != 0x04){
    incrementFrequency();
  }
}
			<|endoftext|>


<commit_before>// Helper classes for writing unittests testing the entire asynchronous
// stack. Allows to send incoming messages (in gridconnect format) and set
// expectations on messages produced.
//
// Only include this file in unittests.

#ifndef _UTILS_ASYNC_IF_TEST_HELPER_HXX_
#define _UTILS_ASYNC_IF_TEST_HELPER_HXX_

#include "nmranet/AliasAllocator.hxx"
#include "nmranet/IfCan.hxx"
#include "nmranet/EventService.hxx"
#include "nmranet/DefaultNode.hxx"
#include "nmranet/NodeInitializeFlow.hxx"
#include "nmranet_config.h"
#include "utils/GridConnectHub.hxx"
#include "utils/test_main.hxx"

using ::testing::AtLeast;
using ::testing::AtMost;
using ::testing::Eq;
using ::testing::Field;
using ::testing::Invoke;
using ::testing::IsNull;
using ::testing::Mock;
using ::testing::NiceMock;
using ::testing::NotNull;
using ::testing::Pointee;
using ::testing::Return;
using ::testing::StrCaseEq;
using ::testing::StrictMock;
using ::testing::WithArg;
using ::testing::SaveArg;
using ::testing::_;

class TrainTestHelper;

///@todo(balazs.racz) remove
// void (*g_invoke)(Notifiable *) = &InvokeNotification;

HubFlow gc_hub0(&g_service);
CanHubFlow can_hub0(&g_service);
GCAdapterBase *g_gc_adapter = nullptr;

HubFlow gc_hub1(&g_service);
CanHubFlow can_hub1(&g_service);
GCAdapterBase *g_gc_adapter1 = nullptr;

nmranet::InitializeFlow g_init_flow(&g_service);

/** Helper class for setting expectation on the CANbus traffic in unit
 * tests. */
class MockSend : public HubPort
{
public:
    MockSend()
        : HubPort(&g_service)
    {
    }

    MOCK_METHOD1(mwrite, void(const string &s));

    virtual Action entry()
    {
        string s(message()->data()->data(), message()->data()->size());
        mwrite(s);
        return release_and_exit();
    }
};

void InvokeNotification(Notifiable *done)
{
    done->notify();
}

static void print_packet(const string &pkt)
{
    fprintf(stderr, "%s\n", pkt.c_str());
}

/// Test fixture base class for tests that need a CAN-based interface(but not
/// necessary specific to OpenLCB). The direct use of this class is useful only
/// when other CAN-based protocol flows need to be tested. The OpenLCB test
/// fixtures are inheriting from this class.
class AsyncCanTest : public testing::Test
{
public:
    static void SetUpTestCase()
    {
        g_gc_adapter =
            GCAdapterBase::CreateGridConnectAdapter(&gc_hub0, &can_hub0, false);
    }

    static void TearDownTestCase()
    {
        delete g_gc_adapter;
    }

protected:
    AsyncCanTest()
    {
        gc_hub0.register_port(&canBus_);
    }

    ~AsyncCanTest()
    {
        gc_hub0.unregister_port(&canBus_);
        if (printer_.get())
        {
            gc_hub0.unregister_port(printer_.get());
        }
    }

    /** Delays the current thread until we are certain that all asynchrnous
        processing has completed. */
    void wait()
    {
        wait_for_main_executor();
    }

#ifdef __EMSCRIPTEN__
    void usleep(unsigned long usecs) {
        long long deadline = usecs;
        deadline *= 1000;
        deadline += os_get_time_monotonic();
        while (os_get_time_monotonic() < deadline) {
            os_emscripten_yield();
        }
    }
#endif

/** Adds an expectation that the code will send a packet to the CANbus.

    Example:
    expect_packet(":X1954412DN05010101FFFF0000;");

    @param gc_packet the packet in GridConnect format, including the leading
    : and trailing ;
*/
#define expect_packet(gc_packet)                                               \
    EXPECT_CALL(canBus_, mwrite(StrCaseEq(gc_packet)))

    /** Ignores all produced packets.
     *
     *  Tihs can be used in tests where the expectations are tested in a higher
     *  level than monitoring the CANbus traffic.
    */
    void expect_any_packet()
    {
        print_all_packets();
        EXPECT_CALL(canBus_, mwrite(_)).Times(AtLeast(0));
        //.WillRepeatedly(WithArg<0>(Invoke(print_packet)));
    }

    /** Prints all packets sent to the canbus until the end of the current test
     * function.
    */
    void print_all_packets()
    {
        HASSERT(!printer_ && "cannot have more than one print_all_packets call");
        NiceMock<MockSend> *m = new NiceMock<MockSend>();
        EXPECT_CALL(*m, mwrite(_)).Times(AtLeast(0)).WillRepeatedly(
            WithArg<0>(Invoke(print_packet)));
        gc_hub0.register_port(m);
        printer_.reset(m);
    }

    /** Injects a packet to the interface. This acts as if a different node on
        the CANbus had sent that packet.

        Example:
        send_packet(":X195B4001N05010101FFFF0000;");

        @param gc_packet the packet in GridConnect format, including the leading
        : and trailing ;
    */
    void send_packet(const string &gc_packet)
    {
        Buffer<HubData> *packet;
        mainBufferPool->alloc(&packet);
        packet->data()->assign(gc_packet);
        packet->data()->skipMember_ = &canBus_;
        gc_hub0.send(packet);
    }

    void clear_expect(bool strict = false)
    {
        Mock::VerifyAndClear(&canBus_);
        if (strict) {
            EXPECT_CALL(canBus_, mwrite(_)).Times(0);
        }
    }

/** Injects an incoming packet to the interface and expects that the node
    will send out a response packet for it.

    As a side effect, clears all pending expectations on the CANbus.

    Example:
    send_packet_and_expect_response(":X198F4001N05010101FFFF0000;",
                                    ":X194C412DN05010101FFFF0000;");

    @param pkt is the packet to inject, in GridConnect format.
    @param resp is the response to expect, also in GridConnect format.
*/
#define send_packet_and_expect_response(pkt, resp)                             \
    do                                                                         \
    {                                                                          \
        expect_packet(resp);                                                   \
        send_packet_and_flush_expect(pkt);                                     \
    } while (0)

    void send_packet_and_flush_expect(const string &pkt)
    {
        send_packet(pkt);
        wait();
        Mock::VerifyAndClear(&canBus_);
    }

    /// Helper object for setting expectations on the packets sent on the bus.
    NiceMock<MockSend> canBus_;
    /// Object for debug-printing every packet (if requested).
    std::unique_ptr<HubPort> printer_;
};

/// Test fixture base class for a second CAN-bus. Usage: use multiple
/// inheritance in the test fixture to merge both AsyncCanTest and
/// AsyncCan1Test.
class AsyncCan1Test {
protected:
  AsyncCan1Test() { gc_hub1.register_port(&canBus1_); }
  ~AsyncCan1Test() {
    wait_for_main_executor();
    gc_hub1.unregister_port(&canBus1_);
  }

  static void SetUpTestCase() {
    g_gc_adapter1 =
        GCAdapterBase::CreateGridConnectAdapter(&gc_hub1, &can_hub1, false);
  }

  static void TearDownTestCase() {
    delete g_gc_adapter1;
  }

#define expect_packet1(gc_packet) \
  EXPECT_CALL(canBus1_, mwrite(StrCaseEq(gc_packet)))

  void send_packet1(const string &gc_packet) {
    Buffer<HubData> *packet;
    mainBufferPool->alloc(&packet);
    packet->data()->assign(gc_packet);
    packet->data()->skipMember_ = &canBus1_;
    gc_hub1.send(packet);
  }

  /// Helper object for setting expectations on the packets sent on the bus.
  StrictMock<MockSend> canBus1_;
};

/*
template<class T, typename... Args>
Buffer<T>* invoke_flow(FlowInterface<Buffer<T>>* flow, Args... args) {
    Buffer<T>* b = flow->alloc();
    b->data()->reset();
    }*/

namespace nmranet
{

static const NodeID TEST_NODE_ID = 0x02010d000003ULL;

/** Test fixture base class with helper methods for exercising the asynchronous
 * interface code.
 *
 * Usage:
 *
 * Inherit your test fixture class from AsyncIfTest.
 */
class AsyncIfTest : public AsyncCanTest
{
protected:
    AsyncIfTest()
        : pendingAliasAllocation_(false)
    {
        ifCan_.reset(new IfCan(&g_executor, &can_hub0, 10, 10, 5));
        ifCan_->local_aliases()->add(TEST_NODE_ID, 0x22A);
    }

    ~AsyncIfTest()
    {
        wait();
        if (pendingAliasAllocation_)
        {
            ifCan_->alias_allocator()->TEST_finish_pending_allocation();
            wait();
        }
    }

    friend class ::TrainTestHelper;

    /** Creates an alias allocator flow, and injects an already allocated
     *  alias. */
    void create_allocated_alias()
    {
        inject_allocated_alias(0x33A, true);
        aliasSeed_ = 0x44C;
        pendingAliasAllocation_ = false;
    }

    void inject_allocated_alias(NodeAlias alias, bool repeat = false)
    {
        if (!ifCan_->alias_allocator()) {
            ifCan_->set_alias_allocator(
                new AliasAllocator(TEST_NODE_ID, ifCan_.get()));
        }
        Buffer<AliasInfo> *a;
        mainBufferPool->alloc(&a);
        a->data()->reset();
        a->data()->alias = alias;
        a->data()->state = AliasInfo::STATE_RESERVED;
        if (!repeat) {
            a->data()->do_not_reallocate();
        }
        ifCan_->local_aliases()->add(AliasCache::RESERVED_ALIAS_NODE_ID,
                                     a->data()->alias);
        ifCan_->alias_allocator()->reserved_aliases()->insert(a);
    }

    void expect_next_alias_allocation(NodeAlias a = 0)
    {
        pendingAliasAllocation_ = true;
        if (!a)
        {
            ifCan_->alias_allocator()->seed_ = aliasSeed_;
            a = aliasSeed_;
            aliasSeed_++;
        }
        EXPECT_CALL(canBus_, mwrite(StringPrintf(":X17020%03XN;", a)))
            .Times(1)
            .RetiresOnSaturation();
        EXPECT_CALL(canBus_, mwrite(StringPrintf(":X1610D%03XN;", a)))
            .Times(1)
            .RetiresOnSaturation();
        EXPECT_CALL(canBus_, mwrite(StringPrintf(":X15000%03XN;", a)))
            .Times(1)
            .RetiresOnSaturation();
        EXPECT_CALL(canBus_, mwrite(StringPrintf(":X14003%03XN;", a)))
            .Times(1)
            .RetiresOnSaturation();

        EXPECT_CALL(canBus_, mwrite(StringPrintf(":X10700%03XN;", a)))
            .Times(AtMost(1))
            .RetiresOnSaturation();
    }

    BarrierNotifiable *get_notifiable()
    {
        bn_.reset(&n_);
        return &bn_;
    }

    void wait_for_notification()
    {
        n_.wait_for_notification();
    }

    SyncNotifiable n_;
    BarrierNotifiable bn_;

    /// The interface under test.
    std::unique_ptr<IfCan> ifCan_;
    /** Temporary object used to send aliases around in the alias allocator
     *  flow. */
    AliasInfo testAlias_;
    /// The next alias we will make the allocator create.
    NodeAlias aliasSeed_;
    /// true if we have a pending async alias allocation task.
    bool pendingAliasAllocation_;
};

/// Base class for test cases with one virtual node on a CANbus interface.
class AsyncNodeTest : public AsyncIfTest
{
protected:
    AsyncNodeTest()
        : eventService_(ifCan_.get())
    {
        EXPECT_CALL(canBus_, mwrite(":X1910022AN02010D000003;")).Times(1);
        ownedNode_.reset(new DefaultNode(ifCan_.get(), TEST_NODE_ID));
        node_ = ownedNode_.get();
        ifCan_->add_addressed_message_support();
        wait();
        Mock::VerifyAndClear(&canBus_);
        // AddEventHandlerToIf(ifCan_.get());
    }

    ~AsyncNodeTest()
    {
        wait_for_event_thread();
    }

    void wait_for_event_thread()
    {
        while (EventService::instance->event_processing_pending())
        {
#ifdef __EMSCRIPTEN__
            os_emscripten_yield();
#else
            usleep(100);
#endif
        }
        AsyncIfTest::wait();
    }

    EventService eventService_;
    std::unique_ptr<DefaultNode> ownedNode_;
    Node *node_;
};

/// Test handler for receiving incoming nmranet Message objects from a bus. The
/// incoming messages need GoogleMock expectations.
///
/// Usage: see file src/nmranet/IfCan.cxxtest
class MockMessageHandler : public MessageHandler
{
public:
    MOCK_METHOD2(handle_message,
                 void(NMRAnetMessage *message, unsigned priority));
    virtual void send(Buffer<NMRAnetMessage> *message, unsigned priority)
    {
        handle_message(message->data(), priority);
        message->unref();
    }
};

/// GoogleMock matcher on a Payload being equal to a given 64-bit value in
/// network byte order. (Typically an event id.)
MATCHER_P(IsBufferValue, id, "")
{
    uint64_t value = htobe64(id);
    if (arg.size() != 8)
        return false;
    if (memcmp(&value, arg.data(), 8))
        return false;
    return true;
}

/// GoogleMock matcher on a Payload being equal to a given string (C or C++
/// style).
MATCHER_P(IsBufferValueString, expected, "")
{
    string s(expected);
    return arg == s;
}

/// GoogleMock matcher on a Payload being equal to a given 48-bit value in
/// network byte order (typically a Node ID).
MATCHER_P(IsBufferNodeValue, id, "")
{
    uint64_t value = htobe64(id);
    if (arg->used() != 6)
        return false;
    uint8_t *expected = reinterpret_cast<uint8_t *>(&value) + 2;
    uint8_t *actual = static_cast<uint8_t *>(arg->start());
    if (memcmp(expected, actual, 6))
    {
        for (int i = 0; i < 6; ++i)
        {
            if (expected[i] != actual[i])
            {
                LOG(INFO, "mismatch at position %d, expected %02x actual %02x",
                    i, expected[i], actual[i]);
            }
        }
        return false;
    }
    return true;
}

/// GoogleMock matcher on a Payload being equal to a given 6-byte string.
MATCHER_P(IsBufferNodeValueString, id, "")
{
    uint64_t value = htobe64(id);
    if (arg.size() != 6)
        return false;
    uint8_t *expected = reinterpret_cast<uint8_t *>(&value) + 2;
    uint8_t *actual = static_cast<uint8_t *>(arg->start());
    if (memcmp(expected, actual, 6))
    {
        for (int i = 0; i < 6; ++i)
        {
            if (expected[i] != actual[i])
            {
                LOG(INFO, "mismatch at position %d, expected %02x actual %02x",
                    i, expected[i], actual[i]);
            }
        }
        return false;
    }
    return true;
}

} // namespace nmranet

#endif // _UTILS_ASYNC_IF_TEST_HELPER_HXX_
<commit_msg>Increases the max number of local nodes in tests.<commit_after>// Helper classes for writing unittests testing the entire asynchronous
// stack. Allows to send incoming messages (in gridconnect format) and set
// expectations on messages produced.
//
// Only include this file in unittests.

#ifndef _UTILS_ASYNC_IF_TEST_HELPER_HXX_
#define _UTILS_ASYNC_IF_TEST_HELPER_HXX_

#include "nmranet/AliasAllocator.hxx"
#include "nmranet/IfCan.hxx"
#include "nmranet/EventService.hxx"
#include "nmranet/DefaultNode.hxx"
#include "nmranet/NodeInitializeFlow.hxx"
#include "nmranet_config.h"
#include "utils/GridConnectHub.hxx"
#include "utils/test_main.hxx"

using ::testing::AtLeast;
using ::testing::AtMost;
using ::testing::Eq;
using ::testing::Field;
using ::testing::Invoke;
using ::testing::IsNull;
using ::testing::Mock;
using ::testing::NiceMock;
using ::testing::NotNull;
using ::testing::Pointee;
using ::testing::Return;
using ::testing::StrCaseEq;
using ::testing::StrictMock;
using ::testing::WithArg;
using ::testing::SaveArg;
using ::testing::_;

class TrainTestHelper;

///@todo(balazs.racz) remove
// void (*g_invoke)(Notifiable *) = &InvokeNotification;

HubFlow gc_hub0(&g_service);
CanHubFlow can_hub0(&g_service);
GCAdapterBase *g_gc_adapter = nullptr;

HubFlow gc_hub1(&g_service);
CanHubFlow can_hub1(&g_service);
GCAdapterBase *g_gc_adapter1 = nullptr;

nmranet::InitializeFlow g_init_flow(&g_service);

/** Helper class for setting expectation on the CANbus traffic in unit
 * tests. */
class MockSend : public HubPort
{
public:
    MockSend()
        : HubPort(&g_service)
    {
    }

    MOCK_METHOD1(mwrite, void(const string &s));

    virtual Action entry()
    {
        string s(message()->data()->data(), message()->data()->size());
        mwrite(s);
        return release_and_exit();
    }
};

void InvokeNotification(Notifiable *done)
{
    done->notify();
}

static void print_packet(const string &pkt)
{
    fprintf(stderr, "%s\n", pkt.c_str());
}

/// Test fixture base class for tests that need a CAN-based interface(but not
/// necessary specific to OpenLCB). The direct use of this class is useful only
/// when other CAN-based protocol flows need to be tested. The OpenLCB test
/// fixtures are inheriting from this class.
class AsyncCanTest : public testing::Test
{
public:
    static void SetUpTestCase()
    {
        g_gc_adapter =
            GCAdapterBase::CreateGridConnectAdapter(&gc_hub0, &can_hub0, false);
    }

    static void TearDownTestCase()
    {
        delete g_gc_adapter;
    }

protected:
    AsyncCanTest()
    {
        gc_hub0.register_port(&canBus_);
    }

    ~AsyncCanTest()
    {
        gc_hub0.unregister_port(&canBus_);
        if (printer_.get())
        {
            gc_hub0.unregister_port(printer_.get());
        }
    }

    /** Delays the current thread until we are certain that all asynchrnous
        processing has completed. */
    void wait()
    {
        wait_for_main_executor();
    }

#ifdef __EMSCRIPTEN__
    void usleep(unsigned long usecs) {
        long long deadline = usecs;
        deadline *= 1000;
        deadline += os_get_time_monotonic();
        while (os_get_time_monotonic() < deadline) {
            os_emscripten_yield();
        }
    }
#endif

/** Adds an expectation that the code will send a packet to the CANbus.

    Example:
    expect_packet(":X1954412DN05010101FFFF0000;");

    @param gc_packet the packet in GridConnect format, including the leading
    : and trailing ;
*/
#define expect_packet(gc_packet)                                               \
    EXPECT_CALL(canBus_, mwrite(StrCaseEq(gc_packet)))

    /** Ignores all produced packets.
     *
     *  Tihs can be used in tests where the expectations are tested in a higher
     *  level than monitoring the CANbus traffic.
    */
    void expect_any_packet()
    {
        print_all_packets();
        EXPECT_CALL(canBus_, mwrite(_)).Times(AtLeast(0));
        //.WillRepeatedly(WithArg<0>(Invoke(print_packet)));
    }

    /** Prints all packets sent to the canbus until the end of the current test
     * function.
    */
    void print_all_packets()
    {
        HASSERT(!printer_ && "cannot have more than one print_all_packets call");
        NiceMock<MockSend> *m = new NiceMock<MockSend>();
        EXPECT_CALL(*m, mwrite(_)).Times(AtLeast(0)).WillRepeatedly(
            WithArg<0>(Invoke(print_packet)));
        gc_hub0.register_port(m);
        printer_.reset(m);
    }

    /** Injects a packet to the interface. This acts as if a different node on
        the CANbus had sent that packet.

        Example:
        send_packet(":X195B4001N05010101FFFF0000;");

        @param gc_packet the packet in GridConnect format, including the leading
        : and trailing ;
    */
    void send_packet(const string &gc_packet)
    {
        Buffer<HubData> *packet;
        mainBufferPool->alloc(&packet);
        packet->data()->assign(gc_packet);
        packet->data()->skipMember_ = &canBus_;
        gc_hub0.send(packet);
    }

    void clear_expect(bool strict = false)
    {
        Mock::VerifyAndClear(&canBus_);
        if (strict) {
            EXPECT_CALL(canBus_, mwrite(_)).Times(0);
        }
    }

/** Injects an incoming packet to the interface and expects that the node
    will send out a response packet for it.

    As a side effect, clears all pending expectations on the CANbus.

    Example:
    send_packet_and_expect_response(":X198F4001N05010101FFFF0000;",
                                    ":X194C412DN05010101FFFF0000;");

    @param pkt is the packet to inject, in GridConnect format.
    @param resp is the response to expect, also in GridConnect format.
*/
#define send_packet_and_expect_response(pkt, resp)                             \
    do                                                                         \
    {                                                                          \
        expect_packet(resp);                                                   \
        send_packet_and_flush_expect(pkt);                                     \
    } while (0)

    void send_packet_and_flush_expect(const string &pkt)
    {
        send_packet(pkt);
        wait();
        Mock::VerifyAndClear(&canBus_);
    }

    /// Helper object for setting expectations on the packets sent on the bus.
    NiceMock<MockSend> canBus_;
    /// Object for debug-printing every packet (if requested).
    std::unique_ptr<HubPort> printer_;
};

/// Test fixture base class for a second CAN-bus. Usage: use multiple
/// inheritance in the test fixture to merge both AsyncCanTest and
/// AsyncCan1Test.
class AsyncCan1Test {
protected:
  AsyncCan1Test() { gc_hub1.register_port(&canBus1_); }
  ~AsyncCan1Test() {
    wait_for_main_executor();
    gc_hub1.unregister_port(&canBus1_);
  }

  static void SetUpTestCase() {
    g_gc_adapter1 =
        GCAdapterBase::CreateGridConnectAdapter(&gc_hub1, &can_hub1, false);
  }

  static void TearDownTestCase() {
    delete g_gc_adapter1;
  }

#define expect_packet1(gc_packet) \
  EXPECT_CALL(canBus1_, mwrite(StrCaseEq(gc_packet)))

  void send_packet1(const string &gc_packet) {
    Buffer<HubData> *packet;
    mainBufferPool->alloc(&packet);
    packet->data()->assign(gc_packet);
    packet->data()->skipMember_ = &canBus1_;
    gc_hub1.send(packet);
  }

  /// Helper object for setting expectations on the packets sent on the bus.
  StrictMock<MockSend> canBus1_;
};

/*
template<class T, typename... Args>
Buffer<T>* invoke_flow(FlowInterface<Buffer<T>>* flow, Args... args) {
    Buffer<T>* b = flow->alloc();
    b->data()->reset();
    }*/

namespace nmranet
{

static const NodeID TEST_NODE_ID = 0x02010d000003ULL;

/** Test fixture base class with helper methods for exercising the asynchronous
 * interface code.
 *
 * Usage:
 *
 * Inherit your test fixture class from AsyncIfTest.
 */
class AsyncIfTest : public AsyncCanTest
{
protected:
    AsyncIfTest()
        : pendingAliasAllocation_(false)
    {
        ifCan_.reset(new IfCan(&g_executor, &can_hub0, 10, 10, 9));
        ifCan_->local_aliases()->add(TEST_NODE_ID, 0x22A);
    }

    ~AsyncIfTest()
    {
        wait();
        if (pendingAliasAllocation_)
        {
            ifCan_->alias_allocator()->TEST_finish_pending_allocation();
            wait();
        }
    }

    friend class ::TrainTestHelper;

    /** Creates an alias allocator flow, and injects an already allocated
     *  alias. */
    void create_allocated_alias()
    {
        inject_allocated_alias(0x33A, true);
        aliasSeed_ = 0x44C;
        pendingAliasAllocation_ = false;
    }

    void inject_allocated_alias(NodeAlias alias, bool repeat = false)
    {
        if (!ifCan_->alias_allocator()) {
            ifCan_->set_alias_allocator(
                new AliasAllocator(TEST_NODE_ID, ifCan_.get()));
        }
        Buffer<AliasInfo> *a;
        mainBufferPool->alloc(&a);
        a->data()->reset();
        a->data()->alias = alias;
        a->data()->state = AliasInfo::STATE_RESERVED;
        if (!repeat) {
            a->data()->do_not_reallocate();
        }
        ifCan_->local_aliases()->add(AliasCache::RESERVED_ALIAS_NODE_ID,
                                     a->data()->alias);
        ifCan_->alias_allocator()->reserved_aliases()->insert(a);
    }

    void expect_next_alias_allocation(NodeAlias a = 0)
    {
        pendingAliasAllocation_ = true;
        if (!a)
        {
            ifCan_->alias_allocator()->seed_ = aliasSeed_;
            a = aliasSeed_;
            aliasSeed_++;
        }
        EXPECT_CALL(canBus_, mwrite(StringPrintf(":X17020%03XN;", a)))
            .Times(1)
            .RetiresOnSaturation();
        EXPECT_CALL(canBus_, mwrite(StringPrintf(":X1610D%03XN;", a)))
            .Times(1)
            .RetiresOnSaturation();
        EXPECT_CALL(canBus_, mwrite(StringPrintf(":X15000%03XN;", a)))
            .Times(1)
            .RetiresOnSaturation();
        EXPECT_CALL(canBus_, mwrite(StringPrintf(":X14003%03XN;", a)))
            .Times(1)
            .RetiresOnSaturation();

        EXPECT_CALL(canBus_, mwrite(StringPrintf(":X10700%03XN;", a)))
            .Times(AtMost(1))
            .RetiresOnSaturation();
    }

    BarrierNotifiable *get_notifiable()
    {
        bn_.reset(&n_);
        return &bn_;
    }

    void wait_for_notification()
    {
        n_.wait_for_notification();
    }

    SyncNotifiable n_;
    BarrierNotifiable bn_;

    /// The interface under test.
    std::unique_ptr<IfCan> ifCan_;
    /** Temporary object used to send aliases around in the alias allocator
     *  flow. */
    AliasInfo testAlias_;
    /// The next alias we will make the allocator create.
    NodeAlias aliasSeed_;
    /// true if we have a pending async alias allocation task.
    bool pendingAliasAllocation_;
};

/// Base class for test cases with one virtual node on a CANbus interface.
class AsyncNodeTest : public AsyncIfTest
{
protected:
    AsyncNodeTest()
        : eventService_(ifCan_.get())
    {
        EXPECT_CALL(canBus_, mwrite(":X1910022AN02010D000003;")).Times(1);
        ownedNode_.reset(new DefaultNode(ifCan_.get(), TEST_NODE_ID));
        node_ = ownedNode_.get();
        ifCan_->add_addressed_message_support();
        wait();
        Mock::VerifyAndClear(&canBus_);
        // AddEventHandlerToIf(ifCan_.get());
    }

    ~AsyncNodeTest()
    {
        wait_for_event_thread();
    }

    void wait_for_event_thread()
    {
        while (EventService::instance->event_processing_pending())
        {
#ifdef __EMSCRIPTEN__
            os_emscripten_yield();
#else
            usleep(100);
#endif
        }
        AsyncIfTest::wait();
    }

    EventService eventService_;
    std::unique_ptr<DefaultNode> ownedNode_;
    Node *node_;
};

/// Test handler for receiving incoming nmranet Message objects from a bus. The
/// incoming messages need GoogleMock expectations.
///
/// Usage: see file src/nmranet/IfCan.cxxtest
class MockMessageHandler : public MessageHandler
{
public:
    MOCK_METHOD2(handle_message,
                 void(NMRAnetMessage *message, unsigned priority));
    virtual void send(Buffer<NMRAnetMessage> *message, unsigned priority)
    {
        handle_message(message->data(), priority);
        message->unref();
    }
};

/// GoogleMock matcher on a Payload being equal to a given 64-bit value in
/// network byte order. (Typically an event id.)
MATCHER_P(IsBufferValue, id, "")
{
    uint64_t value = htobe64(id);
    if (arg.size() != 8)
        return false;
    if (memcmp(&value, arg.data(), 8))
        return false;
    return true;
}

/// GoogleMock matcher on a Payload being equal to a given string (C or C++
/// style).
MATCHER_P(IsBufferValueString, expected, "")
{
    string s(expected);
    return arg == s;
}

/// GoogleMock matcher on a Payload being equal to a given 48-bit value in
/// network byte order (typically a Node ID).
MATCHER_P(IsBufferNodeValue, id, "")
{
    uint64_t value = htobe64(id);
    if (arg->used() != 6)
        return false;
    uint8_t *expected = reinterpret_cast<uint8_t *>(&value) + 2;
    uint8_t *actual = static_cast<uint8_t *>(arg->start());
    if (memcmp(expected, actual, 6))
    {
        for (int i = 0; i < 6; ++i)
        {
            if (expected[i] != actual[i])
            {
                LOG(INFO, "mismatch at position %d, expected %02x actual %02x",
                    i, expected[i], actual[i]);
            }
        }
        return false;
    }
    return true;
}

/// GoogleMock matcher on a Payload being equal to a given 6-byte string.
MATCHER_P(IsBufferNodeValueString, id, "")
{
    uint64_t value = htobe64(id);
    if (arg.size() != 6)
        return false;
    uint8_t *expected = reinterpret_cast<uint8_t *>(&value) + 2;
    uint8_t *actual = static_cast<uint8_t *>(arg->start());
    if (memcmp(expected, actual, 6))
    {
        for (int i = 0; i < 6; ++i)
        {
            if (expected[i] != actual[i])
            {
                LOG(INFO, "mismatch at position %d, expected %02x actual %02x",
                    i, expected[i], actual[i]);
            }
        }
        return false;
    }
    return true;
}

} // namespace nmranet

#endif // _UTILS_ASYNC_IF_TEST_HELPER_HXX_
<|endoftext|>