<commit_before>#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/portability/CppUnitMap.h>
#include <cppunit/TestSuite.h>
#include <assert.h>

CPPUNIT_NS_BEGIN

/*! \brief (INTERNAL) List of all TestFactoryRegistry.
 */
class TestFactoryRegistryList
{
private:
  typedef CppUnitMap<std::string, TestFactoryRegistry *> Registries;
  Registries m_registries;

  enum State {
    doNotChange =0,
    notCreated,
    exist,
    destroyed
  };

  static State stateFlag( State newState = doNotChange )
  {
    static State state = notCreated;
    if ( newState != doNotChange )
      state = newState;
    return state;
  }

  static TestFactoryRegistryList *getInstance()
  {
    static TestFactoryRegistryList list;
    return &list;
  }

  TestFactoryRegistry *getInternalRegistry( const std::string &name )
  {
    Registries::const_iterator foundIt = m_registries.find( name );
    if ( foundIt == m_registries.end() )
    {
      TestFactoryRegistry *factory = new TestFactoryRegistry( name );
      m_registries.insert( std::make_pair( name, factory ) );
      return factory;
    }
    return foundIt->second;
  }

public:
  TestFactoryRegistryList()
  {
    stateFlag( exist );
  }

  ~TestFactoryRegistryList()
  {
    for ( Registries::iterator it = m_registries.begin(); it != m_registries.end(); ++it )
      delete it->second;

    stateFlag( destroyed );
  }

  static TestFactoryRegistry *getRegistry( const std::string &name )
  {
    // If the following assertion failed, then TestFactoryRegistry::getRegistry()
    // was called during static variable destruction without checking the registry
    // validity beforehand using TestFactoryRegistry::isValid() beforehand.
    assert( isValid() );
    if ( !isValid() )         // release mode
      return NULL;            // => force CRASH

    return getInstance()->getInternalRegistry( name );
  }

  static bool isValid()
  {
    return stateFlag() != destroyed;
  }
};

TestFactoryRegistry::TestFactoryRegistry( std::string name ) :
    m_name( name )
{
}

TestFactoryRegistry::~TestFactoryRegistry()
{
}

TestFactoryRegistry &
TestFactoryRegistry::getRegistry( const std::string &name )
{
  return *TestFactoryRegistryList::getRegistry( name );
}

void
TestFactoryRegistry::registerFactory( const std::string &name,
                                      TestFactory *factory )
{
  registerFactory( factory );
}

void
TestFactoryRegistry::registerFactory( TestFactory *factory )
{
  m_factories.insert( factory );
}

void
TestFactoryRegistry::unregisterFactory( TestFactory *factory )
{
  m_factories.erase( factory );
}

void
TestFactoryRegistry::addRegistry( const std::string &name )
{
  registerFactory( &getRegistry( name ) );
}

Test *
TestFactoryRegistry::makeTest()
{
  TestSuite *suite = new TestSuite( m_name );
  addTestToSuite( suite );
  return suite;
}

void
TestFactoryRegistry::addTestToSuite( TestSuite *suite )
{
  for ( Factories::iterator it = m_factories.begin();
        it != m_factories.end();
        ++it )
  {
    TestFactory *factory = *it;
    suite->addTest( factory->makeTest() );
  }
}

bool
TestFactoryRegistry::isValid()
{
  return TestFactoryRegistryList::isValid();
}

CPPUNIT_NS_END
<commit_msg>map needs comparator, make_pair to pair, and map dereference fix (SUN4)<commit_after>#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/portability/CppUnitMap.h>
#include <cppunit/TestSuite.h>
#include <assert.h>

CPPUNIT_NS_BEGIN

/*! \brief (INTERNAL) List of all TestFactoryRegistry.
 */
class TestFactoryRegistryList
{
private:
  typedef CppUnitMap<std::string, TestFactoryRegistry *, std::less<std::string> > Registries;
  Registries m_registries;

  enum State {
    doNotChange =0,
    notCreated,
    exist,
    destroyed
  };

  static State stateFlag( State newState = doNotChange )
  {
    static State state = notCreated;
    if ( newState != doNotChange )
      state = newState;
    return state;
  }

  static TestFactoryRegistryList *getInstance()
  {
    static TestFactoryRegistryList list;
    return &list;
  }

  TestFactoryRegistry *getInternalRegistry( const std::string &name )
  {
    Registries::const_iterator foundIt = m_registries.find( name );
    if ( foundIt == m_registries.end() )
    {
      TestFactoryRegistry *factory = new TestFactoryRegistry( name );
      m_registries.insert( std::pair<const std::string, TestFactoryRegistry*>( name, factory ) );
      return factory;
    }
    return (*foundIt).second;
  }

public:
  TestFactoryRegistryList()
  {
    stateFlag( exist );
  }

  ~TestFactoryRegistryList()
  {
    for ( Registries::iterator it = m_registries.begin(); it != m_registries.end(); ++it )
      delete (*it).second;

    stateFlag( destroyed );
  }

  static TestFactoryRegistry *getRegistry( const std::string &name )
  {
    // If the following assertion failed, then TestFactoryRegistry::getRegistry()
    // was called during static variable destruction without checking the registry
    // validity beforehand using TestFactoryRegistry::isValid() beforehand.
    assert( isValid() );
    if ( !isValid() )         // release mode
      return NULL;            // => force CRASH

    return getInstance()->getInternalRegistry( name );
  }

  static bool isValid()
  {
    return stateFlag() != destroyed;
  }
};

TestFactoryRegistry::TestFactoryRegistry( std::string name ) :
    m_name( name )
{
}

TestFactoryRegistry::~TestFactoryRegistry()
{
}

TestFactoryRegistry &
TestFactoryRegistry::getRegistry( const std::string &name )
{
  return *TestFactoryRegistryList::getRegistry( name );
}

void
TestFactoryRegistry::registerFactory( const std::string &name,
                                      TestFactory *factory )
{
  registerFactory( factory );
}

void
TestFactoryRegistry::registerFactory( TestFactory *factory )
{
  m_factories.insert( factory );
}

void
TestFactoryRegistry::unregisterFactory( TestFactory *factory )
{
  m_factories.erase( factory );
}

void
TestFactoryRegistry::addRegistry( const std::string &name )
{
  registerFactory( &getRegistry( name ) );
}

Test *
TestFactoryRegistry::makeTest()
{
  TestSuite *suite = new TestSuite( m_name );
  addTestToSuite( suite );
  return suite;
}

void
TestFactoryRegistry::addTestToSuite( TestSuite *suite )
{
  for ( Factories::iterator it = m_factories.begin();
        it != m_factories.end();
        ++it )
  {
    TestFactory *factory = *it;
    suite->addTest( factory->makeTest() );
  }
}

bool
TestFactoryRegistry::isValid()
{
  return TestFactoryRegistryList::isValid();
}

CPPUNIT_NS_END
<|endoftext|>


<commit_before>//=====================================================================//
/*!	@file
	@brief	A/D 変換のサンプル @n
			P22/ANI2(54)、P23/ANI3(53) を変換して表示
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cstdint>
#include "common/port_utils.hpp"
#include "common/fifo.hpp"
#include "common/uart_io.hpp"
#include "common/format.hpp"
#include "common/itimer.hpp"
#include "common/adc_io.hpp"
#include "common/task.hpp"

namespace {
	void wait_()
	{
		asm("nop");
	}

	typedef utils::fifo<uint8_t, 32> buffer;
	device::uart_io<device::SAU02, device::SAU03, buffer, buffer> uart_;

	device::itimer<uint8_t> itm_;

	// 最終チャネル番号＋１を設定
	typedef device::adc_io<4, utils::null_task> adc;
	adc adc_;
}

/// 割り込みベクターの定義
const void* ivec_[] __attribute__ ((section (".ivec"))) = {
	/*  0 */  nullptr,
	/*  1 */  nullptr,
	/*  2 */  nullptr,
	/*  3 */  nullptr,
	/*  4 */  nullptr,
	/*  5 */  nullptr,
	/*  6 */  nullptr,
	/*  7 */  nullptr,
	/*  8 */  nullptr,
	/*  9 */  nullptr,
	/* 10 */  nullptr,
	/* 11 */  nullptr,
	/* 12 */  nullptr,
	/* 13 */  nullptr,
	/* 14 */  nullptr,
	/* 15 */  nullptr,
	/* 16 */  reinterpret_cast<void*>(uart_.send_task),  // UART1-TX
	/* 17 */  reinterpret_cast<void*>(uart_.recv_task),  // UART1-RX
	/* 18 */  reinterpret_cast<void*>(uart_.error_task), // UART1-ER
	/* 19 */  nullptr,
	/* 20 */  nullptr,
	/* 21 */  nullptr,
	/* 22 */  nullptr,
	/* 23 */  nullptr,
	/* 24 */  reinterpret_cast<void*>(adc_.task),
	/* 25 */  nullptr,
	/* 26 */  reinterpret_cast<void*>(itm_.task),
};

extern "C" {
	void sci_putch(char ch)
	{
		uart_.putch(ch);
	}

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

int main(int argc, char* argv[])
{
	utils::port::pullup_all();  ///< 安全の為、全ての入力をプルアップ

	device::PM4.B3 = 0;  // output

	{
		uint8_t intr_level = 1;
		uart_.start(115200, intr_level);
	}

	{
		uint8_t intr_level = 1;
		itm_.start(60, intr_level);
	}

	{
		device::PM2.B2 = 1;
		device::PM2.B3 = 1;
		uint8_t intr_level = 1;  // 割り込み設定
		adc_.start(adc::REFP::VDD, adc::REFM::VSS, intr_level);
	}

	uart_.puts("Start RL78/G13 A/D Convert sample\n");

	uint8_t n = 0;
	uint8_t t = 0;
	while(1) {
		itm_.sync();
		adc_.start_scan(2);  // スキャン開始チャネル

		if(t >= 30) {
			auto val = adc_.get(2);
			val >>= 6;
#if 1
			uint32_t vol = static_cast<uint32_t>(val) * 1024 / 310;  // Vref: 3.3V とした場合の電圧
			utils::format("A/D CH2: %4.2:10y [V] (%d)\n") % vol % val;
#else
			float vol = static_cast<float>(val) * 3.3f / 1023.0f;
			utils::format("A/D CH2: %4.2f [V] (%d)\n") % vol % val;
#endif
			val = adc_.get(3);
			val >>= 6;
#if 1
			vol = static_cast<uint32_t>(val) * 1024 / 310;
			utils::format("A/D CH3: %4.2:10y [V] (%d)\n") % vol % val;
#else
			vol = static_cast<float>(val) * 3.3f / 1023.0f;
			utils::format("A/D CH3: %4.2f [V] (%d)\n") % vol % val;
#endif
			t = 0;
		} else {
			++t;
		}

		++n;
		if(n >= 30) n = 0;
		device::P4.B3 = n < 10 ? false : true;
	}
}
<commit_msg>fix A/D scan sync<commit_after>//=====================================================================//
/*!	@file
	@brief	A/D 変換のサンプル @n
			P22/ANI2(54)、P23/ANI3(53) を変換して表示
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cstdint>
#include "common/port_utils.hpp"
#include "common/fifo.hpp"
#include "common/uart_io.hpp"
#include "common/format.hpp"
#include "common/itimer.hpp"
#include "common/adc_io.hpp"
#include "common/task.hpp"

namespace {
	void wait_()
	{
		asm("nop");
	}

	typedef utils::fifo<uint8_t, 32> buffer;
	device::uart_io<device::SAU02, device::SAU03, buffer, buffer> uart_;

	device::itimer<uint8_t> itm_;

	// 最終チャネル番号＋１を設定
	typedef device::adc_io<4, utils::null_task> adc;
	adc adc_;
}

/// 割り込みベクターの定義
const void* ivec_[] __attribute__ ((section (".ivec"))) = {
	/*  0 */  nullptr,
	/*  1 */  nullptr,
	/*  2 */  nullptr,
	/*  3 */  nullptr,
	/*  4 */  nullptr,
	/*  5 */  nullptr,
	/*  6 */  nullptr,
	/*  7 */  nullptr,
	/*  8 */  nullptr,
	/*  9 */  nullptr,
	/* 10 */  nullptr,
	/* 11 */  nullptr,
	/* 12 */  nullptr,
	/* 13 */  nullptr,
	/* 14 */  nullptr,
	/* 15 */  nullptr,
	/* 16 */  reinterpret_cast<void*>(uart_.send_task),  // UART1-TX
	/* 17 */  reinterpret_cast<void*>(uart_.recv_task),  // UART1-RX
	/* 18 */  reinterpret_cast<void*>(uart_.error_task), // UART1-ER
	/* 19 */  nullptr,
	/* 20 */  nullptr,
	/* 21 */  nullptr,
	/* 22 */  nullptr,
	/* 23 */  nullptr,
	/* 24 */  reinterpret_cast<void*>(adc_.task),
	/* 25 */  nullptr,
	/* 26 */  reinterpret_cast<void*>(itm_.task),
};

