<commit_before>// Copyright eeGeo Ltd (2012-2015), All Rights Reserved

#include "InteriorsExplorerController.h"
#include "InteriorsExplorerModel.h"
#include "InteriorsExplorerViewModel.h"
#include "IInteriorsExplorerView.h"
#include "IMenuViewModel.h"
#include "IScreenControlViewModel.h"
#include "IMyPinCreationInitiationViewModel.h"
#include "InteriorsExplorerFloorSelectionDraggedMessage.h"
#include "ApplyScreenControl.h"
#include "WorldPinVisibility.h"

namespace ExampleApp
{
    namespace InteriorsExplorer
    {
        namespace View
        {
            InteriorsExplorerController::InteriorsExplorerController(SdkModel::InteriorsExplorerModel& model,
                                                                     IInteriorsExplorerView& view,
                                                                     InteriorsExplorerViewModel& viewModel,
                                                                     ExampleAppMessaging::TMessageBus& messageBus)
            : m_model(model)
            , m_view(view)
            , m_viewModel(viewModel)
            , m_replayTutorials(false)
            , m_messageBus(messageBus)
            , m_appMode(AppModes::SdkModel::WorldMode)
            , m_dismissedCallback(this, &InteriorsExplorerController::OnDismiss)
            , m_selectFloorCallback(this, &InteriorsExplorerController::OnSelectFloor)
            , m_stateChangedCallback(this, &InteriorsExplorerController::OnStateChanged)
            , m_floorSelectedCallback(this, &InteriorsExplorerController::OnFloorSelected)
            , m_draggingFloorSelectionCallback(this, &InteriorsExplorerController::OnFloorSelectionDragged)
            , m_viewStateCallback(this, &InteriorsExplorerController::OnViewStateChangeScreenControl)
            , m_appModeChangedCallback(this, &InteriorsExplorerController::OnAppModeChanged)
            , m_interiorsUINotificationCallback(this, &InteriorsExplorerController::OnInteriorsUINotificationRequired)
            {
                m_messageBus.SubscribeUi(m_stateChangedCallback);
                m_messageBus.SubscribeUi(m_floorSelectedCallback);
                m_messageBus.SubscribeUi(m_appModeChangedCallback);
                m_messageBus.SubscribeUi(m_interiorsUINotificationCallback);

                m_viewModel.InsertOnScreenStateChangedCallback(m_viewStateCallback);

                m_view.InsertDismissedCallback(m_dismissedCallback);
                m_view.InsertFloorSelectedCallback(m_selectFloorCallback);
                m_view.InsertFloorSelectionDraggedCallback(m_draggingFloorSelectionCallback);
            }

            InteriorsExplorerController::~InteriorsExplorerController()
            {
                m_view.RemoveFloorSelectionDraggedCallback(m_draggingFloorSelectionCallback);
                m_view.RemoveDismissedCallback(m_dismissedCallback);
                m_view.RemoveFloorSelectedCallback(m_selectFloorCallback);

                m_viewModel.RemoveOnScreenStateChangedCallback(m_viewStateCallback);

                m_messageBus.UnsubscribeUi(m_interiorsUINotificationCallback);
                m_messageBus.UnsubscribeUi(m_stateChangedCallback);
                m_messageBus.UnsubscribeUi(m_floorSelectedCallback);
                m_messageBus.UnsubscribeUi(m_appModeChangedCallback);
            }

            void InteriorsExplorerController::OnDismiss()
            {
                m_messageBus.Publish(InteriorsExplorerExitMessage());
                m_view.SetTouchEnabled(false);
            }

            void InteriorsExplorerController::OnSelectFloor(int& selected)
            {
                m_messageBus.Publish(InteriorsExplorerSelectFloorMessage(selected));
            }

            void InteriorsExplorerController::OnFloorSelectionDragged(float &dragParam)
            {
                m_messageBus.Publish(InteriorsExplorerFloorSelectionDraggedMessage(dragParam));
            }

            void InteriorsExplorerController::OnFloorSelected(const InteriorsExplorerFloorSelectedMessage& message)
            {
                m_view.SetFloorName(message.GetFloorName());

                if(m_viewModel.IsFullyOnScreen())
                {
                    m_view.SetSelectedFloorIndex(message.GetFloorIndex());
                }
            }

            void InteriorsExplorerController::OnStateChanged(const InteriorsExplorerStateChangedMessage& message)
            {
                if(message.IsInteriorVisible())
                {
                    m_view.UpdateFloors(message.GetFloorShortNames(), message.GetSelectedFloorIndex());
                    m_view.SetTouchEnabled(true);

                    OnFloorSelected(InteriorsExplorerFloorSelectedMessage(message.GetSelectedFloorIndex(), message.GetSelectedFloorName()));

					const int maxTutorialViews = 2;
					bool showExitTutorial = m_replayTutorials || m_model.GetInteriorExitTutorialViewedCount() < maxTutorialViews;
					bool showChangeFloorTutorial = (m_replayTutorials || m_model.GetInteriorChangeFloorTutorialViewedCount() < maxTutorialViews) && m_view.GetCanShowChangeFloorTutorialDialog();

					if(showExitTutorial || showChangeFloorTutorial)
					{
						m_view.AddTutorialDialogs(showExitTutorial, showChangeFloorTutorial);

						if(showExitTutorial)
						{
							m_model.RecordHasViewedInteriorExitTutorial();
						}

						if(showChangeFloorTutorial)
						{
							m_model.RecordHasViewedInteriorChangeFloorTutorial();
						}
					}
                    ReplayTutorials(false);

                    m_viewModel.AddToScreen();
                }
                else
                {
                    m_viewModel.RemoveFromScreen();
                }
            }

            void InteriorsExplorerController::OnViewStateChangeScreenControl(ScreenControl::View::IScreenControlViewModel &viewModel, float &state)
            {
                ScreenControl::View::Apply(m_viewModel, m_view);
            }

            void InteriorsExplorerController::OnAppModeChanged(const AppModes::AppModeChangedMessage& message)
            {
                m_appMode = message.GetAppMode();
            }

            void InteriorsExplorerController::OnInteriorsUINotificationRequired(const InteriorsExplorerUINotifyMessage & message)
            {
                m_view.PlaySliderAnim();
            }

            void InteriorsExplorerController::ReplayTutorials(const bool enableTutorials)
            {
                m_replayTutorials = enableTutorials;
                m_replayTutorialsCallbacks.ExecuteCallbacks(m_replayTutorials);
            }

            void InteriorsExplorerController::InsertReplayTutorialsChangedCallback(Eegeo::Helpers::ICallback1<bool>& callback)
            {
                m_replayTutorialsCallbacks.AddCallback(callback);
            }

            void InteriorsExplorerController::RemoveReplayTutorialsChangedCallback(Eegeo::Helpers::ICallback1<bool>& callback)
            {
                m_replayTutorialsCallbacks.RemoveCallback(callback);
            }
        }
    }
}
<commit_msg>Always show tutorial dialogs after attract mode ends. Buddy: Blair.<commit_after>// Copyright eeGeo Ltd (2012-2015), All Rights Reserved

#include "InteriorsExplorerController.h"
#include "InteriorsExplorerModel.h"
#include "InteriorsExplorerViewModel.h"
#include "IInteriorsExplorerView.h"
#include "IMenuViewModel.h"
#include "IScreenControlViewModel.h"
#include "IMyPinCreationInitiationViewModel.h"
#include "InteriorsExplorerFloorSelectionDraggedMessage.h"
#include "ApplyScreenControl.h"
#include "WorldPinVisibility.h"

namespace ExampleApp
{
    namespace InteriorsExplorer
    {
        namespace View
        {
            InteriorsExplorerController::InteriorsExplorerController(SdkModel::InteriorsExplorerModel& model,
                                                                     IInteriorsExplorerView& view,
                                                                     InteriorsExplorerViewModel& viewModel,
                                                                     ExampleAppMessaging::TMessageBus& messageBus)
            : m_model(model)
            , m_view(view)
            , m_viewModel(viewModel)
            , m_replayTutorials(false)
            , m_messageBus(messageBus)
            , m_appMode(AppModes::SdkModel::WorldMode)
            , m_dismissedCallback(this, &InteriorsExplorerController::OnDismiss)
            , m_selectFloorCallback(this, &InteriorsExplorerController::OnSelectFloor)
            , m_stateChangedCallback(this, &InteriorsExplorerController::OnStateChanged)
            , m_floorSelectedCallback(this, &InteriorsExplorerController::OnFloorSelected)
            , m_draggingFloorSelectionCallback(this, &InteriorsExplorerController::OnFloorSelectionDragged)
            , m_viewStateCallback(this, &InteriorsExplorerController::OnViewStateChangeScreenControl)
            , m_appModeChangedCallback(this, &InteriorsExplorerController::OnAppModeChanged)
            , m_interiorsUINotificationCallback(this, &InteriorsExplorerController::OnInteriorsUINotificationRequired)
            {
                m_messageBus.SubscribeUi(m_stateChangedCallback);
                m_messageBus.SubscribeUi(m_floorSelectedCallback);
                m_messageBus.SubscribeUi(m_appModeChangedCallback);
                m_messageBus.SubscribeUi(m_interiorsUINotificationCallback);

                m_viewModel.InsertOnScreenStateChangedCallback(m_viewStateCallback);

                m_view.InsertDismissedCallback(m_dismissedCallback);
                m_view.InsertFloorSelectedCallback(m_selectFloorCallback);
                m_view.InsertFloorSelectionDraggedCallback(m_draggingFloorSelectionCallback);
            }

            InteriorsExplorerController::~InteriorsExplorerController()
            {
                m_view.RemoveFloorSelectionDraggedCallback(m_draggingFloorSelectionCallback);
                m_view.RemoveDismissedCallback(m_dismissedCallback);
                m_view.RemoveFloorSelectedCallback(m_selectFloorCallback);

                m_viewModel.RemoveOnScreenStateChangedCallback(m_viewStateCallback);

                m_messageBus.UnsubscribeUi(m_interiorsUINotificationCallback);
                m_messageBus.UnsubscribeUi(m_stateChangedCallback);
                m_messageBus.UnsubscribeUi(m_floorSelectedCallback);
                m_messageBus.UnsubscribeUi(m_appModeChangedCallback);
            }

            void InteriorsExplorerController::OnDismiss()
            {
                m_messageBus.Publish(InteriorsExplorerExitMessage());
                m_view.SetTouchEnabled(false);
            }

            void InteriorsExplorerController::OnSelectFloor(int& selected)
            {
                m_messageBus.Publish(InteriorsExplorerSelectFloorMessage(selected));
            }

            void InteriorsExplorerController::OnFloorSelectionDragged(float &dragParam)
            {
                m_messageBus.Publish(InteriorsExplorerFloorSelectionDraggedMessage(dragParam));
            }

            void InteriorsExplorerController::OnFloorSelected(const InteriorsExplorerFloorSelectedMessage& message)
            {
                m_view.SetFloorName(message.GetFloorName());

                if(m_viewModel.IsFullyOnScreen())
                {
                    m_view.SetSelectedFloorIndex(message.GetFloorIndex());
                }
            }

