<commit_before>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include <cctype>
#include <algorithm>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

namespace
{

	using namespace libtorrent;

	int decode_digit(char c)
	{
		if (std::isdigit(c)) return c - '0';
		return unsigned(c) - 'A' + 10;
	}

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (id[0] != '-' || !std::isprint(id[1]) || (id[2] < '0')
			|| (id[3] < '0') || (id[4] < '0')
			|| (id[5] < '0') || (id[6] < '0')
			|| id[7] != '-')
			return boost::optional<fingerprint>();

		ret.name[0] = id[1];
		ret.name[1] = id[2];
		ret.major_version = decode_digit(id[3]);
		ret.minor_version = decode_digit(id[4]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = decode_digit(id[6]);

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (!std::isalnum(id[0]))
			return boost::optional<fingerprint>();

		if (std::equal(id.begin()+4, id.begin()+6, "--"))
		{
			if ((id[1] < '0') || (id[2] < '0')
				|| (id[3] < '0'))
				return boost::optional<fingerprint>();
			ret.major_version = decode_digit(id[1]);
			ret.minor_version = decode_digit(id[2]);
			ret.revision_version = decode_digit(id[3]);
		}
		else
		{
			if (id[8] != 0 || id[1] > 127 || id[2] > 127 || id[3] > 127)
				return boost::optional<fingerprint>();
			ret.major_version = id[1];
			ret.minor_version = id[2];
			ret.revision_version = id[3];
		}

		ret.name[0] = id[0];
		ret.name[1] = 0;

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		char ids[21];
		std::copy(id.begin(), id.end(), ids);
		ids[20] = 0;
		fingerprint ret("..", 0, 0, 0, 0);
		ret.name[1] = 0;
		ret.tag_version = 0;
		if (sscanf(ids, "%c%d-%d-%d--", &ret.name[0], &ret.major_version, &ret.minor_version
			, &ret.revision_version) != 4
			|| !std::isprint(ret.name[0]))
			return boost::optional<fingerprint>();

		return boost::optional<fingerprint>(ret);
	}

	struct map_entry
	{
		char const* id;
		char const* name;
	};

	// only support BitTorrentSpecification
	// must be ordered alphabetically
	map_entry name_map[] =
	{
		{"A",  "ABC"}
		, {"AG",  "Ares"}
		, {"AR", "Arctic Torrent"}
		, {"AV", "Avicora"}
		, {"AX", "BitPump"}
		, {"AZ", "Azureus"}
		, {"A~",  "Ares"}
		, {"BB", "BitBuddy"}
		, {"BC", "BitComet"}
		, {"BF", "Bitflu"}
		, {"BG", "BTG"}
		, {"BR", "BitRocket"}
		, {"BS", "BTSlave"}
		, {"BX", "BittorrentX"}
		, {"CD", "Enhanced CTorrent"}
		, {"CT", "CTorrent"}
		, {"DE", "Deluge Torrent"}
		, {"EB", "EBit"}
		, {"ES", "electric sheep"}
		, {"HL", "Halite"}
		, {"HN", "Hydranode"}
		, {"KT", "KTorrent"}
		, {"LK", "Linkage"}
		, {"LP", "lphant"}
		, {"LT", "libtorrent"}
		, {"M",  "Mainline"}
		, {"ML", "MLDonkey"}
		, {"MO", "Mono Torrent"}
		, {"MP", "MooPolice"}
		, {"MT", "Moonlight Torrent"}
		, {"O",  "Osprey Permaseed"}
		, {"PD",  "Pando"}
		, {"Q", "BTQueue"}
		, {"QT", "Qt 4"}
		, {"R",  "Tribler"}
		, {"S",  "Shadow"}
		, {"SB", "Swiftbit"}
		, {"SN", "ShareNet"}
		, {"SS", "SwarmScope"}
		, {"ST", "SymTorrent"}
		, {"SZ", "Shareaza"}
		, {"S~",  "Shareaza (beta)"}
		, {"T",  "BitTornado"}
		, {"TN", "Torrent.NET"}
		, {"TR", "Transmission"}
		, {"TS", "TorrentStorm"}
		, {"TT", "TuoTu"}
		, {"U",  "UPnP"}
		, {"UL", "uLeecher"}
		, {"UT", "uTorrent"}
		, {"XL", "Xunlei"}
		, {"XT", "XanTorrent"}
		, {"XX", "Xtorrent"}
		, {"ZT", "ZipTorrent"}
		, {"lt", "rTorrent"}
		, {"pX", "pHoeniX"}
		, {"qB", "qBittorrent"}
		, {"st", "SharkTorrent"}
	};

	struct generic_map_entry
	{
		int offset;
		char const* id;
		char const* name;
	};
	// non-standard names
	generic_map_entry generic_mappings[] =
	{
		{0, "Deadman Walking-", "Deadman"}
		, {5, "Azureus", "Azureus 2.0.3.2"}
		, {0, "DansClient", "XanTorrent"}
		, {4, "btfans", "SimpleBT"}
		, {0, "PRC.P---", "Bittorrent Plus! II"}
		, {0, "P87.P---", "Bittorrent Plus!"}
		, {0, "S587Plus", "Bittorrent Plus!"}
		, {0, "martini", "Martini Man"}
		, {0, "Plus---", "Bittorrent Plus"}
		, {0, "turbobt", "TurboBT"}
		, {0, "a00---0", "Swarmy"}
		, {0, "a02---0", "Swarmy"}
		, {0, "T00---0", "Teeweety"}
		, {0, "BTDWV-", "Deadman Walking"}
		, {2, "BS", "BitSpirit"}
		, {0, "Pando-", "Pando"}
		, {0, "LIME", "LimeWire"}
		, {0, "btuga", "BTugaXP"}
		, {0, "oernu", "BTugaXP"}
		, {0, "Mbrst", "Burst!"}
		, {0, "PEERAPP", "PeerApp"}
		, {0, "Plus", "Plus!"}
		, {0, "-Qt-", "Qt"}
		, {0, "exbc", "BitComet"}
		, {0, "DNA", "BitTorrent DNA"}
		, {0, "-G3", "G3 Torrent"}
		, {0, "-FG", "FlashGet"}
		, {0, "-ML", "MLdonkey"}
		, {0, "XBT", "XBT"}
		, {0, "OP", "Opera"}
		, {2, "RS", "Rufus"}
		, {0, "AZ2500BT", "BitTyrant"}
	};

	bool compare_id(map_entry const& lhs, map_entry const& rhs)
	{
		return lhs.id[0] < rhs.id[0]
			|| ((lhs.id[0] == rhs.id[0]) && (lhs.id[1] < rhs.id[1]));
	}

	std::string lookup(fingerprint const& f)
	{
		std::stringstream identity;

		const int size = sizeof(name_map)/sizeof(name_map[0]);
		map_entry tmp = {f.name, ""};
		map_entry* i =
			std::lower_bound(name_map, name_map + size
				, tmp, &compare_id);

#ifndef NDEBUG
		for (int i = 1; i < size; ++i)
		{
			TORRENT_ASSERT(compare_id(name_map[i-1]
				, name_map[i]));
		}
#endif

		if (i < name_map + size && std::equal(f.name, f.name + 2, i->id))
			identity << i->name;
		else
		{
			identity << f.name[0];
			if (f.name[1] != 0) identity << f.name[1];
		}

		identity << " " << (int)f.major_version
			<< "." << (int)f.minor_version
			<< "." << (int)f.revision_version;

		if (f.name[1] != 0)
			identity << "." << (int)f.tag_version;

		return identity.str();
	}

	bool find_string(unsigned char const* id, char const* search)
	{
		return std::equal(search, search + std::strlen(search), id);
	}
}

namespace libtorrent
{

	boost::optional<fingerprint> client_fingerprint(peer_id const& p)
	{
		// look for azureus style id
		boost::optional<fingerprint> f;
		f = parse_az_style(p);
		if (f) return f;

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return f;

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return f;
		return f;
	}