extern "C" {
	void sci_putch(char ch)
	{
		uart_.putch(ch);
	}

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

int main(int argc, char* argv[])
{
	utils::port::pullup_all();  ///< 安全の為、全ての入力をプルアップ

	device::PM4.B3 = 0;  // output

	{
		uint8_t intr_level = 1;
		uart_.start(115200, intr_level);
	}

	{
		uint8_t intr_level = 1;
		itm_.start(60, intr_level);
	}

	{
		device::PM2.B2 = 1;
		device::PM2.B3 = 1;
		uint8_t intr_level = 1;  // 割り込み設定
		adc_.start(adc::REFP::VDD, adc::REFM::VSS, intr_level);
	}

	uart_.puts("Start RL78/G13 A/D Convert sample\n");

	uint8_t n = 0;
	uint8_t t = 0;
	while(1) {
		itm_.sync();
		adc_.start_scan(2);  // スキャン開始チャネル

		adc_.sync();  // スキャン終了待ち

		if(t >= 30) {
			auto val = adc_.get(2);
			val >>= 6;
#if 1
			uint32_t vol = static_cast<uint32_t>(val) * 1024 / 310;  // Vref: 3.3V とした場合の電圧
			utils::format("A/D CH2: %4.2:10y [V] (%d)\n") % vol % val;
#else
			float vol = static_cast<float>(val) * 3.3f / 1023.0f;
			utils::format("A/D CH2: %4.2f [V] (%d)\n") % vol % val;
#endif
			val = adc_.get(3);
			val >>= 6;
#if 1
			vol = static_cast<uint32_t>(val) * 1024 / 310;
			utils::format("A/D CH3: %4.2:10y [V] (%d)\n") % vol % val;
#else
			vol = static_cast<float>(val) * 3.3f / 1023.0f;
			utils::format("A/D CH3: %4.2f [V] (%d)\n") % vol % val;
#endif
			t = 0;
		} else {
			++t;
		}

		++n;
		if(n >= 30) n = 0;
		device::P4.B3 = n < 10 ? false : true;
	}
}
<|endoftext|>


<commit_before>//=====================================================================//
/*!	@file
	@brief	A/D 変換のサンプル @n
			P22/ANI2(54)、P23/ANI3(53) を変換して表示
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2016 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RL78/blob/master/LICENSE
*/
//=====================================================================//
#include <cstdint>
#include "common/renesas.hpp"
#include "common/port_utils.hpp"
#include "common/fifo.hpp"
#include "common/uart_io.hpp"
#include "common/format.hpp"
#include "common/itimer.hpp"
#include "common/adc_io.hpp"
#include "common/task.hpp"

namespace {
	void wait_()
	{
		asm("nop");
	}

	typedef utils::fifo<uint8_t, 32> BUFFER;
	typedef device::uart_io<device::SAU02, device::SAU03, BUFFER, BUFFER> UART1;
	UART1	uart_;

	typedef device::itimer<uint8_t> ITM;
	ITM		itm_;

	// 最終チャネル番号＋１を設定
	typedef device::adc_io<4, utils::null_task> ADC;
	ADC 	adc_;
}

extern "C" {

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

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

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

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

	void UART1_TX_intr(void)
	{
		uart_.send_task();
	}

	void UART1_RX_intr(void)
	{
		uart_.recv_task();
	}

	void UART1_ER_intr(void)
	{
		uart_.error_task();
	}

	void ADC_intr(void)
	{
		adc_.task();
	}

	void ITM_intr(void)
	{
		itm_.task();
	}
};

int main(int argc, char* argv[])
{
	utils::port::pullup_all();  ///< 安全の為、全ての入力をプルアップ

	device::PM4.B3 = 0;  // output

	{
		uint8_t intr_level = 1;
		uart_.start(115200, intr_level);
	}

	{
		uint8_t intr_level = 1;
		itm_.start(60, intr_level);
	}

	{
		device::PM2.B2 = 1;
		device::PM2.B3 = 1;
		uint8_t intr_level = 1;  // 割り込み設定
		adc_.start(ADC::REFP::VDD, ADC::REFM::VSS, intr_level);
	}

	uart_.puts("Start RL78/G13 A/D Convert sample\n");

	uint8_t n = 0;
	uint8_t t = 0;
	while(1) {
		itm_.sync();
		adc_.start_scan(2);  // スキャン開始チャネル

		adc_.sync();  // スキャン終了待ち

		if(t >= 30) {
			auto val = adc_.get(2);
			val >>= 6;
#if 1
			uint32_t vol = static_cast<uint32_t>(val) * 1024 / 310;  // Vref: 3.3V とした場合の電圧
			utils::format("A/D CH2: %4.2:10y [V] (%d)\n") % vol % val;
#else
			float vol = static_cast<float>(val) * 3.3f / 1023.0f;
			utils::format("A/D CH2: %4.2f [V] (%d)\n") % vol % val;
#endif
			val = adc_.get(3);
			val >>= 6;
#if 1
			vol = static_cast<uint32_t>(val) * 1024 / 310;
			utils::format("A/D CH3: %4.2:10y [V] (%d)\n") % vol % val;
#else
			vol = static_cast<float>(val) * 3.3f / 1023.0f;
			utils::format("A/D CH3: %4.2f [V] (%d)\n") % vol % val;
#endif
			t = 0;
		} else {
			++t;
		}

		++n;
		if(n >= 30) n = 0;
		device::P4.B3 = n < 10 ? false : true;
	}
}
<commit_msg>update interrnal temp<commit_after>//=====================================================================//
/*!	@file
	@brief	A/D 変換のサンプル @n
			P22/ANI2(54)、P23/ANI3(53) を変換して表示
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2016 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RL78/blob/master/LICENSE
*/
//=====================================================================//
#include <cstdint>
#include "common/renesas.hpp"
#include "common/port_utils.hpp"
#include "common/fifo.hpp"
#include "common/uart_io.hpp"
#include "common/format.hpp"
#include "common/itimer.hpp"
#include "common/adc_io.hpp"
#include "common/task.hpp"

namespace {
	void wait_()
	{
		asm("nop");
	}

	typedef utils::fifo<uint8_t, 32> BUFFER;
	typedef device::uart_io<device::SAU02, device::SAU03, BUFFER, BUFFER> UART1;
	UART1	uart_;

	typedef device::itimer<uint8_t> ITM;
	ITM		itm_;

	// 最終チャネル番号＋１を設定
	typedef device::adc_io<4, utils::null_task> ADC;
	ADC 	adc_;
}

extern "C" {

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

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

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

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

	void UART1_TX_intr(void)
	{
		uart_.send_task();
	}

	void UART1_RX_intr(void)
	{
		uart_.recv_task();
	}

	void UART1_ER_intr(void)
	{
		uart_.error_task();
	}

	void ADC_intr(void)
	{
		adc_.task();
	}

	void ITM_intr(void)
	{
		itm_.task();
	}
};

int main(int argc, char* argv[])
{
	utils::port::pullup_all();  ///< 安全の為、全ての入力をプルアップ

	device::PM4.B3 = 0;  // output

	{
		uint8_t intr_level = 1;
		uart_.start(115200, intr_level);
	}

	{
		uint8_t intr_level = 1;
		itm_.start(60, intr_level);
	}

	{
		device::PM2.B2 = 1;
		device::PM2.B3 = 1;
		uint8_t intr_level = 1;  // 割り込み設定
		adc_.start(ADC::REFP::VDD, ADC::REFM::VSS, intr_level);
	}

	uart_.puts("Start RL78/G13 A/D Convert sample\n");

	uint8_t n = 0;
	uint8_t t = 0;
	while(1) {
		itm_.sync();
		adc_.start_scan(2, true);  // スキャン開始チャネル、温度取得

		adc_.sync();  // スキャン終了待ち

		if(t >= 30) {
			auto val = adc_.get(2);
			val >>= 6;
#if 1
			uint32_t vol = static_cast<uint32_t>(val) * 1024 / 310;  // Vref: 3.3V とした場合の電圧
			utils::format("A/D CH2: %4.2:10y [V] (%d)\n") % vol % val;
#else
			float vol = static_cast<float>(val) * 3.3f / 1023.0f;
			utils::format("A/D CH2: %4.2f [V] (%d)\n") % vol % val;
#endif
			val = adc_.get(3);
			val >>= 6;
#if 1
			vol = static_cast<uint32_t>(val) * 1024 / 310;
			utils::format("A/D CH3: %4.2:10y [V] (%d)\n") % vol % val;
#else
			vol = static_cast<float>(val) * 3.3f / 1023.0f;
			utils::format("A/D CH3: %4.2f [V] (%d)\n") % vol % val;
#endif
			// 温度表示
			val = adc_.get_temp();
			val >>= 6;
			// 1.05V: 25.0度, 3.6mV/度
			float tv = static_cast<float>(val) * 3.3f / 1023.0f;
			float temp = (1.05f - tv) / 0.0036f + 25.0f;
			utils::format("A/D TEMP: %4.2f [K], %4.3f [V]\n") % temp % tv;

			t = 0;
		} else {
			++t;
		}

		++n;
		if(n >= 30) n = 0;
		device::P4.B3 = n < 10 ? false : true;
	}
}
<|endoftext|>


<commit_before>//  ROS Building Operating System digital temperature and humidity
//  sensor driver based on:
//  How to access GPIO registers from C-code on the Raspberry-Pi
//  Example program
//  15-January-2012
//  Dom and Gert
//

// Access from ARM Running Linux

#define BCM2708_PERI_BASE        0x20000000
#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <assert.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <bcm2835.h>
#include <unistd.h>

#include "ros/ros.h"
#include "std_msgs/Float32.h"

#define MAXTIMINGS 100

#define DEBUG

#define DHT11 11
#define DHT22 22
#define AM2302 22

int readDHT(int type, int pin, float* t, float* h);

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

  if (!bcm2835_init()) return 1;

  if (argc < 3) {
    printf("usage: %s {11|22|2302} GPIOpin# [ROS Parameters]\n", argv[0]);
    printf("example: %s 2302 4 - Read from an AM2302 connected to GPIO #4\n", argv[0]);
    return 2;
  }

  int type = 0;
  if (strcmp(argv[1], "11") == 0) type = DHT11;
  if (strcmp(argv[1], "22") == 0) type = DHT22;
  if (strcmp(argv[1], "2302") == 0) type = AM2302;
  if (type == 0) {
    printf("Select 11, 22, 2302 as type!\n");
    return 3;
  }

  int dhtpin = atoi(argv[2]);
  if (dhtpin <= 0) {
     printf("Please select a valid GPIO pin #\n");
     return 3;
  }

  printf("Using pin #%d\n", dhtpin);

  ros::init(argc, argv, "raspi_dht");

  ros::NodeHandle n;

  ros::Publisher temperature_pub = n.advertise<std_msgs::Float32>("temperature", 1);
  ros::Publisher humidity_pub    = n.advertise<std_msgs::Float32>("humidity", 1);

  ros::Rate loop_rate(0.016);
  ros::Duration retry_interval(5.0);

  while (ros::ok()) {
    std_msgs::Float32 temperature_msg, humidity_msg;
    float t, h;

    ros::spinOnce();

    if (readDHT(type, dhtpin, &t, &h)) {
      temperature_msg.data = t;
      temperature_pub.publish(temperature_msg);
      humidity_msg.data = h;
      humidity_pub.publish(humidity_msg);
      loop_rate.sleep();
    }
    else {
#ifdef DEBUG
      printf("No data, retrying soon\n");
#endif
      retry_interval.sleep();
    }
  }

  return 0;

} // main