            void InteriorsExplorerController::OnStateChanged(const InteriorsExplorerStateChangedMessage& message)
            {
                if(message.IsInteriorVisible())
                {
                    m_view.UpdateFloors(message.GetFloorShortNames(), message.GetSelectedFloorIndex());
                    m_view.SetTouchEnabled(true);

                    OnFloorSelected(InteriorsExplorerFloorSelectedMessage(message.GetSelectedFloorIndex(), message.GetSelectedFloorName()));

					const int maxTutorialViews = 2;
					bool showExitTutorial = m_replayTutorials || m_model.GetInteriorExitTutorialViewedCount() < maxTutorialViews;
					bool showChangeFloorTutorial = (m_replayTutorials || m_model.GetInteriorChangeFloorTutorialViewedCount() < maxTutorialViews) && m_view.GetCanShowChangeFloorTutorialDialog();

					if(showExitTutorial || showChangeFloorTutorial)
					{
						m_view.AddTutorialDialogs(showExitTutorial, showChangeFloorTutorial);

						if(showExitTutorial)
						{
							m_model.RecordHasViewedInteriorExitTutorial();
						}

						if(showChangeFloorTutorial)
						{
							m_model.RecordHasViewedInteriorChangeFloorTutorial();
						}
					}
                    ReplayTutorials(false);

                    m_viewModel.AddToScreen();
                }
                else
                {
                    m_viewModel.RemoveFromScreen();
                }
            }

            void InteriorsExplorerController::OnViewStateChangeScreenControl(ScreenControl::View::IScreenControlViewModel &viewModel, float &state)
            {
                ScreenControl::View::Apply(m_viewModel, m_view);
            }

            void InteriorsExplorerController::OnAppModeChanged(const AppModes::AppModeChangedMessage& message)
            {
                m_appMode = message.GetAppMode();
                if (m_appMode == AppModes::SdkModel::AppMode::AttractMode)
                {
                    ReplayTutorials(true);
                }
            }

            void InteriorsExplorerController::OnInteriorsUINotificationRequired(const InteriorsExplorerUINotifyMessage & message)
            {
                m_view.PlaySliderAnim();
            }

            void InteriorsExplorerController::ReplayTutorials(const bool enableTutorials)
            {
                m_replayTutorials = enableTutorials;
                m_replayTutorialsCallbacks.ExecuteCallbacks(m_replayTutorials);
            }

            void InteriorsExplorerController::InsertReplayTutorialsChangedCallback(Eegeo::Helpers::ICallback1<bool>& callback)
            {
                m_replayTutorialsCallbacks.AddCallback(callback);
            }

            void InteriorsExplorerController::RemoveReplayTutorialsChangedCallback(Eegeo::Helpers::ICallback1<bool>& callback)
            {
                m_replayTutorialsCallbacks.RemoveCallback(callback);
            }
        }
    }
}
<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2016 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name PX4 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 "log_writer_file.h"
#include "messages.h"
#include <fcntl.h>
#include <string.h>

#include <mathlib/mathlib.h>
#include <px4_posix.h>

namespace px4
{
namespace logger
{
constexpr size_t LogWriterFile::_min_write_chunk;

LogWriterFile::LogWriterFile(size_t buffer_size) :
	//We always write larger chunks (orb messages) to the buffer, so the buffer
	//needs to be larger than the minimum write chunk (300 is somewhat arbitrary)
	_buffer_size(math::max(buffer_size, _min_write_chunk + 300))
{
	pthread_mutex_init(&_mtx, nullptr);
	pthread_cond_init(&_cv, nullptr);
	/* allocate write performance counters */
	_perf_write = perf_alloc(PC_ELAPSED, "sd write");
	_perf_fsync = perf_alloc(PC_ELAPSED, "sd fsync");
}

bool LogWriterFile::init()
{
	if (_buffer) {
		return true;
	}

	_buffer = new uint8_t[_buffer_size];

	return _buffer;
}

LogWriterFile::~LogWriterFile()
{
	pthread_mutex_destroy(&_mtx);
	pthread_cond_destroy(&_cv);
	perf_free(_perf_write);
	perf_free(_perf_fsync);

	if (_buffer) {
		delete[] _buffer;
	}
}

void LogWriterFile::start_log(const char *filename)
{
	_fd = ::open(filename, O_CREAT | O_WRONLY, PX4_O_MODE_666);

	if (_fd < 0) {
		PX4_ERR("Can't open log file %s", filename);
		_should_run = false;
		return;

	} else {
		PX4_INFO("Opened log file: %s", filename);
		_should_run = true;
		_running = true;
	}

	// Clear buffer and counters
	_head = 0;
	_count = 0;
	_total_written = 0;
	notify();
}

void LogWriterFile::stop_log()
{
	_should_run = false;
	notify();
}

int LogWriterFile::thread_start()
{
	pthread_attr_t thr_attr;
	pthread_attr_init(&thr_attr);

	sched_param param;
	/* low priority, as this is expensive disk I/O */
	param.sched_priority = SCHED_PRIORITY_DEFAULT - 40;
	(void)pthread_attr_setschedparam(&thr_attr, &param);

	pthread_attr_setstacksize(&thr_attr, PX4_STACK_ADJUSTED(1024));

	int ret = pthread_create(&_thread, &thr_attr, &LogWriterFile::run_helper, this);
	pthread_attr_destroy(&thr_attr);

	return ret;
}

void LogWriterFile::thread_stop()
{
	// this will terminate the main loop of the writer thread
	_exit_thread = true;
	_should_run = false;

	notify();

	// wait for thread to complete
	int ret = pthread_join(_thread, NULL);

	if (ret) {
		PX4_WARN("join failed: %d", ret);
	}

}

void *LogWriterFile::run_helper(void *context)
{
	px4_prctl(PR_SET_NAME, "log_writer_file", px4_getpid());

	reinterpret_cast<LogWriterFile *>(context)->run();
	return nullptr;
}

void LogWriterFile::run()
{
	while (!_exit_thread) {
		// Outer endless loop
		// Wait for _should_run flag
		while (!_exit_thread) {
			bool start = false;
			pthread_mutex_lock(&_mtx);
			pthread_cond_wait(&_cv, &_mtx);
			start = _should_run;
			pthread_mutex_unlock(&_mtx);

			if (start) {
				break;
			}
		}

		int poll_count = 0;
		int written = 0;

		while (true) {
			size_t available = 0;
			void *read_ptr = nullptr;
			bool is_part = false;

			/* lock _buffer
			 * wait for sufficient data, cycle on notify()
			 */
			pthread_mutex_lock(&_mtx);

			while (true) {
				available = get_read_ptr(&read_ptr, &is_part);

				/* if sufficient data available or partial read or terminating, exit this wait loop */
				if ((available >= _min_write_chunk) || is_part || !_should_run) {
					/* GOTO end of block */
					break;
				}

				/* wait for a call to notify()
				 * this call unlocks the mutex while waiting, and returns with the mutex locked
				 */
				pthread_cond_wait(&_cv, &_mtx);
			}

			pthread_mutex_unlock(&_mtx);
			written = 0;

			if (available > 0) {
				perf_begin(_perf_write);
				written = ::write(_fd, read_ptr, available);
				perf_end(_perf_write);

				/* call fsync periodically to minimize potential loss of data */
				if (++poll_count >= 100) {
					perf_begin(_perf_fsync);
					::fsync(_fd);
					perf_end(_perf_fsync);
					poll_count = 0;
				}

				if (written < 0) {
					PX4_WARN("error writing log file");
					_should_run = false;
					/* GOTO end of block */
					break;
				}

				pthread_mutex_lock(&_mtx);
				/* subtract bytes written from number in _buffer (_count -= written) */
				mark_read(written);
				pthread_mutex_unlock(&_mtx);

				_total_written += written;
			}

			if (!_should_run && written == static_cast<int>(available) && !is_part) {
				// Stop only when all data written
				_running = false;
				_head = 0;
				_count = 0;

				if (_fd >= 0) {
					int res = ::close(_fd);
					_fd = -1;

					if (res) {
						PX4_WARN("error closing log file");

					} else {
						PX4_INFO("closed logfile, bytes written: %zu", _total_written);
					}
				}

				break;
			}
		}
	}
}

int LogWriterFile::write_message(void *ptr, size_t size, uint64_t dropout_start)
{
	if (_need_reliable_transfer) {
		int ret;

		while ((ret = write(ptr, size, dropout_start)) == -1) {
			unlock();
			notify();
			usleep(3000);
			lock();
		}

		return ret;
	}

	return write(ptr, size, dropout_start);
}

int LogWriterFile::write(void *ptr, size_t size, uint64_t dropout_start)
{
	if (!is_started()) {
		return 0;
	}

	// Bytes available to write
	size_t available = _buffer_size - _count;
	size_t dropout_size = 0;

	if (dropout_start) {
		dropout_size = sizeof(ulog_message_dropout_s);
	}

	if (size + dropout_size > available) {
		// buffer overflow
		return -1;
	}

	if (dropout_start) {
		//write dropout msg
		ulog_message_dropout_s dropout_msg;
		dropout_msg.duration = (uint16_t)(hrt_elapsed_time(&dropout_start) / 1000);
		write_no_check(&dropout_msg, sizeof(dropout_msg));
	}

	write_no_check(ptr, size);
	return 0;
}

void LogWriterFile::write_no_check(void *ptr, size_t size)
{
	size_t n = _buffer_size - _head;	// bytes to end of the buffer

	uint8_t *buffer_c = reinterpret_cast<uint8_t *>(ptr);

	if (size > n) {
		// Message goes over the end of the buffer
		memcpy(&(_buffer[_head]), buffer_c, n);
		_head = 0;

	} else {
		n = 0;
	}

	// now: n = bytes already written
	size_t p = size - n;	// number of bytes to write
	memcpy(&(_buffer[_head]), &(buffer_c[n]), p);
	_head = (_head + p) % _buffer_size;
	_count += size;
}

size_t LogWriterFile::get_read_ptr(void **ptr, bool *is_part)
{
	// bytes available to read
	int read_ptr = _head - _count;

	if (read_ptr < 0) {
		read_ptr += _buffer_size;
		*ptr = &_buffer[read_ptr];
		*is_part = true;
		return _buffer_size - read_ptr;

	} else {
		*ptr = &_buffer[read_ptr];
		*is_part = false;
		return _count;
	}
}

}
}
<commit_msg>add errno to error message<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2016 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name PX4 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 "log_writer_file.h"
#include "messages.h"
#include <fcntl.h>
#include <string.h>

#include <mathlib/mathlib.h>
#include <px4_posix.h>