	std::string identify_client(peer_id const& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unknown";

		// ----------------------
		// non standard encodings
		// ----------------------

		int num_generic_mappings = sizeof(generic_mappings) / sizeof(generic_mappings[0]);

		for (int i = 0; i < num_generic_mappings; ++i)
		{
			generic_map_entry const& e = generic_mappings[i];
			if (find_string(PID + e.offset, e.id)) return e.name;
		}

		if (find_string(PID, "-BOW") && PID[7] == '-')
			return "Bits on Wheels " + std::string(PID + 4, PID + 7);

		if (find_string(PID, "eX"))
		{
			std::string user(PID + 2, PID + 14);
			return std::string("eXeem ('") + user.c_str() + "')";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
			return "Experimental 3.2.1b2";

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Experimental 3.1";

		// look for azureus style id
		f = parse_az_style(p);
		if (f) return lookup(*f);

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return lookup(*f);

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return lookup(*f);

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Generic";

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<commit_msg>added Miro to the identifiable clients<commit_after>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include <cctype>
#include <algorithm>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

namespace
{

	using namespace libtorrent;

	int decode_digit(char c)
	{
		if (std::isdigit(c)) return c - '0';
		return unsigned(c) - 'A' + 10;
	}

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (id[0] != '-' || !std::isprint(id[1]) || (id[2] < '0')
			|| (id[3] < '0') || (id[4] < '0')
			|| (id[5] < '0') || (id[6] < '0')
			|| id[7] != '-')
			return boost::optional<fingerprint>();

		ret.name[0] = id[1];
		ret.name[1] = id[2];
		ret.major_version = decode_digit(id[3]);
		ret.minor_version = decode_digit(id[4]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = decode_digit(id[6]);

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (!std::isalnum(id[0]))
			return boost::optional<fingerprint>();

		if (std::equal(id.begin()+4, id.begin()+6, "--"))
		{
			if ((id[1] < '0') || (id[2] < '0')
				|| (id[3] < '0'))
				return boost::optional<fingerprint>();
			ret.major_version = decode_digit(id[1]);
			ret.minor_version = decode_digit(id[2]);
			ret.revision_version = decode_digit(id[3]);
		}
		else
		{
			if (id[8] != 0 || id[1] > 127 || id[2] > 127 || id[3] > 127)
				return boost::optional<fingerprint>();
			ret.major_version = id[1];
			ret.minor_version = id[2];
			ret.revision_version = id[3];
		}

		ret.name[0] = id[0];
		ret.name[1] = 0;

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		char ids[21];
		std::copy(id.begin(), id.end(), ids);
		ids[20] = 0;
		fingerprint ret("..", 0, 0, 0, 0);
		ret.name[1] = 0;
		ret.tag_version = 0;
		if (sscanf(ids, "%c%d-%d-%d--", &ret.name[0], &ret.major_version, &ret.minor_version
			, &ret.revision_version) != 4
			|| !std::isprint(ret.name[0]))
			return boost::optional<fingerprint>();

		return boost::optional<fingerprint>(ret);
	}

	struct map_entry
	{
		char const* id;
		char const* name;
	};

	// only support BitTorrentSpecification
	// must be ordered alphabetically
	map_entry name_map[] =
	{
		{"A",  "ABC"}
		, {"AG",  "Ares"}
		, {"AR", "Arctic Torrent"}
		, {"AV", "Avicora"}
		, {"AX", "BitPump"}
		, {"AZ", "Azureus"}
		, {"A~",  "Ares"}
		, {"BB", "BitBuddy"}
		, {"BC", "BitComet"}
		, {"BF", "Bitflu"}
		, {"BG", "BTG"}
		, {"BR", "BitRocket"}
		, {"BS", "BTSlave"}
		, {"BX", "BittorrentX"}
		, {"CD", "Enhanced CTorrent"}
		, {"CT", "CTorrent"}
		, {"DE", "Deluge Torrent"}
		, {"EB", "EBit"}
		, {"ES", "electric sheep"}
		, {"HL", "Halite"}
		, {"HN", "Hydranode"}
		, {"KT", "KTorrent"}
		, {"LK", "Linkage"}
		, {"LP", "lphant"}
		, {"LT", "libtorrent"}
		, {"M",  "Mainline"}
		, {"ML", "MLDonkey"}
		, {"MO", "Mono Torrent"}
		, {"MP", "MooPolice"}
		, {"MR", "Miro"}
		, {"MT", "Moonlight Torrent"}
		, {"O",  "Osprey Permaseed"}
		, {"PD",  "Pando"}
		, {"Q", "BTQueue"}
		, {"QT", "Qt 4"}
		, {"R",  "Tribler"}
		, {"S",  "Shadow"}
		, {"SB", "Swiftbit"}
		, {"SN", "ShareNet"}
		, {"SS", "SwarmScope"}
		, {"ST", "SymTorrent"}
		, {"SZ", "Shareaza"}
		, {"S~",  "Shareaza (beta)"}
		, {"T",  "BitTornado"}
		, {"TN", "Torrent.NET"}
		, {"TR", "Transmission"}
		, {"TS", "TorrentStorm"}
		, {"TT", "TuoTu"}
		, {"U",  "UPnP"}
		, {"UL", "uLeecher"}
		, {"UT", "uTorrent"}
		, {"XL", "Xunlei"}
		, {"XT", "XanTorrent"}
		, {"XX", "Xtorrent"}
		, {"ZT", "ZipTorrent"}
		, {"lt", "rTorrent"}
		, {"pX", "pHoeniX"}
		, {"qB", "qBittorrent"}
		, {"st", "SharkTorrent"}
	};

	struct generic_map_entry
	{
		int offset;
		char const* id;
		char const* name;
	};
	// non-standard names
	generic_map_entry generic_mappings[] =
	{
		{0, "Deadman Walking-", "Deadman"}
		, {5, "Azureus", "Azureus 2.0.3.2"}
		, {0, "DansClient", "XanTorrent"}
		, {4, "btfans", "SimpleBT"}
		, {0, "PRC.P---", "Bittorrent Plus! II"}
		, {0, "P87.P---", "Bittorrent Plus!"}
		, {0, "S587Plus", "Bittorrent Plus!"}
		, {0, "martini", "Martini Man"}
		, {0, "Plus---", "Bittorrent Plus"}
		, {0, "turbobt", "TurboBT"}
		, {0, "a00---0", "Swarmy"}
		, {0, "a02---0", "Swarmy"}
		, {0, "T00---0", "Teeweety"}
		, {0, "BTDWV-", "Deadman Walking"}
		, {2, "BS", "BitSpirit"}
		, {0, "Pando-", "Pando"}
		, {0, "LIME", "LimeWire"}
		, {0, "btuga", "BTugaXP"}
		, {0, "oernu", "BTugaXP"}
		, {0, "Mbrst", "Burst!"}
		, {0, "PEERAPP", "PeerApp"}
		, {0, "Plus", "Plus!"}
		, {0, "-Qt-", "Qt"}
		, {0, "exbc", "BitComet"}
		, {0, "DNA", "BitTorrent DNA"}
		, {0, "-G3", "G3 Torrent"}
		, {0, "-FG", "FlashGet"}
		, {0, "-ML", "MLdonkey"}
		, {0, "XBT", "XBT"}
		, {0, "OP", "Opera"}
		, {2, "RS", "Rufus"}
		, {0, "AZ2500BT", "BitTyrant"}
	};

	bool compare_id(map_entry const& lhs, map_entry const& rhs)
	{
		return lhs.id[0] < rhs.id[0]
			|| ((lhs.id[0] == rhs.id[0]) && (lhs.id[1] < rhs.id[1]));
	}

	std::string lookup(fingerprint const& f)
	{
		std::stringstream identity;

		const int size = sizeof(name_map)/sizeof(name_map[0]);
		map_entry tmp = {f.name, ""};
		map_entry* i =
			std::lower_bound(name_map, name_map + size
				, tmp, &compare_id);

#ifndef NDEBUG
		for (int i = 1; i < size; ++i)
		{
			TORRENT_ASSERT(compare_id(name_map[i-1]
				, name_map[i]));
		}
#endif

		if (i < name_map + size && std::equal(f.name, f.name + 2, i->id))
			identity << i->name;
		else
		{
			identity << f.name[0];
			if (f.name[1] != 0) identity << f.name[1];
		}

		identity << " " << (int)f.major_version
			<< "." << (int)f.minor_version
			<< "." << (int)f.revision_version;

		if (f.name[1] != 0)
			identity << "." << (int)f.tag_version;

		return identity.str();
	}

	bool find_string(unsigned char const* id, char const* search)
	{
		return std::equal(search, search + std::strlen(search), id);
	}
}

namespace libtorrent
{

	boost::optional<fingerprint> client_fingerprint(peer_id const& p)
	{
		// look for azureus style id
		boost::optional<fingerprint> f;
		f = parse_az_style(p);
		if (f) return f;

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return f;

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return f;
		return f;
	}

	std::string identify_client(peer_id const& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unknown";

		// ----------------------
		// non standard encodings
		// ----------------------

		int num_generic_mappings = sizeof(generic_mappings) / sizeof(generic_mappings[0]);

		for (int i = 0; i < num_generic_mappings; ++i)
		{
			generic_map_entry const& e = generic_mappings[i];
			if (find_string(PID + e.offset, e.id)) return e.name;
		}

		if (find_string(PID, "-BOW") && PID[7] == '-')
			return "Bits on Wheels " + std::string(PID + 4, PID + 7);

		if (find_string(PID, "eX"))
		{
			std::string user(PID + 2, PID + 14);
			return std::string("eXeem ('") + user.c_str() + "')";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
			return "Experimental 3.2.1b2";

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Experimental 3.1";

		// look for azureus style id
		f = parse_az_style(p);
		if (f) return lookup(*f);

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return lookup(*f);

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return lookup(*f);

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Generic";

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<|endoftext|>


<commit_before>/************************************************************************/
/*                                                                      */
/*               Copyright 2002 by Gunnar Kedenburg                     */
/*       Cognitive Systems Group, University of Hamburg, Germany        */
/*                                                                      */
/*    This file is part of the VIGRA computer vision library.           */
/*    The VIGRA Website is                                              */
/*        http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/      */
/*    Please direct questions, bug reports, and contributions to        */
/*        koethe@informatik.uni-hamburg.de          or                  */
/*        vigra@kogs1.informatik.uni-hamburg.de                         */
/*                                                                      */
/*    Permission is hereby granted, free of charge, to any person       */
/*    obtaining a copy of this software and associated documentation    */
/*    files (the "Software"), to deal in the Software without           */
/*    restriction, including without limitation the rights to use,      */
/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
/*    sell copies of the Software, and to permit persons to whom the    */
/*    Software is furnished to do so, subject to the following          */
/*    conditions:                                                       */
/*                                                                      */
/*    The above copyright notice and this permission notice shall be    */
/*    included in all copies or substantial portions of the             */
/*    Software.                                                         */
/*                                                                      */
/*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
/*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
/*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
/*                                                                      */
/************************************************************************/

#ifndef VIGRA_BYTEORDER_HXX
#define VIGRA_BYTEORDER_HXX

#include <vector>
#include <memory>
#include <string>
#include <fstream>
#include <algorithm>
#include "vigra/sized_int.hxx"

namespace vigra
{
    class byteorder
    {
        class host
        {
            std::string m_string;

        public:

            // ctor, dtor

            host();

            // methods

            const std::string & get() const;
        };

        // attributes

        static const host m_host;

        // data byte order, can be changed

        std::string m_string;
        bool native;

        // delegation methods

        template< class T >
        void reversebytes( T & x ) const
        {
            const unsigned int n = sizeof(T);
            UInt8 t[n];
            UInt8 * c = reinterpret_cast< UInt8 * >(&x);
            unsigned int i;
            for( i = 0; i < n; ++i )
                t[i] = c[ n - 1 - i ];
            for( i = 0; i < n; ++i )
                c[i] = t[i];
        }

    public:

        // ctor, dtor

        byteorder(); // uses the host byteorder
        byteorder( const std::string & );

        // methods

        void set( const std::string & );
        const std::string & get() const;
        const std::string & get_host_byteorder() const;

        template< class T >
        void convert_to_host( T & x ) const
        {
            if (!native)
                reversebytes(x);
        }

        template< class T >
        void convert_to_host( T * x, unsigned int num ) const
        {
            if (!native)
                for( unsigned int i = 0; i < num; ++i )
                    reversebytes(x[i]);
        }

        template< class T >
        void convert_from_host( T & x ) const
        {
            if (!native)
                reversebytes(x);
        }

        template< class T >
        void convert_from_host( T * x, unsigned int num ) const
        {
            if (!native)
                for( unsigned int i = 0; i < num; ++i )
                    reversebytes(x[i]);
        }

        void convert_to_host( char & x ) const {}
        void convert_to_host( Int8 & x ) const {}
        void convert_to_host( UInt8 & x ) const {}

        void convert_to_host( char * x , unsigned int) const {}
        void convert_to_host( Int8 * x, unsigned int) const {}
        void convert_to_host( UInt8 * x, unsigned int) const {}

        void convert_from_host( char & x ) const {}
        void convert_from_host( Int8 & x ) const {}
        void convert_from_host( UInt8 & x ) const {}

        void convert_from_host( char * x , unsigned int) const {}
        void convert_from_host( Int8 * x, unsigned int) const {}
        void convert_from_host( UInt8 * x, unsigned int) const {}
    };

    template< class T >
    void read_field( std::ifstream & stream, const byteorder & bo, T & x )
    {
        stream.read( reinterpret_cast< char * >(&x), sizeof(T) );
        bo.convert_to_host(x);
    }

    template< class T >
    void read_array( std::ifstream & stream, const byteorder & bo, T * x,
                     unsigned int num )
    {
        stream.read( reinterpret_cast< char * >(x), sizeof(T) * num );
        bo.convert_to_host( x, num );
    }

    template< class T >
    void write_field( std::ofstream & stream, const byteorder & bo, T t )
    {
        bo.convert_from_host(t);
        stream.write( reinterpret_cast< char * >(&t), sizeof(T) );
    }

    template< class T >
    void write_array( std::ofstream & stream, const byteorder & bo,
                      const T * x, unsigned int num )
    {
        for( unsigned int i = 0; i < num; ++i )
            write_field( stream, bo, x[i] );
    }

} // namespace vigra

#endif // VIGRA_BYTEORDER_HXX
<commit_msg>changed unsigned int => size_t<commit_after>/************************************************************************/
/*                                                                      */
/*               Copyright 2002 by Gunnar Kedenburg                     */
/*       Cognitive Systems Group, University of Hamburg, Germany        */
/*                                                                      */
/*    This file is part of the VIGRA computer vision library.           */
/*    The VIGRA Website is                                              */
/*        http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/      */
/*    Please direct questions, bug reports, and contributions to        */
/*        koethe@informatik.uni-hamburg.de          or                  */
/*        vigra@kogs1.informatik.uni-hamburg.de                         */
/*                                                                      */
/*    Permission is hereby granted, free of charge, to any person       */
/*    obtaining a copy of this software and associated documentation    */
/*    files (the "Software"), to deal in the Software without           */
/*    restriction, including without limitation the rights to use,      */
/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
/*    sell copies of the Software, and to permit persons to whom the    */
/*    Software is furnished to do so, subject to the following          */
/*    conditions:                                                       */
/*                                                                      */
/*    The above copyright notice and this permission notice shall be    */
/*    included in all copies or substantial portions of the             */
/*    Software.                                                         */
/*                                                                      */
/*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
/*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
/*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
/*                                                                      */
/************************************************************************/

#ifndef VIGRA_BYTEORDER_HXX
#define VIGRA_BYTEORDER_HXX

#include <vector>
#include <memory>
#include <string>
#include <fstream>
#include <algorithm>
#include "vigra/sized_int.hxx"

namespace vigra
{
    class byteorder
    {
        class host
        {
            std::string m_string;

        public:

            // ctor, dtor

            host();

            // methods

            const std::string & get() const;
        };

        // attributes

        static const host m_host;

        // data byte order, can be changed

        std::string m_string;
        bool native;

        // delegation methods

        template< class T >
        void reversebytes( T & x ) const
        {
            const size_t n = sizeof(T);
            UInt8 t[n];
            UInt8 * c = reinterpret_cast< UInt8 * >(&x);
            size_t i;
            for( i = 0; i < n; ++i )
                t[i] = c[ n - 1 - i ];
            for( i = 0; i < n; ++i )
                c[i] = t[i];
        }

    public:

        // ctor, dtor

        byteorder(); // uses the host byteorder
        byteorder( const std::string & );

        // methods

        void set( const std::string & );
        const std::string & get() const;
        const std::string & get_host_byteorder() const;

        template< class T >
        void convert_to_host( T & x ) const
        {
            if (!native)
                reversebytes(x);
        }

        template< class T >
        void convert_to_host( T * x, size_t num ) const
        {
            if (!native)
                for( size_t i = 0; i < num; ++i )
                    reversebytes(x[i]);
        }

        template< class T >
        void convert_from_host( T & x ) const
        {
            if (!native)
                reversebytes(x);
        }

        template< class T >
        void convert_from_host( T * x, size_t num ) const
        {
            if (!native)
                for( size_t i = 0; i < num; ++i )
                    reversebytes(x[i]);
        }

        void convert_to_host( char & x ) const {}
        void convert_to_host( Int8 & x ) const {}
        void convert_to_host( UInt8 & x ) const {}

        void convert_to_host( char * x , size_t) const {}
        void convert_to_host( Int8 * x, size_t) const {}
        void convert_to_host( UInt8 * x, size_t) const {}

        void convert_from_host( char & x ) const {}
        void convert_from_host( Int8 & x ) const {}
        void convert_from_host( UInt8 & x ) const {}

        void convert_from_host( char * x , size_t) const {}
        void convert_from_host( Int8 * x, size_t) const {}
        void convert_from_host( UInt8 * x, size_t) const {}
    };

    template< class T >
    void read_field( std::ifstream & stream, const byteorder & bo, T & x )
    {
        stream.read( reinterpret_cast< char * >(&x), sizeof(T) );
        bo.convert_to_host(x);
    }

    template< class T >
    void read_array( std::ifstream & stream, const byteorder & bo, T * x,
                     size_t num )
    {
        stream.read( reinterpret_cast< char * >(x), static_cast<std::streamsize>(sizeof(T) * num) );
        bo.convert_to_host( x, num );
    }

    template< class T >
    void write_field( std::ofstream & stream, const byteorder & bo, T t )
    {
        bo.convert_from_host(t);
        stream.write( reinterpret_cast< char * >(&t), sizeof(T) );
    }

    template< class T >
    void write_array( std::ofstream & stream, const byteorder & bo,
                      const T * x, size_t num )
    {
        for( size_t i = 0; i < num; ++i )
            write_field( stream, bo, x[i] );
    }

} // namespace vigra

#endif // VIGRA_BYTEORDER_HXX
<|endoftext|>


<commit_before>/**
 * PWM.cpp
 *
 * This implementation file contains the function implementation for the PWM
 * class in libbbbpwm.  This class encapsulates the fileops needed to activate
 * the PWM interface on the BeagleBone Black running the 3.8 kernel.
 *
 * Copyright (C) 2014 Nathan Hui <ntlhui@gmail.com> (408.838.5393)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the license, 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
 * USA
 */

// Includes
#include "PWM.hpp"

using namespace std;

// Internal Defines

PWM::PWM(const uint8_t pin, const uint32_t frequency){
	_pin = pin;

	_ocpDir = "/sys/devices/ocp.3";

	switch(pin){
		case 0:
			_ocpDir += "/pwm_test_P8_13.11";
			break;
		case 1:
			_ocpDir += "/pwm_test_P8_19.14";
			break;
		case 2:
			_ocpDir += "/pwm_test_P8_34.12";
			break;
		case 3:
			_ocpDir += "/pwm_test_P8_36.15";
			break;
		case 4:
			_ocpDir += "/pwm_test_P8_45.";	// TODO add suffix
			break;
		case 5:
			_ocpDir += "/pwm_test_P8_46.";	// TODO add suffix
			break;
		case 6:
			_ocpDir += "/pwm_test_P9_14.";	// TODO add suffix
			break;
		case 7:
			_ocpDir += "/pwm_test_P9_16.";	// TODO add suffix
			break;
		case 8:
			_ocpDir += "/pwm_test_P9_21.16";
			break;
		case 9:
			_ocpDir += "/pwm_test_P9_22.17";
			break;
		case 10:
			_ocpDir += "/pwm_test_P9_28.18";
			break;
		case 11:
			_ocpDir += "/pwm_test_P9_29.";	// TODO add suffix
			break;
		case 12:
			_ocpDir += "/pwm_test_P9_31.";	// TODO add suffix
			break;
		case 13:
			_ocpDir += "/pwm_Test_P9_42.19";
			break;
		default:
			assert(pin <= 13);
	}

	// Set initial frequency
	fstream freqFile (_ocpDir + "/period", fstream::out | fstream :: app);
	cout << _ocpDir << endl;
	assert(freqFile.good());

	_period = 1e9 / frequency;
	freqFile << _period;
	freqFile.close();
}

PWM::~PWM(){

}

void PWM::setDuty(const float dutyPercentage){
	assert(!_period);
	assert(dutyPercentage >= 1);

	_pulseWidth = dutyPercentage * _period;
	fstream file (_ocpDir + "/duty", fstream::out | fstream::app);
	if(file.bad()){
		throw runtime_error("Failed to open " + _ocpDir + "/duty!");
	}
	file << _pulseWidth << flush;
	if(file.bad()){
		throw runtime_error("Failed to write to " + _ocpDir + "/duty!");
	}
	file.close();
}

void PWM::setPeriod(const uint32_t period){
	assert(period >= 1000000000);
	_period = period;

	fstream file (_ocpDir + "/period", fstream::out | fstream::app);
	if(file.bad()){
		throw runtime_error("Failed to open " + _ocpDir + "/period!");
	}
	file << _period << flush;
	if(file.bad()){
		throw runtime_error("Failed to write to " + _ocpDir + "/period!");
	}
	file.close();
}

void PWM::setOnTime(const uint32_t onTime){
	cout << _period << endl;
	assert(_period > 0);
	assert(onTime < _period);

	_pulseWidth = onTime;
	fstream file(_ocpDir + "/duty", fstream::out | fstream::app);
	if(file.bad()){
		throw runtime_error("Failed to open " + _ocpDir + "/duty");
	}
	file << _pulseWidth << flush;
	if(file.bad()){
		throw runtime_error("Failed to write to " + _ocpDir + "/duty");
	}
	file.close();
}

void PWM::setPolarity(const bool polarity){
	_polarity = polarity;

	fstream file(_ocpDir + "/polarity", fstream::out | fstream::app);
	if(file.bad()){
		throw runtime_error("Failed to open " + _ocpDir + "/polarity");
	}
	file << _polarity << flush;
	if(file.bad()){
		throw runtime_error("Failed to write to " + _ocpDir + "/polarity");
	}
	file.close();
}
<commit_msg>Implemented setState<commit_after>/**
 * PWM.cpp
 *
 * This implementation file contains the function implementation for the PWM
 * class in libbbbpwm.  This class encapsulates the fileops needed to activate
 * the PWM interface on the BeagleBone Black running the 3.8 kernel.
 *
 * Copyright (C) 2014 Nathan Hui <ntlhui@gmail.com> (408.838.5393)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the license, 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
 * USA
 */

// Includes
#include "PWM.hpp"

using namespace std;

// Internal Defines

PWM::PWM(const uint8_t pin, const uint32_t frequency){
	_pin = pin;

	_ocpDir = "/sys/devices/ocp.3";

	switch(pin){
		case 0:
			_ocpDir += "/pwm_test_P8_13.11";
			break;
		case 1:
			_ocpDir += "/pwm_test_P8_19.14";
			break;
		case 2:
			_ocpDir += "/pwm_test_P8_34.12";
			break;
		case 3:
			_ocpDir += "/pwm_test_P8_36.15";
			break;
		case 4:
			_ocpDir += "/pwm_test_P8_45.";	// TODO add suffix
			break;
		case 5:
			_ocpDir += "/pwm_test_P8_46.";	// TODO add suffix
			break;
		case 6:
			_ocpDir += "/pwm_test_P9_14.";	// TODO add suffix
			break;
		case 7:
			_ocpDir += "/pwm_test_P9_16.";	// TODO add suffix
			break;
		case 8:
			_ocpDir += "/pwm_test_P9_21.16";
			break;
		case 9:
			_ocpDir += "/pwm_test_P9_22.17";
			break;
		case 10:
			_ocpDir += "/pwm_test_P9_28.18";
			break;
		case 11:
			_ocpDir += "/pwm_test_P9_29.";	// TODO add suffix
			break;
		case 12:
			_ocpDir += "/pwm_test_P9_31.";	// TODO add suffix
			break;
		case 13:
			_ocpDir += "/pwm_Test_P9_42.19";
			break;
		default:
			assert(pin <= 13);
	}

	// Set initial frequency
	fstream freqFile (_ocpDir + "/period", fstream::out | fstream :: app);
	cout << _ocpDir << endl;
	assert(freqFile.good());

	_period = 1e9 / frequency;
	freqFile << _period;
	freqFile.close();
}

PWM::~PWM(){

}

void PWM::setDuty(const float dutyPercentage){
	assert(!_period);
	assert(dutyPercentage >= 1);

	_pulseWidth = dutyPercentage * _period;
	fstream file (_ocpDir + "/duty", fstream::out | fstream::app);
	if(file.bad()){
		throw runtime_error("Failed to open " + _ocpDir + "/duty!");
	}
	file << _pulseWidth << flush;
	if(file.bad()){
		throw runtime_error("Failed to write to " + _ocpDir + "/duty!");
	}
	file.close();
}

void PWM::setPeriod(const uint32_t period){
	assert(period >= 1000000000);
	_period = period;

	fstream file (_ocpDir + "/period", fstream::out | fstream::app);
	if(file.bad()){
		throw runtime_error("Failed to open " + _ocpDir + "/period!");
	}
	file << _period << flush;
	if(file.bad()){
		throw runtime_error("Failed to write to " + _ocpDir + "/period!");
	}
	file.close();
}

void PWM::setOnTime(const uint32_t onTime){
	cout << _period << endl;
	assert(_period > 0);
	assert(onTime < _period);

	_pulseWidth = onTime;
	fstream file(_ocpDir + "/duty", fstream::out | fstream::app);
	if(file.bad()){
		throw runtime_error("Failed to open " + _ocpDir + "/duty");
	}
	file << _pulseWidth << flush;
	if(file.bad()){
		throw runtime_error("Failed to write to " + _ocpDir + "/duty");
	}
	file.close();
}

void PWM::setPolarity(const bool polarity){
	_polarity = polarity;

	fstream file(_ocpDir + "/polarity", fstream::out | fstream::app);
	if(file.bad()){
		throw runtime_error("Failed to open " + _ocpDir + "/polarity");
	}
	file << _polarity << flush;
	if(file.bad()){
		throw runtime_error("Failed to write to " + _ocpDir + "/polarity");
	}
	file.close();
}

void PWM::setState(const bool running){
	_running = running;

	fstream file(_ocpDir + "/run", fstream::out | fstream::app);
	if(file.bad()){
		throw runtime_error("Failed to open " + _ocpDir + "/run");
	}
	file << _running << flush;
	if(file.bad()){
		throw runtime_error("Failed to write to " + _ocpDir + "/run");
	}
	file.close();
}
<|endoftext|>


<commit_before>/* Siconos-Kernel, Copyright INRIA 2005-2010.
 * Siconos is a program dedicated to modeling, simulation and control
 * of non smooth dynamical systems.
 * Siconos is a 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.
 * Siconos 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 Siconos; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Contact: Vincent ACARY, siconos-team@lists.gforge.inria.fr
 */

#include "NewtonEulerRFC3D.hpp"
#include "NewtonEulerDS.hpp"
#include <boost/math/quaternion.hpp>
using namespace std;
//#define NEFC3D_DEBUG
/*
  See devNotes.pdf for details.
 */
void NewtonEulerRFC3D::initComponents()
{
  NewtonEulerRImpact::initComponents();
  /*keep only the distance.*/
  /*Warning, in current version, user of FC3D has to set _y and _yProj in the computeh */
  _yProj.reset(new SimpleVector(1));
  _Mabs_C.reset(new SimpleMatrix(3, 3));
  _AUX2.reset(new SimpleMatrix(3, 3));
}
void NewtonEulerRFC3D::FC3DcomputeJachqTFromContacts(SP::NewtonEulerDS d1)
{

  double Nx = _Nc->getValue(0);
  double Ny = _Nc->getValue(1);
  double Nz = _Nc->getValue(2);
  double Px = _Pc1->getValue(0);
  double Py = _Pc1->getValue(1);
  double Pz = _Pc1->getValue(2);
  double G1x = d1->q()->getValue(0);
  double G1y = d1->q()->getValue(1);
  double G1z = d1->q()->getValue(2);
#ifdef NEFC3D_DEBUG
  printf("contact normal:\n");
  _Nc->display();
  printf("point de contact :\n");
  _Pc1->display();
  printf("center of masse :\n");
  d1->q()->display();
#endif
  double t[6];
  double * pt = t;
  orthoBaseFromVector(&Nx, &Ny, &Nz, pt, pt + 1, pt + 2, pt + 3, pt + 4, pt + 5);
  pt = t;
  _Mabs_C->setValue(0, 0, Nx);
  _Mabs_C->setValue(1, 0, *pt);
  _Mabs_C->setValue(2, 0, *(pt + 3));
  _Mabs_C->setValue(0, 1, Ny);
  _Mabs_C->setValue(1, 1, *(pt + 1));
  _Mabs_C->setValue(2, 1, *(pt + 4));
  _Mabs_C->setValue(0, 2, Nz);
  _Mabs_C->setValue(1, 2, *(pt + 2));
  _Mabs_C->setValue(2, 2, *(pt + 5));
#ifdef NEFC3D_DEBUG
  printf("_Mabs_C:\n");
  _Mabs_C->display();
#endif
  _NPG1->zero();

  (*_NPG1)(0, 0) = 0;
  (*_NPG1)(0, 1) = -(G1z - Pz);
  (*_NPG1)(0, 2) = (G1y - Py);
  (*_NPG1)(1, 0) = (G1z - Pz);
  (*_NPG1)(1, 1) = 0;
  (*_NPG1)(1, 2) = -(G1x - Px);
  (*_NPG1)(2, 0) = -(G1y - Py);
  (*_NPG1)(2, 1) = (G1x - Px);
  (*_NPG1)(2, 2) = 0;

  d1->updateMObjToAbs();
  SP::SimpleMatrix Mobj1_abs = d1->MObjToAbs();

#ifdef NEFC3D_DEBUG
  printf("NewtonEulerRFC3D::FC3DcomputeJachqTFromContacts, Mobj1_abs:");
  Mobj1_abs->display();
#endif

  prod(*_NPG1, *Mobj1_abs, *_AUX1, true);
  prod(*_Mabs_C, *_AUX1, *_AUX2, true);

  for (unsigned int ii = 0; ii < 3; ii++)
    for (unsigned int jj = 0; jj < 3; jj++)
      _jachqT->setValue(ii, jj, _Mabs_C->getValue(ii, jj));

  for (unsigned int ii = 0; ii < 3; ii++)
    for (unsigned int jj = 3; jj < 6; jj++)
      _jachqT->setValue(ii, jj, _AUX2->getValue(ii, jj - 3));
#ifdef NEFC3D_DEBUG
  printf("NewtonEulerRFC3D::FC3DcomputeJachqTFromContacts, jhqT:\n");
  _jachqT->display();
  SP::SimpleMatrix jaux(new SimpleMatrix(*jhqT));
  jaux->trans();
  SP::SimpleVector v(new SimpleVector(3));
  SP::SimpleVector vRes(new SimpleVector(6));
  v->zero();
  v->setValue(0, 1);
  prod(*jaux, *v, *vRes, true);
  vRes->display();
  v->zero();
  v->setValue(1, 1);
  prod(*jaux, *v, *vRes, true);
  vRes->display();
  v->zero();
  v->setValue(2, 1);
  prod(*jaux, *v, *vRes, true);
  vRes->display();
#endif
}

void NewtonEulerRFC3D::FC3DcomputeJachqTFromContacts(SP::NewtonEulerDS d1, SP::NewtonEulerDS d2)
{
  double Nx = _Nc->getValue(0);
  double Ny = _Nc->getValue(1);
  double Nz = _Nc->getValue(2);
  double Px = _Pc1->getValue(0);
  double Py = _Pc1->getValue(1);
  double Pz = _Pc1->getValue(2);
  double G1x = d1->q()->getValue(0);
  double G1y = d1->q()->getValue(1);
  double G1z = d1->q()->getValue(2);

  double t[6];
  double * pt = t;
  orthoBaseFromVector(&Nx, &Ny, &Nz, pt, pt + 1, pt + 2, pt + 3, pt + 4, pt + 5);
  pt = t;
  _Mabs_C->setValue(0, 0, Nx);
  _Mabs_C->setValue(1, 0, *pt);
  _Mabs_C->setValue(2, 0, *(pt + 3));
  _Mabs_C->setValue(0, 1, Ny);
  _Mabs_C->setValue(1, 1, *(pt + 1));
  _Mabs_C->setValue(2, 1, *(pt + 4));
  _Mabs_C->setValue(0, 2, Nz);
  _Mabs_C->setValue(1, 2, *(pt + 2));
  _Mabs_C->setValue(2, 2, *(pt + 5));

  _NPG1->zero();

  (*_NPG1)(0, 0) = 0;
  (*_NPG1)(0, 1) = -(G1z - Pz);
  (*_NPG1)(0, 2) = (G1y - Py);
  (*_NPG1)(1, 0) = (G1z - Pz);
  (*_NPG1)(1, 1) = 0;
  (*_NPG1)(1, 2) = -(G1x - Px);
  (*_NPG1)(2, 0) = -(G1y - Py);
  (*_NPG1)(2, 1) = (G1x - Px);
  (*_NPG1)(2, 2) = 0;

  d1->updateMObjToAbs();
  SP::SimpleMatrix Mobj1_abs = d1->MObjToAbs();

  prod(*_NPG1, *Mobj1_abs, *_AUX1, true);
  prod(*_Mabs_C, *_AUX1, *_AUX2, true);

  for (unsigned int ii = 0; ii < 3; ii++)
    for (unsigned int jj = 0; jj < 3; jj++)
      _jachqT->setValue(ii, jj, _Mabs_C->getValue(ii, jj));

  for (unsigned int ii = 0; ii < 3; ii++)
    for (unsigned int jj = 3; jj < 6; jj++)
      _jachqT->setValue(ii, jj, _AUX2->getValue(ii, jj - 3));

  d2->updateMObjToAbs();
  SP::SimpleMatrix Mobj2_abs = d1->MObjToAbs();

  prod(*_NPG2, *Mobj2_abs, *_AUX1, true);
  prod(*_Mabs_C, *_AUX1, *_AUX2, true);

  for (unsigned int ii = 0; ii < 3; ii++)
    for (unsigned int jj = 0; jj < 3; jj++)
      _jachqT->setValue(ii, jj + 6, -_Mabs_C->getValue(ii, jj));

  for (unsigned int ii = 0; ii < 3; ii++)
    for (unsigned int jj = 3; jj < 6; jj++)
      _jachqT->setValue(ii, jj + 6, -_AUX2->getValue(ii, jj - 3));

}
void NewtonEulerRFC3D::computeJachqT()
{
  DSIterator itDS = interaction()->dynamicalSystemsBegin();
  SP::NewtonEulerDS d1 =  boost::static_pointer_cast<NewtonEulerDS> (*itDS);
  itDS++;
  if (itDS != interaction()->dynamicalSystemsEnd())
  {
    SP::NewtonEulerDS d2 =  boost::static_pointer_cast<NewtonEulerDS> (*itDS);
    FC3DcomputeJachqTFromContacts(d1, d2);
  }
  else
  {
    FC3DcomputeJachqTFromContacts(d1);
  }
}
<commit_msg>Fix a Bug: missing a part of nablaqT when two bodies collide<commit_after>/* Siconos-Kernel, Copyright INRIA 2005-2010.
 * Siconos is a program dedicated to modeling, simulation and control
 * of non smooth dynamical systems.
 * Siconos is a 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.
 * Siconos 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 Siconos; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Contact: Vincent ACARY, siconos-team@lists.gforge.inria.fr
 */

#include "NewtonEulerRFC3D.hpp"
#include "NewtonEulerDS.hpp"
#include <boost/math/quaternion.hpp>
using namespace std;
//#define NEFC3D_DEBUG
/*
  See devNotes.pdf for details.
 */
void NewtonEulerRFC3D::initComponents()
{
  NewtonEulerRImpact::initComponents();
  /*keep only the distance.*/
  /*Warning, in current version, user of FC3D has to set _y and _yProj in the computeh */
  _yProj.reset(new SimpleVector(1));
  _Mabs_C.reset(new SimpleMatrix(3, 3));
  _AUX2.reset(new SimpleMatrix(3, 3));
}
void NewtonEulerRFC3D::FC3DcomputeJachqTFromContacts(SP::NewtonEulerDS d1)
{

  double Nx = _Nc->getValue(0);
  double Ny = _Nc->getValue(1);
  double Nz = _Nc->getValue(2);
  double Px = _Pc1->getValue(0);
  double Py = _Pc1->getValue(1);
  double Pz = _Pc1->getValue(2);
  double G1x = d1->q()->getValue(0);
  double G1y = d1->q()->getValue(1);
  double G1z = d1->q()->getValue(2);
#ifdef NEFC3D_DEBUG
  printf("contact normal:\n");
  _Nc->display();
  printf("point de contact :\n");
  _Pc1->display();
  printf("center of masse :\n");
  d1->q()->display();
#endif
  double t[6];
  double * pt = t;
  orthoBaseFromVector(&Nx, &Ny, &Nz, pt, pt + 1, pt + 2, pt + 3, pt + 4, pt + 5);
  pt = t;
  _Mabs_C->setValue(0, 0, Nx);
  _Mabs_C->setValue(1, 0, *pt);
  _Mabs_C->setValue(2, 0, *(pt + 3));
  _Mabs_C->setValue(0, 1, Ny);
  _Mabs_C->setValue(1, 1, *(pt + 1));
  _Mabs_C->setValue(2, 1, *(pt + 4));
  _Mabs_C->setValue(0, 2, Nz);
  _Mabs_C->setValue(1, 2, *(pt + 2));
  _Mabs_C->setValue(2, 2, *(pt + 5));
#ifdef NEFC3D_DEBUG
  printf("_Mabs_C:\n");
  _Mabs_C->display();
#endif
  _NPG1->zero();

  (*_NPG1)(0, 0) = 0;
  (*_NPG1)(0, 1) = -(G1z - Pz);
  (*_NPG1)(0, 2) = (G1y - Py);
  (*_NPG1)(1, 0) = (G1z - Pz);
  (*_NPG1)(1, 1) = 0;
  (*_NPG1)(1, 2) = -(G1x - Px);
  (*_NPG1)(2, 0) = -(G1y - Py);
  (*_NPG1)(2, 1) = (G1x - Px);
  (*_NPG1)(2, 2) = 0;

  d1->updateMObjToAbs();
  SP::SimpleMatrix Mobj1_abs = d1->MObjToAbs();

#ifdef NEFC3D_DEBUG
  printf("NewtonEulerRFC3D::FC3DcomputeJachqTFromContacts, Mobj1_abs:");
  Mobj1_abs->display();
#endif

  prod(*_NPG1, *Mobj1_abs, *_AUX1, true);
  prod(*_Mabs_C, *_AUX1, *_AUX2, true);

  for (unsigned int ii = 0; ii < 3; ii++)
    for (unsigned int jj = 0; jj < 3; jj++)
      _jachqT->setValue(ii, jj, _Mabs_C->getValue(ii, jj));

  for (unsigned int ii = 0; ii < 3; ii++)
    for (unsigned int jj = 3; jj < 6; jj++)
      _jachqT->setValue(ii, jj, _AUX2->getValue(ii, jj - 3));
#ifdef NEFC3D_DEBUG
  printf("NewtonEulerRFC3D::FC3DcomputeJachqTFromContacts, jhqT:\n");
  _jachqT->display();
  SP::SimpleMatrix jaux(new SimpleMatrix(*jhqT));
  jaux->trans();
  SP::SimpleVector v(new SimpleVector(3));
  SP::SimpleVector vRes(new SimpleVector(6));
  v->zero();
  v->setValue(0, 1);
  prod(*jaux, *v, *vRes, true);
  vRes->display();
  v->zero();
  v->setValue(1, 1);
  prod(*jaux, *v, *vRes, true);
  vRes->display();
  v->zero();
  v->setValue(2, 1);
  prod(*jaux, *v, *vRes, true);
  vRes->display();
#endif
}

void NewtonEulerRFC3D::FC3DcomputeJachqTFromContacts(SP::NewtonEulerDS d1, SP::NewtonEulerDS d2)
{
  double Nx = _Nc->getValue(0);
  double Ny = _Nc->getValue(1);
  double Nz = _Nc->getValue(2);
  double Px = _Pc1->getValue(0);
  double Py = _Pc1->getValue(1);
  double Pz = _Pc1->getValue(2);
  double G1x = d1->q()->getValue(0);
  double G1y = d1->q()->getValue(1);
  double G1z = d1->q()->getValue(2);
  double G2x = d2->q()->getValue(0);
  double G2y = d2->q()->getValue(1);
  double G2z = d2->q()->getValue(2);

  double t[6];
  double * pt = t;
  orthoBaseFromVector(&Nx, &Ny, &Nz, pt, pt + 1, pt + 2, pt + 3, pt + 4, pt + 5);
  pt = t;
  _Mabs_C->setValue(0, 0, Nx);
  _Mabs_C->setValue(1, 0, *pt);
  _Mabs_C->setValue(2, 0, *(pt + 3));
  _Mabs_C->setValue(0, 1, Ny);
  _Mabs_C->setValue(1, 1, *(pt + 1));
  _Mabs_C->setValue(2, 1, *(pt + 4));
  _Mabs_C->setValue(0, 2, Nz);
  _Mabs_C->setValue(1, 2, *(pt + 2));
  _Mabs_C->setValue(2, 2, *(pt + 5));

  _NPG1->zero();

  (*_NPG1)(0, 0) = 0;
  (*_NPG1)(0, 1) = -(G1z - Pz);
  (*_NPG1)(0, 2) = (G1y - Py);
  (*_NPG1)(1, 0) = (G1z - Pz);
  (*_NPG1)(1, 1) = 0;
  (*_NPG1)(1, 2) = -(G1x - Px);
  (*_NPG1)(2, 0) = -(G1y - Py);
  (*_NPG1)(2, 1) = (G1x - Px);
  (*_NPG1)(2, 2) = 0;

  _NPG2->zero();

  (*_NPG2)(0, 0) = 0;
  (*_NPG2)(0, 1) = -(G2z - Pz);
  (*_NPG2)(0, 2) = (G2y - Py);
  (*_NPG2)(1, 0) = (G2z - Pz);
  (*_NPG2)(1, 1) = 0;
  (*_NPG2)(1, 2) = -(G2x - Px);
  (*_NPG2)(2, 0) = -(G2y - Py);
  (*_NPG2)(2, 1) = (G2x - Px);
  (*_NPG2)(2, 2) = 0;

  d1->updateMObjToAbs();
  SP::SimpleMatrix Mobj1_abs = d1->MObjToAbs();

  prod(*_NPG1, *Mobj1_abs, *_AUX1, true);
  prod(*_Mabs_C, *_AUX1, *_AUX2, true);

  for (unsigned int ii = 0; ii < 3; ii++)
    for (unsigned int jj = 0; jj < 3; jj++)
      _jachqT->setValue(ii, jj, _Mabs_C->getValue(ii, jj));

  for (unsigned int ii = 0; ii < 3; ii++)
    for (unsigned int jj = 3; jj < 6; jj++)
      _jachqT->setValue(ii, jj, _AUX2->getValue(ii, jj - 3));

  d2->updateMObjToAbs();
  SP::SimpleMatrix Mobj2_abs = d1->MObjToAbs();

  prod(*_NPG2, *Mobj2_abs, *_AUX1, true);
  prod(*_Mabs_C, *_AUX1, *_AUX2, true);

  for (unsigned int ii = 0; ii < 3; ii++)
    for (unsigned int jj = 0; jj < 3; jj++)
      _jachqT->setValue(ii, jj + 6, -_Mabs_C->getValue(ii, jj));

  for (unsigned int ii = 0; ii < 3; ii++)
    for (unsigned int jj = 3; jj < 6; jj++)
      _jachqT->setValue(ii, jj + 6, -_AUX2->getValue(ii, jj - 3));

}
void NewtonEulerRFC3D::computeJachqT()
{
  DSIterator itDS = interaction()->dynamicalSystemsBegin();
  SP::NewtonEulerDS d1 =  boost::static_pointer_cast<NewtonEulerDS> (*itDS);
  itDS++;
  if (itDS != interaction()->dynamicalSystemsEnd())
  {
    SP::NewtonEulerDS d2 =  boost::static_pointer_cast<NewtonEulerDS> (*itDS);
    FC3DcomputeJachqTFromContacts(d1, d2);
  }
  else
  {
    FC3DcomputeJachqTFromContacts(d1);
  }
}
<|endoftext|>


<commit_before>/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool isSymmetricBFS(TreeNode* root) {
        if (root == nullptr)    return true;
        std::queue<TreeNode*> q1, q2;
        q1.push(root->left);
        q2.push(root->right);
        while (!q1.empty() && !q2.empty()) {
            TreeNode *n1 = q1.front(), *n2 = q2.front();
            q1.pop();
            q2.pop();
            if (n1 == nullptr && n2 == nullptr)
                continue;
            if (n1 == nullptr || n2 == nullptr)
                return false;
            if (n1->val != n2->val)
                return false;
            q1.push(n1->left);
            q1.push(n1->right);
            q2.push(n2->right);
            q2.push(n2->left);
        }
        return true;
    }
};<commit_msg>101 added DFS<commit_after>/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool isSymmetricBFS(TreeNode* root) {
        if (root == nullptr)    return true;
        std::queue<TreeNode*> q1, q2;
        q1.push(root->left);
        q2.push(root->right);
        while (!q1.empty() && !q2.empty()) {
            TreeNode *n1 = q1.front(), *n2 = q2.front();
            q1.pop();
            q2.pop();
            if (n1 == nullptr && n2 == nullptr)
                continue;
            if (n1 == nullptr || n2 == nullptr)
                return false;
            if (n1->val != n2->val)
                return false;
            q1.push(n1->left);
            q1.push(n1->right);
            q2.push(n2->right);
            q2.push(n2->left);
        }
        return true;
    }
    bool isSymmetric(TreeNode* root) {
        return DFS(root, root);
    }

    bool DFS(TreeNode* a, TreeNode* b) {
        if (a == nullptr && b == nullptr)
            return true;
        if (a == nullptr || b == nullptr)
            return false;
        if (a->val != b->val)
            return false;
        return DFS(a->left, b->right) && DFS(a->right, b->left);
    }
};<|endoftext|>


<commit_before>#include "board/Board.h"
#include "board/common/indicators/Variables.h"
#include "Constants.h"

///
/// \brief Buffer in which outgoing data is stored.
///
static RingBuff_t   txBuffer;

///
/// \brief Buffer in which incoming data is stored.
///
static RingBuff_t   rxBuffer;

///
/// \brief Flag determining whether or not UART loopback functionality is enabled.
/// When enabled, all incoming UART traffic is immediately passed on to UART TX.
///
static bool         loopbackEnabled;

///
/// \brief Flag determining whether or not OpenDeck UART format is configured.
///
static bool         odUARTconfigured;

///
/// \brief ISR used to store incoming data from UART to buffer.
///
ISR(USART_RX_vect)
{
    uint8_t data = UDR;

    if (!loopbackEnabled)
    {
        if (!RingBuffer_IsFull(&rxBuffer))
        {
            RingBuffer_Insert(&rxBuffer, data);
        }
    }
    else
    {
        if (!RingBuffer_IsFull(&txBuffer))
        {
            RingBuffer_Insert(&txBuffer, data);
            UCSRB |= (1<<UDRIE);
            #if !defined(BOARD_A_MEGA) && !defined(BOARD_A_UNO)
            MIDIsent = true;
            MIDIreceived = true;
            #endif
        }
}
}

///
/// \brief ISR used to write outgoing data in buffer to UART.
///
ISR(USART_UDRE_vect)
{
    if (RingBuffer_IsEmpty(&txBuffer))
    {
        //buffer is empty, disable transmit interrupt
        UCSRB &= ~(1<<UDRIE);
    }
    else
    {
        uint8_t data = RingBuffer_Remove(&txBuffer);
        UDR = data;
    }
}

void Board::initMIDI_UART()
{
    int32_t baud_count = ((F_CPU / 8) + (MIDI_BAUD_RATE / 2)) / MIDI_BAUD_RATE;

    //clear registers first
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
    {
        UCSRA = 0;
        UCSRB = 0;
        UCSRC = 0;
        UBRR = 0;
    }

    if ((baud_count & 1) && baud_count <= 4096)
    {
        UCSRA = (1<<U2X); //double speed uart
        UBRR = baud_count - 1;
    }
    else
    {
        UCSRA = 0;
        UBRR = (baud_count >> 1) - 1;
    }

    //8 bit, no parity, 1 stop bit
    UCSRC = (1<<UCSZ1) | (1<<UCSZ0);

    //enable receiver, transmitter and receive interrupt
    UCSRB = (1<<RXEN) | (1<<TXEN) | (1<<RXCIE);

    RingBuffer_InitBuffer(&rxBuffer);
    RingBuffer_InitBuffer(&txBuffer);

    #ifndef BOARD_A_xu2
    #if defined(BOARD_A_MEGA) || defined(BOARD_A_UNO)
    //enable od format immediately for these boards
    setOD_UART();
    #else
    midi.handleUARTread(board.MIDIread_UART);
    midi.handleUARTwrite(board.MIDIwrite_UART);
    #endif
    #endif
}

int16_t Board::MIDIread_UART()
{
    if (RingBuffer_IsEmpty(&rxBuffer))
    {
        return -1;
    }

    uint8_t data = RingBuffer_Remove(&rxBuffer);
    #if !defined(BOARD_A_MEGA) && !defined(BOARD_A_UNO) && !defined(BOARD_A_xu2)
    MIDIreceived = true;
    #endif
    return data;
}

int8_t Board::MIDIwrite_UART(uint8_t data)
{
    //if both the outgoing buffer and the UART data register are empty
    //write the byte to the data register directly
    if (RingBuffer_IsEmpty(&txBuffer) && (UCSRA & (1<<UDRE)))
    {
        ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
        {
            UDR = data;
        }

        #if !defined(BOARD_A_MEGA) && !defined(BOARD_A_UNO)
        MIDIsent = true;
        #endif

        return 1;
    }

    while (RingBuffer_IsFull(&txBuffer));
    RingBuffer_Insert(&txBuffer, data);
    UCSRB |= (1<<UDRIE);
    #if !defined(BOARD_A_MEGA) && !defined(BOARD_A_UNO)
    MIDIsent = true;
    #endif

    return 1;
}

bool Board::MIDIwrite_UART_OD(USBMIDIpacket_t& USBMIDIpacket)
{
    RingBuffer_Insert(&txBuffer, 0xF1);
    RingBuffer_Insert(&txBuffer, USBMIDIpacket.Event);
    RingBuffer_Insert(&txBuffer, USBMIDIpacket.Data1);
    RingBuffer_Insert(&txBuffer, USBMIDIpacket.Data2);
    RingBuffer_Insert(&txBuffer, USBMIDIpacket.Data3);
    RingBuffer_Insert(&txBuffer, USBMIDIpacket.Event ^ USBMIDIpacket.Data1 ^ USBMIDIpacket.Data2 ^ USBMIDIpacket.Data3);

    UCSRB |= (1<<UDRIE);
    #if !defined(BOARD_A_MEGA) && !defined(BOARD_A_UNO) && !defined(BOARD_A_xu2)
    MIDIsent = true;
    #endif

    return true;
}

bool Board::MIDIread_UART_OD()
{
    if (RingBuffer_GetCount(&rxBuffer) >= 6)
    {
        int16_t data = MIDIread_UART();

        if (data == 0xF1)
        {
            //start of frame, read rest of the packet
            for (int i=0; i<5; i++)
            {
                data = MIDIread_UART();

                switch(i)
                {
                    case 0:
                    usbMIDIpacket.Event = data;
                    break;

                    case 1:
                    usbMIDIpacket.Data1 = data;
                    break;

                    case 2:
                    usbMIDIpacket.Data2 = data;
                    break;

                    case 3:
                    usbMIDIpacket.Data3 = data;
                    break;

                    case 4:
                    //xor byte, do nothing
                    break;
                }
            }

            //everything fine so far
            #if !defined(BOARD_A_MEGA) && !defined(BOARD_A_UNO) && !defined(BOARD_A_xu2)
            MIDIreceived = true;
            #endif

            //error check
            uint8_t dataXOR = usbMIDIpacket.Event ^ usbMIDIpacket.Data1 ^ usbMIDIpacket.Data2 ^ usbMIDIpacket.Data3;

            return (dataXOR == data);
        }
    }

    return false;
}

bool usbRead_od(USBMIDIpacket_t& USBMIDIpacket)
{
    return board.MIDIread_UART_OD();
}

void Board::setUARTloopbackState(bool state)
{
    loopbackEnabled = state;
}

bool Board::getUARTloopbackState()
{
    return loopbackEnabled;
}

bool Board::isRXempty()
{
    return RingBuffer_IsEmpty(&rxBuffer);
}

bool Board::isTXempty()
{
    return RingBuffer_IsEmpty(&txBuffer);
}

void Board::setOD_UART()
{
    #ifdef BOARD_OPEN_DECK
    if (isUSBconnected())
    {
        //master board
        midi.handleUSBread(board.MIDIread_USB_write_UART_OD);
        midi.handleUSBwrite(board.MIDIwrite_USB);
        midi.handleUARTread(NULL); //parsed internally
        midi.handleUARTwrite(NULL);
    }
    else
    {
        //slave
        midi.handleUSBread(usbRead_od); //loopback used on inner slaves
        midi.handleUSBwrite(board.MIDIwrite_UART_OD);
        midi.handleUARTread(NULL);
        midi.handleUARTwrite(NULL);
    }

    odUARTconfigured = true;
    #elif defined(BOARD_A_MEGA) || defined(BOARD_A_UNO)
    midi.handleUSBread(usbRead_od);
    midi.handleUSBwrite(board.MIDIwrite_UART_OD);
    midi.handleUARTread(NULL);
    midi.handleUARTwrite(NULL);
    odUARTconfigured = true;
    #endif
}

bool Board::getOD_UART()
{
    return odUARTconfigured;
}
<commit_msg>remove duplicate functionality<commit_after>#include "board/Board.h"
#include "board/common/indicators/Variables.h"
#include "Constants.h"

///
/// \brief Buffer in which outgoing data is stored.
///
static RingBuff_t   txBuffer;

///
/// \brief Buffer in which incoming data is stored.
///
static RingBuff_t   rxBuffer;

///
/// \brief Flag determining whether or not UART loopback functionality is enabled.
/// When enabled, all incoming UART traffic is immediately passed on to UART TX.
///
static bool         loopbackEnabled;

///
/// \brief Flag determining whether or not OpenDeck UART format is configured.
///
static bool         odUARTconfigured;

///
/// \brief ISR used to store incoming data from UART to buffer.
///
ISR(USART_RX_vect)
{
    uint8_t data = UDR;

    if (!loopbackEnabled)
    {
        if (!RingBuffer_IsFull(&rxBuffer))
        {
            RingBuffer_Insert(&rxBuffer, data);
        }
    }
    else
    {
        if (!RingBuffer_IsFull(&txBuffer))
        {
            RingBuffer_Insert(&txBuffer, data);
            UCSRB |= (1<<UDRIE);
            #if !defined(BOARD_A_MEGA) && !defined(BOARD_A_UNO)
            MIDIsent = true;
            MIDIreceived = true;
            #endif
        }
}
}

///
/// \brief ISR used to write outgoing data in buffer to UART.
///
ISR(USART_UDRE_vect)
{
    if (RingBuffer_IsEmpty(&txBuffer))
    {
        //buffer is empty, disable transmit interrupt
        UCSRB &= ~(1<<UDRIE);
    }
    else
    {
        uint8_t data = RingBuffer_Remove(&txBuffer);
        UDR = data;
    }
}

void Board::initMIDI_UART()
{
    int32_t baud_count = ((F_CPU / 8) + (MIDI_BAUD_RATE / 2)) / MIDI_BAUD_RATE;

    //clear registers first
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
    {
        UCSRA = 0;
        UCSRB = 0;
        UCSRC = 0;
        UBRR = 0;
    }

    if ((baud_count & 1) && baud_count <= 4096)
    {
        UCSRA = (1<<U2X); //double speed uart
        UBRR = baud_count - 1;
    }
    else
    {
        UCSRA = 0;
        UBRR = (baud_count >> 1) - 1;
    }

    //8 bit, no parity, 1 stop bit
    UCSRC = (1<<UCSZ1) | (1<<UCSZ0);

    //enable receiver, transmitter and receive interrupt
    UCSRB = (1<<RXEN) | (1<<TXEN) | (1<<RXCIE);

    RingBuffer_InitBuffer(&rxBuffer);
    RingBuffer_InitBuffer(&txBuffer);

    #ifndef BOARD_A_xu2
    #if defined(BOARD_A_MEGA) || defined(BOARD_A_UNO)
    //enable od format immediately for these boards
    setOD_UART();
    #else
    midi.handleUARTread(board.MIDIread_UART);
    midi.handleUARTwrite(board.MIDIwrite_UART);
    #endif
    #endif
}

int16_t Board::MIDIread_UART()
{
    if (RingBuffer_IsEmpty(&rxBuffer))
    {
        return -1;
    }

    uint8_t data = RingBuffer_Remove(&rxBuffer);
    #if !defined(BOARD_A_MEGA) && !defined(BOARD_A_UNO) && !defined(BOARD_A_xu2)
    MIDIreceived = true;
    #endif
    return data;
}

int8_t Board::MIDIwrite_UART(uint8_t data)
{
    //if both the outgoing buffer and the UART data register are empty
    //write the byte to the data register directly
    if (RingBuffer_IsEmpty(&txBuffer) && (UCSRA & (1<<UDRE)))
    {
        ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
        {
            UDR = data;
        }

        #if !defined(BOARD_A_MEGA) && !defined(BOARD_A_UNO)
        MIDIsent = true;
        #endif

        return 1;
    }

    while (RingBuffer_IsFull(&txBuffer));
    RingBuffer_Insert(&txBuffer, data);
    UCSRB |= (1<<UDRIE);
    #if !defined(BOARD_A_MEGA) && !defined(BOARD_A_UNO)
    MIDIsent = true;
    #endif

    return 1;
}

bool Board::MIDIwrite_UART_OD(USBMIDIpacket_t& USBMIDIpacket)
{
    RingBuffer_Insert(&txBuffer, 0xF1);
    RingBuffer_Insert(&txBuffer, USBMIDIpacket.Event);
    RingBuffer_Insert(&txBuffer, USBMIDIpacket.Data1);
    RingBuffer_Insert(&txBuffer, USBMIDIpacket.Data2);
    RingBuffer_Insert(&txBuffer, USBMIDIpacket.Data3);
    RingBuffer_Insert(&txBuffer, USBMIDIpacket.Event ^ USBMIDIpacket.Data1 ^ USBMIDIpacket.Data2 ^ USBMIDIpacket.Data3);

    UCSRB |= (1<<UDRIE);
    #if !defined(BOARD_A_MEGA) && !defined(BOARD_A_UNO) && !defined(BOARD_A_xu2)
    MIDIsent = true;
    #endif

    return true;
}

bool Board::MIDIread_UART_OD()
{
    if (RingBuffer_GetCount(&rxBuffer) >= 6)
    {
        int16_t data = MIDIread_UART();

        if (data == 0xF1)
        {
            //start of frame, read rest of the packet
            for (int i=0; i<5; i++)
            {
                data = MIDIread_UART();

                switch(i)
                {
                    case 0:
                    usbMIDIpacket.Event = data;
                    break;

                    case 1:
                    usbMIDIpacket.Data1 = data;
                    break;

                    case 2:
                    usbMIDIpacket.Data2 = data;
                    break;

                    case 3:
                    usbMIDIpacket.Data3 = data;
                    break;

                    case 4:
                    //xor byte, do nothing
                    break;
                }
            }

            //error check
            uint8_t dataXOR = usbMIDIpacket.Event ^ usbMIDIpacket.Data1 ^ usbMIDIpacket.Data2 ^ usbMIDIpacket.Data3;

            return (dataXOR == data);
        }
    }

    return false;
}

bool usbRead_od(USBMIDIpacket_t& USBMIDIpacket)
{
    return board.MIDIread_UART_OD();
}

void Board::setUARTloopbackState(bool state)
{
    loopbackEnabled = state;
}

bool Board::getUARTloopbackState()
{
    return loopbackEnabled;
}

bool Board::isRXempty()
{
    return RingBuffer_IsEmpty(&rxBuffer);
}

bool Board::isTXempty()
{
    return RingBuffer_IsEmpty(&txBuffer);
}

void Board::setOD_UART()
{
    #ifdef BOARD_OPEN_DECK
    if (isUSBconnected())
    {
        //master board
        midi.handleUSBread(board.MIDIread_USB_write_UART_OD);
        midi.handleUSBwrite(board.MIDIwrite_USB);
        midi.handleUARTread(NULL); //parsed internally
        midi.handleUARTwrite(NULL);
    }
    else
    {
        //slave
        midi.handleUSBread(usbRead_od); //loopback used on inner slaves
        midi.handleUSBwrite(board.MIDIwrite_UART_OD);
        midi.handleUARTread(NULL);
        midi.handleUARTwrite(NULL);
    }

    odUARTconfigured = true;
    #elif defined(BOARD_A_MEGA) || defined(BOARD_A_UNO)
    midi.handleUSBread(usbRead_od);
    midi.handleUSBwrite(board.MIDIwrite_UART_OD);
    midi.handleUARTread(NULL);
    midi.handleUARTwrite(NULL);
    odUARTconfigured = true;
    #endif
}

bool Board::getOD_UART()
{
    return odUARTconfigured;
}
<|endoftext|>


<commit_before>#ifndef _MATH_VECTOR_HPP
#define _MATH_VECTOR_HPP

#include <cmath>
#include <numeric>
#include <iterator>
#include <algorithm>
#include <type_traits>
#include <iosfwd>

namespace math {

	namespace internal {
		template <typename _T, std::size_t _N>
		struct vector_base {
		private:
			_T _data[_N];

		public:
			_T& operator [](std::size_t index) noexcept { return _data[index]; }
			_T const& operator [](std::size_t index) const noexcept { return _data[index]; }
		};

		template <typename _T>
		struct vector_base<_T, 2> {
			_T x, y;

			vector_base(_T x, _T y) : x(x), y(y) {}

			_T& operator [](std::size_t index) noexcept { return *(reinterpret_cast<_T*>(this) + index); }
			_T const& operator [](std::size_t index) const noexcept { return *(reinterpret_cast<_T const*>(this) + index); }
		};

		template <typename _T>
		struct vector_base<_T, 3> {
			_T x, y, z;

			vector_base(_T x, _T y, _T z = static_cast<_T>(1))
				: x(x), y(y), z(z) {}

			_T& operator [](std::size_t index) noexcept { return *(reinterpret_cast<_T*>(this) + index); }
			_T const& operator [](std::size_t index) const noexcept { return *(reinterpret_cast<_T const*>(this) + index); }
		};

		template <typename _T>
		struct vector_base<_T, 4> {
			_T x, y, z, w;

			vector_base(_T x, _T y, _T z, _T w = static_cast<_T>(1))
				: x(x), y(y), z(z), w(w) {}

			_T& operator [](std::size_t index) noexcept { return *(reinterpret_cast<_T*>(this) + index); }
			_T const& operator [](std::size_t index) const noexcept { return *(reinterpret_cast<_T const*>(this) + index); }
		};
	}

	template <typename _T, std::size_t _N>
	struct vector : public internal::vector_base<_T, _N> {
		static_assert(std::is_arithmetic<_T>::value, "vector<_T> requires arithmetic type.");

		////////////////////////////////////////////////////////////////////////////////
		// type definitions.

		typedef _T value_type;
		typedef _T* pointer;
		typedef _T& reference;
		typedef _T const* const_pointer;
		typedef _T const& const_reference;
		typedef std::size_t size_type;

		typedef _T* iterator;
		typedef _T const* const_iterator;
		typedef std::reverse_iterator<iterator> reverse_iterator;
		typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

		////////////////////////////////////////////////////////////////////////////////
		// construction.

		using internal::vector_base<_T, _N>::vector_base;

		constexpr vector operator -() const noexcept { return *this; }
		constexpr vector operator +() const noexcept { return *this; }

		////////////////////////////////////////////////////////////////////////////////
		// compound arithmetic operators.

		vector& operator += (vector const& other) noexcept {
			std::transform(this->begin(), this->end(), other.begin(),
				this->begin(), std::plus<_T>());
			return *this;
		}

		vector& operator -= (vector const& other) noexcept {
			std::transform(this->begin(), this->end(), other.begin(),
				this->begin(), std::minus<_T>());
			return *this;
		}

		vector& operator *= (value_type scalar) noexcept {
			std::transform(this->begin(), this->end(), this->begin(),
				std::bind(std::multiplies<_T>(), std::placeholders::_1, scalar));
			return *this;
		}

		vector& operator /= (value_type scalar) noexcept {
			std::transform(this->begin(), this->end(), this->begin(),
				std::bind(std::divides<_T>(), std::placeholders::_1, scalar));
			return *this;
		}

		////////////////////////////////////////////////////////////////////////////////
		// methods.

		typename std::common_type<_T, float>::type length() const noexcept{
			return std::sqrt(this->length_sqr());
		}

		typename std::common_type<_T, float>::type length_sqr() const noexcept {
			return dot_product(*this, *this);
		}

		////////////////////////////////////////////////////////////////////////////////
		// iteration.

		iterator begin() noexcept { return std::addressof((*this)[0]); }
		iterator end() noexcept { return std::addressof((*this)[_N]); }

		const_iterator begin() const noexcept { return std::addressof((*this)[0]); }
		const_iterator end() const noexcept { return std::addressof((*this)[_N]); }

		const_iterator cbegin() const noexcept { return std::addressof((*this)[0]); }
		const_iterator cend() const noexcept { return std::addressof((*this)[_N]); }

		reverse_iterator rbegin() noexcept { return this->end(); }
		reverse_iterator rend() noexcept { return this->begin(); }

		const_reverse_iterator rbegin() const noexcept { return this->end(); }
		const_reverse_iterator rend() const noexcept { return this->begin(); }

		const_reverse_iterator crbegin() const noexcept { return this->cend(); }
		const_reverse_iterator crend() const noexcept { return this->cbegin(); }
	};

	template <typename _T> using vector2 = vector<_T, 2>;
	template <typename _T> using vector3 = vector<_T, 3>;
	template <typename _T> using vector4 = vector<_T, 4>;

	////////////////////////////////////////////////////////////////////////////////

	template <typename _T, typename _U, std::size_t _N>
	bool operator == (vector<_T, _N> const& lhs, vector<_U, _N> const& rhs);

	template <typename _T, typename _U, std::size_t _N>
	bool operator != (vector<_T, _N> const& lhs, vector<_U, _N> const& rhs);

	////////////////////////////////////////////////////////////////////////////////

	template <typename _T, typename _U, std::size_t _N>
	vector<typename std::common_type<_T, _U>::type, _N> operator + (vector<_T, _N> const& lhs, vector<_U, _N> const& rhs) {
		typedef typename std::common_type<_T, _U>::type common_t;
		return vector<common_t, _N>(lhs) += rhs;
	}

	template <typename _T, typename _U, std::size_t _N>
	vector<typename std::common_type<_T, _U>::type, _N> operator - (vector<_T, _N> const& lhs, vector<_U, _N> const& rhs) {
		typedef typename std::common_type<_T, _U>::type common_t;
		return vector<common_t, _N>(lhs) -= rhs;
	}

	template <typename _T, typename _U, std::size_t _N>
	vector<typename std::common_type<_T, _U>::type, _N> operator * (vector<_T, _N> const& vec, _U scalar) {
		typedef typename std::common_type<_T, _U>::type common_t;
		return vector<common_t, _N>(vec) *= scalar;
	}

	template <typename _T, typename _U, std::size_t _N>
	vector<typename std::common_type<_T, _U>::type, _N> operator * (_T scalar, vector<_U, _N> const& vec) {
		typedef typename std::common_type<_T, _U>::type common_t;
		return vector<common_t, _N>(vec) *= scalar;
	}

	template <typename _T, typename _U, std::size_t _N>
	vector<typename std::common_type<_T, _U>::type, _N> operator / (vector<_T, _N> const& vec, _U scalar) {
		typedef typename std::common_type<_T, _U>::type common_t;
		return vector<common_t, _N>(vec) /= scalar;
	}

	////////////////////////////////////////////////////////////////////////////////

	template <typename _T, typename _U, std::size_t _N>
	typename std::common_type<_T, _U, float>::type dot_product(vector<_T, _N> const& lhs, vector<_U, _N> const& rhs) {
		typedef typename std::common_type<_T, _U, float>::type common_t;
		return std::inner_product(lhs.begin(), lhs.end(), rhs.begin(), static_cast<common_t>(0));
	}

 	template <typename _T, typename _U, std::size_t _N>
 	vector<typename std::common_type<_T, _U, float>::type, _N> projection(vector<_T, _N> const& vec, vector<_U, _N> const& n) {
		return dot_product(vec, n) / dot_product(n, n) * n;
	}

	template <typename _T, typename _U, std::size_t _N>
 	vector<typename std::common_type<_T, _U, float>::type, _N> reflection(vector<_T, _N> const& vec, vector<_U, _N> const& n) {
		typedef typename std::common_type<_T, _U, float>::type common_t;
		return vec - static_cast<common_t>(2) * projection(vec, n);
	}

	////////////////////////////////////////////////////////////////////////////////

	template <typename _Elem, typename _Traits, typename _T, std::size_t _N>
	std::basic_ostream<_Elem, _Traits>& operator << (std::basic_ostream<_Elem, _Traits>& os, vector<_T, _N> const& vec) {
		std::copy(vec.begin(), vec.end(), std::ostream_iterator<_T, _Elem, _Traits>(os, " "));
		return os << '\b';
	}
}

#endif  // _MATH_VECTOR_HPP<commit_msg>Add comma seperator when outputing vector with stream operator<commit_after>#ifndef _MATH_VECTOR_HPP
#define _MATH_VECTOR_HPP

#include <cmath>
#include <numeric>
#include <iterator>
#include <algorithm>
#include <type_traits>
#include <iosfwd>

namespace math {

	namespace internal {
		template <typename _T, std::size_t _N>
		struct vector_base {
		private:
			_T _data[_N];

		public:
			_T& operator [](std::size_t index) noexcept { return _data[index]; }
			_T const& operator [](std::size_t index) const noexcept { return _data[index]; }
		};

		template <typename _T>
		struct vector_base<_T, 2> {
			_T x, y;

			vector_base(_T x, _T y) : x(x), y(y) {}

			_T& operator [](std::size_t index) noexcept { return *(reinterpret_cast<_T*>(this) + index); }
			_T const& operator [](std::size_t index) const noexcept { return *(reinterpret_cast<_T const*>(this) + index); }
		};

		template <typename _T>
		struct vector_base<_T, 3> {
			_T x, y, z;

			vector_base(_T x, _T y, _T z = static_cast<_T>(1))
				: x(x), y(y), z(z) {}

			_T& operator [](std::size_t index) noexcept { return *(reinterpret_cast<_T*>(this) + index); }
			_T const& operator [](std::size_t index) const noexcept { return *(reinterpret_cast<_T const*>(this) + index); }
		};

		template <typename _T>
		struct vector_base<_T, 4> {
			_T x, y, z, w;

			vector_base(_T x, _T y, _T z, _T w = static_cast<_T>(1))
				: x(x), y(y), z(z), w(w) {}

			_T& operator [](std::size_t index) noexcept { return *(reinterpret_cast<_T*>(this) + index); }
			_T const& operator [](std::size_t index) const noexcept { return *(reinterpret_cast<_T const*>(this) + index); }
		};
	}

	template <typename _T, std::size_t _N>
	struct vector : public internal::vector_base<_T, _N> {
		static_assert(std::is_arithmetic<_T>::value, "vector<_T> requires arithmetic type.");

		////////////////////////////////////////////////////////////////////////////////
		// type definitions.

		typedef _T value_type;
		typedef _T* pointer;
		typedef _T& reference;
		typedef _T const* const_pointer;
		typedef _T const& const_reference;
		typedef std::size_t size_type;

		typedef _T* iterator;
		typedef _T const* const_iterator;
		typedef std::reverse_iterator<iterator> reverse_iterator;
		typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

		////////////////////////////////////////////////////////////////////////////////
		// construction.

		using internal::vector_base<_T, _N>::vector_base;

		constexpr vector operator -() const noexcept { return *this; }
		constexpr vector operator +() const noexcept { return *this; }

		////////////////////////////////////////////////////////////////////////////////
		// compound arithmetic operators.

		vector& operator += (vector const& other) noexcept {
			std::transform(this->begin(), this->end(), other.begin(),
				this->begin(), std::plus<_T>());
			return *this;
		}

		vector& operator -= (vector const& other) noexcept {
			std::transform(this->begin(), this->end(), other.begin(),
				this->begin(), std::minus<_T>());
			return *this;
		}

		vector& operator *= (value_type scalar) noexcept {
			std::transform(this->begin(), this->end(), this->begin(),
				std::bind(std::multiplies<_T>(), std::placeholders::_1, scalar));
			return *this;
		}

		vector& operator /= (value_type scalar) noexcept {
			std::transform(this->begin(), this->end(), this->begin(),
				std::bind(std::divides<_T>(), std::placeholders::_1, scalar));
			return *this;
		}

		////////////////////////////////////////////////////////////////////////////////
		// methods.

		typename std::common_type<_T, float>::type length() const noexcept{
			return std::sqrt(this->length_sqr());
		}

		typename std::common_type<_T, float>::type length_sqr() const noexcept {
			return dot_product(*this, *this);
		}

		////////////////////////////////////////////////////////////////////////////////
		// iteration.

		iterator begin() noexcept { return std::addressof((*this)[0]); }
		iterator end() noexcept { return std::addressof((*this)[_N]); }

		const_iterator begin() const noexcept { return std::addressof((*this)[0]); }
		const_iterator end() const noexcept { return std::addressof((*this)[_N]); }

		const_iterator cbegin() const noexcept { return std::addressof((*this)[0]); }
		const_iterator cend() const noexcept { return std::addressof((*this)[_N]); }

		reverse_iterator rbegin() noexcept { return this->end(); }
		reverse_iterator rend() noexcept { return this->begin(); }

		const_reverse_iterator rbegin() const noexcept { return this->end(); }
		const_reverse_iterator rend() const noexcept { return this->begin(); }

		const_reverse_iterator crbegin() const noexcept { return this->cend(); }
		const_reverse_iterator crend() const noexcept { return this->cbegin(); }
	};

	template <typename _T> using vector2 = vector<_T, 2>;
	template <typename _T> using vector3 = vector<_T, 3>;
	template <typename _T> using vector4 = vector<_T, 4>;

	////////////////////////////////////////////////////////////////////////////////

	template <typename _T, typename _U, std::size_t _N>
	bool operator == (vector<_T, _N> const& lhs, vector<_U, _N> const& rhs);

	template <typename _T, typename _U, std::size_t _N>
	bool operator != (vector<_T, _N> const& lhs, vector<_U, _N> const& rhs);

	////////////////////////////////////////////////////////////////////////////////

	template <typename _T, typename _U, std::size_t _N>
	vector<typename std::common_type<_T, _U>::type, _N> operator + (vector<_T, _N> const& lhs, vector<_U, _N> const& rhs) {
		typedef typename std::common_type<_T, _U>::type common_t;
		return vector<common_t, _N>(lhs) += rhs;
	}

	template <typename _T, typename _U, std::size_t _N>
	vector<typename std::common_type<_T, _U>::type, _N> operator - (vector<_T, _N> const& lhs, vector<_U, _N> const& rhs) {
		typedef typename std::common_type<_T, _U>::type common_t;
		return vector<common_t, _N>(lhs) -= rhs;
	}

	template <typename _T, typename _U, std::size_t _N>
	vector<typename std::common_type<_T, _U>::type, _N> operator * (vector<_T, _N> const& vec, _U scalar) {
		typedef typename std::common_type<_T, _U>::type common_t;
		return vector<common_t, _N>(vec) *= scalar;
	}

	template <typename _T, typename _U, std::size_t _N>
	vector<typename std::common_type<_T, _U>::type, _N> operator * (_T scalar, vector<_U, _N> const& vec) {
		typedef typename std::common_type<_T, _U>::type common_t;
		return vector<common_t, _N>(vec) *= scalar;
	}

	template <typename _T, typename _U, std::size_t _N>
	vector<typename std::common_type<_T, _U>::type, _N> operator / (vector<_T, _N> const& vec, _U scalar) {
		typedef typename std::common_type<_T, _U>::type common_t;
		return vector<common_t, _N>(vec) /= scalar;
	}

	////////////////////////////////////////////////////////////////////////////////

	template <typename _T, typename _U, std::size_t _N>
	typename std::common_type<_T, _U, float>::type dot_product(vector<_T, _N> const& lhs, vector<_U, _N> const& rhs) {
		typedef typename std::common_type<_T, _U, float>::type common_t;
		return std::inner_product(lhs.begin(), lhs.end(), rhs.begin(), static_cast<common_t>(0));
	}

 	template <typename _T, typename _U, std::size_t _N>
 	vector<typename std::common_type<_T, _U, float>::type, _N> projection(vector<_T, _N> const& vec, vector<_U, _N> const& n) {
		return dot_product(vec, n) / dot_product(n, n) * n;
	}

	template <typename _T, typename _U, std::size_t _N>
 	vector<typename std::common_type<_T, _U, float>::type, _N> reflection(vector<_T, _N> const& vec, vector<_U, _N> const& n) {
		typedef typename std::common_type<_T, _U, float>::type common_t;
		return vec - static_cast<common_t>(2) * projection(vec, n);
	}

	////////////////////////////////////////////////////////////////////////////////

	template <typename _Elem, typename _Traits, typename _T, std::size_t _N>
	std::basic_ostream<_Elem, _Traits>& operator << (std::basic_ostream<_Elem, _Traits>& os, vector<_T, _N> const& vec) {
		std::copy(vec.begin(), vec.end(), std::ostream_iterator<_T, _Elem, _Traits>(os, ", "));
		return os << "\b\b \b";
	}
}

#endif  // _MATH_VECTOR_HPP<|endoftext|>