int bits[250], data[100];
int bitidx = 0;

int readDHT(int type, int pin, float* t, float* h) {
  int counter = 0;
  int laststate = HIGH;
  int j=0;

  // Set GPIO pin to output
  bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_OUTP);

  bcm2835_gpio_write(pin, HIGH);
  usleep(500000);  // 500 ms
  bcm2835_gpio_write(pin, LOW);
  usleep(20000);

  bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_INPT);

  data[0] = data[1] = data[2] = data[3] = data[4] = 0;

  // wait for pin to drop?
  while (bcm2835_gpio_lev(pin) == 1) {
    usleep(1);
  }

  // read data!
  for (int i=0; i< MAXTIMINGS; i++) {
    counter = 0;
    while ( bcm2835_gpio_lev(pin) == laststate) {
	counter++;
	//nanosleep(1);		// overclocking might change this?
        if (counter == 1000)
	  break;
    }
    laststate = bcm2835_gpio_lev(pin);
    if (counter == 1000) break;
    bits[bitidx++] = counter;

    if ((i>3) && (i%2 == 0)) {
      // shove each bit into the storage bytes
      data[j/8] <<= 1;
      if (counter > 200)
        data[j/8] |= 1;
      j++;
    }
  }

#ifdef DEBUG
  for (int i=3; i<bitidx; i+=2) {
    printf("bit %d: %d\n", i-3, bits[i]);
    printf("bit %d: %d (%d)\n", i-2, bits[i+1], bits[i+1] > 200);
  }
#endif

  if ((j >= 39) &&
      (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) ) {
    // yay!
    if (type == DHT11) {
      *t = (float)data[2];
      *h = (float)data[0];
#ifdef DEBUG
      printf("Temp = %d *C, Hum = %d \%\n", data[2], data[0]);
#endif
    }
     if (type == DHT22) {
	*h = data[0] * 256 + data[1];
	*h /= 10;

	*t = (data[2] & 0x7F)* 256 + data[3];
        *t /= 10.0;
        if (data[2] & 0x80) *t *= -1;
#ifdef DEBUG
	printf("Temp =  %.1f *C, Hum = %.1f \%\n", *t, *h);
#endif
    }
    return 1;
  }

  return 0;
}
<commit_msg>Now working with Avahi enabled on raspberry pi and ROS_HOSTNAME environmental variable set and exported. However there is a buffer overrun bug in the readDHT routine.<commit_after>//  ROS Building Operating System digital temperature and humidity
//  sensor driver based on:
//  How to access GPIO registers from C-code on the Raspberry-Pi
//  Example program
//  15-January-2012
//  Dom and Gert
//

// Access from ARM Running Linux

#define BCM2708_PERI_BASE        0x20000000
#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <assert.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <bcm2835.h>
#include <unistd.h>

#include "ros/ros.h"
#include "std_msgs/Float32.h"

#define MAXTIMINGS 100

//#define DEBUG

#define DHT11 11
#define DHT22 22
#define AM2302 22

int readDHT(int type, int pin, float* t, float* h);

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

  if (!bcm2835_init()) return 1;

  if (argc < 3) {
    printf("usage: %s {11|22|2302} GPIOpin# [ROS Parameters]\n", argv[0]);
    printf("example: %s 2302 4 - Read from an AM2302 connected to GPIO #4\n", argv[0]);
    return 2;
  }

  int type = 0;
  if (strcmp(argv[1], "11") == 0) type = DHT11;
  if (strcmp(argv[1], "22") == 0) type = DHT22;
  if (strcmp(argv[1], "2302") == 0) type = AM2302;
  if (type == 0) {
    printf("Select 11, 22, 2302 as type!\n");
    return 3;
  }

  int dhtpin = atoi(argv[2]);
  if (dhtpin <= 0) {
     printf("Please select a valid GPIO pin #\n");
     return 3;
  }

  printf("Using pin #%d\n", dhtpin);

  ros::init(argc, argv, "raspi_dht");

  ros::NodeHandle n;

  ros::Publisher temperature_pub = n.advertise<std_msgs::Float32>("temperature", 2);
  ros::Publisher humidity_pub    = n.advertise<std_msgs::Float32>("humidity", 2);

  ros::Rate loop_rate(0.016);
  ros::Duration retry_interval(5.0);
  ros::Duration backoff_interval(200);

  bool last_had_data = true;

  while (ros::ok()) {
    std_msgs::Float32 temperature_msg, humidity_msg;
    float t, h;

    if (readDHT(type, dhtpin, &t, &h)) {
      temperature_msg.data = t;
      humidity_msg.data = h;
#ifdef DEBUG
      printf("Publishing data: t=%f, h=%f\n", t, h);
      ROS_INFO("BOS_RASPI_DHT_NODE: %f, %f", t, h);
#endif
      temperature_pub.publish(temperature_msg);
      humidity_pub.publish(humidity_msg);
      ros::spinOnce();
      loop_rate.sleep();
      last_had_data = true;
    }
    else {
      if (last_had_data) {
	ROS_INFO("BOS_raspi_DHT_node: no data, retrying soon");
	retry_interval.sleep();
      }
      else {
	ROS_INFO("BOS_raspi_DHT_node: no data, waiting a while");
	backoff_interval.sleep();
      }
      last_had_data = false;
    }
  }

  return 0;

} // main

int bits[250], data[100];
int bitidx = 0;

int readDHT(int type, int pin, float* t, float* h) {
  int counter = 0;
  int laststate = HIGH;
  int j=0;

  // Set GPIO pin to output
  bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_OUTP);

  bcm2835_gpio_write(pin, HIGH);
  usleep(500000);  // 500 ms
  bcm2835_gpio_write(pin, LOW);
  usleep(20000);

  bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_INPT);

  data[0] = data[1] = data[2] = data[3] = data[4] = 0;

  // wait for pin to drop?
  while (bcm2835_gpio_lev(pin) == 1) {
    usleep(1);
  }

  // read data!
  for (int i=0; i< MAXTIMINGS; i++) {
    counter = 0;
    while ( bcm2835_gpio_lev(pin) == laststate) {
	counter++;
	//nanosleep(1);		// overclocking might change this?
        if (counter == 1000)
	  break;
    }
    laststate = bcm2835_gpio_lev(pin);
    if (counter == 1000) break;
    bits[bitidx++] = counter;

    if ((i>3) && (i%2 == 0)) {
      // shove each bit into the storage bytes
      data[j/8] <<= 1;
      if (counter > 200)
        data[j/8] |= 1;
      j++;
    }
  }

#ifdef DEBUG
  for (int i=3; i<bitidx; i+=2) {
    printf("bit %d: %d\n", i-3, bits[i]);
    printf("bit %d: %d (%d)\n", i-2, bits[i+1], bits[i+1] > 200);
  }
#endif

  if ((j >= 39) &&
      (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) ) {
    // yay!
    if (type == DHT11) {
      *t = (float)data[2];
      *h = (float)data[0];
#ifdef DEBUG
      printf("Temp = %d *C, Hum = %d \%\n", data[2], data[0]);
#endif
    }
     if (type == DHT22) {
	*h = data[0] * 256 + data[1];
	*h /= 10;

	*t = (data[2] & 0x7F)* 256 + data[3];
        *t /= 10.0;
        if (data[2] & 0x80) *t *= -1;
#ifdef DEBUG
	printf("Temp =  %.1f *C, Hum = %.1f \%\n", *t, *h);
#endif
    }
    return 1;
  }

  return 0;
}
<|endoftext|>


<commit_before>/*
 * ====================================================================
 * Copyright (c) 2002-2005 The RapidSvn Group.  All rights reserved.
 *
 * 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 (in the file LGPL.txt); if not,
 * write to the Free Software Foundation, Inc., 51 Franklin St,
 * Fifth Floor, Boston, MA  02110-1301  USA
 *
 * This software consists of voluntary contributions made by many
 * individuals.  For exact contribution history, see the revision
 * history and logs, available at http://rapidsvn.tigris.org/.
 * ====================================================================
 */
#if defined( _MSC_VER) && _MSC_VER <= 1200
#pragma warning( disable: 4786 )// debug symbol truncated
#endif
// svncpp
#include "client_impl.hpp"

// Subversion api
#include "svn_client.h"
#include "svn_path.h"

#include "exception.hpp"
#include "pool.hpp"
#include "status.hpp"
#include "svnqt_defines.hpp"

namespace svn
{
  /**
   * a quick way to create error messages
   */
  static void
  fail (apr_pool_t *pool, apr_status_t status, const char *fmt, ...)
  {
    va_list ap;
    char *msg;
    svn_error_t * error;

    va_start (ap, fmt);
    msg = apr_pvsprintf (pool, fmt, ap);
    va_end (ap);

    error = svn_error_create (status, NULL, msg);
    throw ClientException (error);
  }

  /**
   * closes and deletes temporary files that diff has been using
   */
  static void
  diffCleanup (apr_file_t * outfile, const char * outfileName,
               apr_file_t * errfile, const char * errfileName,
               apr_pool_t *pool)
  {
    if (outfile != NULL)
      apr_file_close (outfile);

    if (errfile != NULL)
      apr_file_close (errfile);

    if (outfileName != NULL)
      svn_error_clear (svn_io_remove_file (outfileName, pool));

    if (errfileName != NULL)
      svn_error_clear (svn_io_remove_file (errfileName, pool));
  }

  QByteArray
  Client_impl::diff (const Path & tmpPath, const Path & path,
                const Revision & revision1, const Revision & revision2,
                const bool recurse, const bool ignoreAncestry,
                const bool noDiffDeleted,const bool ignore_contenttype) throw (ClientException)
  {
    return diff(tmpPath,path,path,revision1,revision2,recurse,ignoreAncestry,noDiffDeleted,ignore_contenttype);
  }