namespace px4
{
namespace logger
{
constexpr size_t LogWriterFile::_min_write_chunk;

LogWriterFile::LogWriterFile(size_t buffer_size) :
	//We always write larger chunks (orb messages) to the buffer, so the buffer
	//needs to be larger than the minimum write chunk (300 is somewhat arbitrary)
	_buffer_size(math::max(buffer_size, _min_write_chunk + 300))
{
	pthread_mutex_init(&_mtx, nullptr);
	pthread_cond_init(&_cv, nullptr);
	/* allocate write performance counters */
	_perf_write = perf_alloc(PC_ELAPSED, "sd write");
	_perf_fsync = perf_alloc(PC_ELAPSED, "sd fsync");
}

bool LogWriterFile::init()
{
	if (_buffer) {
		return true;
	}

	_buffer = new uint8_t[_buffer_size];

	return _buffer;
}

LogWriterFile::~LogWriterFile()
{
	pthread_mutex_destroy(&_mtx);
	pthread_cond_destroy(&_cv);
	perf_free(_perf_write);
	perf_free(_perf_fsync);

	if (_buffer) {
		delete[] _buffer;
	}
}

void LogWriterFile::start_log(const char *filename)
{
	_fd = ::open(filename, O_CREAT | O_WRONLY, PX4_O_MODE_666);

	if (_fd < 0) {
		PX4_ERR("Can't open log file %s, errno: %d", filename, errno);
		_should_run = false;
		return;

	} else {
		PX4_INFO("Opened log file: %s", filename);
		_should_run = true;
		_running = true;
	}

	// Clear buffer and counters
	_head = 0;
	_count = 0;
	_total_written = 0;
	notify();
}

void LogWriterFile::stop_log()
{
	_should_run = false;
	notify();
}

int LogWriterFile::thread_start()
{
	pthread_attr_t thr_attr;
	pthread_attr_init(&thr_attr);

	sched_param param;
	/* low priority, as this is expensive disk I/O */
	param.sched_priority = SCHED_PRIORITY_DEFAULT - 40;
	(void)pthread_attr_setschedparam(&thr_attr, &param);

	pthread_attr_setstacksize(&thr_attr, PX4_STACK_ADJUSTED(1024));

	int ret = pthread_create(&_thread, &thr_attr, &LogWriterFile::run_helper, this);
	pthread_attr_destroy(&thr_attr);

	return ret;
}

void LogWriterFile::thread_stop()
{
	// this will terminate the main loop of the writer thread
	_exit_thread = true;
	_should_run = false;

	notify();

	// wait for thread to complete
	int ret = pthread_join(_thread, NULL);

	if (ret) {
		PX4_WARN("join failed: %d", ret);
	}

}

void *LogWriterFile::run_helper(void *context)
{
	px4_prctl(PR_SET_NAME, "log_writer_file", px4_getpid());

	reinterpret_cast<LogWriterFile *>(context)->run();
	return nullptr;
}

void LogWriterFile::run()
{
	while (!_exit_thread) {
		// Outer endless loop
		// Wait for _should_run flag
		while (!_exit_thread) {
			bool start = false;
			pthread_mutex_lock(&_mtx);
			pthread_cond_wait(&_cv, &_mtx);
			start = _should_run;
			pthread_mutex_unlock(&_mtx);

			if (start) {
				break;
			}
		}

		int poll_count = 0;
		int written = 0;

		while (true) {
			size_t available = 0;
			void *read_ptr = nullptr;
			bool is_part = false;

			/* lock _buffer
			 * wait for sufficient data, cycle on notify()
			 */
			pthread_mutex_lock(&_mtx);

			while (true) {
				available = get_read_ptr(&read_ptr, &is_part);

				/* if sufficient data available or partial read or terminating, exit this wait loop */
				if ((available >= _min_write_chunk) || is_part || !_should_run) {
					/* GOTO end of block */
					break;
				}

				/* wait for a call to notify()
				 * this call unlocks the mutex while waiting, and returns with the mutex locked
				 */
				pthread_cond_wait(&_cv, &_mtx);
			}

			pthread_mutex_unlock(&_mtx);
			written = 0;

			if (available > 0) {
				perf_begin(_perf_write);
				written = ::write(_fd, read_ptr, available);
				perf_end(_perf_write);

				/* call fsync periodically to minimize potential loss of data */
				if (++poll_count >= 100) {
					perf_begin(_perf_fsync);
					::fsync(_fd);
					perf_end(_perf_fsync);
					poll_count = 0;
				}

				if (written < 0) {
					PX4_WARN("error writing log file");
					_should_run = false;
					/* GOTO end of block */
					break;
				}

				pthread_mutex_lock(&_mtx);
				/* subtract bytes written from number in _buffer (_count -= written) */
				mark_read(written);
				pthread_mutex_unlock(&_mtx);

				_total_written += written;
			}

			if (!_should_run && written == static_cast<int>(available) && !is_part) {
				// Stop only when all data written
				_running = false;
				_head = 0;
				_count = 0;

				if (_fd >= 0) {
					int res = ::close(_fd);
					_fd = -1;

					if (res) {
						PX4_WARN("error closing log file");

					} else {
						PX4_INFO("closed logfile, bytes written: %zu", _total_written);
					}
				}

				break;
			}
		}
	}
}

int LogWriterFile::write_message(void *ptr, size_t size, uint64_t dropout_start)
{
	if (_need_reliable_transfer) {
		int ret;

		while ((ret = write(ptr, size, dropout_start)) == -1) {
			unlock();
			notify();
			usleep(3000);
			lock();
		}

		return ret;
	}

	return write(ptr, size, dropout_start);
}

int LogWriterFile::write(void *ptr, size_t size, uint64_t dropout_start)
{
	if (!is_started()) {
		return 0;
	}

	// Bytes available to write
	size_t available = _buffer_size - _count;
	size_t dropout_size = 0;

	if (dropout_start) {
		dropout_size = sizeof(ulog_message_dropout_s);
	}

	if (size + dropout_size > available) {
		// buffer overflow
		return -1;
	}

	if (dropout_start) {
		//write dropout msg
		ulog_message_dropout_s dropout_msg;
		dropout_msg.duration = (uint16_t)(hrt_elapsed_time(&dropout_start) / 1000);
		write_no_check(&dropout_msg, sizeof(dropout_msg));
	}

	write_no_check(ptr, size);
	return 0;
}

void LogWriterFile::write_no_check(void *ptr, size_t size)
{
	size_t n = _buffer_size - _head;	// bytes to end of the buffer

	uint8_t *buffer_c = reinterpret_cast<uint8_t *>(ptr);

	if (size > n) {
		// Message goes over the end of the buffer
		memcpy(&(_buffer[_head]), buffer_c, n);
		_head = 0;

	} else {
		n = 0;
	}

	// now: n = bytes already written
	size_t p = size - n;	// number of bytes to write
	memcpy(&(_buffer[_head]), &(buffer_c[n]), p);
	_head = (_head + p) % _buffer_size;
	_count += size;
}

size_t LogWriterFile::get_read_ptr(void **ptr, bool *is_part)
{
	// bytes available to read
	int read_ptr = _head - _count;

	if (read_ptr < 0) {
		read_ptr += _buffer_size;
		*ptr = &_buffer[read_ptr];
		*is_part = true;
		return _buffer_size - read_ptr;

	} else {
		*ptr = &_buffer[read_ptr];
		*is_part = false;
		return _count;
	}
}

}
}
<|endoftext|>


<commit_before>#ifndef __se3_sample_models_hpp__
#define __se3_sample_models_hpp__

#include "pinocchio/multibody/model.hpp"

namespace se3
{
  namespace buildModels
  {

    void  humanoid2d( Model& model)
    {
      model.addBody(model.getBodyId("universe"),JointModelRX(),SE3::Random(),Inertia::Random(),"ff1");
      model.addBody(model.getBodyId("ff1"),JointModelRX(),SE3::Random(),Inertia::Random(),"root");

      model.addBody(model.getBodyId("root"),JointModelRX(),SE3::Random(),Inertia::Random(),"lleg1");
      model.addBody(model.getBodyId("lleg1"),JointModelRX(),SE3::Random(),Inertia::Random(),"lleg2");

      model.addBody(model.getBodyId("root"),JointModelRX(),SE3::Random(),Inertia::Random(),"rleg1");
      model.addBody(model.getBodyId("rleg1"),JointModelRX(),SE3::Random(),Inertia::Random(),"rleg2");

      model.addBody(model.getBodyId("root"),JointModelRX(),SE3::Random(),Inertia::Random(),"torso1");
      model.addBody(model.getBodyId("torso1"),JointModelRX(),SE3::Random(),Inertia::Random(),"chest");

      model.addBody(model.getBodyId("chest"),JointModelRX(),SE3::Random(),Inertia::Random(),"rarm1");
      model.addBody(model.getBodyId("rarm1"),JointModelRX(),SE3::Random(),Inertia::Random(),"rarm2");

      model.addBody(model.getBodyId("chest"),JointModelRX(),SE3::Random(),Inertia::Random(),"larm1");
      model.addBody(model.getBodyId("larm1"),JointModelRX(),SE3::Random(),Inertia::Random(),"larm2");
    }

    void humanoidSimple( Model& model, bool usingFF = true)
    {
      if(! usingFF )
	{
	  model.addBody(model.getBodyId("universe"),JointModelRX(),SE3::Random(),Inertia::Random(),"ff1");
	  model.addBody(model.getBodyId("ff1"),JointModelRX(),SE3::Random(),Inertia::Random(),"ff2");
	  model.addBody(model.getBodyId("ff2"),JointModelRX(),SE3::Random(),Inertia::Random(),"ff3");
	  model.addBody(model.getBodyId("ff3"),JointModelRX(),SE3::Random(),Inertia::Random(),"ff4");
	  model.addBody(model.getBodyId("ff4"),JointModelRX(),SE3::Random(),Inertia::Random(),"ff5");
	  model.addBody(model.getBodyId("ff5"),JointModelRX(),SE3::Random(),Inertia::Random(),"root");
	}
      else
	model.addBody(model.getBodyId("universe"),JointModelFreeFlyer(),SE3::Random(),Inertia::Random(),"root");

      model.addBody(model.getBodyId("root"),JointModelRX(),SE3::Random(),Inertia::Random(),"lleg1");
      model.addBody(model.getBodyId("lleg1"),JointModelRX(),SE3::Random(),Inertia::Random(),"lleg2");
      model.addBody(model.getBodyId("lleg2"),JointModelRX(),SE3::Random(),Inertia::Random(),"lleg3");
      model.addBody(model.getBodyId("lleg3"),JointModelRX(),SE3::Random(),Inertia::Random(),"lleg4");
      model.addBody(model.getBodyId("lleg4"),JointModelRX(),SE3::Random(),Inertia::Random(),"lleg5");
      model.addBody(model.getBodyId("lleg5"),JointModelRX(),SE3::Random(),Inertia::Random(),"lleg6");

      model.addBody(model.getBodyId("root"),JointModelRX(),SE3::Random(),Inertia::Random(),"rleg1");
      model.addBody(model.getBodyId("rleg1"),JointModelRX(),SE3::Random(),Inertia::Random(),"rleg2");
      model.addBody(model.getBodyId("rleg2"),JointModelRX(),SE3::Random(),Inertia::Random(),"rleg3");
      model.addBody(model.getBodyId("rleg3"),JointModelRX(),SE3::Random(),Inertia::Random(),"rleg4");
      model.addBody(model.getBodyId("rleg4"),JointModelRX(),SE3::Random(),Inertia::Random(),"rleg5");
      model.addBody(model.getBodyId("rleg5"),JointModelRX(),SE3::Random(),Inertia::Random(),"rleg6");

      model.addBody(model.getBodyId("root"),JointModelRX(),SE3::Random(),Inertia::Random(),"torso1");
      model.addBody(model.getBodyId("torso1"),JointModelRX(),SE3::Random(),Inertia::Random(),"chest");

      model.addBody(model.getBodyId("chest"),JointModelRX(),SE3::Random(),Inertia::Random(),"rarm1");
      model.addBody(model.getBodyId("rarm1"),JointModelRX(),SE3::Random(),Inertia::Random(),"rarm2");
      model.addBody(model.getBodyId("rarm2"),JointModelRX(),SE3::Random(),Inertia::Random(),"rarm3");
      model.addBody(model.getBodyId("rarm3"),JointModelRX(),SE3::Random(),Inertia::Random(),"rarm4");
      model.addBody(model.getBodyId("rarm4"),JointModelRX(),SE3::Random(),Inertia::Random(),"rarm5");
      model.addBody(model.getBodyId("rarm5"),JointModelRX(),SE3::Random(),Inertia::Random(),"rarm6");

      model.addBody(model.getBodyId("chest"),JointModelRX(),SE3::Random(),Inertia::Random(),"larm1");
      model.addBody(model.getBodyId("larm1"),JointModelRX(),SE3::Random(),Inertia::Random(),"larm2");
      model.addBody(model.getBodyId("larm2"),JointModelRX(),SE3::Random(),Inertia::Random(),"larm3");
      model.addBody(model.getBodyId("larm3"),JointModelRX(),SE3::Random(),Inertia::Random(),"larm4");
      model.addBody(model.getBodyId("larm4"),JointModelRX(),SE3::Random(),Inertia::Random(),"larm5");
      model.addBody(model.getBodyId("larm5"),JointModelRX(),SE3::Random(),Inertia::Random(),"larm6");
    }

  } // namespace buildModels
} // namespace se3

#endif // ifndef __se3_sample_models_hpp__
<commit_msg>Set FF to SE3::Identity in model-sample.<commit_after>#ifndef __se3_sample_models_hpp__
#define __se3_sample_models_hpp__

#include "pinocchio/multibody/model.hpp"

namespace se3
{
  namespace buildModels
  {

    void  humanoid2d( Model& model)
    {
      model.addBody(model.getBodyId("universe"),JointModelRX(),SE3::Identity(),Inertia::Random(),"ff1");
      model.addBody(model.getBodyId("ff1"),JointModelRY(),SE3::Identity(),Inertia::Random(),"root");

      model.addBody(model.getBodyId("root"),JointModelRZ(),SE3::Random(),Inertia::Random(),"lleg1");
      model.addBody(model.getBodyId("lleg1"),JointModelRY(),SE3::Random(),Inertia::Random(),"lleg2");

      model.addBody(model.getBodyId("root"),JointModelRZ(),SE3::Random(),Inertia::Random(),"rleg1");
      model.addBody(model.getBodyId("rleg1"),JointModelRY(),SE3::Random(),Inertia::Random(),"rleg2");

      model.addBody(model.getBodyId("root"),JointModelRY(),SE3::Random(),Inertia::Random(),"torso1");
      model.addBody(model.getBodyId("torso1"),JointModelRZ(),SE3::Random(),Inertia::Random(),"chest");

      model.addBody(model.getBodyId("chest"),JointModelRX(),SE3::Random(),Inertia::Random(),"rarm1");
      model.addBody(model.getBodyId("rarm1"),JointModelRZ(),SE3::Random(),Inertia::Random(),"rarm2");

      model.addBody(model.getBodyId("chest"),JointModelRX(),SE3::Random(),Inertia::Random(),"larm1");
      model.addBody(model.getBodyId("larm1"),JointModelRZ(),SE3::Random(),Inertia::Random(),"larm2");
    }

    void humanoidSimple( Model& model, bool usingFF = true)
    {
      if(! usingFF )
	{
	  model.addBody(model.getBodyId("universe"),JointModelRX(),SE3::Identity(),Inertia::Random(),"ff1");
	  model.addBody(model.getBodyId("ff1"),JointModelRY(),SE3::Identity(),Inertia::Random(),"ff2");
	  model.addBody(model.getBodyId("ff2"),JointModelRZ(),SE3::Identity(),Inertia::Random(),"ff3");
	  model.addBody(model.getBodyId("ff3"),JointModelRZ(),SE3::Random(),Inertia::Random(),"ff4");
	  model.addBody(model.getBodyId("ff4"),JointModelRY(),SE3::Identity(),Inertia::Random(),"ff5");
	  model.addBody(model.getBodyId("ff5"),JointModelRX(),SE3::Identity(),Inertia::Random(),"root");
	}
      else
	model.addBody(model.getBodyId("universe"),JointModelFreeFlyer(),SE3::Identity(),Inertia::Random(),"root");

      model.addBody(model.getBodyId("root"),JointModelRX(),SE3::Random(),Inertia::Random(),"lleg1");
      model.addBody(model.getBodyId("lleg1"),JointModelRX(),SE3::Random(),Inertia::Random(),"lleg2");
      model.addBody(model.getBodyId("lleg2"),JointModelRX(),SE3::Random(),Inertia::Random(),"lleg3");
      model.addBody(model.getBodyId("lleg3"),JointModelRX(),SE3::Random(),Inertia::Random(),"lleg4");
      model.addBody(model.getBodyId("lleg4"),JointModelRX(),SE3::Random(),Inertia::Random(),"lleg5");
      model.addBody(model.getBodyId("lleg5"),JointModelRX(),SE3::Random(),Inertia::Random(),"lleg6");

      model.addBody(model.getBodyId("root"),JointModelRX(),SE3::Random(),Inertia::Random(),"rleg1");
      model.addBody(model.getBodyId("rleg1"),JointModelRX(),SE3::Random(),Inertia::Random(),"rleg2");
      model.addBody(model.getBodyId("rleg2"),JointModelRX(),SE3::Random(),Inertia::Random(),"rleg3");
      model.addBody(model.getBodyId("rleg3"),JointModelRX(),SE3::Random(),Inertia::Random(),"rleg4");
      model.addBody(model.getBodyId("rleg4"),JointModelRX(),SE3::Random(),Inertia::Random(),"rleg5");
      model.addBody(model.getBodyId("rleg5"),JointModelRX(),SE3::Random(),Inertia::Random(),"rleg6");

      model.addBody(model.getBodyId("root"),JointModelRX(),SE3::Random(),Inertia::Random(),"torso1");
      model.addBody(model.getBodyId("torso1"),JointModelRX(),SE3::Random(),Inertia::Random(),"chest");

      model.addBody(model.getBodyId("chest"),JointModelRX(),SE3::Random(),Inertia::Random(),"rarm1");
      model.addBody(model.getBodyId("rarm1"),JointModelRX(),SE3::Random(),Inertia::Random(),"rarm2");
      model.addBody(model.getBodyId("rarm2"),JointModelRX(),SE3::Random(),Inertia::Random(),"rarm3");
      model.addBody(model.getBodyId("rarm3"),JointModelRX(),SE3::Random(),Inertia::Random(),"rarm4");
      model.addBody(model.getBodyId("rarm4"),JointModelRX(),SE3::Random(),Inertia::Random(),"rarm5");
      model.addBody(model.getBodyId("rarm5"),JointModelRX(),SE3::Random(),Inertia::Random(),"rarm6");

      model.addBody(model.getBodyId("chest"),JointModelRX(),SE3::Random(),Inertia::Random(),"larm1");
      model.addBody(model.getBodyId("larm1"),JointModelRX(),SE3::Random(),Inertia::Random(),"larm2");
      model.addBody(model.getBodyId("larm2"),JointModelRX(),SE3::Random(),Inertia::Random(),"larm3");
      model.addBody(model.getBodyId("larm3"),JointModelRX(),SE3::Random(),Inertia::Random(),"larm4");
      model.addBody(model.getBodyId("larm4"),JointModelRX(),SE3::Random(),Inertia::Random(),"larm5");
      model.addBody(model.getBodyId("larm5"),JointModelRX(),SE3::Random(),Inertia::Random(),"larm6");
    }

  } // namespace buildModels
} // namespace se3

#endif // ifndef __se3_sample_models_hpp__
<|endoftext|>


<commit_before>#include "BoundingBox.hpp"
#include "QuadKey.hpp"
#include "entities/Element.hpp"
#include "entities/Node.hpp"
#include "entities/Way.hpp"
#include "entities/Area.hpp"
#include "entities/Relation.hpp"
#include "index/ElementStore.hpp"
#include "index/ElementGeometryClipper.hpp"

using namespace utymap;
using namespace utymap::entities;
using namespace utymap::formats;

using namespace utymap::mapcss;

namespace {
    using PointLocation = utymap::index::ElementGeometryClipper::PointLocation;

    template<typename T>
    inline PointLocation setPath(const BoundingBox& bbox, const T& t, ClipperLib::Path& shape) {
        shape.reserve(t.coordinates.size());
        bool allInside = true;
        bool allOutside = true;
        for (const GeoCoordinate& coord : t.coordinates) {
            bool contains = bbox.contains(coord);
            allInside &= contains;
            allOutside &= !contains;

            auto x = static_cast<ClipperLib::cInt>(coord.longitude * utymap::index::ElementGeometryClipper::Scale);
            auto y = static_cast<ClipperLib::cInt>(coord.latitude * utymap::index::ElementGeometryClipper::Scale);
            shape.push_back(ClipperLib::IntPoint(x, y));
        }

        return allInside ? PointLocation::AllInside :
               (allOutside ? PointLocation::AllOutside : PointLocation::Mixed);
    }
}