  QByteArray
  Client_impl::diff (const Path & tmpPath, const Path & path1,const Path&path2,
                const Revision & revision1, const Revision & revision2,
                const bool recurse, const bool ignoreAncestry,
                const bool noDiffDeleted,const bool ignore_contenttype) throw (ClientException)
  {

    Pool pool;
    svn_error_t * error;
    apr_status_t status;
    apr_file_t * outfile = 0L;
    const char * outfileName = 0L;
    apr_file_t * errfile = 0L;
    const char * errfileName = 0L;
    apr_array_header_t * options;
    svn_stringbuf_t * stringbuf;
    bool working_copy_present = false;
    bool url_is_present = false;
    Revision r1,r2;
    r1 = revision1;
    r2 = revision2;

    if (svn_path_is_url(path1.cstr())) {
        url_is_present = true;
    } else {
        working_copy_present = true;
    }
    if (svn_path_is_url(path2.cstr())) {
        url_is_present = true;
    } else {
        working_copy_present = true;
    }

    if (revision1.revision()->kind==svn_opt_revision_unspecified && working_copy_present) {
        r1 = svn_opt_revision_base;
    }
    if (revision2.revision()->kind==svn_opt_revision_unspecified) {
        r2 = working_copy_present?svn_opt_revision_working : svn_opt_revision_head;
    }
    // svn_client_diff needs an options array, even if it is empty
    options = apr_array_make (pool, 0, 0);

    // svn_client_diff needs a temporary file to write diff output to
    error = svn_io_open_unique_file (&outfile, &outfileName,
                                     tmpPath.path().TOUTF8(),
                                     ".tmp",
                                     FALSE, pool);

    if (error != NULL)
    {
      diffCleanup (outfile, outfileName, errfile, errfileName, pool);
      throw ClientException (error);
    }

    // and another one to write errors to
    error = svn_io_open_unique_file (&errfile, &errfileName,
                                     tmpPath.path().TOUTF8(), ".error.tmp",
                                     FALSE, pool);

    if (error != NULL)
    {
      diffCleanup (outfile, outfileName, errfile, errfileName, pool);
      throw ClientException (error);
    }

    // run diff
    error = svn_client_diff2 (options,
                             path1.cstr (), r1.revision (),
                             path2.cstr (), r2.revision (),
                             recurse, ignoreAncestry, noDiffDeleted, ignore_contenttype,
                             outfile, errfile,
                             *m_context,
                             pool);

    if (error != NULL)
    {
      diffCleanup (outfile, outfileName, errfile, errfileName, pool);
      throw ClientException (error);
    }

    // then we reopen outfile for reading
    status = apr_file_close (outfile);
    if (status)
    {
      diffCleanup (outfile, outfileName, errfile, errfileName, pool);
      fail (pool, status, "failed to close '%s'", outfileName);
    }

    status = apr_file_open (&outfile, outfileName, APR_READ, APR_OS_DEFAULT, pool);
    if (status)
    {
      diffCleanup (outfile, outfileName, errfile, errfileName, pool);
      fail (pool, status, "failed to open '%s'", outfileName);
    }

    // now we can read the diff output from outfile and return that
    error = svn_stringbuf_from_aprfile (&stringbuf, outfile, pool);

    if (error != NULL)
    {
      diffCleanup (outfile, outfileName, errfile, errfileName, pool);
      throw ClientException (error);
    }

    diffCleanup (outfile, outfileName, errfile, errfileName, pool);
#if QT_VERSION < 0x040000
    QByteArray res;
    /// @todo check if realy dup or just assign!
    res.duplicate(stringbuf->data,stringbuf->len);
#else
    QByteArray res( stringbuf->data, stringbuf->len );
#endif
    return res;
  }
}

/* -----------------------------------------------------------------
 * local variables:
 * eval: (load-file "../../rapidsvn-dev.el")
 * end:
 */
<commit_msg>diff reads the result direct into QByteArray instead of copy it from string_buffer<commit_after>/*
 * ====================================================================
 * Copyright (c) 2002-2005 The RapidSvn Group.  All rights reserved.
 *
 * 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 (in the file LGPL.txt); if not,
 * write to the Free Software Foundation, Inc., 51 Franklin St,
 * Fifth Floor, Boston, MA  02110-1301  USA
 *
 * This software consists of voluntary contributions made by many
 * individuals.  For exact contribution history, see the revision
 * history and logs, available at http://rapidsvn.tigris.org/.
 * ====================================================================
 */
#if defined( _MSC_VER) && _MSC_VER <= 1200
#pragma warning( disable: 4786 )// debug symbol truncated
#endif
// svncpp
#include "client_impl.hpp"

// Subversion api
#include "svn_client.h"
#include "svn_path.h"

#include "exception.hpp"
#include "pool.hpp"
#include "status.hpp"
#include "svnqt_defines.hpp"

#include <qfile.h>

namespace svn
{
  /**
   * a quick way to create error messages
   */
  static void
  fail (apr_pool_t *pool, apr_status_t status, const char *fmt, ...)
  {
    va_list ap;
    char *msg;
    svn_error_t * error;

    va_start (ap, fmt);
    msg = apr_pvsprintf (pool, fmt, ap);
    va_end (ap);

    error = svn_error_create (status, NULL, msg);
    throw ClientException (error);
  }

  /**
   * closes and deletes temporary files that diff has been using
   */
  static void
  diffCleanup (apr_file_t * outfile, const char * outfileName,
               apr_file_t * errfile, const char * errfileName,
               apr_pool_t *pool)
  {
    if (outfile != NULL)
      apr_file_close (outfile);

    if (errfile != NULL)
      apr_file_close (errfile);

    if (outfileName != NULL)
      svn_error_clear (svn_io_remove_file (outfileName, pool));

    if (errfileName != NULL)
      svn_error_clear (svn_io_remove_file (errfileName, pool));
  }

  QByteArray
  Client_impl::diff (const Path & tmpPath, const Path & path,
                const Revision & revision1, const Revision & revision2,
                const bool recurse, const bool ignoreAncestry,
                const bool noDiffDeleted,const bool ignore_contenttype) throw (ClientException)
  {
    return diff(tmpPath,path,path,revision1,revision2,recurse,ignoreAncestry,noDiffDeleted,ignore_contenttype);
  }

  QByteArray
  Client_impl::diff (const Path & tmpPath, const Path & path1,const Path&path2,
                const Revision & revision1, const Revision & revision2,
                const bool recurse, const bool ignoreAncestry,
                const bool noDiffDeleted,const bool ignore_contenttype) throw (ClientException)
  {

    Pool pool;
    svn_error_t * error;
    apr_status_t status;
    apr_file_t * outfile = 0L;
    const char * outfileName = 0L;
    apr_file_t * errfile = 0L;
    const char * errfileName = 0L;
    apr_array_header_t * options;
    bool working_copy_present = false;
    bool url_is_present = false;
    Revision r1,r2;
    r1 = revision1;
    r2 = revision2;

    if (svn_path_is_url(path1.cstr())) {
        url_is_present = true;
    } else {
        working_copy_present = true;
    }
    if (svn_path_is_url(path2.cstr())) {
        url_is_present = true;
    } else {
        working_copy_present = true;
    }

    if (revision1.revision()->kind==svn_opt_revision_unspecified && working_copy_present) {
        r1 = svn_opt_revision_base;
    }
    if (revision2.revision()->kind==svn_opt_revision_unspecified) {
        r2 = working_copy_present?svn_opt_revision_working : svn_opt_revision_head;
    }
    // svn_client_diff needs an options array, even if it is empty
    options = apr_array_make (pool, 0, 0);

    // svn_client_diff needs a temporary file to write diff output to
    error = svn_io_open_unique_file (&outfile, &outfileName,
                                     tmpPath.path().TOUTF8(),
                                     ".tmp",
                                     FALSE, pool);

    if (error != NULL)
    {
      diffCleanup (outfile, outfileName, errfile, errfileName, pool);
      throw ClientException (error);
    }

    // and another one to write errors to
    error = svn_io_open_unique_file (&errfile, &errfileName,
                                     tmpPath.path().TOUTF8(), ".error.tmp",
                                     FALSE, pool);

    if (error != NULL)
    {
      diffCleanup (outfile, outfileName, errfile, errfileName, pool);
      throw ClientException (error);
    }

    // run diff
    error = svn_client_diff2 (options,
                             path1.cstr (), r1.revision (),
                             path2.cstr (), r2.revision (),
                             recurse, ignoreAncestry, noDiffDeleted, ignore_contenttype,
                             outfile, errfile,
                             *m_context,
                             pool);

    if (error != NULL)
    {
      diffCleanup (outfile, outfileName, errfile, errfileName, pool);
      throw ClientException (error);
    }

    status = apr_file_close (outfile);
    if (status)
    {
      diffCleanup (outfile, outfileName, errfile, errfileName, pool);
      fail (pool, status, "failed to close '%s'", outfileName);
    }

    QFile fi(outfileName);
#if QT_VERSION < 0x040000
    if (!fi.open(IO_ReadOnly|IO_Raw)) {
#else
    if (!fi.open(QIODevice::IO_ReadOnly)) {
#endif
        diffCleanup (outfile, outfileName, errfile, errfileName, pool);
        fail(pool,0,fi.errorString()+"'%s'",outfileName);
    }

    QByteArray res = fi.readAll();
    fi.close();

    diffCleanup (outfile, outfileName, errfile, errfileName, pool);
    return res;
  }
}

/* -----------------------------------------------------------------
 * local variables:
 * eval: (load-file "../../rapidsvn-dev.el")
 * end:
 */
<|endoftext|>


<commit_before>#ifndef CLIENT_WS_HPP
#define	CLIENT_WS_HPP

#include <boost/asio.hpp>

#include <unordered_map>
#include <iostream>
#include <regex>
#include <random>

namespace SimpleWeb {
    template <class socket_type>
    class ClientBase {
    public:
        class Response {
            friend class ClientBase<socket_type>;

        public:
            std::string http_version, status_code;

            std::istream content;

            std::unordered_map<std::string, std::string> header;

        private:
            boost::asio::streambuf content_buffer;

            Response(): content(&content_buffer) {};
        };

        //TODO add header parameters
        std::shared_ptr<Response> request(const std::string& request_type, const std::string& path="/") {
            std::stringstream empty_ss;
            return request(request_type, path, empty_ss);
        }