namespace utymap { namespace index {

const double ElementGeometryClipper::Scale = 1E7;

void ElementGeometryClipper::clipAndCall(const Element& element, const QuadKey& quadKey, const BoundingBox& quadKeyBbox)
{
    quadKey_ = quadKey;
    quadKeyBbox_ = quadKeyBbox;
    element.accept(*this);
}

void ElementGeometryClipper:: visitNode(const Node& node)
{
    // here, node should be always in tile
    callback_(node, quadKey_);
}

void ElementGeometryClipper::visitWay(const Way& way)
{
    ClipperLib::Path wayShape;
    PointLocation pointLocation = setPath(quadKeyBbox_, way, wayShape);
    // 1. all geometry inside current quadkey: no need to truncate.
    if (pointLocation == PointLocation::AllInside) {
        callback_(way, quadKey_);
        return;
    }

    // 2. all geometry outside : way should be skipped
    if (pointLocation == PointLocation::AllOutside) {
        return;
    }

    ClipperLib::PolyTree solution;
    clipper_.AddPath(wayShape, ClipperLib::ptSubject, false);
    clipper_.AddPath(createPathFromBoundingBox(), ClipperLib::ptClip, true);
    clipper_.Execute(ClipperLib::ctIntersection, solution);
    clipper_.Clear();
    std::size_t count = static_cast<std::size_t>(solution.Total());

    // 3. way intersects border only once: store a copy with clipped geometry
    if (count == 1) {
        Way clippedWay;
        setData(clippedWay, way, solution.GetFirst()->Contour);
        callback_(clippedWay, quadKey_);
    }
        // 4. in this case, result should be stored as relation (collection of ways)
    else {
        Relation relation;
        relation.id = way.id;
        relation.tags = way.tags;
        relation.elements.reserve(count);
        ClipperLib::PolyNode* polyNode = solution.GetFirst();
        while (polyNode) {
            auto clippedWay = std::make_shared<Way>();
            clippedWay->id = way.id;
            setCoordinates(*clippedWay, polyNode->Contour);
            relation.elements.push_back(clippedWay);
            polyNode = polyNode->GetNext();
        }
        callback_(relation, quadKey_);
    }
}

void ElementGeometryClipper::visitArea(const Area& area)
{
    ClipperLib::Path areaShape;
    PointLocation pointLocation = setPath(quadKeyBbox_, area, areaShape);
    // 1. all geometry inside current quadkey: no need to truncate.
    if (pointLocation == PointLocation::AllInside) {
        callback_(area, quadKey_);
        return;
    }

    // 2. all geometry outside: skip
    if (pointLocation == PointLocation::AllOutside) {
        return;
    }

    ClipperLib::Paths solution;
    clipper_.AddPath(areaShape, ClipperLib::ptSubject, true);
    clipper_.AddPath(createPathFromBoundingBox(), ClipperLib::ptClip, true);
    clipper_.Execute(ClipperLib::ctIntersection, solution);
    clipper_.Clear();

    // 3. way intersects border only once: store a copy with clipped geometry
    if (solution.size() == 1) {
        Area clippedArea;
        setData(clippedArea, area, solution[0]);
        callback_(clippedArea, quadKey_);
    }
        // 4. in this case, result should be stored as relation (collection of areas)
    else {
        Relation relation;
        relation.id = area.id;
        relation.tags = area.tags;
        relation.elements.reserve(solution.size());
        for (auto it = solution.begin(); it != solution.end(); ++it) {
            auto clippedArea = std::make_shared<Area> ();
            clippedArea->id = area.id;
            setCoordinates(*clippedArea, *it);
            relation.elements.push_back(clippedArea);
        }
        callback_(relation, quadKey_);
    }
}

void ElementGeometryClipper::visitRelation(const Relation& relation)
{
    struct RelationVisitor : public ElementVisitor
    {
        RelationVisitor(const BoundingBox& quadKeyBbox, ClipperLib::Clipper& clipper) :
                bbox_(quadKeyBbox), clipper_(clipper) { }

        void visitNode(const Node& node)
        {
            // TODO
        }

        void visitWay(const Way& way)
        {
            ClipperLib::Path wayShape;
            setPath(bbox_, way, wayShape);
            clipper_.AddPath(wayShape, ClipperLib::ptSubject, false);
        }

        void visitArea(const Area& area)
        {
            ClipperLib::Path areaShape;
            setPath(bbox_, area, areaShape);
            clipper_.AddPath(areaShape, ClipperLib::ptSubject, true);
        }

        void visitRelation(const Relation& relation)
        {
            for (const auto& element : relation.elements) {
                element->accept(*this);
            }
        }

    private:
        const BoundingBox& bbox_;
        ClipperLib::Clipper& clipper_;

    } visitor(quadKeyBbox_, clipper_);

    relation.accept(visitor);

    // Process results
    ClipperLib::PolyTree solution;
    clipper_.AddPath(createPathFromBoundingBox(), ClipperLib::ptClip, true);
    clipper_.Execute(ClipperLib::ctIntersection, solution);
    clipper_.Clear();

    std::size_t count = static_cast<size_t>(solution.Total());
    // Do not store one result as relation
    if (count == 1) {
        ClipperLib::PolyNode* node = solution.GetFirst();
        if (node->IsOpen()) {
            Way way;
            setData(way, relation, node->Contour);
            callback_(way, quadKey_);
        }
        else {
            if (!node->IsHole()) {
                Area area;
                setData(area, relation, node->Contour);
                callback_(area, quadKey_);
            }
        }
    }
    else if (count > 1) {
        Relation newRelation;
        newRelation.id = relation.id;
        newRelation.tags = relation.tags;
        newRelation.elements.reserve(count);

        ClipperLib::PolyNode* polyNode = solution.GetFirst();
        while (polyNode) {
            if (polyNode->IsOpen()) {
                auto way = std::make_shared<Way>();
                setCoordinates(*way, polyNode->Contour);
                newRelation.elements.push_back(way);
            }
            else {
                auto area = std::make_shared<Area>();
                setCoordinates(*area, polyNode->Contour);
                newRelation.elements.push_back(area);
            }
            polyNode = polyNode->GetNext();
        }
        callback_(newRelation, quadKey_);
    }
}

ClipperLib::Path ElementGeometryClipper::createPathFromBoundingBox()
{
    double xMin = quadKeyBbox_.minPoint.longitude, yMin = quadKeyBbox_.minPoint.latitude,
            xMax = quadKeyBbox_.maxPoint.longitude, yMax = quadKeyBbox_.maxPoint.latitude;
    ClipperLib::Path rect;
    rect.push_back(ClipperLib::IntPoint(static_cast<ClipperLib::cInt>(xMin*Scale),
                                        static_cast<ClipperLib::cInt>(yMin*Scale)));

    rect.push_back(ClipperLib::IntPoint(static_cast<ClipperLib::cInt>(xMax*Scale),
                                        static_cast<ClipperLib::cInt>(yMin*Scale)));

    rect.push_back(ClipperLib::IntPoint(static_cast<ClipperLib::cInt>(xMax*Scale),
                                        static_cast<ClipperLib::cInt>(yMax*Scale)));

    rect.push_back(ClipperLib::IntPoint(static_cast<ClipperLib::cInt>(xMin*Scale),
                                        static_cast<ClipperLib::cInt>(yMax*Scale)));
    return std::move(rect);
}

}}
<commit_msg>core: fix issue with missing terrain regions<commit_after>#include "BoundingBox.hpp"
#include "QuadKey.hpp"
#include "entities/Element.hpp"
#include "entities/Node.hpp"
#include "entities/Way.hpp"
#include "entities/Area.hpp"
#include "entities/Relation.hpp"
#include "index/ElementStore.hpp"
#include "index/ElementGeometryClipper.hpp"

using namespace utymap;
using namespace utymap::entities;
using namespace utymap::formats;

using namespace utymap::mapcss;

namespace {
    using PointLocation = utymap::index::ElementGeometryClipper::PointLocation;

    template<typename T>
    inline PointLocation setPath(const BoundingBox& bbox, const T& t, ClipperLib::Path& shape) {
        shape.reserve(t.coordinates.size());
        bool allInside = true;
        bool allOutside = true;
        for (const GeoCoordinate& coord : t.coordinates) {
            bool contains = bbox.contains(coord);
            allInside &= contains;
            allOutside &= !contains;

            auto x = static_cast<ClipperLib::cInt>(coord.longitude * utymap::index::ElementGeometryClipper::Scale);
            auto y = static_cast<ClipperLib::cInt>(coord.latitude * utymap::index::ElementGeometryClipper::Scale);
            shape.push_back(ClipperLib::IntPoint(x, y));
        }

        return allInside ? PointLocation::AllInside :
               (allOutside ? PointLocation::AllOutside : PointLocation::Mixed);
    }
}

namespace utymap { namespace index {

const double ElementGeometryClipper::Scale = 1E7;

void ElementGeometryClipper::clipAndCall(const Element& element, const QuadKey& quadKey, const BoundingBox& quadKeyBbox)
{
    quadKey_ = quadKey;
    quadKeyBbox_ = quadKeyBbox;
    element.accept(*this);
}

void ElementGeometryClipper:: visitNode(const Node& node)
{
    // here, node should be always in tile
    callback_(node, quadKey_);
}

void ElementGeometryClipper::visitWay(const Way& way)
{
    ClipperLib::Path wayShape;
    PointLocation pointLocation = setPath(quadKeyBbox_, way, wayShape);
    // 1. all geometry inside current quadkey: no need to truncate.
    if (pointLocation == PointLocation::AllInside) {
        callback_(way, quadKey_);
        return;
    }

    // 2. all geometry outside : way should be skipped
    if (pointLocation == PointLocation::AllOutside) {
        return;
    }

    ClipperLib::PolyTree solution;
    clipper_.AddPath(wayShape, ClipperLib::ptSubject, false);
    clipper_.AddPath(createPathFromBoundingBox(), ClipperLib::ptClip, true);
    clipper_.Execute(ClipperLib::ctIntersection, solution);
    clipper_.Clear();
    std::size_t count = static_cast<std::size_t>(solution.Total());

    // 3. way intersects border only once: store a copy with clipped geometry
    if (count == 1) {
        Way clippedWay;
        setData(clippedWay, way, solution.GetFirst()->Contour);
        callback_(clippedWay, quadKey_);
    }
        // 4. in this case, result should be stored as relation (collection of ways)
    else {
        Relation relation;
        relation.id = way.id;
        relation.tags = way.tags;
        relation.elements.reserve(count);
        ClipperLib::PolyNode* polyNode = solution.GetFirst();
        while (polyNode) {
            auto clippedWay = std::make_shared<Way>();
            clippedWay->id = way.id;
            setCoordinates(*clippedWay, polyNode->Contour);
            relation.elements.push_back(clippedWay);
            polyNode = polyNode->GetNext();
        }
        callback_(relation, quadKey_);
    }
}

void ElementGeometryClipper::visitArea(const Area& area)
{
    ClipperLib::Path areaShape;
    PointLocation pointLocation = setPath(quadKeyBbox_, area, areaShape);
    // 1. all geometry inside current quadkey: no need to truncate.
    if (pointLocation == PointLocation::AllInside) {
        callback_(area, quadKey_);
        return;
    }

    // 2. all geometry outside: use geometry of quadkey
    if (pointLocation == PointLocation::AllOutside) {
        Area newArea;
        newArea.id = area.id;
        newArea.tags = area.tags;

        newArea.coordinates.reserve(4);
        newArea.coordinates.push_back(quadKeyBbox_.minPoint);
        newArea.coordinates.push_back(GeoCoordinate(quadKeyBbox_.maxPoint.latitude, quadKeyBbox_.minPoint.longitude));
        newArea.coordinates.push_back(quadKeyBbox_.maxPoint);
        newArea.coordinates.push_back(GeoCoordinate(quadKeyBbox_.minPoint.latitude, quadKeyBbox_.maxPoint.longitude));

        callback_(newArea, quadKey_);
        return;
    }

    ClipperLib::Paths solution;
    clipper_.AddPath(areaShape, ClipperLib::ptSubject, true);
    clipper_.AddPath(createPathFromBoundingBox(), ClipperLib::ptClip, true);
    clipper_.Execute(ClipperLib::ctIntersection, solution);
    clipper_.Clear();

    // 3. way intersects border only once: store a copy with clipped geometry
    if (solution.size() == 1) {
        Area clippedArea;
        setData(clippedArea, area, solution[0]);
        callback_(clippedArea, quadKey_);
    }
        // 4. in this case, result should be stored as relation (collection of areas)
    else {
        Relation relation;
        relation.id = area.id;
        relation.tags = area.tags;
        relation.elements.reserve(solution.size());
        for (auto it = solution.begin(); it != solution.end(); ++it) {
            auto clippedArea = std::make_shared<Area> ();
            clippedArea->id = area.id;
            setCoordinates(*clippedArea, *it);
            relation.elements.push_back(clippedArea);
        }
        callback_(relation, quadKey_);
    }
}

void ElementGeometryClipper::visitRelation(const Relation& relation)
{
    struct RelationVisitor : public ElementVisitor
    {
        RelationVisitor(const BoundingBox& quadKeyBbox, ClipperLib::Clipper& clipper) :
                bbox_(quadKeyBbox), clipper_(clipper) { }

        void visitNode(const Node& node)
        {
            // TODO
        }

        void visitWay(const Way& way)
        {
            ClipperLib::Path wayShape;
            setPath(bbox_, way, wayShape);
            clipper_.AddPath(wayShape, ClipperLib::ptSubject, false);
        }

        void visitArea(const Area& area)
        {
            ClipperLib::Path areaShape;
            setPath(bbox_, area, areaShape);
            clipper_.AddPath(areaShape, ClipperLib::ptSubject, true);
        }

        void visitRelation(const Relation& relation)
        {
            for (const auto& element : relation.elements) {
                element->accept(*this);
            }
        }

    private:
        const BoundingBox& bbox_;
        ClipperLib::Clipper& clipper_;

    } visitor(quadKeyBbox_, clipper_);

    relation.accept(visitor);

    // Process results
    ClipperLib::PolyTree solution;
    clipper_.AddPath(createPathFromBoundingBox(), ClipperLib::ptClip, true);
    clipper_.Execute(ClipperLib::ctIntersection, solution);
    clipper_.Clear();

    std::size_t count = static_cast<size_t>(solution.Total());
    // Do not store one result as relation
    if (count == 1) {
        ClipperLib::PolyNode* node = solution.GetFirst();
        if (node->IsOpen()) {
            Way way;
            setData(way, relation, node->Contour);
            callback_(way, quadKey_);
        }
        else {
            if (!node->IsHole()) {
                Area area;
                setData(area, relation, node->Contour);
                callback_(area, quadKey_);
            }
        }
    }
    else if (count > 1) {
        Relation newRelation;
        newRelation.id = relation.id;
        newRelation.tags = relation.tags;
        newRelation.elements.reserve(count);

        ClipperLib::PolyNode* polyNode = solution.GetFirst();
        while (polyNode) {
            if (polyNode->IsOpen()) {
                auto way = std::make_shared<Way>();
                setCoordinates(*way, polyNode->Contour);
                newRelation.elements.push_back(way);
            }
            else {
                auto area = std::make_shared<Area>();
                setCoordinates(*area, polyNode->Contour);
                newRelation.elements.push_back(area);
            }
            polyNode = polyNode->GetNext();
        }
        callback_(newRelation, quadKey_);
    }
}

ClipperLib::Path ElementGeometryClipper::createPathFromBoundingBox()
{
    double xMin = quadKeyBbox_.minPoint.longitude, yMin = quadKeyBbox_.minPoint.latitude,
            xMax = quadKeyBbox_.maxPoint.longitude, yMax = quadKeyBbox_.maxPoint.latitude;
    ClipperLib::Path rect;
    rect.push_back(ClipperLib::IntPoint(static_cast<ClipperLib::cInt>(xMin*Scale),
                                        static_cast<ClipperLib::cInt>(yMin*Scale)));

    rect.push_back(ClipperLib::IntPoint(static_cast<ClipperLib::cInt>(xMax*Scale),
                                        static_cast<ClipperLib::cInt>(yMin*Scale)));

    rect.push_back(ClipperLib::IntPoint(static_cast<ClipperLib::cInt>(xMax*Scale),
                                        static_cast<ClipperLib::cInt>(yMax*Scale)));

    rect.push_back(ClipperLib::IntPoint(static_cast<ClipperLib::cInt>(xMin*Scale),
                                        static_cast<ClipperLib::cInt>(yMax*Scale)));
    return std::move(rect);
}

}}
<|endoftext|>


<commit_before>/* ******************************************************************************
 *
 *
 * This program and the accompanying materials are made available under the
 * terms of the Apache License, Version 2.0 which is available at
 * https://www.apache.org/licenses/LICENSE-2.0.
 *
 *  See the NOTICE file distributed with this work for additional
 *  information regarding copyright ownership.
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 ******************************************************************************/

//
//  @author raver119@gmail.com
//

#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_shape_of)

#include <ops/declarable/CustomOperations.h>

namespace sd {
namespace ops {
CUSTOM_OP_IMPL(shape_of, 1, 1, false, 0, 0) {
  auto x = INPUT_VARIABLE(0);
  auto z = OUTPUT_VARIABLE(0);

  for (int e = 0; e < x->rankOf(); e++) z->p(e, x->sizeAt(e));

  STORE_RESULT(z);

  return sd::Status::OK;
};
DECLARE_SYN(shape, shape_of);

DECLARE_SHAPE_FN(shape_of) {
  auto inShape = inputShape->at(0);

  // LONG by default
  auto dtype = DataType::INT64;
  if (block.numI() > 0) dtype = DataTypeUtils::fromInt(INT_ARG(0));

  return SHAPELIST(ConstantShapeHelper::getInstance().vectorShapeInfo(shape::rank(inShape), dtype));
};

DECLARE_TYPES(shape_of) {
  getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_INTS});
}
#endif

#if NOT_EXCLUDED(set_shape)
CUSTOM_OP_IMPL(set_shape, 2, 1, true, 0, 0) {
  auto x = INPUT_VARIABLE(0);
  auto shape = INPUT_VARIABLE(1);
  auto z = OUTPUT_VARIABLE(0);
  REQUIRE_TRUE(shape->isVector() || shape->isScalar(), 0, "Shape must be either a scalar or a vector");
  auto newShapeInfo = ConstantShapeHelper::getInstance().createShapeInfo(x->dataType(), x->ordering(),
                                                                         shape->asVectorT<sd::LongType>());
  z->setShapeInfo(newShapeInfo);
  // if x and z aren't the same reference ensure the elements are the same.
  // this op should almost always be used in place and in very specific circumstances.
  if (x != z) {
    z->assign(x, true);
  }
  return sd::Status::OK;
};

DECLARE_SHAPE_FN(set_shape) {
  auto inShape = INPUT_VARIABLE(1);
  return SHAPELIST(inShape->shapeInfo());
};

DECLARE_TYPES(set_shape) {
  getOpDescriptor()
      ->setAllowedInputTypes(0, sd::DataType::ANY)
      ->setAllowedInputTypes(1, sd::DataType::INT64)
      ->setAllowedOutputTypes({sd::DataType::ANY});
}
}  // namespace ops
}  // namespace sd

#endif
<commit_msg>Update shape.cpp<commit_after>/* ******************************************************************************
 *
 *
 * This program and the accompanying materials are made available under the
 * terms of the Apache License, Version 2.0 which is available at
 * https://www.apache.org/licenses/LICENSE-2.0.
 *
 *  See the NOTICE file distributed with this work for additional
 *  information regarding copyright ownership.
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 ******************************************************************************/

//
//  @author raver119@gmail.com
//

#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_shape_of)

#include <ops/declarable/CustomOperations.h>

namespace sd {
namespace ops {
CUSTOM_OP_IMPL(shape_of, 1, 1, false, 0, 0) {
  auto x = INPUT_VARIABLE(0);
  auto z = OUTPUT_VARIABLE(0);

  for (int e = 0; e < x->rankOf(); e++) z->p(e, x->sizeAt(e));

  STORE_RESULT(z);

  return sd::Status::OK;
};
DECLARE_SYN(shape, shape_of);

DECLARE_SHAPE_FN(shape_of) {
  auto inShape = inputShape->at(0);

  // LONG by default
  auto dtype = DataType::INT64;
  if (block.numI() > 0) dtype = DataTypeUtils::fromInt(INT_ARG(0));

  return SHAPELIST(ConstantShapeHelper::getInstance().vectorShapeInfo(shape::rank(inShape), dtype));
};

DECLARE_TYPES(shape_of) {
  getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_INTS});
}
#endif

#if NOT_EXCLUDED(OP_set_shape)
CUSTOM_OP_IMPL(set_shape, 2, 1, true, 0, 0) {
  auto x = INPUT_VARIABLE(0);
  auto shape = INPUT_VARIABLE(1);
  auto z = OUTPUT_VARIABLE(0);
  REQUIRE_TRUE(shape->isVector() || shape->isScalar(), 0, "Shape must be either a scalar or a vector");
  auto newShapeInfo = ConstantShapeHelper::getInstance().createShapeInfo(x->dataType(), x->ordering(),
                                                                         shape->asVectorT<sd::LongType>());
  z->setShapeInfo(newShapeInfo);
  // if x and z aren't the same reference ensure the elements are the same.
  // this op should almost always be used in place and in very specific circumstances.
  if (x != z) {
    z->assign(x, true);
  }
  return sd::Status::OK;
};

DECLARE_SHAPE_FN(set_shape) {
  auto inShape = INPUT_VARIABLE(1);
  return SHAPELIST(inShape->shapeInfo());
};

DECLARE_TYPES(set_shape) {
  getOpDescriptor()
      ->setAllowedInputTypes(0, sd::DataType::ANY)
      ->setAllowedInputTypes(1, sd::DataType::INT64)
      ->setAllowedOutputTypes({sd::DataType::ANY});
}
}  // namespace ops
}  // namespace sd

#endif
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////
//
// File NektarUnivTypeDefs.hpp
//
// For more information, please see: http://www.nektar.info
//
// The MIT License
//
// Copyright (c) 2006 Scientific Computing and Imaging Institute,
// University of Utah (USA) and Department of Aeronautics, Imperial
// College London (UK).
//
// License for the specific language governing rights and limitations under
// 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.
//
// Description: Universal type defines  in the Nektar Library
//
///////////////////////////////////////////////////////////////////////////////

#ifndef  NEKTARUNIVTYPEDEF_HPP
#define  NEKTARUNIVTYPEDEF_HPP

#include <boost/multi_array.hpp>
#include <boost/shared_ptr.hpp>
#include <vector>

namespace Nektar
{
    typedef double NekDouble;

    enum Dimension
    {
        OneD = 1,
        TwoD = 2,
        ThreeD = 3
    };

} //end of namespace

#endif

/***
$Log: NektarUnivTypeDefs.hpp,v $
Revision 1.10  2007/07/20 00:39:54  bnelson
Replaced boost::shared_ptr with Nektar::ptr

Revision 1.9  2007/05/14 23:47:43  bnelson
Removed old SharedArray typedefs.  Added new Dimension enumeration.

Revision 1.8  2007/04/29 00:31:12  jfrazier
Continued conversion to multi_arrays.

Revision 1.7  2007/04/26 21:52:09  jfrazier
Converted to new multi_array implementation.

Revision 1.6  2007/04/10 14:00:44  sherwin
Update to include SharedArray in all 2D element (including Nodal tris). Have also remvoed all new and double from 2D shapes in StdRegions

Revision 1.5  2007/03/31 15:37:51  bnelson
Removed boost::shared_array.hpp

Revision 1.4  2007/03/29 18:44:11  bnelson
Replaced boost::shared_array with SharedArray

Revision 1.3  2007/03/20 13:48:05  sherwin
Compiling version

Revision 1.2  2007/03/20 12:27:39  sherwin
Changed shared_ptr to shared_array

Revision 1.1  2007/03/20 11:56:25  sherwin
.

**/
<commit_msg>Added enumerations for the 3 principal directions. These are to be used in GetD(Direction).<commit_after>///////////////////////////////////////////////////////////////////////////////
//
// File NektarUnivTypeDefs.hpp
//
// For more information, please see: http://www.nektar.info
//
// The MIT License
//
// Copyright (c) 2006 Scientific Computing and Imaging Institute,
// University of Utah (USA) and Department of Aeronautics, Imperial
// College London (UK).
//
// License for the specific language governing rights and limitations under
// 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.
//
// Description: Universal type defines  in the Nektar Library
//
///////////////////////////////////////////////////////////////////////////////

#ifndef  NEKTARUNIVTYPEDEF_HPP
#define  NEKTARUNIVTYPEDEF_HPP

#include <boost/multi_array.hpp>
#include <boost/shared_ptr.hpp>
#include <vector>

namespace Nektar
{
    typedef double NekDouble;

    enum Dimension
    {
        OneD = 1,
        TwoD = 2,
        ThreeD = 3
    };

    enum Direction
    {
        xDir = 0,
        yDir = 1,
        zDir = 2
    };

} //end of namespace

#endif

/***
$Log: NektarUnivTypeDefs.hpp,v $
Revision 1.11  2007/07/22 23:03:24  bnelson
Backed out Nektar::ptr.

Revision 1.10  2007/07/20 00:39:54  bnelson
Replaced boost::shared_ptr with Nektar::ptr

Revision 1.9  2007/05/14 23:47:43  bnelson
Removed old SharedArray typedefs.  Added new Dimension enumeration.

Revision 1.8  2007/04/29 00:31:12  jfrazier
Continued conversion to multi_arrays.

Revision 1.7  2007/04/26 21:52:09  jfrazier
Converted to new multi_array implementation.

Revision 1.6  2007/04/10 14:00:44  sherwin
Update to include SharedArray in all 2D element (including Nodal tris). Have also remvoed all new and double from 2D shapes in StdRegions

Revision 1.5  2007/03/31 15:37:51  bnelson
Removed boost::shared_array.hpp

Revision 1.4  2007/03/29 18:44:11  bnelson
Replaced boost::shared_array with SharedArray

Revision 1.3  2007/03/20 13:48:05  sherwin
Compiling version

Revision 1.2  2007/03/20 12:27:39  sherwin
Changed shared_ptr to shared_array

Revision 1.1  2007/03/20 11:56:25  sherwin
.

**/
<|endoftext|>