        std::shared_ptr<Response> request(const std::string& request_type, const std::string& path, std::ostream& content) {
            std::string corrected_path=path;
            if(corrected_path=="")
                corrected_path="/";

            content.seekp(0, std::ios::end);
            size_t content_length=content.tellp();
            content.seekp(0, std::ios::beg);

            boost::asio::streambuf write_buffer;
            std::ostream write_stream(&write_buffer);
            write_stream << request_type << " " << corrected_path << " HTTP/1.1\r\n";
            write_stream << "Host: " << host << "\r\n";
            if(content_length>0)
                write_stream << "Content-Length: " << std::to_string(content_length) << "\r\n";
            write_stream << "\r\n";
            if(content_length>0)
                write_stream << content.rdbuf();

            std::shared_ptr<Response> response(new Response());

            try {
                connect();

                boost::asio::write(*socket, write_buffer);

                size_t bytes_transferred = boost::asio::read_until(*socket, response->content_buffer, "\r\n\r\n");

                size_t num_additional_bytes=response->content_buffer.size()-bytes_transferred;

                parse_response_header(response, response->content);

                if(response->header.count("Content-Length")>0) {
                    boost::asio::read(*socket, response->content_buffer,
                            boost::asio::transfer_exactly(stoull(response->header["Content-Length"])-num_additional_bytes));
                }
                else if(response->header.count("Transfer-Encoding")>0 && response->header["Transfer-Encoding"]=="chunked") {
                    boost::asio::streambuf streambuf;
                    std::ostream content(&streambuf);

                    size_t length;
                    std::string buffer;
                    do {
                        size_t bytes_transferred = boost::asio::read_until(*socket, response->content_buffer, "\r\n");
                        std::string line;
                        getline(response->content, line);
                        bytes_transferred-=line.size()+1;
                        line.pop_back();
                        length=stoull(line, 0, 16);

                        size_t num_additional_bytes=response->content_buffer.size()-bytes_transferred;

                        if((2+length)>num_additional_bytes) {
                            boost::asio::read(*socket, response->content_buffer,
                                boost::asio::transfer_exactly(2+length-num_additional_bytes));
                        }

                        buffer.resize(length);
                        response->content.read(&buffer[0], length);
                        content.write(&buffer[0], length);

                        //Remove "\r\n"
                        response->content.get();
                        response->content.get();
                    } while(length>0);

                    std::ostream response_content_output_stream(&response->content_buffer);
                    response_content_output_stream << content.rdbuf();
                }
            }
            catch(const std::exception& e) {
                socket_error=true;
                throw std::invalid_argument(e.what());
            }

            return response;
        }

    protected:
        boost::asio::io_service asio_io_service;
        boost::asio::ip::tcp::endpoint asio_endpoint;
        boost::asio::ip::tcp::resolver asio_resolver;

        std::shared_ptr<socket_type> socket;
        bool socket_error;

        std::string host;
        unsigned short port;

        ClientBase(const std::string& host_port, unsigned short default_port) :
                asio_resolver(asio_io_service), socket_error(false) {
            std::regex e("^([^:/]+):?([0-9]*)$");

            std::smatch sm;

            if(std::regex_match(host_port, sm, e)) {
                host=sm[1];
                port=default_port;
                if(sm[2]!="")
                    port=(unsigned short)std::stoul(sm[2]);
                asio_endpoint=boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port);
            }
            else {
                throw std::invalid_argument("Error parsing host_port");
            }
        }

        virtual void connect()=0;

        void parse_response_header(std::shared_ptr<Response> response, std::istream& stream) const {
            std::smatch sm;

            //Parse the first line
            std::string line;
            getline(stream, line);
            line.pop_back();

            std::regex e("^HTTP/([^ ]*) (.*)$");
            if(std::regex_match(line, sm, e)) {
                response->http_version=sm[1];
                response->status_code=sm[2];

                e="^([^:]*): ?(.*)$";
                //Parse the rest of the header
                bool matched;
                do {
                    getline(stream, line);
                    line.pop_back();
                    matched=std::regex_match(line, sm, e);
                    if(matched) {
                        response->header[sm[1]]=sm[2];
                    }

                } while(matched==true);
            }
        }
    };

    template<class socket_type>
    class Client : public ClientBase<socket_type> {};

    typedef boost::asio::ip::tcp::socket HTTP;

    template<>
    class Client<HTTP> : public ClientBase<HTTP> {
    public:
        Client(const std::string& server_port_path) : ClientBase<HTTP>::ClientBase(server_port_path, 80) {
            socket=std::make_shared<HTTP>(asio_io_service);
        };

    private:
        void connect() {
            if(socket_error || !socket->is_open()) {
                boost::asio::ip::tcp::resolver::query query(host, std::to_string(port));
                boost::asio::connect(*socket, asio_resolver.resolve(query));
                socket_error=false;
            }
        }
    };
}

#endif	/* CLIENT_WS_HPP */<commit_msg>added header parameter to Client::request<commit_after>#ifndef CLIENT_WS_HPP
#define	CLIENT_WS_HPP

#include <boost/asio.hpp>

#include <unordered_map>
#include <map>
#include <iostream>
#include <regex>
#include <random>

namespace SimpleWeb {
    template <class socket_type>
    class ClientBase {
    public:
        class Response {
            friend class ClientBase<socket_type>;

        public:
            std::string http_version, status_code;

            std::istream content;

            std::unordered_map<std::string, std::string> header;

        private:
            boost::asio::streambuf content_buffer;

            Response(): content(&content_buffer) {};
        };

        //TODO add header parameters
        std::shared_ptr<Response> request(const std::string& request_type, const std::string& path="/",
                const std::map<std::string, std::string>& header={{}}) {
            std::stringstream empty_ss;
            return request(request_type, path, empty_ss, header);
        }

        std::shared_ptr<Response> request(const std::string& request_type, const std::string& path, std::ostream& content,
                const std::map<std::string, std::string>& header={{}}) {
            std::string corrected_path=path;
            if(corrected_path=="")
                corrected_path="/";

            content.seekp(0, std::ios::end);
            size_t content_length=content.tellp();
            content.seekp(0, std::ios::beg);

            boost::asio::streambuf write_buffer;
            std::ostream write_stream(&write_buffer);
            write_stream << request_type << " " << corrected_path << " HTTP/1.1\r\n";
            write_stream << "Host: " << host << "\r\n";
            for(auto& h: header) {
                write_stream << h.first << ": " << h.second << "\r\n";
            }
            if(content_length>0)
                write_stream << "Content-Length: " << std::to_string(content_length) << "\r\n";
            write_stream << "\r\n";
            if(content_length>0)
                write_stream << content.rdbuf();

            std::shared_ptr<Response> response(new Response());

            try {
                connect();

                boost::asio::write(*socket, write_buffer);

                size_t bytes_transferred = boost::asio::read_until(*socket, response->content_buffer, "\r\n\r\n");

                size_t num_additional_bytes=response->content_buffer.size()-bytes_transferred;

                parse_response_header(response, response->content);

                if(response->header.count("Content-Length")>0) {
                    boost::asio::read(*socket, response->content_buffer,
                            boost::asio::transfer_exactly(stoull(response->header["Content-Length"])-num_additional_bytes));
                }
                else if(response->header.count("Transfer-Encoding")>0 && response->header["Transfer-Encoding"]=="chunked") {
                    boost::asio::streambuf streambuf;
                    std::ostream content(&streambuf);

                    size_t length;
                    std::string buffer;
                    do {
                        size_t bytes_transferred = boost::asio::read_until(*socket, response->content_buffer, "\r\n");
                        std::string line;
                        getline(response->content, line);
                        bytes_transferred-=line.size()+1;
                        line.pop_back();
                        length=stoull(line, 0, 16);

                        size_t num_additional_bytes=response->content_buffer.size()-bytes_transferred;

                        if((2+length)>num_additional_bytes) {
                            boost::asio::read(*socket, response->content_buffer,
                                boost::asio::transfer_exactly(2+length-num_additional_bytes));
                        }

                        buffer.resize(length);
                        response->content.read(&buffer[0], length);
                        content.write(&buffer[0], length);

                        //Remove "\r\n"
                        response->content.get();
                        response->content.get();
                    } while(length>0);

                    std::ostream response_content_output_stream(&response->content_buffer);
                    response_content_output_stream << content.rdbuf();
                }
            }
            catch(const std::exception& e) {
                socket_error=true;
                throw std::invalid_argument(e.what());
            }

            return response;
        }

    protected:
        boost::asio::io_service asio_io_service;
        boost::asio::ip::tcp::endpoint asio_endpoint;
        boost::asio::ip::tcp::resolver asio_resolver;

        std::shared_ptr<socket_type> socket;
        bool socket_error;

        std::string host;
        unsigned short port;

        ClientBase(const std::string& host_port, unsigned short default_port) :
                asio_resolver(asio_io_service), socket_error(false) {
            std::regex e("^([^:/]+):?([0-9]*)$");

            std::smatch sm;

            if(std::regex_match(host_port, sm, e)) {
                host=sm[1];
                port=default_port;
                if(sm[2]!="")
                    port=(unsigned short)std::stoul(sm[2]);
                asio_endpoint=boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port);
            }
            else {
                throw std::invalid_argument("Error parsing host_port");
            }
        }

        virtual void connect()=0;

        void parse_response_header(std::shared_ptr<Response> response, std::istream& stream) const {
            std::smatch sm;

            //Parse the first line
            std::string line;
            getline(stream, line);
            line.pop_back();

            std::regex e("^HTTP/([^ ]*) (.*)$");
            if(std::regex_match(line, sm, e)) {
                response->http_version=sm[1];
                response->status_code=sm[2];

                e="^([^:]*): ?(.*)$";
                //Parse the rest of the header
                bool matched;
                do {
                    getline(stream, line);
                    line.pop_back();
                    matched=std::regex_match(line, sm, e);
                    if(matched) {
                        response->header[sm[1]]=sm[2];
                    }

                } while(matched==true);
            }
        }
    };

    template<class socket_type>
    class Client : public ClientBase<socket_type> {};

    typedef boost::asio::ip::tcp::socket HTTP;

    template<>
    class Client<HTTP> : public ClientBase<HTTP> {
    public:
        Client(const std::string& server_port_path) : ClientBase<HTTP>::ClientBase(server_port_path, 80) {
            socket=std::make_shared<HTTP>(asio_io_service);
        };

    private:
        void connect() {
            if(socket_error || !socket->is_open()) {
                boost::asio::ip::tcp::resolver::query query(host, std::to_string(port));
                boost::asio::connect(*socket, asio_resolver.resolve(query));
                socket_error=false;
            }
        }
    };
}

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


<commit_before>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "TriangulatedMeshGenerator.h"

// poly2tri triangulation library
#include "poly2tri.h"

registerMooseObject("ReactorApp", TriangulatedMeshGenerator);

InputParameters
TriangulatedMeshGenerator::validParams()
{
  InputParameters params = MeshGenerator::validParams();

  params.addRangeCheckedParam<SubdomainID>(
    "subdomain_id",
    "subdomain_id>=0",
    "The subdomain ID given to the TRI3 elements in the triangulation.");
  params.addRequiredParam<MeshGeneratorName>(
    "inner_boundary_mesh",
    "The mesh to use for the inner boundary of the triangulation.");
  params.addRangeCheckedParam<boundary_id_type>(
    "inner_boundary_id",
    "inner_boundary_id>=0",
    "The boundary ID of the inner mesh outer boundary.");
  params.addParam<std::string>(
    "inner_boundary_name",
    "The boundary name of the inner mesh outer boundary.");
  params.addRequiredRangeCheckedParam<Real>(
    "outer_circle_radius",
    "outer_circle_radius>0",
    "Radius of outer circle boundary.");
  params.addRequiredRangeCheckedParam<unsigned int>(
    "outer_circle_num_segments",
    "outer_circle_num_segments>0",
    "Number of radial segments to subdivide outer circle boundary.");
  params.addRangeCheckedParam<boundary_id_type>(
    "outer_boundary_id",
    "outer_boundary_id>=0",
    "The boundary id for the generated mesh outer boundary.");
  // params.addParam<std::string>(
  //   "outer_boundary_name",
  //   "The boundary name of the generated mesh outer boundary.");
  params.addParam<std::vector<Real>>(
    "extra_circle_radii",
    "Radii of extra Steiner point circles.");
  params.addParam<std::vector<unsigned int>>(
    "extra_circle_num_segments",
    "Number of segments for extra Steiner point circles.");
  params.addClassDescription(
    "This TriangulatedMeshGenerator object is designed to generate "
    "a triangulated mesh between a generated outer circle boundary "
    "and a provided inner mesh.");

  return params;
}