<commit_before>// Copyright (c) 2017 ASMlover. 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 ofconditions 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 materialsprovided with the
//    distribution.
//
// 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 HOLDER 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 <Chaos/Types.h>

int main(int argc, char* argv[]) {
  CHAOS_UNUSED(argc), CHAOS_UNUSED(argv);

  return 0;
}
<commit_msg>:white_check_mark: tests(ConcurrencyCopy): add unittest for concurrency copying gc<commit_after>// Copyright (c) 2017 ASMlover. 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 ofconditions 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 materialsprovided with the
//    distribution.
//
// 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 HOLDER 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 <Chaos/Types.h>
#include "concurrency_copy.h"

int main(int argc, char* argv[]) {
  CHAOS_UNUSED(argc), CHAOS_UNUSED(argv);

  constexpr int kCount = 1000;
  constexpr int kReleaseCount = 20;
  constexpr int kCreateCount = kReleaseCount * 3;
  for (auto i = 0; i < kCount; ++i) {
    for (auto j = 0; j < kCreateCount; ++j) {
      if ((j + 1) % 3 == 0) {
        auto* second = gc::ConcurrencyCopy::get_instance().fetch_out();
        auto* first = gc::ConcurrencyCopy::get_instance().fetch_out();
        gc::ConcurrencyCopy::get_instance().put_in(first, second);
      }
      else {
        gc::ConcurrencyCopy::get_instance().put_in(i * j);
      }
    }

    for (auto j = 0; j < kReleaseCount; ++j)
      gc::ConcurrencyCopy::get_instance().fetch_out();
  }
  gc::ConcurrencyCopy::get_instance().collect();

  return 0;
}
<|endoftext|>


<commit_before>/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2014 BMW Car IT GmbH
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
#include "gtest/gtest.h"
#include "gmock/gmock.h"

#include "joynr/PrivateCopyAssign.h"

#include "joynr/MessageQueue.h"
#include "joynr/Timer.h"

#include <chrono>
#include <cstdint>

using namespace joynr;

class MessageQueueTest : public ::testing::Test {
public:
    MessageQueueTest()
        : messageQueue(),
          cleanerTimer(),
          expiryDate(std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()) + std::chrono::milliseconds(100))
    {
    }

    ~MessageQueueTest() = default;

    void SetUp()
    {
        cleanerTimer.addTimer(
            [this](joynr::Timer::TimerId) {
                this->messageQueue.removeOutdatedMessages();
            },
            [](Timer::TimerId) { },
            50,
            true
        );
    }

    void TearDown()
    {
        cleanerTimer.shutdown();
    }

protected:
    MessageQueue messageQueue;
    Timer cleanerTimer;
    JoynrTimePoint expiryDate;

private:
    DISALLOW_COPY_AND_ASSIGN(MessageQueueTest);
};

TEST_F(MessageQueueTest, initialQueueIsEmpty) {
    EXPECT_EQ(messageQueue.getQueueLength(), 0);
}

TEST_F(MessageQueueTest, addMultipleMessages) {
    JoynrMessage msg1;
    msg1.setHeaderExpiryDate(expiryDate);
    EXPECT_EQ(messageQueue.queueMessage(msg1), 1);
    JoynrMessage msg2;
    msg2.setHeaderExpiryDate(expiryDate);
    EXPECT_EQ(messageQueue.queueMessage(msg2), 2);
    JoynrMessage msg3;
    msg3.setHeaderExpiryDate(expiryDate);
    EXPECT_EQ(messageQueue.queueMessage(msg3), 3);
    JoynrMessage msg4;
    msg4.setHeaderExpiryDate(expiryDate);
    EXPECT_EQ(messageQueue.queueMessage(msg4), 4);
}

TEST_F(MessageQueueTest, queueDequeueMessages) {
    // add messages to the queue
    JoynrMessage msg1;
    msg1.setHeaderTo("TEST1");
    msg1.setHeaderExpiryDate(expiryDate);
    messageQueue.queueMessage(msg1);

    JoynrMessage msg2;
    msg2.setHeaderTo("TEST2");
    msg2.setHeaderExpiryDate(expiryDate);
    messageQueue.queueMessage(msg2);
    EXPECT_EQ(messageQueue.getQueueLength(), 2);

    // get messages from queue
    MessageQueueItem* item = messageQueue.getNextMessageForParticipant("TEST1");
    EXPECT_EQ(item->getContent(), msg1);
    EXPECT_EQ(messageQueue.getQueueLength(), 1);

    item = messageQueue.getNextMessageForParticipant("TEST2");
    EXPECT_EQ(item->getContent(), msg2);
    EXPECT_EQ(messageQueue.getQueueLength(), 0);
}

TEST_F(MessageQueueTest, queueDequeueMultipleMessagesForOneParticipant) {
    // add messages to the queue
    JoynrMessage msg;
    msg.setHeaderTo("TEST");
    msg.setHeaderExpiryDate(expiryDate);
    messageQueue.queueMessage(msg);
    messageQueue.queueMessage(msg);
    EXPECT_EQ(messageQueue.getQueueLength(), 2);

    // get messages from queue
    MessageQueueItem* item = messageQueue.getNextMessageForParticipant("TEST");
    EXPECT_EQ(item->getContent(), msg);
    EXPECT_EQ(messageQueue.getQueueLength(), 1);

    item = messageQueue.getNextMessageForParticipant("TEST");
    EXPECT_EQ(item->getContent(), msg);
    EXPECT_EQ(messageQueue.getQueueLength(), 0);
}

TEST_F(MessageQueueTest, dequeueInvalidParticipantId) {
    EXPECT_FALSE(messageQueue.getNextMessageForParticipant("TEST"));
}
<commit_msg>[C++] Remove timer from MessageQueueTest<commit_after>/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2014 BMW Car IT GmbH
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
#include "gtest/gtest.h"
#include "gmock/gmock.h"

#include "joynr/PrivateCopyAssign.h"

#include "joynr/MessageQueue.h"

#include <chrono>
#include <cstdint>

using namespace joynr;

class MessageQueueTest : public ::testing::Test {
public:
    MessageQueueTest()
        : messageQueue(),
          expiryDate(std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()) + std::chrono::milliseconds(100))
    {
    }

    ~MessageQueueTest() = default;

protected:
    MessageQueue messageQueue;
    JoynrTimePoint expiryDate;

private:
    DISALLOW_COPY_AND_ASSIGN(MessageQueueTest);
};

TEST_F(MessageQueueTest, initialQueueIsEmpty) {
    EXPECT_EQ(messageQueue.getQueueLength(), 0);
}

TEST_F(MessageQueueTest, addMultipleMessages) {
    JoynrMessage msg1;
    msg1.setHeaderExpiryDate(expiryDate);
    EXPECT_EQ(messageQueue.queueMessage(msg1), 1);
    JoynrMessage msg2;
    msg2.setHeaderExpiryDate(expiryDate);
    EXPECT_EQ(messageQueue.queueMessage(msg2), 2);
    JoynrMessage msg3;
    msg3.setHeaderExpiryDate(expiryDate);
    EXPECT_EQ(messageQueue.queueMessage(msg3), 3);
    JoynrMessage msg4;
    msg4.setHeaderExpiryDate(expiryDate);
    EXPECT_EQ(messageQueue.queueMessage(msg4), 4);
}

TEST_F(MessageQueueTest, queueDequeueMessages) {
    // add messages to the queue
    JoynrMessage msg1;
    msg1.setHeaderTo("TEST1");
    msg1.setHeaderExpiryDate(expiryDate);
    messageQueue.queueMessage(msg1);

    JoynrMessage msg2;
    msg2.setHeaderTo("TEST2");
    msg2.setHeaderExpiryDate(expiryDate);
    messageQueue.queueMessage(msg2);
    EXPECT_EQ(messageQueue.getQueueLength(), 2);

    // get messages from queue
    MessageQueueItem* item = messageQueue.getNextMessageForParticipant("TEST1");
    EXPECT_EQ(item->getContent(), msg1);
    EXPECT_EQ(messageQueue.getQueueLength(), 1);

    item = messageQueue.getNextMessageForParticipant("TEST2");
    EXPECT_EQ(item->getContent(), msg2);
    EXPECT_EQ(messageQueue.getQueueLength(), 0);
}

TEST_F(MessageQueueTest, queueDequeueMultipleMessagesForOneParticipant) {
    // add messages to the queue
    JoynrMessage msg;
    msg.setHeaderTo("TEST");
    msg.setHeaderExpiryDate(expiryDate);
    messageQueue.queueMessage(msg);
    messageQueue.queueMessage(msg);
    EXPECT_EQ(messageQueue.getQueueLength(), 2);

    // get messages from queue
    MessageQueueItem* item = messageQueue.getNextMessageForParticipant("TEST");
    EXPECT_EQ(item->getContent(), msg);
    EXPECT_EQ(messageQueue.getQueueLength(), 1);

    item = messageQueue.getNextMessageForParticipant("TEST");
    EXPECT_EQ(item->getContent(), msg);
    EXPECT_EQ(messageQueue.getQueueLength(), 0);
}

TEST_F(MessageQueueTest, dequeueInvalidParticipantId) {
    EXPECT_FALSE(messageQueue.getNextMessageForParticipant("TEST"));
}
<|endoftext|>


<commit_before>/****************************************************************************
** Copyright (c) 2000-2003 Wayne Roth
** Copyright (c) 2004-2007 Stefan Sander
** Copyright (c) 2007 Michal Policht
** Copyright (c) 2008 Brandon Fosdick
** Copyright (c) 2009-2010 Liam Staskawicz
** Copyright (c) 2011 Debao Zhang
** Copyright (c) 2012 Doug Brown
** All right reserved.
** Web: http://code.google.com/p/qextserialport/
**
** 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.
**
****************************************************************************/

#include "qextserialenumerator.h"
#include "qextserialenumerator_p.h"
#include <QtCore/QDebug>
#include <QtCore/QStringList>
#include <QtCore/QDir>

void QextSerialEnumeratorPrivate::platformSpecificInit()
{
#ifndef QESP_NO_UDEV
    monitor = NULL;
    notifierFd = -1;
    notifier = NULL;

    udev = udev_new();
    if (!udev)
        qCritical() << "Unable to initialize udev notifications";
#endif
}

void QextSerialEnumeratorPrivate::platformSpecificDestruct()
{
#ifndef QESP_NO_UDEV
    if (notifier) {
        notifier->setEnabled(false);
        delete notifier;
    }

    if (monitor)
        udev_monitor_unref(monitor);

    if (udev)
        udev_unref(udev);
#endif
}

#ifndef QESP_NO_UDEV
static QextPortInfo portInfoFromDevice(struct udev_device *dev)
{
    QString vendor = QString::fromLatin1(udev_device_get_property_value(dev, "ID_VENDOR_ID"));
    QString product = QString::fromLatin1(udev_device_get_property_value(dev, "ID_MODEL_ID"));

    QextPortInfo pi;
    pi.vendorID = vendor.toInt(0, 16);
    pi.productID = product.toInt(0, 16);
    pi.portName = QString::fromLatin1(udev_device_get_devnode(dev));
    pi.physName = pi.portName;

    return pi;
}
#endif