TriangulatedMeshGenerator::TriangulatedMeshGenerator(const InputParameters & parameters)
  : MeshGenerator(parameters),
    _tri_subdomain_id(isParamValid("subdomain_id") ? getParam<SubdomainID>("subdomain_id") : 0),
    _inner_boundary_mesh(getMesh("inner_boundary_mesh")),
    _outer_circle_radius(getParam<Real>("outer_circle_radius")),
    _outer_circle_num_segments(getParam<unsigned int>("outer_circle_num_segments")),
    _outer_boundary_id(isParamValid("outer_boundary_id") ? getParam<boundary_id_type>("outer_boundary_id") : 0),
    // _outer_boundary_name(isParamValid("outer_boundary_name") ? getParam<std::string>("outer_boundary_name") : std::string("outside")),
    _extra_circle_radii(getParam<std::vector<Real>>("extra_circle_radii")),
    _extra_circle_num_segments(getParam<std::vector<unsigned int>>("extra_circle_num_segments"))
{
  // confirm either id or name (exclusive or) for inner mesh boundary is provided
  if ((!isParamValid("inner_boundary_id") && !isParamValid("inner_boundary_name")) ||
      (isParamValid("inner_boundary_id") && isParamValid("inner_boundary_name"))) {
    paramError(
      "inner_boundary_id",
      "Either 'inner_boundary_id' or 'inner_boundary_name' must be provided, but not both.");
  }

  // confirm Steiner inputs are equal length
  if (_extra_circle_radii.size() != _extra_circle_num_segments.size()) {
    paramError(
      "extra_circle_num_segments",
      "The size of 'extra_circle_num_segments' must be equal to the size of 'extra_circle_radii'.");
  }
}

std::unique_ptr<MeshBase>
TriangulatedMeshGenerator::generate()
{
  //
  // Set up mesh based on input inner mesh
  //

  std::unique_ptr<MeshBase> mesh = std::move(_inner_boundary_mesh);
  BoundaryInfo & boundary_info = mesh->get_boundary_info();

  // set inner boundary id based on give input
  if(isParamValid("inner_boundary_id")) {
    _inner_boundary_id = getParam<boundary_id_type>("inner_boundary_id");
  }
  if(isParamValid("inner_boundary_name")) {
    _inner_boundary_id = boundary_info.get_id_by_name(getParam<std::string>("inner_boundary_name"));
  }

  // build nodesets and sidesets
  boundary_info.build_node_list_from_side_list();
  boundary_info.build_side_list_from_node_list();

  //
  // extract boundary nodes from input mesh inner boundary
  // poly2tri requires input boundary nodes be sorted in connected order
  //

  std::vector<Node*> inner_boundary_nodes;
  _create_sorted_boundary_node_list(mesh, inner_boundary_nodes);

  //
  // C2T storage
  //

  /// Polylines
  std::vector<p2t::Point*> outer_polyline;
  std::vector<p2t::Point*> inner_polyline;
  std::vector<p2t::Point*> steiner_points;

  // store association map for reference
  std::map<p2t::Point*, Node*> point_node_map;

  //
  // Inner P2T boundary; extract from existing mesh
  //

  // POLYLINE NEEDS TO BE DIRECTED

  // DEBUG
  // std::cout << "Created Inner Polyline" << std::endl;

  for (Node* node : inner_boundary_nodes) {
    // extract (x, y) coords
    Real x = (*node)(0);
    Real y = (*node)(1);
    // create Point
    p2t::Point *point = new p2t::Point(x, y);
    // add to inner boundary list
    inner_polyline.push_back(point);
    // add to association map
    point_node_map[point] = node;

    // DEBUG
    // std::cout << *node << std::endl;
  }

  //
  // Outer P2T boundary; create circle from input parameters
  //

  // DEBUG
  // std::cout << "Creating Outer Polyline" << std::endl;

  // radial spacing
  Real d_theta = 2.0 * M_PI / _outer_circle_num_segments;

  for (unsigned int i = 0; i < _outer_circle_num_segments; i++) {
    // rotation angle
    Real theta = i * d_theta;
    // calculate (x, y) coords
    Real x = _outer_circle_radius * std::cos(theta);
    Real y = _outer_circle_radius * std::sin(theta);

    // create Point
    p2t::Point *point = new p2t::Point(x, y);
    // add to outer boundary list
    outer_polyline.push_back(point);
    // create Node and add to mesh
    Node *node = mesh->add_point(Point(x, y, 0.0));
    // add to association map
    point_node_map[point] = node;

    // DEBUG
    // std::cout << *node << std::endl;

  }

  //
  // Additional Steiner points; create additional circles of Steiner points between inner and outer boundaries.
  //

  // DEBUG
  // std::cout << "Creating Steiner points" << std::endl;

  for (std::vector<unsigned int>::size_type idx = 0; idx < _extra_circle_radii.size(); idx++) {
    // extract Steiner point circle parameters
    Real num_segments = _extra_circle_num_segments[idx];
    Real radius = _extra_circle_radii[idx];

    // radial spacing
    d_theta = 2.0 * M_PI / num_segments;

    for (unsigned int i = 0; i < num_segments; i++) {
      // rotation angle
      Real theta = i * d_theta;
      // calculate (x, y) coords
      Real x = radius * std::cos(theta);
      Real y = radius * std::sin(theta);

      // create Point
      p2t::Point *point = new p2t::Point(x, y);
      // add to Steiner point list
      steiner_points.push_back(point);
      // create Node and add to mesh
      Node *node = mesh->add_point(Point(x, y, 0.0));
      // add to association map
      point_node_map[point] = node;

      // DEBUG
      // std::cout << *node << std::endl;

    }
  }

  //
  // Create P2T CDT and add primary (outer) polyline
  // NOTE: polyline must be a simple polygon. The polyline's points constitute constrained edges. No repeat points!!!
  //

  p2t::CDT* cdt = new p2t::CDT(outer_polyline);

  // Add inner boundary
  cdt->AddHole(inner_polyline);

  // Add Steiner points
  for (const auto& point : steiner_points) {
    cdt->AddPoint(point);
  }

  // DEBUG
  // std::cout << "Triangulating" << std::endl;

  // Triangulate!
  cdt->Triangulate();

  // DEBUG
  // std::cout << "Triangulating complete" << std::endl;

  //
  // Translate triangulated C2T points/triangles to libMesh nodes/Tri3s
  //

  // Extract triangle list from triangulation
  std::vector<p2t::Triangle*> triangles = cdt->GetTriangles();

  // process each P2T triangle into libMesh Tri3
  for (p2t::Triangle* triangle : triangles) {

    // create Tri3 element
    Tri3* tri_elem = new Tri3();

    // process each point on triangle
    for (const int i : std::vector<int>{0,1,2}) {
      // extract p2t::point from triangle
      p2t::Point* point = triangle->GetPoint(i);

      // check if node has been created for point
      // if not, create and add to map
      if (point_node_map.find(point) == point_node_map.end()) {
        point_node_map[point] = mesh->add_point(Point(point->x, point->y, 0.0));
      }

      // retrieve node and add to element
      tri_elem->set_node(i) = point_node_map[point];
    }

    // set element subdomain id
    tri_elem->subdomain_id() = _tri_subdomain_id;

    // add completed element to mesh
    mesh->add_elem(tri_elem);
  }

  //
  // add nodesets for boundaries
  //

  for (p2t::Point* point : outer_polyline) {
    boundary_info.add_node(point_node_map[point], _outer_boundary_id);
  }
  // boundary_info.sideset_name(_outer_boundary_id) = _outer_boundary_name;

  // generate sidesets from nodesets
  // boundary_info.build_side_list_from_node_list();

  //
  // Cleanup P2T objects
  //

  delete cdt;
  _clearPoints(outer_polyline);
  _clearPoints(inner_polyline);
  _clearPoints(steiner_points);

  //
  // finalize mesh and return
  //

  mesh->prepare_for_use();

  return dynamic_pointer_cast<MeshBase>(mesh);
}

void TriangulatedMeshGenerator::_create_sorted_boundary_node_list(std::unique_ptr<MeshBase>& mesh, std::vector<Node*>& inner_boundary_nodes)
{
  BoundaryInfo & boundary_info = mesh->get_boundary_info();

  // poly2tri requires input boundary nodes be in connected order
  // create edge node pairs to sort by connectivity

  // vector of <element_id, side_id, boundary_id> tuples
  auto side_list = boundary_info.build_side_list();

  std::vector<std::pair<dof_id_type, dof_id_type>> boundary_node_assm;

  // create edge node pairs for sides on the specified boundary
  for (const auto entry : side_list) {
    // select out tuple components
    dof_id_type element_id = std::get<0>(entry);
    unsigned short int side_id = std::get<1>(entry);
    boundary_id_type boundary_id = std::get<2>(entry);

    // skip sides not in given boundary id
    if (boundary_id != _inner_boundary_id) {
      continue;
    }

    // select out nodes for given side and add to list
    auto side = mesh->elem_ptr(element_id)->side_ptr(side_id);

    boundary_node_assm.push_back(
        std::make_pair(side->node_id(0), side->node_id(1))
    );
  }

  //
  // sort boundary sides into connected order
  //

  std::vector<dof_id_type> boundary_ordered_node_list;
  bool isFlipped = false;

  // start sorted node list with nodes from first side in side list, first two nodes are sorted
  // remove side from side list to be sorted
  boundary_ordered_node_list.push_back(boundary_node_assm.front().first);
  boundary_ordered_node_list.push_back(boundary_node_assm.front().second);
  boundary_node_assm.erase(boundary_node_assm.begin());

  // save initial length of the list, size will shrink during loop
  const unsigned int boundary_node_assm_size_0 = boundary_node_assm.size();
  // iterate over all remaining side pairs
  for (unsigned int i = 0; i < boundary_node_assm_size_0; i++) {
    // use the last node in the sorted node list for lookup
    // find the side in the remaining side list that connects to this node
    dof_id_type end_node_id = boundary_ordered_node_list.back();

    // create lambda functions to search remaining side list
    // lambda to check if current end_node_id is in pair first position
    auto node_in_first_pos =
        [end_node_id](std::pair<dof_id_type, dof_id_type> old_id_pair) {
          return old_id_pair.first == end_node_id;
        };
    // lambda to check if current end_node_id is in pair second position
    auto node_in_second_pos =
        [end_node_id](std::pair<dof_id_type, dof_id_type> old_id_pair) {
          return old_id_pair.second == end_node_id;
        };

    // search for pair with current end_node_id in first position
    auto result = std::find_if(
      boundary_node_assm.begin(),
      boundary_node_assm.end(),
      node_in_first_pos);

    // check if first location pair was found
    // if not, re-search in second position
    bool match_first;
    if (result != boundary_node_assm.end()) {
      match_first = true;
    } else {
      match_first = false;
      result = std::find_if(
        boundary_node_assm.begin(),
        boundary_node_assm.end(),
        node_in_second_pos);
    }

    // check that a pair was found in either first or second position
    if (result != boundary_node_assm.end()) {
      // based on where the existing node was found
      // add the correct connected node to sorted node list
      boundary_ordered_node_list.push_back(match_first ? (*result).second : (*result).first);
      // remove pair from remaining side list
      boundary_node_assm.erase(result);
    }
    else {
    // If there are still elements in boundary_node_assm and result ==
    // boundary_node_assm.end(), this means the boundary is not a loop, the
    // boundary_ordered_node_list is flipped and try the other direction Has not
    // been tested yet.
      if (isFlipped) {
        mooseError("The boundary has more than one segments. This code does not work for that case.");
      }

      isFlipped = true;
      std::reverse(boundary_ordered_node_list.begin(), boundary_ordered_node_list.end());
      // As this iteration is wasted, reset the iterator
      i--;
    }
  }
  // If the boundary is a loop, remove the last node as it should be the same as
  // the first one
  if (boundary_ordered_node_list.front() == boundary_ordered_node_list.back()) {
    boundary_ordered_node_list.erase(boundary_ordered_node_list.end() - 1);
  }

  // resolve node_ids to Node pointers
  for (dof_id_type node_id : boundary_ordered_node_list) {
    Node *node = mesh->node_ptr(node_id);
    inner_boundary_nodes.push_back(node);
  }
}

void TriangulatedMeshGenerator::_clearPoints(std::vector<p2t::Point*>& point_list)
{
  for (auto point : point_list) {
    delete point;
  }
  point_list.clear();
}
<commit_msg>Removed development std::cout debug statements.<commit_after>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "TriangulatedMeshGenerator.h"

// poly2tri triangulation library
#include "poly2tri.h"

registerMooseObject("ReactorApp", TriangulatedMeshGenerator);

InputParameters
TriangulatedMeshGenerator::validParams()
{
  InputParameters params = MeshGenerator::validParams();

  params.addRangeCheckedParam<SubdomainID>(
    "subdomain_id",
    "subdomain_id>=0",
    "The subdomain ID given to the TRI3 elements in the triangulation.");
  params.addRequiredParam<MeshGeneratorName>(
    "inner_boundary_mesh",
    "The mesh to use for the inner boundary of the triangulation.");
  params.addRangeCheckedParam<boundary_id_type>(
    "inner_boundary_id",
    "inner_boundary_id>=0",
    "The boundary ID of the inner mesh outer boundary.");
  params.addParam<std::string>(
    "inner_boundary_name",
    "The boundary name of the inner mesh outer boundary.");
  params.addRequiredRangeCheckedParam<Real>(
    "outer_circle_radius",
    "outer_circle_radius>0",
    "Radius of outer circle boundary.");
  params.addRequiredRangeCheckedParam<unsigned int>(
    "outer_circle_num_segments",
    "outer_circle_num_segments>0",
    "Number of radial segments to subdivide outer circle boundary.");
  params.addRangeCheckedParam<boundary_id_type>(
    "outer_boundary_id",
    "outer_boundary_id>=0",
    "The boundary id for the generated mesh outer boundary.");
  // params.addParam<std::string>(
  //   "outer_boundary_name",
  //   "The boundary name of the generated mesh outer boundary.");
  params.addParam<std::vector<Real>>(
    "extra_circle_radii",
    "Radii of extra Steiner point circles.");
  params.addParam<std::vector<unsigned int>>(
    "extra_circle_num_segments",
    "Number of segments for extra Steiner point circles.");
  params.addClassDescription(
    "This TriangulatedMeshGenerator object is designed to generate "
    "a triangulated mesh between a generated outer circle boundary "
    "and a provided inner mesh.");

  return params;
}

TriangulatedMeshGenerator::TriangulatedMeshGenerator(const InputParameters & parameters)
  : MeshGenerator(parameters),
    _tri_subdomain_id(isParamValid("subdomain_id") ? getParam<SubdomainID>("subdomain_id") : 0),
    _inner_boundary_mesh(getMesh("inner_boundary_mesh")),
    _outer_circle_radius(getParam<Real>("outer_circle_radius")),
    _outer_circle_num_segments(getParam<unsigned int>("outer_circle_num_segments")),
    _outer_boundary_id(isParamValid("outer_boundary_id") ? getParam<boundary_id_type>("outer_boundary_id") : 0),
    // _outer_boundary_name(isParamValid("outer_boundary_name") ? getParam<std::string>("outer_boundary_name") : std::string("outside")),
    _extra_circle_radii(getParam<std::vector<Real>>("extra_circle_radii")),
    _extra_circle_num_segments(getParam<std::vector<unsigned int>>("extra_circle_num_segments"))
{
  // confirm either id or name (exclusive or) for inner mesh boundary is provided
  if ((!isParamValid("inner_boundary_id") && !isParamValid("inner_boundary_name")) ||
      (isParamValid("inner_boundary_id") && isParamValid("inner_boundary_name"))) {
    paramError(
      "inner_boundary_id",
      "Either 'inner_boundary_id' or 'inner_boundary_name' must be provided, but not both.");
  }

  // confirm Steiner inputs are equal length
  if (_extra_circle_radii.size() != _extra_circle_num_segments.size()) {
    paramError(
      "extra_circle_num_segments",
      "The size of 'extra_circle_num_segments' must be equal to the size of 'extra_circle_radii'.");
  }
}

std::unique_ptr<MeshBase>
TriangulatedMeshGenerator::generate()
{
  //
  // Set up mesh based on input inner mesh
  //

  std::unique_ptr<MeshBase> mesh = std::move(_inner_boundary_mesh);
  BoundaryInfo & boundary_info = mesh->get_boundary_info();

  // set inner boundary id based on give input
  if(isParamValid("inner_boundary_id")) {
    _inner_boundary_id = getParam<boundary_id_type>("inner_boundary_id");
  }
  if(isParamValid("inner_boundary_name")) {
    _inner_boundary_id = boundary_info.get_id_by_name(getParam<std::string>("inner_boundary_name"));
  }

  // build nodesets and sidesets
  boundary_info.build_node_list_from_side_list();
  boundary_info.build_side_list_from_node_list();

  //
  // extract boundary nodes from input mesh inner boundary
  // poly2tri requires input boundary nodes be sorted in connected order
  //

  std::vector<Node*> inner_boundary_nodes;
  _create_sorted_boundary_node_list(mesh, inner_boundary_nodes);

  //
  // C2T storage
  //

  /// Polylines
  std::vector<p2t::Point*> outer_polyline;
  std::vector<p2t::Point*> inner_polyline;
  std::vector<p2t::Point*> steiner_points;

  // store association map for reference
  std::map<p2t::Point*, Node*> point_node_map;

  //
  // Inner P2T boundary; extract from existing mesh
  //

  // POLYLINE NEEDS TO BE DIRECTED

  for (Node* node : inner_boundary_nodes) {
    // extract (x, y) coords
    Real x = (*node)(0);
    Real y = (*node)(1);
    // create Point
    p2t::Point *point = new p2t::Point(x, y);
    // add to inner boundary list
    inner_polyline.push_back(point);
    // add to association map
    point_node_map[point] = node;
  }

  //
  // Outer P2T boundary; create circle from input parameters
  //

  // radial spacing
  Real d_theta = 2.0 * M_PI / _outer_circle_num_segments;

  for (unsigned int i = 0; i < _outer_circle_num_segments; i++) {
    // rotation angle
    Real theta = i * d_theta;
    // calculate (x, y) coords
    Real x = _outer_circle_radius * std::cos(theta);
    Real y = _outer_circle_radius * std::sin(theta);

    // create Point
    p2t::Point *point = new p2t::Point(x, y);
    // add to outer boundary list
    outer_polyline.push_back(point);
    // create Node and add to mesh
    Node *node = mesh->add_point(Point(x, y, 0.0));
    // add to association map
    point_node_map[point] = node;
  }

  //
  // Additional Steiner points; create additional circles of Steiner points between inner and outer boundaries.
  //

  for (std::vector<unsigned int>::size_type idx = 0; idx < _extra_circle_radii.size(); idx++) {
    // extract Steiner point circle parameters
    Real num_segments = _extra_circle_num_segments[idx];
    Real radius = _extra_circle_radii[idx];

    // radial spacing
    d_theta = 2.0 * M_PI / num_segments;

    for (unsigned int i = 0; i < num_segments; i++) {
      // rotation angle
      Real theta = i * d_theta;
      // calculate (x, y) coords
      Real x = radius * std::cos(theta);
      Real y = radius * std::sin(theta);

      // create Point
      p2t::Point *point = new p2t::Point(x, y);
      // add to Steiner point list
      steiner_points.push_back(point);
      // create Node and add to mesh
      Node *node = mesh->add_point(Point(x, y, 0.0));
      // add to association map
      point_node_map[point] = node;
    }
  }

  //
  // Create P2T CDT and add primary (outer) polyline
  // NOTE: polyline must be a simple polygon. The polyline's points constitute constrained edges. No repeat points!!!
  //

  p2t::CDT* cdt = new p2t::CDT(outer_polyline);

  // Add inner boundary
  cdt->AddHole(inner_polyline);

  // Add Steiner points
  for (const auto& point : steiner_points) {
    cdt->AddPoint(point);
  }

  // Triangulate!
  cdt->Triangulate();

  //
  // Translate triangulated C2T points/triangles to libMesh nodes/Tri3s
  //

  // Extract triangle list from triangulation
  std::vector<p2t::Triangle*> triangles = cdt->GetTriangles();

  // process each P2T triangle into libMesh Tri3
  for (p2t::Triangle* triangle : triangles) {

    // create Tri3 element
    Tri3* tri_elem = new Tri3();

    // process each point on triangle
    for (const int i : std::vector<int>{0,1,2}) {
      // extract p2t::point from triangle
      p2t::Point* point = triangle->GetPoint(i);

      // check if node has been created for point
      // if not, create and add to map
      if (point_node_map.find(point) == point_node_map.end()) {
        point_node_map[point] = mesh->add_point(Point(point->x, point->y, 0.0));
      }

      // retrieve node and add to element
      tri_elem->set_node(i) = point_node_map[point];
    }

    // set element subdomain id
    tri_elem->subdomain_id() = _tri_subdomain_id;

    // add completed element to mesh
    mesh->add_elem(tri_elem);
  }

  //
  // add nodesets for boundaries
  //

  for (p2t::Point* point : outer_polyline) {
    boundary_info.add_node(point_node_map[point], _outer_boundary_id);
  }
  // boundary_info.sideset_name(_outer_boundary_id) = _outer_boundary_name;

  // generate sidesets from nodesets
  // boundary_info.build_side_list_from_node_list();

  //
  // Cleanup P2T objects
  //

  delete cdt;
  _clearPoints(outer_polyline);
  _clearPoints(inner_polyline);
  _clearPoints(steiner_points);

  //
  // finalize mesh and return
  //

  mesh->prepare_for_use();

  return dynamic_pointer_cast<MeshBase>(mesh);
}