QList<QextPortInfo> QextSerialEnumeratorPrivate::getPorts_sys()
{
    QList<QextPortInfo> infoList;
#ifndef QESP_NO_UDEV
    struct udev *ud = udev_new();
    if (!ud) {
        qCritical() << "Unable to enumerate ports because udev is not initialized.";
        return infoList;
    }

    struct udev_enumerate *enumerate = udev_enumerate_new(ud);
    udev_enumerate_add_match_subsystem(enumerate, "tty");
    udev_enumerate_scan_devices(enumerate);
    struct udev_list_entry *list = udev_enumerate_get_list_entry(enumerate);
    struct udev_list_entry *entry;
    udev_list_entry_foreach(entry, list) {
        const char *path;
        struct udev_device *dev;

        // Have to grab the actual udev device here...
        path = udev_list_entry_get_name(entry);
        dev = udev_device_new_from_syspath(ud, path);

        infoList.append(portInfoFromDevice(dev));

        // Done with this device
        udev_device_unref(dev);
    }
    // Done with the list and this udev
    udev_enumerate_unref(enumerate);
    udev_unref(ud);
#else
    QStringList portNamePrefixes, portNameList;
    portNamePrefixes << QLatin1String("ttyS*"); // list normal serial ports first

    QDir dir(QLatin1String("/dev"));
    portNameList = dir.entryList(portNamePrefixes, (QDir::System | QDir::Files), QDir::Name);

    // remove the values which are not serial ports for e.g.  /dev/ttysa
    for (int i = 0; i < portNameList.size(); i++) {
        bool ok;
        QString current = portNameList.at(i);
        // remove the ttyS part, and check, if the other part is a number
        current.remove(0,4).toInt(&ok, 10);
        if (!ok) {
            portNameList.removeAt(i);
            i--;
        }
    }

    // get the non standard serial ports names
    // (USB-serial, bluetooth-serial, 18F PICs, and so on)
    // if you know an other name prefix for serial ports please let us know
    portNamePrefixes.clear();
    portNamePrefixes << QLatin1String("ttyACM*") << QLatin1String("ttyUSB*") << QLatin1String("rfcomm*");
    portNamePrefixes << QLatin1String("serial/by-id/usb-*")
    portNameList += dir.entryList(portNamePrefixes, (QDir::System | QDir::Files), QDir::Name);

    foreach (QString str , portNameList) {
        QextPortInfo inf;
        inf.physName = QLatin1String("/dev/")+str;
        inf.portName = str;

        if (str.contains(QLatin1String("ttyS"))) {
            inf.friendName = QLatin1String("Serial port ")+str.remove(0, 4);
        }
        else if (str.contains(QLatin1String("ttyUSB"))) {
            inf.friendName = QLatin1String("USB-serial adapter ")+str.remove(0, 6);
        }
        else if (str.contains(QLatin1String("rfcomm"))) {
            inf.friendName = QLatin1String("Bluetooth-serial adapter ")+str.remove(0, 6);
        }
        else if (str.contains(QLatin1String("serial/by-id/usb-"))) {
            inf.friendName = QLatin1String("USB-serial adapter ")+str.remove(0, 17);
        }
        inf.enumName = QLatin1String("/dev"); // is there a more helpful name for this?
        infoList.append(inf);
    }
#endif

    return infoList;
}

bool QextSerialEnumeratorPrivate::setUpNotifications_sys(bool setup)
{
    Q_UNUSED(setup);
#ifndef QESP_NO_UDEV
    Q_Q(QextSerialEnumerator);
    if (!udev) {
        qCritical() << "Unable to initialize notifications because udev is not initialized.";
        return false;
    }

    // Emit signals immediately for devices already connected (Windows version seems to behave
    // this way)
    foreach (QextPortInfo i, getPorts_sys())
        Q_EMIT q->deviceDiscovered(i);

    // Look for tty devices from udev.
    monitor = udev_monitor_new_from_netlink(udev, "udev");
    udev_monitor_filter_add_match_subsystem_devtype(monitor, "tty", NULL);
    udev_monitor_enable_receiving(monitor);
    notifierFd = udev_monitor_get_fd(monitor);
    notifier = new QSocketNotifier(notifierFd, QSocketNotifier::Read);
    q->connect(notifier, SIGNAL(activated(int)), q, SLOT(_q_deviceEvent()));
    notifier->setEnabled(true);

    return true;
#else
    return false;
#endif
}

#ifndef QESP_NO_UDEV
void QextSerialEnumeratorPrivate::_q_deviceEvent()
{
    Q_Q(QextSerialEnumerator);
    struct udev_device *dev = udev_monitor_receive_device(monitor);
    if (dev) {
        QextPortInfo pi = portInfoFromDevice(dev);
        QLatin1String action(udev_device_get_action(dev));

        if (action == QLatin1String("add"))
            Q_EMIT q->deviceDiscovered(pi);
        else if (action == QLatin1String("remove"))
            Q_EMIT q->deviceRemoved(pi);

        udev_device_unref(dev);
    }
}
#endif
<commit_msg>Fixed typo<commit_after>/****************************************************************************
** Copyright (c) 2000-2003 Wayne Roth
** Copyright (c) 2004-2007 Stefan Sander
** Copyright (c) 2007 Michal Policht
** Copyright (c) 2008 Brandon Fosdick
** Copyright (c) 2009-2010 Liam Staskawicz
** Copyright (c) 2011 Debao Zhang
** Copyright (c) 2012 Doug Brown
** All right reserved.
** Web: http://code.google.com/p/qextserialport/
**
** 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.
**
****************************************************************************/

#include "qextserialenumerator.h"
#include "qextserialenumerator_p.h"
#include <QtCore/QDebug>
#include <QtCore/QStringList>
#include <QtCore/QDir>

void QextSerialEnumeratorPrivate::platformSpecificInit()
{
#ifndef QESP_NO_UDEV
    monitor = NULL;
    notifierFd = -1;
    notifier = NULL;

    udev = udev_new();
    if (!udev)
        qCritical() << "Unable to initialize udev notifications";
#endif
}

void QextSerialEnumeratorPrivate::platformSpecificDestruct()
{
#ifndef QESP_NO_UDEV
    if (notifier) {
        notifier->setEnabled(false);
        delete notifier;
    }

    if (monitor)
        udev_monitor_unref(monitor);

    if (udev)
        udev_unref(udev);
#endif
}

#ifndef QESP_NO_UDEV
static QextPortInfo portInfoFromDevice(struct udev_device *dev)
{
    QString vendor = QString::fromLatin1(udev_device_get_property_value(dev, "ID_VENDOR_ID"));
    QString product = QString::fromLatin1(udev_device_get_property_value(dev, "ID_MODEL_ID"));

    QextPortInfo pi;
    pi.vendorID = vendor.toInt(0, 16);
    pi.productID = product.toInt(0, 16);
    pi.portName = QString::fromLatin1(udev_device_get_devnode(dev));
    pi.physName = pi.portName;

    return pi;
}
#endif

QList<QextPortInfo> QextSerialEnumeratorPrivate::getPorts_sys()
{
    QList<QextPortInfo> infoList;
#ifndef QESP_NO_UDEV
    struct udev *ud = udev_new();
    if (!ud) {
        qCritical() << "Unable to enumerate ports because udev is not initialized.";
        return infoList;
    }

    struct udev_enumerate *enumerate = udev_enumerate_new(ud);
    udev_enumerate_add_match_subsystem(enumerate, "tty");
    udev_enumerate_scan_devices(enumerate);
    struct udev_list_entry *list = udev_enumerate_get_list_entry(enumerate);
    struct udev_list_entry *entry;
    udev_list_entry_foreach(entry, list) {
        const char *path;
        struct udev_device *dev;

        // Have to grab the actual udev device here...
        path = udev_list_entry_get_name(entry);
        dev = udev_device_new_from_syspath(ud, path);

        infoList.append(portInfoFromDevice(dev));

        // Done with this device
        udev_device_unref(dev);
    }
    // Done with the list and this udev
    udev_enumerate_unref(enumerate);
    udev_unref(ud);
#else
    QStringList portNamePrefixes, portNameList;
    portNamePrefixes << QLatin1String("ttyS*"); // list normal serial ports first

    QDir dir(QLatin1String("/dev"));
    portNameList = dir.entryList(portNamePrefixes, (QDir::System | QDir::Files), QDir::Name);

    // remove the values which are not serial ports for e.g.  /dev/ttysa
    for (int i = 0; i < portNameList.size(); i++) {
        bool ok;
        QString current = portNameList.at(i);
        // remove the ttyS part, and check, if the other part is a number
        current.remove(0,4).toInt(&ok, 10);
        if (!ok) {
            portNameList.removeAt(i);
            i--;
        }
    }

    // get the non standard serial ports names
    // (USB-serial, bluetooth-serial, 18F PICs, and so on)
    // if you know an other name prefix for serial ports please let us know
    portNamePrefixes.clear();
    portNamePrefixes << QLatin1String("ttyACM*") << QLatin1String("ttyUSB*") << QLatin1String("rfcomm*");
    portNamePrefixes << QLatin1String("serial/by-id/usb-*");
    portNameList += dir.entryList(portNamePrefixes, (QDir::System | QDir::Files), QDir::Name);

    foreach (QString str , portNameList) {
        QextPortInfo inf;
        inf.physName = QLatin1String("/dev/")+str;
        inf.portName = str;

        if (str.contains(QLatin1String("ttyS"))) {
            inf.friendName = QLatin1String("Serial port ")+str.remove(0, 4);
        }
        else if (str.contains(QLatin1String("ttyUSB"))) {
            inf.friendName = QLatin1String("USB-serial adapter ")+str.remove(0, 6);
        }
        else if (str.contains(QLatin1String("rfcomm"))) {
            inf.friendName = QLatin1String("Bluetooth-serial adapter ")+str.remove(0, 6);
        }
        else if (str.contains(QLatin1String("serial/by-id/usb-"))) {
            inf.friendName = QLatin1String("USB-serial adapter ")+str.remove(0, 17);
        }
        inf.enumName = QLatin1String("/dev"); // is there a more helpful name for this?
        infoList.append(inf);
    }
#endif

    return infoList;
}

bool QextSerialEnumeratorPrivate::setUpNotifications_sys(bool setup)
{
    Q_UNUSED(setup);
#ifndef QESP_NO_UDEV
    Q_Q(QextSerialEnumerator);
    if (!udev) {
        qCritical() << "Unable to initialize notifications because udev is not initialized.";
        return false;
    }

    // Emit signals immediately for devices already connected (Windows version seems to behave
    // this way)
    foreach (QextPortInfo i, getPorts_sys())
        Q_EMIT q->deviceDiscovered(i);

    // Look for tty devices from udev.
    monitor = udev_monitor_new_from_netlink(udev, "udev");
    udev_monitor_filter_add_match_subsystem_devtype(monitor, "tty", NULL);
    udev_monitor_enable_receiving(monitor);
    notifierFd = udev_monitor_get_fd(monitor);
    notifier = new QSocketNotifier(notifierFd, QSocketNotifier::Read);
    q->connect(notifier, SIGNAL(activated(int)), q, SLOT(_q_deviceEvent()));
    notifier->setEnabled(true);

    return true;
#else
    return false;
#endif
}

#ifndef QESP_NO_UDEV
void QextSerialEnumeratorPrivate::_q_deviceEvent()
{
    Q_Q(QextSerialEnumerator);
    struct udev_device *dev = udev_monitor_receive_device(monitor);
    if (dev) {
        QextPortInfo pi = portInfoFromDevice(dev);
        QLatin1String action(udev_device_get_action(dev));

        if (action == QLatin1String("add"))
            Q_EMIT q->deviceDiscovered(pi);
        else if (action == QLatin1String("remove"))
            Q_EMIT q->deviceRemoved(pi);

        udev_device_unref(dev);
    }
}
#endif
<|endoftext|>