void TriangulatedMeshGenerator::_create_sorted_boundary_node_list(std::unique_ptr<MeshBase>& mesh, std::vector<Node*>& inner_boundary_nodes)
{
  BoundaryInfo & boundary_info = mesh->get_boundary_info();

  // poly2tri requires input boundary nodes be in connected order
  // create edge node pairs to sort by connectivity

  // vector of <element_id, side_id, boundary_id> tuples
  auto side_list = boundary_info.build_side_list();

  std::vector<std::pair<dof_id_type, dof_id_type>> boundary_node_assm;

  // create edge node pairs for sides on the specified boundary
  for (const auto entry : side_list) {
    // select out tuple components
    dof_id_type element_id = std::get<0>(entry);
    unsigned short int side_id = std::get<1>(entry);
    boundary_id_type boundary_id = std::get<2>(entry);

    // skip sides not in given boundary id
    if (boundary_id != _inner_boundary_id) {
      continue;
    }

    // select out nodes for given side and add to list
    auto side = mesh->elem_ptr(element_id)->side_ptr(side_id);

    boundary_node_assm.push_back(
        std::make_pair(side->node_id(0), side->node_id(1))
    );
  }

  //
  // sort boundary sides into connected order
  //

  std::vector<dof_id_type> boundary_ordered_node_list;
  bool isFlipped = false;

  // start sorted node list with nodes from first side in side list, first two nodes are sorted
  // remove side from side list to be sorted
  boundary_ordered_node_list.push_back(boundary_node_assm.front().first);
  boundary_ordered_node_list.push_back(boundary_node_assm.front().second);
  boundary_node_assm.erase(boundary_node_assm.begin());

  // save initial length of the list, size will shrink during loop
  const unsigned int boundary_node_assm_size_0 = boundary_node_assm.size();
  // iterate over all remaining side pairs
  for (unsigned int i = 0; i < boundary_node_assm_size_0; i++) {
    // use the last node in the sorted node list for lookup
    // find the side in the remaining side list that connects to this node
    dof_id_type end_node_id = boundary_ordered_node_list.back();

    // create lambda functions to search remaining side list
    // lambda to check if current end_node_id is in pair first position
    auto node_in_first_pos =
        [end_node_id](std::pair<dof_id_type, dof_id_type> old_id_pair) {
          return old_id_pair.first == end_node_id;
        };
    // lambda to check if current end_node_id is in pair second position
    auto node_in_second_pos =
        [end_node_id](std::pair<dof_id_type, dof_id_type> old_id_pair) {
          return old_id_pair.second == end_node_id;
        };

    // search for pair with current end_node_id in first position
    auto result = std::find_if(
      boundary_node_assm.begin(),
      boundary_node_assm.end(),
      node_in_first_pos);

    // check if first location pair was found
    // if not, re-search in second position
    bool match_first;
    if (result != boundary_node_assm.end()) {
      match_first = true;
    } else {
      match_first = false;
      result = std::find_if(
        boundary_node_assm.begin(),
        boundary_node_assm.end(),
        node_in_second_pos);
    }

    // check that a pair was found in either first or second position
    if (result != boundary_node_assm.end()) {
      // based on where the existing node was found
      // add the correct connected node to sorted node list
      boundary_ordered_node_list.push_back(match_first ? (*result).second : (*result).first);
      // remove pair from remaining side list
      boundary_node_assm.erase(result);
    }
    else {
    // If there are still elements in boundary_node_assm and result ==
    // boundary_node_assm.end(), this means the boundary is not a loop, the
    // boundary_ordered_node_list is flipped and try the other direction Has not
    // been tested yet.
      if (isFlipped) {
        mooseError("The boundary has more than one segments. This code does not work for that case.");
      }

      isFlipped = true;
      std::reverse(boundary_ordered_node_list.begin(), boundary_ordered_node_list.end());
      // As this iteration is wasted, reset the iterator
      i--;
    }
  }
  // If the boundary is a loop, remove the last node as it should be the same as
  // the first one
  if (boundary_ordered_node_list.front() == boundary_ordered_node_list.back()) {
    boundary_ordered_node_list.erase(boundary_ordered_node_list.end() - 1);
  }

  // resolve node_ids to Node pointers
  for (dof_id_type node_id : boundary_ordered_node_list) {
    Node *node = mesh->node_ptr(node_id);
    inner_boundary_nodes.push_back(node);
  }
}

void TriangulatedMeshGenerator::_clearPoints(std::vector<p2t::Point*>& point_list)
{
  for (auto point : point_list) {
    delete point;
  }
  point_list.clear();
}
<|endoftext|>


<commit_before>#include "StorageBulkCursor.h"
#include "StorageEnvironment.h"
#include "StoragePageCache.h"

StorageBulkCursor::StorageBulkCursor() :
 dataPage(NULL, 0)
{
    chunkID = 0;
    shard = NULL;
    env = NULL;
    isLast = false;
}

StorageBulkCursor::~StorageBulkCursor()
{
    env->numBulkCursors = env->numBulkCursors - 1;
}

StorageKeyValue* StorageBulkCursor::First()
{
    StorageChunk*       chunk;
    StorageChunk**      itChunk;

    itChunk = shard->chunks.First();

    if (itChunk == NULL)
        return NULL;

    chunk = *itChunk;
    assert(chunk != NULL);

    chunkID = chunk->GetChunkID();
//    Log_Message("Iterating chunk %U", chunkID);

    return FromNextBunch(chunk);
}

StorageKeyValue* StorageBulkCursor::Next(StorageKeyValue* it)
{
    StorageKeyValue*    kv;
    StorageChunk*       chunk;
    StorageChunk**      itChunk;

    kv = dataPage.Next((StorageFileKeyValue*) it);

    if (kv != NULL)
    {
        assert(kv->GetKey().GetBuffer()[0] != 0);
        return kv;
    }

    // TODO: what if shard has been deleted?
    FOREACH(itChunk, shard->chunks)
    {
        if ((*itChunk)->GetChunkID() == chunkID)
            break;
    }

    if (itChunk == NULL)
    {
        chunk = shard->GetMemoChunk();
    }
    else
    {
        assert(itChunk != NULL); // TODO: what if chunk has been deleted?
        chunk = *itChunk;
    }
    assert(chunk != NULL);

    chunkID = chunk->GetChunkID();
//    Log_Message("Iterating chunk %U", chunkID);

    kv = FromNextBunch(chunk);
    return kv;
}

void StorageBulkCursor::SetLast(bool isLast_)
{
    isLast = isLast_;
}

ReadBuffer StorageBulkCursor::GetNextKey()
{
    return ReadBuffer(nextKey);
}

void StorageBulkCursor::SetNextKey(ReadBuffer key)
{
    nextKey.Write(key);
}

void StorageBulkCursor::AppendKeyValue(StorageKeyValue* kv)
{
    dataPage.Append(kv);
}

void StorageBulkCursor::FinalizeKeyValues()
{
    dataPage.Finalize();
}

StorageKeyValue* StorageBulkCursor::FromNextBunch(StorageChunk* chunk)
{
    StorageChunk**      itChunk;

    while (true)
    {
        if (!isLast)
        {
            dataPage.Reset();
            chunk->NextBunch(*this, shard);
            if (dataPage.First())
                return dataPage.First();
            else
                continue;
        }

        // go to next chunk
        FOREACH(itChunk, shard->chunks)
        {
            if ((*itChunk)->GetChunkID() == chunkID)
            {
                Log_Debug("Cursor next chunk");
                itChunk = shard->chunks.Next(itChunk);
                isLast = false;
                break;
            }
        }

        if (itChunk)
        {
            chunk = *itChunk;
            chunkID = chunk->GetChunkID();
//            Log_Message("Iterating chunk %U", chunkID);
        }
        else
        {
            if (shard->GetMemoChunk()->GetChunkID() == chunkID)
                return NULL; // end of iteration

            // iterate memoChunk
            chunk = shard->GetMemoChunk();
            chunkID = chunk->GetChunkID();
//            Log_Message("Iterating chunk %U", chunkID);
        }

        dataPage.Reset();
    }
}

void StorageBulkCursor::SetEnvironment(StorageEnvironment* env_)
{
    env = env_;
}

void StorageBulkCursor::SetShard(StorageShard* shard_)
{
    shard = shard_;
}
<commit_msg>Fixed bug in StorageBulkCursor.<commit_after>#include "StorageBulkCursor.h"
#include "StorageEnvironment.h"
#include "StoragePageCache.h"

StorageBulkCursor::StorageBulkCursor() :
 dataPage(NULL, 0)
{
    chunkID = 0;
    shard = NULL;
    env = NULL;
    isLast = false;
}

StorageBulkCursor::~StorageBulkCursor()
{
    env->numBulkCursors = env->numBulkCursors - 1;
}

StorageKeyValue* StorageBulkCursor::First()
{
    StorageChunk*       chunk;
    StorageChunk**      itChunk;

    itChunk = shard->chunks.First();

    if (itChunk == NULL)
        chunk = shard->GetMemoChunk();
    else
        chunk = *itChunk;

    assert(chunk != NULL);

    chunkID = chunk->GetChunkID();
//    Log_Message("Iterating chunk %U", chunkID);

    return FromNextBunch(chunk);
}

StorageKeyValue* StorageBulkCursor::Next(StorageKeyValue* it)
{
    StorageKeyValue*    kv;
    StorageChunk*       chunk;
    StorageChunk**      itChunk;

    kv = dataPage.Next((StorageFileKeyValue*) it);

    if (kv != NULL)
    {
        assert(kv->GetKey().GetBuffer()[0] != 0);
        return kv;
    }

    // TODO: what if shard has been deleted?
    FOREACH(itChunk, shard->chunks)
    {
        if ((*itChunk)->GetChunkID() == chunkID)
            break;
    }

    if (itChunk == NULL)
    {
        chunk = shard->GetMemoChunk();
    }
    else
    {
        assert(itChunk != NULL); // TODO: what if chunk has been deleted?
        chunk = *itChunk;
    }
    assert(chunk != NULL);

    chunkID = chunk->GetChunkID();
//    Log_Message("Iterating chunk %U", chunkID);

    kv = FromNextBunch(chunk);
    return kv;
}

void StorageBulkCursor::SetLast(bool isLast_)
{
    isLast = isLast_;
}

ReadBuffer StorageBulkCursor::GetNextKey()
{
    return ReadBuffer(nextKey);
}

void StorageBulkCursor::SetNextKey(ReadBuffer key)
{
    nextKey.Write(key);
}

void StorageBulkCursor::AppendKeyValue(StorageKeyValue* kv)
{
    dataPage.Append(kv);
}

void StorageBulkCursor::FinalizeKeyValues()
{
    dataPage.Finalize();
}

StorageKeyValue* StorageBulkCursor::FromNextBunch(StorageChunk* chunk)
{
    StorageChunk**      itChunk;

    while (true)
    {
        if (!isLast)
        {
            dataPage.Reset();
            chunk->NextBunch(*this, shard);
            if (dataPage.First())
                return dataPage.First();
            else
                continue;
        }

        // go to next chunk
        FOREACH(itChunk, shard->chunks)
        {
            if ((*itChunk)->GetChunkID() == chunkID)
            {
                Log_Debug("Cursor next chunk");
                itChunk = shard->chunks.Next(itChunk);
                isLast = false;
                break;
            }
        }

        if (itChunk)
        {
            chunk = *itChunk;
            chunkID = chunk->GetChunkID();
//            Log_Message("Iterating chunk %U", chunkID);
        }
        else
        {
            if (shard->GetMemoChunk()->GetChunkID() == chunkID)
                return NULL; // end of iteration

            // iterate memoChunk
            chunk = shard->GetMemoChunk();
            chunkID = chunk->GetChunkID();
//            Log_Message("Iterating chunk %U", chunkID);
        }

        dataPage.Reset();
    }
}

void StorageBulkCursor::SetEnvironment(StorageEnvironment* env_)
{
    env = env_;
}

void StorageBulkCursor::SetShard(StorageShard* shard_)
{
    shard = shard_;
}
<|endoftext|>